- Global MutationCache.onError safety net so mutations without their own onError
no longer fail silently (skips ones that handle errors → no double toast).
- Notifications feed no longer opens its own SignalR connection; it reuses the
one in useOrderAlerts (was double sockets + double cache churn per session).
- "Send test notification" now works on the settings page (force flag bypasses
the tab-visible guard) instead of silently doing nothing.
- POS: re-entry guard on payment confirm (no duplicate payment on double-tap);
notes on already-sent lines are read-only (a note-only edit was silently lost);
ORDER_ALREADY_CLOSED surfaced with a clear Persian message.
- Reservation Confirm/Cancel/Complete buttons disabled while pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nav already hides pages a role can't view (NAV_REQUIRED_PERMISSION). This wraps
the sensitive/CRUD action controls in <Can permission> so users only see what
they can do (server still enforces):
- POS/orders: void → VoidOrder, cancel → VoidOrder, transfer → EditOrder,
pay/split → HandlePayments
- menu/inventory/coupons/customers/reservations/expenses/taxes/branches:
add/edit/delete buttons → the matching Create/Edit/Delete permission
- reports CSV export → ExportReports; SMS send → SendSms, settings → ManageSmsSettings
- home dashboard: revenue/orders KPI queries gated on ViewReports so non-report
roles don't 403 on the landing page
(Refund/discount/comp/cash-drawer have no UI control yet — no buttons to gate.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Full Persian calendar:
- New JalaliDateField — Shamsi popover picker (Saturday-first weeks,
Persian digits, امروز shortcut); wire format stays ISO Gregorian
YYYY-MM-DD. Falls back to the native input for the en locale.
- Replaces all 5 native type="date" inputs (Gregorian-only pickers):
reservations, expenses from/to, reports from/to.
- Reservations list date now renders Jalali instead of the raw ISO
string; branches purge timestamp now formats with fa-IR.
Responsive shell (mobile + tablet):
- New MobileNav: hamburger in the topbar (< md) opening an RTL-aware
slide-over drawer with all nav destinations, permission-filtered,
Escape/backdrop close and body scroll lock.
- Desktop sidebar hidden below md; header center cluster (clock/plan)
hidden below md; language switcher hidden below sm.
- Main content padding scales p-3 → p-4 → p-6.
- Verified at 375px and 768px: no horizontal overflow, drawer and
Jalali picker fully functional.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Delete (every manageable entity that only had "add" now has delete):
- Ingredients (warehouse): new DELETE /inventory/ingredients/{id} (soft-delete via
the global DeletedAt filter — no FK trouble with recipes/movements) + NoOp stub +
trash button in the materials cards.
- Reservations: new DELETE /reservations/{id} (soft-delete) + per-card delete button.
- Coupons & Customers: backend DELETE already existed; wired delete buttons in the UI.
- Shared ConfirmDialog component used by all delete flows (RTL-aware).
- Audit result: tables/branches/taxes/kitchen-stations/expenses/menu/terminals already
had delete; HR has no "add" so no delete needed; shifts intentionally excluded
(financial open/close records, not add-style entities).
Koja visibility:
- New Cafe.ShowOnKoja flag, default TRUE (DB default true so existing cafés stay
listed). Discover query now filters IsVerified && !Deleted && ShowOnKoja.
- public-profile GET/PUT expose showOnKoja; dashboard public-profile panel has an
on-by-default toggle that persists immediately. Platform IsVerified gate unchanged.
- EF migration AddCafeShowOnKoja (defaultValue: true).
Also: added the missing errors.generic i18n key (fa/en/ar) so useApiError's fallback
resolves instead of rendering the literal "errors.generic". 81 API tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>