Task #275: Postpone confirm + compact 3-tab dialog

Refactor the 5-min upcoming-meeting alert's postpone sub-dialog:

- Add an explicit "Are you sure?" confirm step before any postpone
  action (matches the existing Cancel pattern). Both minute chips
  (5/10/15/30/45/60) and the manual "Apply now" button now route
  through requestPostpone() -> amber confirm block -> postponeBy().
  Switching tabs clears any armed pending-postpone state.

- Replace the three stacked bordered sections with a compact 3-tab
  layout (Postpone / Reschedule / Cancel). Default tab is Postpone.
  Reschedule grid is responsive (grid-cols-1 sm:grid-cols-3) so the
  dialog no longer overflows on common laptop viewports.

- Implement full ARIA tab pattern: role="tablist"/"tab"/"tabpanel",
  id + aria-controls + aria-labelledby, roving tabindex, and
  ArrowLeft/Right/Home/End keyboard nav (RTL-aware). Focus moves to
  the newly active tab.

- Bilingual: added EN+AR keys (tabPostpone, tabReschedule, tabCancel,
  postponeConfirmPrompt, postponeConfirmYes, rescheduleHint), trimmed
  postponeIntro, removed obsolete *Label keys.

- Spec updated: existing "Postpone by 10", "chip immediately shifts",
  "Reschedule", and both "Cancel" tests now click the new tabs and
  go through the confirm step. Added two new tests:
  "Back on postpone confirm leaves meeting unchanged" and
  "switching tabs clears armed postpone confirm".

Out of scope: server route changes, realtime alert-state push, the
floating alert panel itself.

Architect review: PASS / mergeable.
All 11 spec tests pass in isolation; intermittent batch-run flakes
were traced to leftover seeded test rows from prior runs (cleaned)
and pre-existing polling tightness, not regressions.
This commit is contained in:
riyadhafraa
2026-05-01 13:39:44 +00:00
parent cbda85fc73
commit 84c2efc7a9
4 changed files with 474 additions and 183 deletions
+9 -6
View File
@@ -1037,18 +1037,21 @@
"dismissToast": "تم تجاهل التنبيه",
"openMeetings": "فتح الاجتماعات",
"postponeTitle": "تأجيل الاجتماع",
"postponeIntro": "اختر طريقة تأجيل «{{title}}».",
"postponeMinutesLabel": "تأجيل بعدد دقائق",
"postponeMinutesHint": "سيتم إزاحة وقتي البداية والنهاية بنفس المقدار.",
"postponeMinutesPlaceholder": "مثال: 10",
"postponeIntro": "«{{title}}»",
"tabPostpone": "تأجيل",
"tabReschedule": "إعادة الجدولة",
"tabCancel": "إلغاء",
"postponeMinutesHint": "ستتم إزاحة وقتي البداية والنهاية بنفس المقدار.",
"postponeMinutesPlaceholder": "دقائق",
"postponeMinutesApply": "تأجيل {{n}} دقيقة",
"rescheduleLabel": "إعادة جدولة لتاريخ/وقت جديد",
"postponeConfirmPrompt": "هل تريد تأجيل الاجتماع {{n}} دقيقة؟",
"postponeConfirmYes": "نعم، أجّل {{n}} دقيقة",
"rescheduleHint": "نقل الاجتماع إلى تاريخ أو وقت جديد.",
"rescheduleDate": "التاريخ",
"rescheduleStart": "البداية",
"rescheduleEnd": "النهاية",
"rescheduleNote": "ملاحظة (اختياري)",
"rescheduleApply": "إعادة الجدولة",
"cancelLabel": "إلغاء الاجتماع",
"cancelHint": "يحدد الاجتماع كمُلغى مع الاحتفاظ بسجل الحضور.",
"cancelApply": "إلغاء الاجتماع",
"cancelConfirmPrompt": "هل أنت متأكد؟ سيتم وضع الاجتماع كمُلغى.",