Skip to content

feat: new button near cart#141

Merged
hmbanan666 merged 1 commit into
mainfrom
average-button
Sep 9, 2025
Merged

feat: new button near cart#141
hmbanan666 merged 1 commit into
mainfrom
average-button

Conversation

@hmbanan666
Copy link
Copy Markdown
Collaborator

@hmbanan666 hmbanan666 commented Sep 9, 2025

Summary by CodeRabbit

  • New Features

    • Added an Average Progress button in the catalog with a donut indicator, gift icon, vibration feedback, and a promo drawer.
    • Updated top navigation: new CatalogCart, AverageProgress, and Categories buttons.
    • Introduced a call confirmation popup with options to copy the number or place a call.
  • Style

    • Refined Cart button visuals; title hides when the Average Progress button is shown.
    • Adjusted animation timing for smoother interactions.

@hmbanan666 hmbanan666 self-assigned this Sep 9, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 9, 2025

Walkthrough

Replaces top-bar buttons in Navigation with catalog-specific buttons. Adds a new AverageProgressButton component with a donut progress indicator and drawer. Updates CartButton to hide title when the average-progress button is shown. Extends useNavigation to expose isAverageProgressButtonShown. Changes menu call flow to a showPopup confirmation and branching actions.

Changes

Cohort / File(s) Summary
Navigation top-bar composition
apps/storefront-telegram/app/components/Navigation.vue
Replaced CartButton and CatalogCategoriesNavigator with CatalogCartButton, CatalogAverageProgressButton, and CatalogCategoriesButton in sequence.
Catalog buttons
apps/storefront-telegram/app/components/catalog/AverageProgressButton.vue, apps/storefront-telegram/app/components/catalog/CartButton.vue
New AverageProgressButton: donut progress, gift overlay, drawer toggle with vibration, periodic randomized progress, syncs navigation visibility. CartButton: minor class tweaks; hides title when isAverageProgressButtonShown is true; imports new state from useNavigation.
Navigation composable
apps/storefront-telegram/app/composables/useNavigation.ts
Adds computed isAverageProgressButtonShown mirroring isCatalogPage; included in returned object. Public API of composable expanded.
Menu call flow
apps/storefront-telegram/app/pages/menu.vue
Replaced openLink path with showPopup: availability check, popup with copy/recall/close; branches to copy to clipboard or open tel: URL based on buttonId.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant MenuPage as Menu Page
  participant SDK as SDK showPopup
  participant Clipboard as Clipboard
  participant Browser as Browser

  User->>MenuPage: Tap "Call"
  Note right of MenuPage: Trigger vibration (unchanged)
  MenuPage->>SDK: showPopup.isAvailable()
  alt Available
    MenuPage->>SDK: showPopup({ title, message, buttons:[copy, recall, close] })
    SDK-->>MenuPage: buttonId
    alt buttonId == "copy"
      MenuPage->>Clipboard: writeText(formattedNumber)
    else buttonId == "recall"
      MenuPage->>Browser: window.open("tel:+...") 
    else close/other
      Note over MenuPage: No further action
    end
  else Not available
    Note over MenuPage: Skip popup (no call flow here)
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant AvgBtn as AverageProgressButton
  participant Nav as useNavigation
  participant Drawer as UDrawer
  participant Timer as Interval(4s)

  Timer-->>AvgBtn: Update progress (0..99)
  User->>AvgBtn: Click button
  AvgBtn->>AvgBtn: useFeedback().vibrate()
  AvgBtn->>Drawer: Toggle open (v-model:open)
  AvgBtn->>Nav: isNavigationShown = !isDrawerOpened
  Note over AvgBtn,Drawer: Donut + gift overlay rendered when isAverageProgressButtonShown
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks (2 warnings, 1 inconclusive)

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request currently lacks a substantive description summarizing the changes made to the Navigation component, the new AverageProgressButton, CartButton updates, navigation composable, and menu call flow, making it difficult for reviewers to understand the purpose and scope of the work. Please add a concise description that outlines the primary objectives of the PR, including the new AverageProgressButton integration, navigation updates, and call-flow modifications for menu.vue.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The current title “feat: new button near cart” does refer to the addition of a button but is overly generic and does not clearly identify the key AverageProgressButton feature or its role in the top-bar navigation. Consider renaming the title to explicitly reference the new AverageProgressButton or its intended behavior, such as “feat: add AverageProgressButton to top-bar navigation” to improve clarity.

Poem

A bunny taps the cart with glee,
A donut spins—what could it be?
A gift peeks out, a drawer slides,
The menu asks before it dials.
Buttons bop, the state aligns—
Hop, hop—progress shines! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch average-button

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Sep 9, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

@hmbanan666 hmbanan666 merged commit 01a3505 into main Sep 9, 2025
6 of 8 checks passed
@hmbanan666 hmbanan666 deleted the average-button branch September 9, 2025 14:52
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (15)
apps/storefront-telegram/app/pages/menu.vue (5)

70-89: Add a non-Telegram fallback and localize strings.

  • No fallback when showPopup.isAvailable() is false; users get no action.
  • Button texts and message should use i18n, not literals.

Apply:

-  if (showPopup.isAvailable()) {
-    const buttonId = await showPopup({
-      title: formatted,
-      message: 'Выберите действие',
-      buttons: [
+  if (showPopup.isAvailable()) {
+    const buttonId = await showPopup({
+      title: formatted,
+      message: t('menu.call.chooseAction'),
+      buttons: [
         {
-          id: 'copy',
-          type: 'default',
-          text: 'Скопировать',
+          id: 'copy',
+          type: 'default',
+          text: t('common.copy'),
         },
         {
-          id: 'recall',
-          type: 'default',
-          text: 'Нужен обратный звонок',
+          id: 'recall',
+          type: 'default',
+          text: t('menu.call.requestCallback'),
         },
         {
           type: 'close',
         },
       ],
     })
+  } else {
+    // Fallback outside Telegram
+    window.location.href = formattedToCall
   }

And import/use i18n at top:

+import { useI18n } from 'vue-i18n'
+const { t } = useI18n()

91-93: Await clipboard write and handle errors.

Unawaited promise can silently fail (permissions/HTTP context). Provide feedback or fallback.

-    if (buttonId === 'copy') {
-      navigator.clipboard.writeText(formatted)
-    }
+    if (buttonId === 'copy') {
+      try {
+        await navigator.clipboard.writeText(formatted)
+      } catch (e) {
+        console.warn('Clipboard copy failed', e)
+      }
+    }

94-96: Verify dial action in Telegram WebApp; prefer SDK helper or location redirect.

window.open('tel:') may be blocked or ignored. In TG WebApp, openLink is usually safer; outside TG use window.location.href.

-    if (buttonId === 'recall') {
-      window.open(formattedToCall)
-    }
+    if (buttonId === 'recall') {
+      // Prefer Telegram SDK when available; otherwise, redirect
+      try {
+        // import { openLink } from '@telegram-apps/sdk-vue'
+        // await openLink(formattedToCall)
+        window.location.href = formattedToCall
+      } catch {
+        window.location.href = formattedToCall
+      }
+    }

63-66: Guard phone formatting against exceptions.

parsePhoneNumberWithError throws on invalid input. Even if constant today, make it robust.

-const formatted = parsePhoneNumberWithError(tel, 'RU').format('INTERNATIONAL')
+let formatted = `+${tel}`
+try {
+  formatted = parsePhoneNumberWithError(tel, 'RU').format('INTERNATIONAL')
+} catch {}

57-57: Minor: co-locate SDK imports.

If you add openLink (previous comment), import alongside showPopup for consistency.

apps/storefront-telegram/app/composables/useNavigation.ts (2)

38-38: Avoid duplicated predicates for button visibility.

isAverageProgressButtonShown equals isCartButtonShown; derive one from the other to prevent drift.

-const isAverageProgressButtonShown = computed(() => isCatalogPage.value)
+const isAverageProgressButtonShown = computed(() => isCartButtonShown.value)

45-45: Export naming: consider semantic intent.

If this flag means “promo/upsell available,” a more domain-specific name (e.g., isUpsellButtonShown) improves clarity.

apps/storefront-telegram/app/components/catalog/CartButton.vue (3)

6-6: Accessibility: add aria-label when title is hidden.

Icon-only state should expose a label.

-  <UButton
+  <UButton
+    :aria-label="$t('app.cart.title')"

11-11: Micro: consistent typography scale.

text-lg/5 differs from nearby components’ line-height; ensure it matches your design system.


26-26: Composables: import only what you use.

If the title logic changes back, keep isAverageProgressButtonShown; otherwise drop it to avoid unused reactive deps.

apps/storefront-telegram/app/components/catalog/AverageProgressButton.vue (5)

75-77: Don’t globally override navigation state without preserving prior value.

If multiple components touch isNavigationShown, toggling may clobber genuine state.

-const isDrawerOpened = ref(false)
+const isDrawerOpened = ref(false)
+const prevNavShown = ref<boolean | null>(null)
 
-watch(isDrawerOpened, () => {
-  isNavigationShown.value = !isDrawerOpened.value
-})
+watch(isDrawerOpened, (open) => {
+  if (open) {
+    if (prevNavShown.value === null) prevNavShown.value = isNavigationShown.value
+    isNavigationShown.value = false
+  } else if (prevNavShown.value !== null) {
+    isNavigationShown.value = prevNavShown.value
+    prevNavShown.value = null
+  }
+})

35-38: Localize and format currency.

Hard-coded “Еще” and progress * 10 RUB string should use i18n and number formatting.

-      <div class="pr-2 w-12 text-center text-sm/4 font-medium">
-        <p>Еще</p>
-        <p>{{ progress * 10 }} ₽</p>
-      </div>
+      <div class="pr-2 w-12 text-center text-sm/4 font-medium">
+        <p>{{ t('average.more') }}</p>
+        <p>{{ new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB', maximumFractionDigits: 0 }).format(progress * 10) }}</p>
+      </div>

Add:

+import { useI18n } from 'vue-i18n'
+const { t } = useI18n()

45-50: Localize drawer content.

Move header/body text to i18n keys.

-        <h2 class="text-xl/6 font-semibold">
-          Увеличим чек?
-        </h2>
+        <h2 class="text-xl/6 font-semibold">
+          {{ t('average.drawer.title') }}
+        </h2>
...
-        Тут будут подарки и доставка.
+        {{ t('average.drawer.body') }}

1-7: Smooth collapse: hide overflow on wrapper.

Prevents layout artifacts when width toggles.

-  <div
-    class="transition-all duration-200 ease-in-out"
+  <div
+    class="transition-all duration-200 ease-in-out overflow-hidden"

31-32: Decorative icon should be hidden from AT.

Mark as aria-hidden.

-  <UIcon name="i-lucide-gift" class="size-6" />
+  <UIcon name="i-lucide-gift" class="size-6" aria-hidden="true" />
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cd5266 and ee96ed7.

📒 Files selected for processing (5)
  • apps/storefront-telegram/app/components/Navigation.vue (1 hunks)
  • apps/storefront-telegram/app/components/catalog/AverageProgressButton.vue (1 hunks)
  • apps/storefront-telegram/app/components/catalog/CartButton.vue (2 hunks)
  • apps/storefront-telegram/app/composables/useNavigation.ts (1 hunks)
  • apps/storefront-telegram/app/pages/menu.vue (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
apps/storefront-telegram/app/components/Navigation.vue (1)

4-6: LGTM: top-bar composition aligns with new UX.

Order and usage of CatalogCartButton, CatalogAverageProgressButton, CatalogCategoriesButton look consistent with the composable state.

Comment on lines +68 to +71
setInterval(() => {
progress.value = Math.floor(Math.random() * 100)
}, 4000)
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Memory leak: interval not cleared on unmount.

Repeated mounts will accumulate timers.

-onMounted(() => {
-  setInterval(() => {
-    progress.value = Math.floor(Math.random() * 100)
-  }, 4000)
-})
+let timer: ReturnType<typeof setInterval> | undefined
+onMounted(() => {
+  timer = setInterval(() => {
+    progress.value = Math.floor(Math.random() * 100)
+  }, 4000)
+})
+onUnmounted(() => {
+  if (timer) clearInterval(timer)
+})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setInterval(() => {
progress.value = Math.floor(Math.random() * 100)
}, 4000)
})
let timer: ReturnType<typeof setInterval> | undefined
onMounted(() => {
timer = setInterval(() => {
progress.value = Math.floor(Math.random() * 100)
}, 4000)
})
onUnmounted(() => {
if (timer) clearInterval(timer)
})
🤖 Prompt for AI Agents
In apps/storefront-telegram/app/components/catalog/AverageProgressButton.vue
around lines 68 to 71, the setInterval is created but never cleared, causing
timers to accumulate on repeated mounts; store the interval id (const/let timer
= setInterval(...)), and clear it in the component cleanup hook (call
clearInterval(timer) inside onBeforeUnmount or onUnmounted) so the timer is
removed when the component unmounts.

Comment on lines +14 to +16
<p v-if="!isAverageProgressButtonShown">
{{ $t('app.cart.title') }}
</p>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Title will always be hidden with current state logic.

Both isCartButtonShown and isAverageProgressButtonShown are true on catalog page, so the title never renders. Confirm intent.

Example options:

  • Adjust isAverageProgressButtonShown predicate (e.g., feature flag/threshold).
  • Or gate by another condition (screen width/scroll), e.g., v-if="!isCategoriesButtonShown" if suitable.

🏁 Script executed:

#!/bin/bash
# Verify where and how these computed props are defined in CartButton.vue
rg -n "isAverageProgressButtonShown" -n apps/storefront-telegram/app/components/catalog/CartButton.vue
rg -n "isCartButtonShown" -n apps/storefront-telegram/app/components/catalog/CartButton.vue

Length of output: 240


🏁 Script executed:

#!/bin/bash
# Locate the useNavigation implementation
rg -n "export function useNavigation" -C3 apps/storefront-telegram
rg -n "function useNavigation" -C3 apps/storefront-telegram
rg -n "const useNavigation" -C3 apps/storefront-telegram

Length of output: 318


🏁 Script executed:

#!/bin/bash
# Inspect the internal definitions of computed props in _useNavigation
rg -n "function _useNavigation" -C50 apps/storefront-telegram/app/composables/useNavigation.ts

Length of output: 1523


Fix hidden title logic in CartButton.vue
The <p v-if="!isAverageProgressButtonShown"> block never renders because isAverageProgressButtonShown is always true on the catalog page (router.currentRoute.value.path === '/').

  • Adjust isAverageProgressButtonShown to include the intended gating logic (e.g. only true after scroll threshold)
  • Or change/remove the v-if (e.g. use !isCategoriesButtonShown or drop the block if it’s no longer needed)
🤖 Prompt for AI Agents
In apps/storefront-telegram/app/components/catalog/CartButton.vue around lines
14-16, the <p v-if="!isAverageProgressButtonShown"> block never appears because
isAverageProgressButtonShown is always true on the catalog page; update the
gating so the flag reflects the intended visibility (for example make
isAverageProgressButtonShown a computed that returns true only when
router.currentRoute.value.path !== '/' AND the user has scrolled past a
threshold, or otherwise replace the v-if with the intended condition such as
!isCategoriesButtonShown); implement by changing the computed/property logic to
include the scroll threshold check (or route+scroll combination) or by editing
the template to use the correct boolean or remove the block if it is obsolete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant