Skip to content

feat: closed now block#144

Merged
hmbanan666 merged 2 commits into
mainfrom
closed-header
Sep 10, 2025
Merged

feat: closed now block#144
hmbanan666 merged 2 commits into
mainfrom
closed-header

Conversation

@hmbanan666
Copy link
Copy Markdown
Collaborator

@hmbanan666 hmbanan666 commented Sep 10, 2025

Summary by CodeRabbit

  • New Features

    • Added a “We’re closed now” banner on catalog pages, visible above main content.
    • Menu popup now offers to call the kitchen directly; labels updated, including “Заказать обратный звонок”.
  • Style

    • Average progress button now shows a periodic animated “Еще” label with ₽ amount, smoother transitions, timed show/hide cadence.
    • Updated categories button icon for improved clarity; gift icon tint adjusted.

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

coderabbitai Bot commented Sep 10, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a timed width-animated text reveal to AverageProgressButton; swaps CategoriesButton icon; introduces ClosedNowHeader and inserts it into default layout; changes menu.vue phone popup to initiate a call (tel:) instead of copying the number; assigns a base levelId when creating new clients in the Telegram order-bot.

Changes

Cohort / File(s) Change summary
Catalog: Progress button animation
apps/storefront-telegram/app/components/catalog/AverageProgressButton.vue
Adds isTextShown reactive state; shows/hides a width-animated text block ("Еще" + ₽) using a 12s interval with the text visible ~4s; adds transition classes, motion preset, min-width on text, and tints the gift icon.
Catalog: Categories icon
apps/storefront-telegram/app/components/catalog/CategoriesButton.vue
Replaces UButton icon from i-lucide-list-end to i-lucide-text-align-start.
Catalog: Closed banner + layout integration
apps/storefront-telegram/app/components/catalog/ClosedNowHeader.vue, apps/storefront-telegram/app/layouts/default.vue
Adds ClosedNowHeader component (renders "Мы сейчас закрыты" banner on catalog pages) and inserts it into layouts/default.vue immediately after BackgroundConfetti above main content.
Menu: Phone popup flow
apps/storefront-telegram/app/pages/menu.vue
Changes phone popup actions: "Скопировать" → "Позвонить" (button id call) which opens tel: URL via window.open; second action renamed to "Заказать обратный звонок" and currently no-op; removes clipboard copy branch; retains vibration and tel URL construction.
Server: Telegram order-bot client creation
apps/web-app/server/services/telegram/order-bot.ts
When creating a new client in findOrCreateClient, adds levelId: 'hvccipw6t467rw3kxkujj1j8' to the creation payload (baseLevelId constant).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant M as menu.vue
  participant P as Popup
  Note over U,M: Phone action
  U->>M: Tap phone action
  M->>P: openPopup(title, actions=[call, recall])
  P-->>U: Show options
  U-->>P: Select "Позвонить" (call)
  P->>M: onAction(buttonId="call")
  M->>M: build tel:+<number>
  M->>Browser: window.open(tel:+<number>)
  Note over M: "recall" currently no-op
Loading
sequenceDiagram
  autonumber
  participant C as AverageProgressButton
  participant T as 12s Timer
  Note over C: onMounted
  C->>T: start interval (12s)
  loop every 12s
    T->>C: tick
    C->>C: update progress
    C->>C: isTextShown = true
    Note over C: Text visible (~4s)
    C->>C: after 4s → isTextShown = false
  end
Loading
sequenceDiagram
  autonumber
  participant L as default.vue Layout
  participant H as ClosedNowHeader
  participant N as useNavigation()
  L->>H: Render header
  H->>N: isCatalogPage?
  alt On catalog page
    H-->>L: Render banner
  else Elsewhere
    H-->>L: Do not render
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • feat: menu page #136 — Modifies apps/storefront-telegram/app/pages/menu.vue call/tel handling; directly related to the menu call-flow changes.
  • chore: some rework #137 — Also alters apps/storefront-telegram/app/pages/menu.vue phone popup and action behavior; overlaps with this PR.
  • chore: visual rework #140 — Related adjustments to phone call handling and tel URL construction in menu.vue.

Poem

В ушке телефона — звонок, я прыгаю в такт,
Донат шепчет "Ещё" — вспыхнул короткий факт.
Луна на баннере гасит витрину дня,
Иконка сменилась — всё теперь как нельзя.
Я — кролик в коде, тружусь: апдейт прошёл ура! 🐇📣

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 133b3ea and 79873da.

📒 Files selected for processing (1)
  • apps/web-app/server/services/telegram/order-bot.ts (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch closed-header

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.

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

🧹 Nitpick comments (2)
apps/storefront-telegram/app/components/catalog/AverageProgressButton.vue (2)

35-49: Hide overflow during width animation

Content may peek during w-0 → w-14 transition. Add overflow-hidden to the animated container.

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

Also verify duration-600 exists in your Tailwind config. If not, use duration-500/700.


41-47: Currency formatting

Use Intl.NumberFormat for ₽ to avoid raw math and ensure locale formatting.

-          <p class="min-w-12">
-            {{ progress * 10 }} ₽
-          </p>
+          <p class="min-w-12">
+            {{ new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB', maximumFractionDigits: 0 }).format(progress * 10) }}
+          </p>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01a3505 and 133b3ea.

📒 Files selected for processing (5)
  • apps/storefront-telegram/app/components/catalog/AverageProgressButton.vue (4 hunks)
  • apps/storefront-telegram/app/components/catalog/CategoriesButton.vue (1 hunks)
  • apps/storefront-telegram/app/components/catalog/ClosedNowHeader.vue (1 hunks)
  • apps/storefront-telegram/app/layouts/default.vue (1 hunks)
  • apps/storefront-telegram/app/pages/menu.vue (1 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 (2)
apps/storefront-telegram/app/components/catalog/CategoriesButton.vue (1)

14-14: Icon swap LGTM

The glyph change to i-lucide-text-align-start fits the layout; no logic affected.

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

21-23: Confirm reactivity source

Ensure useNavigation().isCatalogPage is a ref/computed, not a reactive prop destructured by value. If it’s from a store object, use storeToRefs or return refs from the composable.

Comment on lines 78 to 87
onMounted(() => {
setInterval(() => {
progress.value = Math.floor(Math.random() * 100)
}, 4000)
isTextShown.value = true

setTimeout(() => {
isTextShown.value = false
}, 4000)
}, 12000)
})
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

Clear intervals/timeouts on unmount

setInterval/setTimeout aren’t cleared → leaks and background updates after navigation.

Apply:

 onMounted(() => {
-  setInterval(() => {
+  const intervalId = setInterval(() => {
     progress.value = Math.floor(Math.random() * 100)
     isTextShown.value = true

-    setTimeout(() => {
+    const timeoutId = setTimeout(() => {
       isTextShown.value = false
     }, 4000)
   }, 12000)
 })
+
+onBeforeUnmount(() => {
+  // @ts-ignore - scope-captured ids if needed
+  if (typeof intervalId !== 'undefined') clearInterval(intervalId)
+  if (typeof timeoutId !== 'undefined') clearTimeout(timeoutId)
+})

Alternative: use @vueuse/core useIntervalFn/useTimeoutFn (auto-cleans).

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/storefront-telegram/app/components/catalog/AverageProgressButton.vue
around lines 78–87 the onMounted block creates an interval and nested timeout
but never clears them, causing memory leaks and background updates after
navigation; store the interval and timeout IDs, call clearInterval and
clearTimeout in an onUnmounted hook to cancel them, or replace the manual timers
with @vueuse/core helpers (useIntervalFn/useTimeoutFn) which auto-clean on
unmount; ensure the timeout ID is cleared before assigning a new one inside the
interval to avoid overlapping timers.

Comment on lines +2 to +18
<div
v-if="isCatalogPage"
class="tg-safe-area bg-violet-950 text-yellow-100 motion-preset-slide-down"
>
<div class="px-4 py-3.5 max-w-[28rem] mx-auto tg-content-safe-area-top">
<div class="flex flex-row items-center gap-2">
<UIcon name="i-lucide-moon" class="size-12 motion-preset-oscillate-sm motion-preset-seesaw motion-duration-3000" />

<div class="flex flex-col">
<h3 class="text-lg font-semibold">
Мы сейчас закрыты
</h3>
<p>Работаем с 10:00 до 22:00</p>
</div>
</div>
</div>
</div>
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

⚠️ Potential issue

Add real open/closed logic and dynamic hours

Static “Мы сейчас закрыты / 10:00–22:00” will be wrong when open or for kitchens with different schedules.

Apply (illustrative):

-  <div
-    v-if="isCatalogPage"
+  <div
+    v-if="isCatalogPage && isClosedNow"
     class="tg-safe-area bg-violet-950 text-yellow-100 motion-preset-slide-down"
   >
     <div class="px-4 py-3.5 max-w-[28rem] mx-auto tg-content-safe-area-top">
       <div class="flex flex-row items-center gap-2">
         <UIcon name="i-lucide-moon" class="size-12 motion-preset-oscillate-sm motion-preset-seesaw motion-duration-3000" />
 
         <div class="flex flex-col">
           <h3 class="text-lg font-semibold">
             Мы сейчас закрыты
           </h3>
-          <p>Работаем с 10:00 до 22:00</p>
+          <p>Работаем с {{ hours.open }} до {{ hours.close }}</p>
         </div>
       </div>
     </div>
   </div>

And in script:

 const { isCatalogPage } = useNavigation()
+const channelStore = useChannelStore()
+const hours = computed(() => channelStore.selectedKitchen?.hours ?? { open: '11:00', close: '22:00' })
+const isClosedNow = computed(() => {
+  // naive example; replace with tz-aware check
+  const [oh, om] = hours.value.open.split(':').map(Number)
+  const [ch, cm] = hours.value.close.split(':').map(Number)
+  const now = new Date()
+  const mins = now.getHours() * 60 + now.getMinutes()
+  const openM = oh * 60 + om
+  const closeM = ch * 60 + cm
+  return !(mins >= openM && mins < closeM)
+})

Also consider i18n for strings.

🤖 Prompt for AI Agents
In apps/storefront-telegram/app/components/catalog/ClosedNowHeader.vue around
lines 2 to 18, the header currently shows static Russian text and fixed hours;
replace this with dynamic open/closed logic and dynamic hours: accept a schedule
prop or fetch the kitchen's hours (e.g., daily open/close times), compute
current local time vs. today's intervals to derive isOpen and formattedHours,
render different icon/text based on isOpen (open label/time vs closed
label/time) and use the schedule to display hours instead of hardcoded
"10:00–22:00"; also wire these strings through i18n keys and ensure reactivity
(update on minute tick or visibility change) and handle edge cases like
overnight periods and multiple intervals per day.

@@ -1,5 +1,6 @@
<template>
<BackgroundConfetti />
<CatalogClosedNowHeader />
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

⚠️ Potential issue

Header shows “closed” unconditionally

CatalogClosedNowHeader currently always renders “Мы сейчас закрыты” on catalog pages. Gate it by actual open/closed state to avoid misinformation.

Example wiring:

-  <CatalogClosedNowHeader />
+  <CatalogClosedNowHeader v-if="isClosedNow" />

and compute isClosedNow in the layout (or inside the header) from kitchen hours/timezone.

I can wire this to channelStore hours with a robust isClosedNow() helper if you share the hours shape.

📝 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
<CatalogClosedNowHeader />
<CatalogClosedNowHeader v-if="isClosedNow" />

Comment on lines 71 to 96
const buttonId = await showPopup({
title: formatted,
message: 'Выберите действие',
message: 'Телефон кухни. Выберите действие',
buttons: [
{
id: 'copy',
id: 'call',
type: 'default',
text: 'Скопировать',
text: 'Позвонить',
},
{
id: 'recall',
type: 'default',
text: 'Нужен обратный звонок',
text: 'Заказать обратный звонок',
},
{
type: 'close',
},
],
})

if (buttonId === 'copy') {
navigator.clipboard.writeText(formatted)
if (buttonId === 'call') {
window.open(formattedToCall)
}
if (buttonId === 'recall') {
window.open(formattedToCall)
//
}
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

Use location.href for tel links + provide non-popup fallback

window.open('tel:') is often blocked in WKWebView/Telegram; location.href is more reliable. Also, if showPopup isn’t available, the action currently no-ops—fallback to direct dial. Finally, the ‘recall’ button is a no-op; either implement or hide to avoid UX dead-ends.

Apply:

-    if (buttonId === 'call') {
-      window.open(formattedToCall)
-    }
+    if (buttonId === 'call') {
+      window.location.href = formattedToCall
+    }
     if (buttonId === 'recall') {
-      //
+      // TODO: implement callback request or remove this button until ready
     }
   }
+  else {
+    // Fallback when Telegram popup API is unavailable
+    window.location.href = formattedToCall
+  }

Optional: compute the popup title separately and keep message concise.


🏁 Script executed:

#!/bin/bash
# Locate all showPopup usages and imports in JS/Vue files
rg -n "showPopup" -C3 --type=js --type=vue

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Locate the menu.vue file
menu_file=$(find . -type f -name "menu.vue")
echo "Found file: $menu_file"

# Print first 200 lines to inspect imports and context
echo "=== Beginning of file ==="
sed -n '1,200p' "$menu_file"
echo "=== End of snippet ==="

# Search for showPopup usage and window.open/formattedToCall context
echo "=== showPopup usages ==="
rg -n "showPopup" -C3 "$menu_file" || echo "No showPopup calls found"
echo "=== window.open usages ==="
rg -n "window.open" -C3 "$menu_file" || echo "No window.open calls found"
echo "=== formattedToCall references ==="
rg -n "formattedToCall" -C3 "$menu_file" || echo "No formattedToCall found"

Length of output: 3674


Use window.location.href for tel: links, add fallback, and handle recall button

  • Replace window.open(formattedToCall) with window.location.href = formattedToCall for reliable tel: handling in WKWebView/Telegram Web Apps (developers.google.com, stackoverflow.com).
  • After if (showPopup.isAvailable()), add an else branch to fallback to window.location.href when the popup API isn’t available.
  • Remove or implement the recall action to avoid a dead-end UX (e.g., show a callback form or hide the button until ready).

Apply:

-    if (buttonId === 'call') {
-      window.open(formattedToCall)
-    }
+    if (buttonId === 'call') {
+      window.location.href = formattedToCall
+    }
     if (buttonId === 'recall') {
-      //
+      // TODO: implement callback request or remove this button until ready
     }
   }
+  else {
+    // Fallback if Telegram popup API is unavailable
+    window.location.href = formattedToCall
+  }
📝 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 buttonId = await showPopup({
title: formatted,
message: 'Выберите действие',
message: 'Телефон кухни. Выберите действие',
buttons: [
{
id: 'copy',
id: 'call',
type: 'default',
text: 'Скопировать',
text: 'Позвонить',
},
{
id: 'recall',
type: 'default',
text: 'Нужен обратный звонок',
text: 'Заказать обратный звонок',
},
{
type: 'close',
},
],
})
if (buttonId === 'copy') {
navigator.clipboard.writeText(formatted)
if (buttonId === 'call') {
window.open(formattedToCall)
}
if (buttonId === 'recall') {
window.open(formattedToCall)
//
}
const buttonId = await showPopup({
title: formatted,
message: 'Телефон кухни. Выберите действие',
buttons: [
{
id: 'call',
type: 'default',
text: 'Позвонить',
},
{
id: 'recall',
type: 'default',
text: 'Заказать обратный звонок',
},
{
type: 'close',
},
],
})
if (buttonId === 'call') {
window.location.href = formattedToCall
}
if (buttonId === 'recall') {
// TODO: implement callback request or remove this button until ready
}
}
else {
// Fallback if Telegram popup API is unavailable
window.location.href = formattedToCall
}
🤖 Prompt for AI Agents
In apps/storefront-telegram/app/pages/menu.vue around lines 71 to 96, replace
the current tel link handling and fix the dead recall action: use
window.location.href = formattedToCall instead of window.open(formattedToCall)
so tel: links work reliably in WKWebView/Telegram Web Apps; wrap the popup call
with a showPopup.isAvailable() check and provide an else branch that directly
sets window.location.href = formattedToCall as a fallback when popups aren’t
available; and either implement the 'recall' branch (e.g., open a callback
form/modal or trigger a follow-up popup to collect the phone/time) or
remove/hide the 'recall' button until that feature is implemented so the UX has
no dead-end.

@sonarqubecloud
Copy link
Copy Markdown

@hmbanan666 hmbanan666 merged commit 51276f2 into main Sep 10, 2025
7 of 8 checks passed
@hmbanan666 hmbanan666 deleted the closed-header branch September 10, 2025 08:23
This was referenced Sep 10, 2025
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