Skip to content

chore: navigation rework#138

Merged
hmbanan666 merged 1 commit into
mainfrom
chore
Sep 8, 2025
Merged

chore: navigation rework#138
hmbanan666 merged 1 commit into
mainfrom
chore

Conversation

@hmbanan666
Copy link
Copy Markdown
Collaborator

@hmbanan666 hmbanan666 commented Sep 8, 2025

Summary by CodeRabbit

  • New Features
    • Centralized navigation state enables route-aware buttons, scroll-to-top behavior, and visibility controls.
    • Call action now triggers dialing on tap; VK link opens in a new tab.
  • Refactor
    • Navigation and client components now consume shared navigation state; catalog no longer manages navigation visibility.
    • Home header fixed to “Суши Love”.
  • Style
    • Enlarged navigation and cart buttons; increased text sizes across headers and screens for readability.
  • Chores
    • Added Russian translations for “Кабинет” and “Меню”.

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

coderabbitai Bot commented Sep 8, 2025

Walkthrough

Introduces a new useNavigation composable and refactors components to consume it for navigation state and routes. Updates Navigation and NavigationButton logic, removes isNavigationShown from useCatalog, adjusts several UI styles, modifies menu call behavior, and adds Russian locale keys for “Кабинет” and “Меню”.

Changes

Cohort / File(s) Summary of changes
Navigation composable (new) and API
apps/storefront-telegram/app/composables/useNavigation.ts
Added shared composable exposing isNavigationShown, route-derived flags (catalog/client, scroll-to-top, return capability), and computed mainRoutes with i18n titles.
Navigation component refactor
apps/storefront-telegram/app/components/Navigation.vue
Sourced isNavigationShown, isCartButtonShown, isCategoriesButtonShown, mainRoutes from useNavigation; removed local router/i18n logic and type import; adjusted container heights; categories button variant/size/motion updated and gated by isCategoriesButtonShown.
Navigation button behavior
apps/storefront-telegram/app/components/NavigationButton.vue
Replaced window-scroll logic with useNavigation flags; click now scrolls only when on catalog, can scroll, and active route; icon rendering conditions updated; otherwise redirects.
Catalog composable contract
apps/storefront-telegram/app/composables/useCatalog.ts
Removed isNavigationShown from return value; now returns visibleCategory and observerOptions only.
Client components using navigation visibility
apps/storefront-telegram/app/components/client/BonusProgramRegistration.vue, .../client/PointsCard.vue
Switched source of isNavigationShown from useCatalog to useNavigation; logic otherwise unchanged.
Cart/UI sizing tweaks
apps/storefront-telegram/app/components/cart/Button.vue
Increased padding/height (px-4, h-14); wrapper text size to text-lg.
Pages: headers and links
apps/storefront-telegram/app/pages/index.vue
Replaced dynamic channel header with static “Суши Love”; removed useChannelStore usage.
Pages: client title style
apps/storefront-telegram/app/pages/client/index.vue
Changed h1 class from text-2xl/5 to text-2xl/6.
Pages: menu interactions
apps/storefront-telegram/app/pages/menu.vue
Adjusted UButton styling via :ui; changed call action to @click handler (window.location to tel:); VK link opens in new tab.
Pages: no-auth title style
apps/storefront-telegram/app/pages/no-auth.vue
Updated h1 classes to text-2xl/6 font-bold tracking-tight.
Localization
apps/storefront-telegram/i18n/locales/ru-RU.json
Added app.cabinet ("Кабинет") and app.menu ("Меню") keys.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Router
  participant Scroll as WindowScroll
  participant useNavigation
  participant NavigationVue as Navigation.vue
  participant NavBtn as NavigationButton.vue

  User->>Router: Navigate (/, /client, /menu)
  Router-->>useNavigation: currentRoute
  Scroll-->>useNavigation: y position

  useNavigation-->>NavigationVue: { isNavigationShown, isCartButtonShown, isCategoriesButtonShown, mainRoutes }
  useNavigation-->>NavBtn: { isCatalogPage, canScrollToTop, isClientInnerPage, canReturnToCabinet }

  User->>NavBtn: Tap button
  alt isCatalogPage && canScrollToTop && isThisRoute
    NavBtn->>NavBtn: handleScrollToTop()
  else
    NavBtn->>Router: handleRedirect(route.path)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my ears at routes anew,
A hop to “Menu,” “Cabinet” too.
Scroll winds whisper: “Back to top!”
Buttons bounce—then gently stop.
With tidy trails and titles spun,
I thump: navigation’s done. 🐇✨

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

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 8, 2025

@hmbanan666 hmbanan666 merged commit fae7d80 into main Sep 8, 2025
7 of 8 checks passed
@hmbanan666 hmbanan666 deleted the chore branch September 8, 2025 14:05
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: 1

🧹 Nitpick comments (11)
apps/storefront-telegram/app/components/client/BonusProgramRegistration.vue (2)

77-83: Centralize nav-visibility toggling to avoid cross-component races

Directly mutating isNavigationShown here can conflict if other drawers/overlays also hide navigation. Prefer a reference-count or reason-based API in useNavigation() (e.g., hide('bonusDrawer') / show('bonusDrawer')) and derive visibility from active reasons.

Apply locally as an interim guard:

-const { isNavigationShown } = useNavigation()
+const { isNavigationShown /* , hide, show */ } = useNavigation()

 watch(isDrawerOpened, () => {
-  isNavigationShown.value = !isDrawerOpened.value
+  // TODO: replace with hide/show API in useNavigation to avoid clobbering
+  isNavigationShown.value = !isDrawerOpened.value
 })

55-69: Localize static Russian strings

These user-facing strings aren’t i18n’d. Move them to locale files for consistency with the rest of navigation text.

apps/storefront-telegram/app/components/NavigationButton.vue (2)

4-4: Deduplicate the condition (readability + single source of truth)

The same predicate gates click behavior and icons. Compute it once.

-@click="(isCatalogPage && canScrollToTop && isThisRoute) ? handleScrollToTop() : handleRedirect(route.path)"
+@click="shouldScrollUp ? handleScrollToTop() : handleRedirect(route.path)"
...
-<UIcon v-if="isCatalogPage && canScrollToTop && isThisRoute"
+<UIcon v-if="shouldScrollUp"
...
-<UIcon v-else-if="isClientInnerPage && canReturnToCabinet && isThisRoute"
+<UIcon v-else-if="shouldShowReturnIcon"
+const shouldScrollUp = computed(() =>
+  isCatalogPage.value && canScrollToTop.value && isThisRoute.value
+)
+const shouldShowReturnIcon = computed(() =>
+  isClientInnerPage.value && canReturnToCabinet.value && isThisRoute.value
+)

Also applies to: 13-19


2-3: Add accessible name for the button

Expose an aria-label for SR users using route title.

-<button
+<button
   class="flex flex-col items-center justify-center gap-1 px-4 cursor-pointer tg-text-subtitle"
+  :aria-label="route.title"
   @click="(isCatalogPage && canScrollToTop && isThisRoute) ? handleScrollToTop() : handleRedirect(route.path)"
>

Also applies to: 34-36

apps/storefront-telegram/app/components/Navigation.vue (1)

7-15: Button a11y: label the icon-only Categories button

The button is icon-only; add an aria-label (e.g., using i18n “menu”/“categories”) for SR users.

 <UButton
   v-if="isCategoriesButtonShown"
   variant="outline"
   color="neutral"
   size="xl"
   icon="i-lucide-logs"
   block
   :ui="{
     base: 'size-14 aspect-square motion-preset-slide-left motion-duration-500',
   }"
+  :aria-label="$t('menu')"
 />
apps/storefront-telegram/app/components/cart/Button.vue (1)

10-18: Avoid hard-coded currency; format dynamically

Render the cart total via a prop/computed and Intl currency formatting instead of a literal "1850 ₽".

-      <p>
-        1850 ₽
-      </p>
+      <p>{{ totalPriceFormatted }}</p>

Add outside this hunk:

<script setup lang="ts">
const props = defineProps<{ total: number }>()
const totalPriceFormatted = computed(() =>
  new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB', maximumFractionDigits: 0 }).format(props.total)
)
</script>
apps/storefront-telegram/app/pages/client/index.vue (1)

33-58: Make “selected city” label reactive

items is a ref with a static array; the city label won’t update when clientStore.selectedCity changes. Derive items from a computed to react to store updates.

Example outside this hunk:

const items = computed(() => [
  // ...
  {
    label: clientStore.selectedCity?.name ?? 'Выбрать город',
    icon: 'i-lucide-locate-fixed',
    onClick: () => { vibrate('success'); clientStore.updateCity(null) },
  },
])
apps/storefront-telegram/app/pages/menu.vue (2)

34-35: Programmatic call is fine, but consider graceful fallback

If tel: isn’t supported, nothing happens. Optionally wrap in a try/catch and show a toast with the number copied to clipboard.


65-69: Guard against SSR and prefer location.assign

Minor: ensure it never runs server-side and use assign for intent clarity.

-function handleCall() {
-  vibrate()
-  // Call phone number on click
-  window.location.href = formattedToCall
-}
+function handleCall() {
+  vibrate()
+  if (process.client) window.location.assign(formattedToCall)
+}
apps/storefront-telegram/app/composables/useNavigation.ts (2)

30-38: Prefer route.name over path literals

Comparing on route.name avoids issues with trailing slashes and future path changes.

-const isCatalogPage = computed(() => router.currentRoute.value.path === '/')
+const isCatalogPage = computed(() => router.currentRoute.value.name === 'home')

Similarly consider deriving “client” checks from name or a route meta flag instead of startsWith('/client').


31-31: Extract magic number for scroll threshold

Name the “650” for clarity and easy tuning.

-const canScrollToTop = computed(() => y.value > 650)
+const SCROLL_TO_TOP_THRESHOLD = 650
+const canScrollToTop = computed(() => y.value > SCROLL_TO_TOP_THRESHOLD)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13289eb and 75c97d4.

📒 Files selected for processing (12)
  • apps/storefront-telegram/app/components/Navigation.vue (2 hunks)
  • apps/storefront-telegram/app/components/NavigationButton.vue (3 hunks)
  • apps/storefront-telegram/app/components/cart/Button.vue (1 hunks)
  • apps/storefront-telegram/app/components/client/BonusProgramRegistration.vue (1 hunks)
  • apps/storefront-telegram/app/components/client/PointsCard.vue (1 hunks)
  • apps/storefront-telegram/app/composables/useCatalog.ts (0 hunks)
  • apps/storefront-telegram/app/composables/useNavigation.ts (1 hunks)
  • apps/storefront-telegram/app/pages/client/index.vue (1 hunks)
  • apps/storefront-telegram/app/pages/index.vue (1 hunks)
  • apps/storefront-telegram/app/pages/menu.vue (3 hunks)
  • apps/storefront-telegram/app/pages/no-auth.vue (1 hunks)
  • apps/storefront-telegram/i18n/locales/ru-RU.json (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/storefront-telegram/app/composables/useCatalog.ts
⏰ 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 (12)
apps/storefront-telegram/app/components/client/PointsCard.vue (1)

124-124: Proper migration to centralized navigation.

The change from useCatalog() to useNavigation() for accessing isNavigationShown aligns with the PR's goal of centralizing navigation state management.

apps/storefront-telegram/app/components/NavigationButton.vue (1)

45-45: Ensure reactivity survives destructuring

If useNavigation() returns a reactive object (not plain refs), destructuring drops reactivity. Safe-guard with toRefs.

-import type { NavigationRoute } from '#shared/types/index'
+import type { NavigationRoute } from '#shared/types/index'
+import { toRefs } from 'vue'

-const { canScrollToTop, isCatalogPage, isClientInnerPage, canReturnToCabinet } = useNavigation()
+const { canScrollToTop, isCatalogPage, isClientInnerPage, canReturnToCabinet } = toRefs(useNavigation())

If useNavigation() already returns refs/computed, ignore this.

apps/storefront-telegram/app/components/Navigation.vue (2)

35-40: Nice centralization via useNavigation

Removing duplicated route/visibility logic from the component and sourcing it from the composable is a solid cleanup.


2-3: Verify stickiness and safe-area after height bump

With sticky inset-0 h-40 and inner h-16, confirm bottom positioning and no overlap with OS/Telegram UI; consider adding padding for safe area if needed.

-<div v-if="clientStore.id" class="z-50 touch-pan-x sticky inset-0 h-40">
+<div v-if="clientStore.id" class="z-50 touch-pan-x sticky inset-0 h-40">
   <div class="w-full h-16 px-4 py-0 flex flex-row gap-2 items-start">
...
-  <nav
+  <nav
     v-if="isNavigationShown"
-    class="w-full h-24 tg-bg-bottom-bar border-t border-default rounded-t-lg motion-preset-slide-up"
+    class="w-full h-24 tg-bg-bottom-bar border-t border-default rounded-t-lg motion-preset-slide-up pb-[env(safe-area-inset-bottom)]"
   >
apps/storefront-telegram/app/components/cart/Button.vue (1)

7-7: Padding/height tweak looks good

The larger tap area should improve ergonomics on mobile.

apps/storefront-telegram/app/pages/client/index.vue (1)

4-4: Typography alignment LGTM

Header leading change to /6 reads better and matches other pages.

apps/storefront-telegram/app/pages/no-auth.vue (1)

3-3: Consistent header style

Matches the new heading scale. All good.

apps/storefront-telegram/i18n/locales/ru-RU.json (1)

55-56: New keys added correctly

app.cabinet and app.menu look good and are consistent with usage.

apps/storefront-telegram/app/pages/index.vue (1)

5-7: Confirm intent: static brand title replaces dynamic channel name

Switching to a hard-coded “Суши Love” may drop per-channel branding and dynamic title updates. If multi-branding is still required, keep a dynamic fallback.

-        <h1 class="text-2xl/6 font-bold tracking-tight">
-          Суши Love
-        </h1>
+        <h1 class="text-2xl/6 font-bold tracking-tight">{{ brandTitle }}</h1>

Add outside this hunk:

const channelStore = useChannelStore()
const brandTitle = computed(() => channelStore.name || 'Суши Love')

useHead({ title: brandTitle.value })
watch(brandTitle, (t) => useHead({ title: t }))
apps/storefront-telegram/app/pages/menu.vue (1)

12-14: Uniform button styling via :ui is fine

Good move to centralize size/leading in UI config.

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

1-3: Imports/types may be implicit; verify TS setup

Ensure createSharedComposable, useWindowScroll, computed, ref, useRouter, and useI18n are resolvable (auto-imported) and that NavigationRoute is imported or globally declared to avoid TS errors.

If explicit imports are preferred:

+import { computed, ref } from 'vue'
+import { useRouter, useI18n } from '#imports'
+import { useWindowScroll, createSharedComposable } from '@vueuse/core'
+// import type { NavigationRoute } from '~/types/navigation'

36-38: Booleans read cleanly

isCartButtonShown and isCategoriesButtonShown are straightforward and match intent.

Comment on lines +42 to 43
target="_blank"
color="neutral"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add rel to external link opened in new tab

Prevent reverse tabnabbing.

-        target="_blank"
+        target="_blank"
+        rel="noopener noreferrer"
📝 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
target="_blank"
color="neutral"
target="_blank"
rel="noopener noreferrer"
color="neutral"
🤖 Prompt for AI Agents
In apps/storefront-telegram/app/pages/menu.vue around lines 42-43, the external
link uses target="_blank" but lacks a rel attribute which risks reverse
tabnabbing; add rel="noopener noreferrer" to the anchor element (or component
prop) that has target="_blank" so the link opens in a new tab safely, ensuring
both noopener and noreferrer are included.

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