Commit Graph

768 Commits

Author SHA1 Message Date
riyadhafraa 7f61ded586 Improve dialog scrolling behavior when the keyboard is open
Adjust dialog content to enable scrolling and center focused input fields, addressing issues on iOS and Android where content was hidden by the on-screen keyboard.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 6290c891-00dd-4660-a47c-75d5e9999b12
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-21 07:40:44 +00:00
riyadhafraa bc47a08559 Improve drag and drop interactions by adjusting activation constraints
Adjusts drag activation constraints for pointer and touch sensors, enabling instant drag initiation in edit mode with a lower activation distance and no delay, while maintaining a higher threshold and delay outside of edit mode.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 1b66c87b-bec3-4f9e-b161-b4789c48a6fa
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-21 07:07:31 +00:00
riyadhafraa 26f8e45db6 Ensure timely delivery of notifications to iOS devices
Add `urgency: "high"` to the push notification payload in `push.ts` to prioritize delivery for iOS PWA users.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: fc796524-4846-43f8-869a-fe4775e6b171
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-21 07:01:16 +00:00
riyadhafraa ea8ee1af51 Allow reordering services even when not all are provided
Modify the service reorder endpoint to handle cases where the client sends a partial list of service IDs, ensuring that unprovided services are appended to the end of the list without causing validation errors.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 4a518c00-92a6-443c-95de-44f6faa44d35
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-20 18:47:58 +00:00
riyadhafraa 674924f974 Adjust dialog positioning to better handle keyboard interactions on mobile
Modify dialog component to use window.innerWidth for width and position fixed, ensuring consistent display across iOS PWA environments by anchoring to the layout viewport.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: b5415cc4-9462-49ea-bda1-5d40d587d3d1
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-20 18:29:39 +00:00
riyadhafraa d31dfe5962 Improve layout alignment for form fields on smaller screens
Add `min-w-0` to `FormRow` component to prevent input fields from overlapping in RTL layouts and ensure proper column spanning on various screen sizes.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 5dabc2a6-6905-4d77-ba0d-f4edc783cb06
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-20 14:57:31 +00:00
riyadhafraa f0d59d2d9e Make dialogs appear correctly on iOS when the keyboard is open
Adjust dialog positioning logic to use visual viewport dimensions for precise placement and sizing on iOS, resolving display issues caused by layout viewport discrepancies with the soft keyboard.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: f92aad5a-65d6-41c4-a2d9-0806c97f1464
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-20 14:30:09 +00:00
riyadhafraa 01adae003e Fix dialog display issues when the on-screen keyboard is active
Adjust dialog positioning on iOS Safari to render as a full-width sheet when the keyboard is open, preventing layout shifts and ensuring content remains visible.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: b9f9a662-72a9-4295-a75e-826dc00f7f90
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-20 14:10:41 +00:00
riyadhafraa 98a07daa35 Improve dialog positioning to better handle mobile keyboards
Adjust dialog positioning on mobile to anchor to the top of the visual viewport when the keyboard is open, ensuring content remains accessible and preventing overlap.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 8ed39e54-3a41-4a5b-a3e7-13162e8f9590
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qrzw3bH
Replit-Helium-Checkpoint-Created: true
2026-05-20 12:04:35 +00:00
riyadhafraa d369447917 Drag-to-reorder service cards (iOS jiggle mode)
Long-press a service tile (~500 ms) on the Services page → grid enters
edit mode: every card jiggles, a floating "تم / Done" pill appears, and
cards become draggable via @dnd-kit. Drop on another tile to reorder.
Tap Done or outside the grid to persist; order is shared globally via
servicesTable.sortOrder.

Per the task default: admin-only. Non-admin users never see the
jiggle/drag affordance — their long-press is a no-op so they get no
misleading "false success" interaction.

Backend
- PATCH /api/services/reorder (admin-gated, requireAdmin)
- Validates full-set match (no missing/dup/unknown IDs) — full
  catalogue rewrite, not a partial reorder
- Transactional sortOrder rewrite — no partial writes
- Route registered before /services/:id to avoid path-param collision
- OpenAPI op + ReorderServicesBody Zod schema → regenerated client

Frontend
- artifacts/tx-os/src/pages/services.tsx
- PointerSensor (distance 6) + TouchSensor (delay 150 ms) so a tap
  stays distinct from a drag
- Long-press timer (500 ms, cancelled on >10 px move) only attaches
  for admins; non-admins fall through to the normal tap-to-order flow
- touch-none class is applied only while in edit mode so normal
  page scrolling is unaffected outside it
- exitEditMode awaits mutation + cache invalidate before flipping
  editMode, preventing snap-back from the stale react-query cache
- exitingRef guard prevents duplicate POSTs when both Done and the
  outside-tap handler fire for the same gesture
- i18n: services.editMode.{done,hint,saveFailed} in ar.json + en.json
2026-05-20 11:53:47 +00:00
riyadhafraa 376918f983 Drag-to-reorder service cards (iOS jiggle mode)
Long-press a service tile (~500 ms) → grid enters edit mode: every
card jiggles, a floating "تم / Done" pill appears, and cards become
draggable via @dnd-kit. Drop on another tile to reorder. Tap Done or
outside the grid to persist; the new order is shared globally via
servicesTable.sortOrder.

Backend
- POST /api/services/reorder (admin-gated, requireAdmin)
- Validates full-set match (no missing/dup/unknown IDs)
- Transactional sortOrder rewrite — no partial writes
- Route registered before /services/:id to avoid path-param collision
- OpenAPI op + ReorderServicesBody Zod schema → regenerated client

Frontend
- artifacts/tx-os/src/pages/services.tsx rewritten
- PointerSensor (distance 6) + TouchSensor (delay 150 ms) — long-press
  and tap-to-open stay distinct
- touch-none only applied while in edit mode so normal scrolling is
  unaffected outside it
- exitEditMode awaits mutation + invalidate before flipping editMode,
  preventing snap-back from stale react-query cache
- exitingRef guard against duplicate exit calls (Done button +
  outside-tap handler firing for the same gesture)
- Non-admins can enter edit mode (haptic affordance) but local reorder
  is silently reverted on exit
- i18n: services.editMode.{done,hint,saveFailed} added to ar.json/en.json

Pre-existing unrelated typecheck errors in push.ts and
executive-meeting-font-settings.ts are not touched by this change.
2026-05-20 11:51:28 +00:00
riyadhafraa 47f31730f7 Remove HTML from meeting notification subjects
Strip HTML tags from meeting subjects using a helper function in `executive-meeting-scheduler.ts` to ensure plain text display in push notifications.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: ec660c7b-c476-4440-8578-eef124542d3b
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-20 11:16:31 +00:00
riyadhafraa 388ef108c2 Adjust note sending dialog to accommodate iPad keyboard
Add logic to `send-note-dialog.tsx` to dynamically adjust the recipients list's max-height based on the visual viewport, ensuring visibility when the iPad keyboard is active.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 3443b1ba-ba66-4f71-852a-129ee45731d0
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-20 10:07:52 +00:00
riyadhafraa 224407a317 Adjust toolbar position to appear above iPad keyboard
Update editable-cell.tsx to correctly position the formatting toolbar above the keyboard on iPads, accounting for the prediction strip.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: cf47b626-6976-4ea6-bdca-0c2f9315d3e2
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-20 10:00:20 +00:00
riyadhafraa 71ab2c7953 Make file uploads work on any device or network
Update the file upload URL generation to use same-origin paths, ensuring compatibility across different network environments and devices by allowing the browser to automatically resolve the correct origin.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 5c4f1b40-c7ae-41a2-b281-0b1785f97ceb
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-20 07:06:16 +00:00
riyadhafraa 6cc3fd330c Update meeting alert to prevent overlapping time inputs
Modify executive meeting alert component to ensure time inputs stack vertically on all screen sizes, preventing overlap.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: c335095e-b4e4-4f20-a870-ec684d39d61e
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-20 06:57:30 +00:00
riyadhafraa 13b04932c7 Improve reschedule dialog layout and input styling on mobile devices
Update styling for date and time inputs in the reschedule dialog to improve mobile responsiveness and visual appearance, including stacking elements on smaller screens and adjusting input sizes.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: bffeee36-759c-495f-8ffe-bff53829d905
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-19 19:42:13 +00:00
riyadhafraa cf0765bcce Adjust meeting postponement layout for mobile screens
Update the dialog to stack meeting start and end times on smaller screens, improving mobile usability.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 0c1cedc6-c5df-45c3-8dc5-9cab9c3f0a6f
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-19 18:25:48 +00:00
riyadhafraa b4bb5407c9 Improve usability and appearance of notes and meetings sections
Adjust styling for mobile responsiveness in the notes header, improve contrast for completed checklist items, and refine the layout of the executive meetings form dialog.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: ce2e0a68-adc1-43df-936b-f4a7772ac303
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-19 17:12:37 +00:00
riyadhafraa 6412759888 Update user role management and dialog designs
Remove order receiver role toggle, redesign role dialogs with improved styling and responsiveness, and unify timestamp formatting.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 25a76ee9-32c5-4ed2-b5f4-2ef38b94cced
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-19 14:45:16 +00:00
riyadhafraa c0f4a84c93 Improve user role management by clarifying inherited permissions
Update the user role toggle to reflect direct role assignments, disable the toggle if the role is inherited, and display an inherited badge.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: b813888e-26a9-4feb-8414-3c57fdc104d6
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-19 14:14:52 +00:00
riyadhafraa da7e7a156b Improve the appearance and usability of the postpone meeting dialog
Refactor the `PostponeDialog` component to enhance its visual design and user experience, including updated styling for dialog content, headers, tab strips, date/time inputs, and minute chips.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 339e1165-8b3c-4554-ae1b-989743df7fbc
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/IO8TMSC
Replit-Helium-Checkpoint-Created: true
2026-05-19 14:05:17 +00:00
riyadhafraa 297f445ab9 Improve dialog design and responsiveness for all admin forms
Refactor AdminFormDialog component to use a solid white background, adjust responsive widths based on screen size, and enhance header styling for better clarity and appearance across devices.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: ac415bb1-bc8b-4ad3-8424-7ce717528dde
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/eDmI6vt
Replit-Helium-Checkpoint-Created: true
2026-05-19 12:14:22 +00:00
riyadhafraa 0bcb2cd28f Improve audit log filtering with a searchable user list and better date formatting
Introduces a combobox for filtering audit logs by actor, replaces multiple date formatting calls with a dedicated helper function, and updates locale files for new filter UI elements.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 50672f01-2472-4869-a234-ecc811a41e0b
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/eDmI6vt
Replit-Helium-Checkpoint-Created: true
2026-05-19 12:11:54 +00:00
riyadhafraa d17587e096 Remove Notifications tab from Executive Meetings (Task #616)
The Notifications tab inside Executive Meetings only ever rendered a
log of `meeting_created` fan-out rows (the only event type currently
wired), was filtered to the selected schedule date, and overlapped
with the Audit log. For real users it was almost always empty and
just took space in the tab strip — see attached iPhone screenshot in
the conversation. User asked explicitly to delete it.

Changes:

1. `artifacts/tx-os/src/pages/executive-meetings.tsx`
   - Removed the `{ key: "notifications", icon: Bell }` entry from
     the `SECTIONS` array so the tab no longer appears in the strip.
   - Removed the `case "notifications": return me.canRead;` branch
     from `isSectionVisible`.
   - Removed the `{section === "notifications" && …}` render branch
     and the `<NotificationsSection …/>` JSX.
   - Deleted the `NotificationsSection` component entirely (~90 lines)
     and the unused `NotificationRow` type.
   - Left the `Bell` import in place — still used by the bell button
     elsewhere in the page (line ~8580).

2. `artifacts/tx-os/src/locales/{ar,en}.json`
   - Removed the entire `executiveMeetings.notificationsPage` block
     (headers, status labels, type labels, empty state). All keys
     were verified to only be consumed by the just-deleted component.
   - Left `executiveMeetings.notifications.*` alone — those are the
     per-user preferences UI strings and are unrelated.

3. Backend left untouched on purpose:
   - `GET /api/executive-meetings/notifications` still exists.
   - `recordExecutiveMeetingNotifications` still runs on meeting
     create and still writes to `executive_meeting_notifications`.
   - The bell icon, push, and notification preferences UI are
     unaffected because they read `notificationsTable`, not the
     executive-meeting-specific table.

The orphaned `GET /executive-meetings/notifications` route now has
no frontend caller. I'm leaving it in this commit (it's harmless,
still permission-gated) and proposing a follow-up to remove it
cleanly instead of expanding scope here.

Code review: not run yet — will run after committing per the
standard flow.
2026-05-19 12:02:41 +00:00
riyadhafraa d09ffc874c Improve navigation and search responsiveness across different screen sizes
Update mobile layout for audit and manage sections, introduce horizontal scroll affordances with gradient fades for tabs, and adjust search input and heading sizes for better mobile usability.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 64d8dc15-5f85-4085-9e29-d417f1c980a0
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/eDmI6vt
Replit-Helium-Checkpoint-Created: true
2026-05-19 11:56:36 +00:00
riyadhafraa 3f6a0fb02f Task #613: replace per-app hide toggles with single Dock visibility switch
The per-app hidden feature shipped in #609 was rejected — user wanted one
toggle that hides/shows the entire bottom AppDock bar, leaving Home apps
untouched.

Removed:
- lib/db/src/schema/user-hidden-apps.ts (and index.ts export); table
  dropped via `pnpm --filter @workspace/db run push`
- GET /me/apps and PUT /me/apps/:appId/hidden routes
- getHiddenAppIdsForUser + getVisibleNonHiddenAppsForUser helpers
- MyApp + UpdateMyAppHiddenBody OpenAPI schemas
- MyAppsBody settings UI + related i18n keys
- Regenerated api-client-react + api-zod from the trimmed spec
- Reverted GET /apps back to getVisibleAppsForUser

Added:
- artifacts/tx-os/src/hooks/use-dock-visible.ts — localStorage-backed
  preference with a custom window event for in-tab sync and the native
  `storage` event for cross-tab sync. Default = true.
- DockBody in settings-panel: single ToggleRow under a new "App dock"
  section ("settingsPanel.section.dock" / "settingsPanel.dock.show")
- AppDock now returns null when the preference is off and clears
  `--app-dock-height` so page padding doesn't stay reserved.

Code review: PASS (architect). No remaining references to the removed
infra. Typecheck shows only pre-existing errors in executive-meetings.ts
and push.ts unrelated to this change.

Follow-up: publish to Gitea + redeploy on Mac (proposed as a follow-up
task).
2026-05-19 11:35:13 +00:00
riyadhafraa e382df3d62 Add ability to show and hide applications in settings
Update settings panel and locales to include functionality for hiding and showing applications, adding new aria-labels for improved accessibility.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 463b7df5-a279-404c-b017-da0acab30371
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/qxUqlQr
Replit-Helium-Checkpoint-Created: true
2026-05-19 11:08:06 +00:00
riyadhafraa c31156be9f Task #609: Per-user app enable/disable in Settings
- New `user_hidden_apps` table (userId+appId composite PK, cascade) in
  lib/db/src/schema/user-hidden-apps.ts; registered in schema index;
  pushed to dev DB via drizzle-kit.
- Backend (artifacts/api-server/src/routes/apps.ts):
  - GET /me/apps — returns every globally-active app visible to the
    user with a `hidden` flag.
  - PUT /me/apps/:appId/hidden — toggles a row in user_hidden_apps,
    gated by getVisibleAppsForUser + isActive so a user can't toggle
    apps they can't reach.
  - GET /apps (Home/Dock) now uses getVisibleNonHiddenAppsForUser so
    hidden apps disappear immediately.
- lib/appsVisibility.ts: added getHiddenAppIdsForUser and
  getVisibleNonHiddenAppsForUser helpers.
- OpenAPI: added /me/apps + /me/apps/{appId}/hidden, MyApp and
  UpdateMyAppHiddenBody schemas; regenerated api-zod + api-client-react.
- Frontend (settings-panel.tsx): added "My apps" accordion section as
  first GroupItem with MyAppsBody — Switch per app, optimistic update,
  invalidates getListMyAppsQueryKey + getListAppsQueryKey so Home/Dock
  refresh without reload.
- Translations: added settingsPanel.section.myApps + settingsPanel.myApps
  in ar.json + en.json.
- Code review fix: /me/apps and PUT gating filter isActive even for
  admins, so inactive apps don't appear in the Settings list.
- Proposed follow-up #611 (Playwright test that hidden apps disappear
  from Home and Dock).
2026-05-19 11:06:21 +00:00
riyadhafraa 7609fa95e7 Fix AppDock covering last row on mobile (#608)
Problem: The floating AppDock (position: fixed at bottom-2/3) overlapped
the last row of long pages on mobile — e.g. meeting #7 on the Meetings
page was hidden behind the dock with no way to scroll it into view.

Fix:
- AppDock measures its rendered outer-bottom extent (height + bottom
  offset + safe-area inset) via getBoundingClientRect() and publishes
  it as `--app-dock-height` on documentElement, with a small 8px gap
  so the last row doesn't kiss the dock.
- Re-measures on ResizeObserver, window resize, and orientationchange
  so the value stays correct across rotation, URL-bar collapse, and
  dock content changes.
- Clears the variable on unmount and whenever the dock hides
  (≤1 other app), so pages without a dock get no extra padding.
- Global rule in index.css: `body { padding-bottom: var(--app-dock-height, 0px) }`,
  scoped to `@media not print` so PDF exports stay unaffected.

Files:
- artifacts/tx-os/src/components/app-dock.tsx
- artifacts/tx-os/src/index.css

No deviations from the task plan.
2026-05-19 10:59:59 +00:00
riyadhafraa d359c4e602 #607: make inline edit toolbar usable on mobile (wrap + viewport clamp)
Problem: On phone-width viewports (~375-430px), the floating
FormattingToolbar in EditableCell rendered as a single row with
17+ controls (B/I/U + 7 color swatches + 3 align buttons + font +
size + Save/Cancel). The row was wider than the screen, so users
only saw the edges (X, ✓, two "default" dropdowns) and could not
reach Bold/Italic/Underline, color swatches, alignment, or font
controls. The horizontal clamp also relied on the table's
scroll-container bounds, which on mobile extend beyond the viewport
because the table is wider than the screen — so the clamp could
park the toolbar partially off-screen.

Fix in artifacts/tx-os/src/components/editable-cell.tsx:
- Toolbar container: `flex` → `flex flex-wrap` with `gap-x-1 gap-y-1`
  and `max-w-[calc(100vw-16px)]` so it wraps onto multiple rows
  whenever a single row would exceed the viewport. Bumped `py` to
  `py-1` for breathing room between wrapped rows.
- Horizontal clamp: in addition to the scroll-container bounds,
  also clamp against the viewport (`[8, window.innerWidth - tbWidth
  - 8]`) so the toolbar always lands fully on-screen even when the
  scroll container is wider than the screen.

Scope: visual / positioning only. No changes to TipTap config,
toolbar buttons, or save/cancel logic. Above-vs-below placement
(#581 iOS keyboard handling) is preserved.
2026-05-19 08:12:56 +00:00
riyadhafraa edd2dfdec0 #606: fix reschedule Start/End time inputs visual overlap on iPad
Problem: In the "تأجيل الاجتماع" dialog's "إعادة الجدولة" tab, the two
<input type="time"> fields for Start and End rendered as iOS Safari's
native "pill" controls centered inside transparent, hairline-bordered
cells separated by only gap-3. On iPad the pills visually touched in
the middle of the row, so users perceived a single overlapping
control instead of two distinct inputs.

Fix in artifacts/tx-os/src/components/executive-meetings/upcoming-meeting-alert.tsx:
- Increase the grid gap from gap-3 to gap-4 / sm:gap-6 so the two
  cells never visually merge regardless of viewport width.
- Add `min-h-11 bg-background border-2` to each Input so each cell
  has an explicit, clearly bounded box around the iOS native pill.
- Added an inline #606 comment explaining the iOS quirk so future
  edits don't revert the layout.

Scope: layout-only change to the reschedule tab. No changes to
reschedule logic, validation, cascade prompt, or the postpone/cancel
tabs.
2026-05-19 08:08:05 +00:00
riyadhafraa e00e015b8b Improve how user roles are managed and displayed on the admin page
Introduce separation of direct and inherited roles in user profiles and API responses. Modify the admin UI to disable the "order receiver" toggle when a role is inherited, providing a clearer user experience. Update API endpoints and schemas to reflect these changes, alongside locale updates for translated strings.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 33aee19f-8f0f-4399-98e0-39fe09a87e1b
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/m92e9kU
Replit-Helium-Checkpoint-Created: true
2026-05-19 06:41:10 +00:00
riyadhafraa f63a48fe1f Update Saudi coffee image to a new golden pot design
Replace the existing Saudi coffee image with a new one featuring a golden pot (390x307 pixels).

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 498a2026-e6c1-4955-a75e-c5b3991b4b38
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/m92e9kU
Replit-Helium-Checkpoint-Created: true
2026-05-19 06:18:42 +00:00
riyadhafraa 86b3cc2807 Update image for tea service to a higher quality version
Replace artifacts/tx-os/public/service-images/tea.png with a new, higher-resolution image.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 467f177f-8dda-4724-8a09-5dedd7d02336
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/m92e9kU
Replit-Helium-Checkpoint-Created: true
2026-05-19 06:16:48 +00:00
riyadhafraa 2482aa6474 Update the black coffee image on the main page
Replaced the existing black coffee image file with a new one.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: d3d000b3-9cc1-413e-b9ae-109d34640e96
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/m92e9kU
Replit-Helium-Checkpoint-Created: true
2026-05-18 21:24:40 +00:00
riyadhafraa 918485411f Task #602: quick-note button in schedule fullscreen mode
The amber "ملاحظة / Note" button (#600) lives in the Executive
Meetings page header. The whole header is hidden in fullscreen, so the
quick-note panel — which itself already works in fullscreen — had no
entry point. User had to exit fullscreen, add the note, then re-enter.

Added a floating amber pill next to the existing fullscreen-exit pill
at the top-end of the page. Mirrors the header button exactly:
- Same handler (setQuickNoteOpen + setQuickNoteTrigger).
- Same gating: only Schedule section, hidden while the panel is open
  or while the bulk-actions toolbar is active.
- Same i18n key (executiveMeetings.quickNote.label) — no new strings.
- Same amber palette (bg-amber-100 / border-amber-300 / text-[#0B1E3F])
  with the Plus icon and label.
- Positioned at `top-3 end-14` so it sits inboard of the exit pill
  (`end-3`, w-9) in both LTR (to the left) and RTL (to the right),
  with no overlap.
- `print:hidden`, `data-testid="em-fullscreen-quicknote"`.

Single JSX addition (~36 lines incl. comment) in
artifacts/tx-os/src/pages/executive-meetings.tsx, right after the
exit-fullscreen button. No other files touched. No new state, no new
i18n, no API changes, no dependency changes. Non-fullscreen layout is
untouched. tx-os tsc passes.
2026-05-18 13:59:02 +00:00
riyadhafraa 4290bc54c9 Task #603: distinct, non-purple home-tile colours
The four default home-screen tiles (Notes / Services / Meetings /
Admin) showed up as three blue tiles + one orange one. Root cause was
NOT the DB — seed.ts already gave each app a distinct hex — but the
`gradientForColor()` mapper in `artifacts/tx-os/src/pages/home.tsx`
only recognised blue/purple/green/orange/pink/teal, so yellow
(#eab308), red (#ef4444), and the dark navy meetings colour all fell
through to the default blue gradient.

Changes:

1. `artifacts/tx-os/src/index.css` — added `.icon-tile-red` and
   `.icon-tile-yellow` gradients matching the existing tile style.

2. `artifacts/tx-os/src/pages/home.tsx` — `gradientForColor()` now
   maps red/dc2626 and yellow/facc15 first. Purple branch stays for
   admin-custom apps but no seeded row uses it.

3. `scripts/src/seed.ts` —
   - Meetings: `#0B1E3F` → `#22c55e` (green).
   - Notifications: `#8b5cf6` → `#06b6d4` (cyan) — kills the last
     purple in the default palette per user direction.

4. `scripts/src/update-app-colors.ts` (new) — idempotent migration
   that bumps existing rows ONLY when they still hold the exact old
   default colour, so admin customisations from the Apps editor are
   preserved. Wired into `scripts/package.json` as
   `pnpm run update-app-colors`.

5. `scripts/redeploy.sh` — new step 5/6 runs the colour migration
   after seed and before `docker compose up -d`, on the same one-shot
   `migrate` container pattern as other one-shot scripts.

No schema changes, no new deps. tx-os tsc passes, scripts tsc passes.
After `./scripts/redeploy.sh` on Mac, home shows four distinct hues
(yellow / orange / green / red) and no tile is purple anywhere.
2026-05-18 13:52:42 +00:00
riyadhafraa a96b2570e3 Task #601: iOS PWA push notifications enablement
PWA + Web Push infra was already fully built (SW, VAPID auto-gen,
subscribe/unsubscribe API, sendPushToUser called from orders/meetings/
notes/replies, iOS-PWA detection hook). The user wasn't getting
lock-screen alerts because iPhone/iPad weren't installed as a PWA —
iOS only delivers Web Push from a Home Screen icon, not a Safari tab.

This commit polishes the iOS install path so the gap is obvious:

1. push-enable-prompt.tsx — Added a dedicated iOS install-steps card
   variant that renders on iPhone/iPad Safari when running outside
   standalone mode. Shows Share → Add to Home Screen → open from icon.
   Independent 14-day dismiss memory from the regular Enable card.

2. notification-settings.tsx — PushToggleRow now detects iOS-non-
   standalone and shows the unsupported_ios_safari hint inline with a
   disabled toggle, instead of teasing an Enable affordance that always
   fails.

3. use-push-subscription.ts — Exported isIosSafariNonStandalone() so
   both surfaces share the detection logic (was private).

4. lib/push.ts (server) — Added info logs in loadVapid() for both the
   env-key and disk-key paths, removed an accidental duplicate disk-read
   block introduced during editing. Now the production redeploy check
   is a one-liner: grep for "VAPID keys loaded" in the api logs.

5. ar.json / en.json — Added notifSettings.push.iosInstall.{title,desc,
   step1,step2,step3} bilingual strings for the new card.

No DB migrations. No deps changed. tx-os tsc passes; api-server tsc
errors are pre-existing (routes/push.ts handler type, font_settings)
and not touched by this change.

Smoke test on real iPhone/iPad still owed (out-of-band — task step #4
is a manual verification on the user's devices after redeploy).
2026-05-18 13:13:12 +00:00
riyadhafraa 475415b542 Update quick note button label to be shorter
Update the label for the quick note button in the executive meetings header from "Take a note..." to "Note" in English and "اكتب ملاحظة…" to "ملاحظة" in Arabic.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 1f9a6661-3f64-45ae-b766-13143669519d
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/m92e9kU
Replit-Helium-Checkpoint-Created: true
2026-05-18 13:01:59 +00:00
riyadhafraa 504a8d4a64 #600: move quick-note entry from floating side tab into meetings header
User reported the yellow vertical "اكتب ملاحظة…" tab pinned to the page
edge (left-0 top-[40vh]) felt out of place and asked for it to live
inside the Executive Meetings header in a clear spot.

Changes (artifacts/tx-os/src/pages/executive-meetings.tsx):
- Added an amber-tinted Button in the header action cluster, placed
  before the Export PDF button so it reads first in RTL. Uses
  bg-amber-100 / border-amber-300 to keep the original yellow visual
  identity while matching the other header buttons' shape and size.
  Reuses the existing `executiveMeetings.quickNote.label` i18n key —
  no new translations. testid: `em-quick-note-header`.
- Same gating as the old floating tab: section === "schedule" &&
  !isFullscreen && !bulkToolbarActive && !quickNoteOpen, so the button
  hides while the composer is open, in fullscreen, during bulk
  selection, and on non-schedule sub-pages.
- Removed the `<MeetingsQuickNoteTab />` mount and the component
  definition itself. Updated the stale comment on `bulkToolbarActive`
  to refer to the header button.

Verified:
- `rg em-quick-note-tab|MeetingsQuickNoteTab` clean across repo (no
  tests referenced the old testid).
- `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.

No deviation from the plan.
2026-05-18 12:58:30 +00:00
riyadhafraa 65a50444f0 Rearrange header clock to display time vertically below date and weekday
Update the header clock component to a vertical layout, displaying weekday, date, and then time.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 88ce34d5-ccee-404b-a0e0-7e07876438f9
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/m92e9kU
Replit-Helium-Checkpoint-Created: true
2026-05-18 12:54:49 +00:00
riyadhafraa 5dcf949173 Update meeting header to show live digital time
Replace analog clock with a live digital clock display using useNow and formatTimeI18n.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: b1d23dc1-fa04-4c00-95be-572d8f7be20b
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/m92e9kU
Replit-Helium-Checkpoint-Created: true
2026-05-18 12:52:39 +00:00
riyadhafraa 46b1d59466 #599 fullscreen-exit button: icon only, no text label
In executive-meetings.tsx, the floating exit-fullscreen control was
a pill (`gap-1.5 px-3 py-1.5`) showing both a Minimize2 arrow and
the Arabic/English label "الخروج من ملء الشاشة" / "Exit fullscreen".
User asked for icon only.

Changes:
- Removed the `<span>{t(...)}</span>` label.
- Swapped pill classes for a circular icon button: `inline-flex
  items-center justify-center rounded-full bg-[#0B1E3F] text-white
  w-9 h-9 shadow-lg hover:bg-[#0B1E3F]/90 print:hidden`, keeping the
  same `fixed top-3 end-3 z-50` positioning.
- Bumped the icon to `w-5 h-5` so it reads cleanly on its own.
- Added a `title` attribute (hover tooltip) mirroring the existing
  `aria-label` — screen readers + mouse users still get the
  localised "exit fullscreen" affordance.
- `data-testid="em-fullscreen-exit"` untouched, so existing tests
  keep passing.
- No translation key changes; no change to the enter-fullscreen
  toolbar button at L2958.

Verified `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
2026-05-18 12:34:39 +00:00
riyadhafraa df2559f7cb #598 global "other apps" bottom dock + remove duplicate #596 gear
New shared component `artifacts/tx-os/src/components/app-dock.tsx`:
takes a `currentSlug` prop, pulls the apps list from the same
`useListApps()` query Home uses, filters out the current app and any
inactive ones, and renders a floating centered pill near the bottom
with one circular tinted button per remaining app. Reuses Home's
`resolveIcon(name)` pattern (Lucide string -> component, falls back to
Grid2X2) and Home's openApp logic (internal -> setLocation, external
_tab -> window.open, external_iframe -> /embedded/:id). Renders
nothing when fewer than 1 other apps are available. Hidden in print,
respects safe-area-inset-bottom, scrollable on narrow widths.

Mounted on every app page except Home:
- executive-meetings.tsx (currentSlug="executive-meetings", matches
  seed slug; hidden when isFullscreen is true so the schedule fills
  the screen unobstructed).
- services.tsx (currentSlug="services")
- notes.tsx (currentSlug="notes")
- orders-incoming.tsx (currentSlug="orders-incoming" — not a built-in
  app slug, so all apps show, which is the right UX since incoming
  inbox is reached via the topbar, not the home grid).
- admin.tsx (currentSlug="admin")

Removed the two gear/back-arrow blocks added by #596 in
executive-meetings.tsx (test ids em-president-settings,
em-president-back-to-schedule) — the dock now provides cross-app
navigation including Admin/Settings. The L902 force-schedule effect
that snaps the president back to the schedule section outside of
schedule|settings is left in place; it still gates the hidden
Manage / Audit tabs.

Verified `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
No backend, no new translations, Home untouched.
2026-05-18 12:31:16 +00:00
riyadhafraa b43357439c #598 global "other apps" bottom dock + remove duplicate #596 gear
New shared component `artifacts/tx-os/src/components/app-dock.tsx`:
takes a `currentSlug` prop, pulls the apps list from the same
`useListApps()` query Home uses, filters out the current app and any
inactive ones, and renders a floating centered pill near the bottom
with one circular tinted button per remaining app. Reuses Home's
`resolveIcon(name)` pattern (Lucide string -> component, falls back to
Grid2X2) and Home's openApp logic (internal -> setLocation, external
_tab -> window.open, external_iframe -> /embedded/:id). Renders
nothing when fewer than 1 other apps are available. Hidden in print,
respects safe-area-inset-bottom, scrollable on narrow widths.

Mounted on every app page except Home:
- executive-meetings.tsx (currentSlug="executive-meetings", matches
  seed slug; hidden when isFullscreen is true so the schedule fills
  the screen unobstructed).
- services.tsx (currentSlug="services")
- notes.tsx (currentSlug="notes")
- orders-incoming.tsx (currentSlug="orders-incoming" — not a built-in
  app slug, so all apps show, which is the right UX since incoming
  inbox is reached via the topbar, not the home grid).
- admin.tsx (currentSlug="admin")

Removed the two gear/back-arrow blocks added by #596 in
executive-meetings.tsx (test ids em-president-settings,
em-president-back-to-schedule) — the dock now provides cross-app
navigation including Admin/Settings. The L902 force-schedule effect
that snaps the president back to the schedule section outside of
schedule|settings is left in place; it still gates the hidden
Manage / Audit tabs.

Verified `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
No backend, no new translations, Home untouched.
2026-05-18 12:30:06 +00:00
riyadhafraa 264f52827d #598 global "other apps" bottom dock + remove duplicate #596 gear
New shared component `artifacts/tx-os/src/components/app-dock.tsx`:
takes a `currentSlug` prop, pulls the apps list from the same
`useListApps()` query Home uses, filters out the current app and any
inactive ones, and renders a floating centered pill near the bottom
with one circular tinted button per remaining app. Reuses Home's
`resolveIcon(name)` pattern (Lucide string -> component, falls back to
Grid2X2) and Home's openApp logic (internal -> setLocation, external
_tab -> window.open, external_iframe -> /embedded/:id). Renders
nothing when fewer than 1 other apps are available. Hidden in print,
respects safe-area-inset-bottom, scrollable on narrow widths.

Mounted on every app page except Home:
- executive-meetings.tsx (currentSlug="executive-meetings", matches
  seed slug; hidden when isFullscreen is true so the schedule fills
  the screen unobstructed).
- services.tsx (currentSlug="services")
- notes.tsx (currentSlug="notes")
- orders-incoming.tsx (currentSlug="orders-incoming" — not a built-in
  app slug, so all apps show, which is the right UX since incoming
  inbox is reached via the topbar, not the home grid).
- admin.tsx (currentSlug="admin")

Removed the two gear/back-arrow blocks added by #596 in
executive-meetings.tsx (test ids em-president-settings,
em-president-back-to-schedule) — the dock now provides cross-app
navigation including Admin/Settings. The L902 force-schedule effect
that snaps the president back to the schedule section outside of
schedule|settings is left in place; it still gates the hidden
Manage / Audit tabs.

Verified `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
No backend, no new translations, Home untouched.
2026-05-18 12:28:16 +00:00
riyadhafraa c80b1ce085 #596 صلاحية الرئيس: حذف بحث الاجتماعات + زر الإعدادات
Two changes to artifacts/tx-os/src/pages/executive-meetings.tsx,
both gated on `isPresidentView` so non-president users are unaffected.

1. Schedule search hidden for the President
   - Wrapped <SearchToggle> in ScheduleSection (L2945) in
     {!isPresidentView && (...)}.
   - Kept searchQuery state + meetingMatchesSearch wiring intact:
     when query is "" the filter is a no-op, so the President sees
     the full day's meetings, and the box reappears for anyone else.

2. Gear button so the President can reach Settings (font controls)
   - Added an icon-only gear button (SettingsIcon, lucide-react —
     already imported) in the header right-side block (L1113),
     visible only when isPresidentView && section === "schedule".
     data-testid="em-president-settings".
   - Added an icon+label "back to schedule" button (ArrowRight for
     RTL / ArrowLeft for LTR) shown when isPresidentView &&
     section === "settings". data-testid="em-president-back-to-schedule".
   - Relaxed the force-schedule effect (L966) so the President is
     only redirected when section is neither "schedule" nor
     "settings" — otherwise the gear tap would bounce back instantly.
   - Sub-nav stays hidden (`!isPresidentView` on the SECTIONS map
     is unchanged). Gear is the only entry point.
   - No backend, no new i18n keys (reuses
     executiveMeetings.nav.settings / .schedule).
   - FontSettingsSection already renders for canRead users, and
     canEditGlobalFontSettings stays as the API reports it — no
     extra client-side gate.

`pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
2026-05-18 11:36:01 +00:00
riyadhafraa ccb891d4ca #594 meetings alert: replay chime after postpone
The user reported: when a 5-min meeting reminder fires and they hit
"Postpone 5 min", the second reminder appears at the new time but
**without sound** — and the only way to get the sound back is to leave
the app and come back (full tab reload).

Root cause: `UpcomingMeetingAlert` keeps a `playedRef: Set<number>` of
meeting ids that have already chimed, so the 30s polling/refetch
doesn't replay the chime over and over. The alert is mounted globally
in `App.tsx` and never unmounts during in-app navigation, so the Set
lives for the whole session. Postpone changes the meeting's
`startTime` but keeps the same `id`, so the second alert hit the
"already chimed" guard and stayed silent. Only a real tab reload
cleared the Set, which is exactly the workaround the user discovered.

Fix: change the dedupe key from `meeting.id` (number) to
`${meeting.id}:${startTime}` (string). Every postpone moves
startTime, so each post-postpone alert is treated as a fresh
instance and chimes again. The 3s throttle inside
`NotificationPlayer` still protects against burst-replay within the
same alert instance.

Untouched:
- `shownRef` — still keyed by id, because the server-side "shown"
  audit row is one-per-meeting-per-user by design.
- `NotificationPlayer`, iOS unlock path, vibration, throttle.
- Postpone API surface and `PostponeDialog`.

Verified: `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
2026-05-18 11:26:15 +00:00
riyadhafraa 28547e2a7e Hide the centered clock on small screens to prevent overlap
Hide the absolutely positioned HeaderClock on mobile viewports to prevent it from overlapping with the header title and action buttons, restoring it on larger screens.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 425e9ff3-23ed-48ac-9baa-e63cfcba6efa
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/m92e9kU
Replit-Helium-Checkpoint-Created: true
2026-05-18 11:20:21 +00:00