Skip to content

feat: menu page#136

Merged
hmbanan666 merged 1 commit into
mainfrom
menu-page
Sep 5, 2025
Merged

feat: menu page#136
hmbanan666 merged 1 commit into
mainfrom
menu-page

Conversation

@hmbanan666
Copy link
Copy Markdown
Collaborator

@hmbanan666 hmbanan666 commented Sep 5, 2025

Summary by CodeRabbit

  • New Features
    • Added a Menu page with quick actions, kitchen address, a call button with formatted dialing, and a VK link.
    • Introduced haptic feedback on menu interactions and city selection for a more responsive experience.
  • Chores
    • Renamed the navigation route to “/menu” and removed the old placeholder navigation page.
    • Set a default kitchen selection so users see a preselected location on first load.

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

coderabbitai Bot commented Sep 5, 2025

Walkthrough

Adds haptic feedback on city and menu interactions, renames the navigation route to “/menu,” introduces a new Menu page, removes the old navigation page template, and sets a default selected kitchen ID in the channel store.

Changes

Cohort / File(s) Summary of changes
Haptics integration
apps/storefront-telegram/app/components/CitySelector.vue, apps/storefront-telegram/app/pages/client/index.vue
Wrapped city click with handleClick that vibrates then updates city; added useFeedback.vibrate calls to client menu items, including success vibration before clearing city.
Navigation route update and page reshuffle
apps/storefront-telegram/app/components/Navigation.vue, apps/storefront-telegram/app/pages/menu.vue, apps/storefront-telegram/app/pages/navigation.vue
Renamed route from /navigation (name: navigation) to /menu (name: menu); added new Menu page with action list, kitchen address, and call button; removed template content from old navigation page.
Channel store default selection
apps/storefront-telegram/app/stores/channel.ts
Set default selectedKitchenId to 'm68foq9qtpsxd69eayom7bjn' (Фрунзе).

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant CitySelector
  participant Feedback as useFeedback.vibrate
  participant ClientStore as clientStore

  User->>CitySelector: Tap city item (id)
  CitySelector->>Feedback: vibrate('success')
  Feedback-->>CitySelector: done
  CitySelector->>ClientStore: updateCity(id)
  ClientStore-->>CitySelector: state updated
  CitySelector-->>User: UI reflects selected city
Loading
sequenceDiagram
  actor User
  participant MenuPage
  participant Feedback as useFeedback.vibrate
  participant PhoneFmt as libphonenumber-js
  participant Device as Dialer

  Note over MenuPage,PhoneFmt: On setup: parse tel → formatted, RFC3966
  User->>MenuPage: Tap action item
  MenuPage->>Feedback: vibrate()
  Feedback-->>MenuPage: done

  User->>MenuPage: Tap call button
  MenuPage->>Device: Open tel: RFC3966 URL
  Device-->>User: Dialer opens
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

A bunny taps the menu, boop—vibes bloom in air,
Cities hop to “success,” with gentle haptic flair.
A kitchen finds its favorite burrow, set by ID’s tune,
The dialer rings a carrot-phone, trilling like the moon.
New paths, new paws, to “/menu” we soon zoom. 🥕✨

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

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Sep 5, 2025

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: 3

🧹 Nitpick comments (5)
apps/storefront-telegram/app/components/Navigation.vue (1)

31-38: Localize static titles for consistency.

Home uses i18n; consider the same for “Кабинет” and “Меню”.

   {
     path: '/client',
     name: 'client',
-    title: 'Кабинет',
+    title: t('app.client'),
     icon: 'i-lucide-user',
   },
   {
     path: '/menu',
     name: 'menu',
-    title: 'Меню',
+    title: t('app.menu'),
     icon: 'i-lucide-menu',
   },
apps/storefront-telegram/app/pages/menu.vue (4)

33-39: Prefer href for tel: links to bypass the router.

Some button/link components treat :to as a client-route. Use an anchor/href to ensure dialing works reliably.

-  <UButton
-    :to="formattedToCall"
+  <UButton
+    as="a"
+    :href="formattedToCall"
     color="neutral"
     variant="ghost"
     class="px-0 text-lg font-medium"
   >

If UButton lacks “as”/“href”, wrap an inside the button slot.


8-20: All items rendered “active”.

Unless intentional, drop active to avoid persistent pressed styling.

-      <UButton
+      <UButton
         v-for="item in items"
         :key="item.label"
-        active
         size="xl"
         color="neutral"
         variant="ghost"
         class="px-0 text-xl/5 font-semibold"
         :label="item.label"
         :to="item.to"
         @click="item.onClick"
       />

22-29: Make address/hours resilient and configurable.

  • Provide a fallback when selectedKitchen is absent.
  • Consider sourcing hours from config/store and localize the text.
-  <p class="font-medium">
-    {{ channelStore.selectedKitchen?.address }}
-  </p>
+  <p class="font-medium">
+    {{ channelStore.selectedKitchen?.address || 'Адрес недоступен' }}
+  </p>
-  <p class="text-sm text-muted">
-    Ежедневно с 11:00 до 22:00
-  </p>
+  <p class="text-sm text-muted">
+    {{ /* t('kitchen.hours', { from: '11:00', to: '22:00' }) or a value from settings */ 'Ежедневно с 11:00 до 22:00' }}
+  </p>

58-64: Self-link to /menu is redundant.

The “Акции” item links to the current page. Remove until a real route exists.

   {
     label: 'Акции',
-    to: '/menu',
     onClick: () => vibrate(),
   },
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3f38d52 and d707bef.

📒 Files selected for processing (6)
  • apps/storefront-telegram/app/components/CitySelector.vue (2 hunks)
  • apps/storefront-telegram/app/components/Navigation.vue (1 hunks)
  • apps/storefront-telegram/app/pages/client/index.vue (1 hunks)
  • apps/storefront-telegram/app/pages/menu.vue (1 hunks)
  • apps/storefront-telegram/app/pages/navigation.vue (0 hunks)
  • apps/storefront-telegram/app/stores/channel.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/storefront-telegram/app/pages/navigation.vue
⏰ 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 (5)
apps/storefront-telegram/app/components/CitySelector.vue (2)

24-25: Haptic on city selection — nice touch.

The wrapper improves UX without bloating the template. LGTM.


33-39: No action needed: the vibrate signature already supports ‘light’ | ‘success’ | ‘error’ with a default of ‘light’, so calling vibrate('success') is valid and consistent.

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

30-49: Haptics on profile actions — LGTM.

Concise and consistent with the new feedback pattern.

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

35-39: Route rename to /menu matches the new page — LGTM.

Navigation entry now aligns with apps/storefront-telegram/app/pages/menu.vue.


35-36: Verified removal of “navigation” route references — searches across all Vue/JS/TS files in apps/ returned no occurrences of the old /navigation path or name: 'navigation'.

Comment on lines 51 to 57
label: clientStore.selectedCity ? clientStore.selectedCity.name : 'Выбрать город',
icon: 'i-lucide-locate-fixed',
onClick: () => clientStore.updateCity(null),
onClick: () => {
vibrate('success')
clientStore.updateCity(null)
},
},
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

City row label won’t update reactively. Build items via computed.

Label is captured at setup time; it won’t reflect later city changes.

-const items = ref([
+const items = computed(() => [
   {
     label: 'Мои заказы',
     icon: 'i-lucide-shopping-basket',
     to: '/client/orders',
     onClick: () => vibrate(),
   },
   {
     label: 'Мои адреса',
     icon: 'i-lucide-map-pin-house',
     onClick: () => vibrate(),
   },
   {
     label: 'Мои данные',
     icon: 'i-lucide-user',
     onClick: () => vibrate(),
   },
   {
-    label: clientStore.selectedCity ? clientStore.selectedCity.name : 'Выбрать город',
+    label: clientStore.selectedCity ? clientStore.selectedCity.name : 'Выбрать город',
     icon: 'i-lucide-locate-fixed',
     onClick: () => {
       vibrate('success')
       clientStore.updateCity(null)
     },
   },
-])
+])
📝 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
label: clientStore.selectedCity ? clientStore.selectedCity.name : 'Выбрать город',
icon: 'i-lucide-locate-fixed',
onClick: () => clientStore.updateCity(null),
onClick: () => {
vibrate('success')
clientStore.updateCity(null)
},
},
// before: const items = ref([
import { computed } from 'vue'
// …
const items = computed(() => [
{
label: 'Мои заказы',
icon: 'i-lucide-shopping-basket',
to: '/client/orders',
onClick: () => vibrate(),
},
{
label: 'Мои адреса',
icon: 'i-lucide-map-pin-house',
onClick: () => vibrate(),
},
{
label: 'Мои данные',
icon: 'i-lucide-user',
onClick: () => vibrate(),
},
{
label: clientStore.selectedCity ? clientStore.selectedCity.name : 'Выбрать город',
icon: 'i-lucide-locate-fixed',
onClick: () => {
vibrate('success')
clientStore.updateCity(null)
},
},
])
🤖 Prompt for AI Agents
In apps/storefront-telegram/app/pages/client/index.vue around lines 51 to 57 the
menu item label is created once at setup and captured as a plain value so it
doesn't update when clientStore.selectedCity changes; change this to build the
items (or at least the city label) inside a computed() so it returns an object
whose label references clientStore.selectedCity.name reactively, and use that
computed value in the template/consumer so the UI updates when the city is
changed.

Comment on lines +54 to +57
const tel = '79999999999'
const formatted = parsePhoneNumberWithError(tel, 'RU').format('INTERNATIONAL')
const formattedToCall = parsePhoneNumberWithError(tel, 'RU').format('RFC3966')

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

Handle phone parsing errors and avoid double parsing.

parsePhoneNumberWithError throws on bad input; doing it twice increases risk without benefit.

-const tel = '79999999999'
-const formatted = parsePhoneNumberWithError(tel, 'RU').format('INTERNATIONAL')
-const formattedToCall = parsePhoneNumberWithError(tel, 'RU').format('RFC3966')
+const tel = '79999999999'
+let formatted = `+${tel}`
+let formattedToCall = `tel:${tel}`
+try {
+  const phone = parsePhoneNumberWithError(tel, 'RU')
+  formatted = phone.format('INTERNATIONAL')
+  formattedToCall = phone.format('RFC3966')
+} catch {
+  // fallback keeps the page functional even if tel becomes invalid
+}
📝 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
const tel = '79999999999'
const formatted = parsePhoneNumberWithError(tel, 'RU').format('INTERNATIONAL')
const formattedToCall = parsePhoneNumberWithError(tel, 'RU').format('RFC3966')
const tel = '79999999999'
let formatted = `+${tel}`
let formattedToCall = `tel:${tel}`
try {
const phone = parsePhoneNumberWithError(tel, 'RU')
formatted = phone.format('INTERNATIONAL')
formattedToCall = phone.format('RFC3966')
} catch {
// fallback keeps the page functional even if tel becomes invalid
}
🤖 Prompt for AI Agents
In apps/storefront-telegram/app/pages/menu.vue around lines 54 to 57, the code
calls parsePhoneNumberWithError twice which both may throw and is redundant;
instead call parsePhoneNumberWithError once inside a try/catch to handle parsing
errors, store the returned PhoneNumber object in a variable, then derive both
the INTERNATIONAL and RFC3966 formats from that single object and use a fallback
or return early on error.

Comment on lines +15 to 16
const selectedKitchenId = ref<string | undefined>('m68foq9qtpsxd69eayom7bjn') // Фрунзе
const selectedKitchen = computed(() => kitchens.value.find((kitchen) => kitchen.id === selectedKitchenId.value))
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

Don’t hard‑code selectedKitchenId; add a post-fetch fallback.

The baked-in ID may not exist across environments and can drift. After loading kitchens, validate the selection and fall back to the first available (or leave undefined).

   kitchens.value = data.kitchens ?? []
+  // Ensure selectedKitchenId points to an existing kitchen
+  if (!kitchens.value.some(k => k.id === selectedKitchenId.value)) {
+    selectedKitchenId.value = kitchens.value[0]?.id
+  }

If this default must be environment-specific, consider sourcing it from the backend payload or runtime config instead of a literal.


🏁 Script executed:

#!/bin/bash
# Find occurrences of selectedKitchenId in channel.ts
rg -n "selectedKitchenId" apps/storefront-telegram/app/stores/channel.ts
# Find occurrences of kitchens.value assignments
rg -n "kitchens\\.value" apps/storefront-telegram/app/stores/channel.ts
# Show the first 200 lines of the file for context
sed -n '1,200p' apps/storefront-telegram/app/stores/channel.ts

Length of output: 2078


Add post-fetch fallback for selectedKitchenId
After kitchens.value = data.kitchens ?? [], ensure selectedKitchenId still matches an existing kitchen and reset it if not:

   kitchens.value = data.kitchens ?? []
+  // Ensure selectedKitchenId points to an existing kitchen
+  if (!kitchens.value.some(k => k.id === selectedKitchenId.value)) {
+    selectedKitchenId.value = kitchens.value[0]?.id
+  }

If you need an environment-specific default, pull that from the backend payload or runtime config instead of hard-coding.

🤖 Prompt for AI Agents
In apps/storefront-telegram/app/stores/channel.ts around lines 15-16, the
selectedKitchenId is hard-coded and may become stale after kitchens.value is
set; after assigning kitchens.value = data.kitchens ?? [], verify that
selectedKitchenId.value corresponds to an existing kitchen
(kitchens.value.find(...)); if it does not, reset selectedKitchenId.value to a
safe fallback pulled from the backend payload or runtime config (e.g.,
data.defaultKitchenId or config.defaultKitchenId) or to undefined rather than
keeping the hard-coded ID.

@hmbanan666 hmbanan666 merged commit 6f30ee7 into main Sep 5, 2025
8 checks passed
@hmbanan666 hmbanan666 deleted the menu-page branch September 5, 2025 11:55
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