Commit Graph

1106 Commits

Author SHA1 Message Date
riyadhafraa 32cac678bf #641 Schedule cell polish: alignment + external text colour
- Attendees column no longer centres its content. AttendeeFlow's <ul>
  switched from justify-center to justify-start; AttendeeGroup header
  and subheading rows (both committed and pending) switched from
  text-center to text-start. Restores cell-start alignment (right in
  AR, left in EN) the user expected on fresh inline-add and on
  existing rows.
- External meetings now render the meeting title cell text and the
  attendee names in red (#b91c1c), matching the row tint family, in
  addition to the existing red background. Implemented by:
  * Conditional text-[#b91c1c] / text-[#0B1E3F] on the meeting <td>
    based on meeting.isExternal.
  * New optional `externalText` prop on AttendeeFlowSharedProps,
    threaded from AttendeesCell (derived from meeting.isExternal) and
    applied as a colour class on the AttendeeFlow root <ul> so all
    attendee names inherit red. Group headers and subheadings keep
    their neutral navy palette per scope.
- Non-external rows and the cancelled/highlighted white-on-red # cell
  are untouched. Print/PDF path reuses the same renderer so the red
  carries through automatically.
- No schema/API/migration changes. TS clean.

Files: artifacts/tx-os/src/pages/executive-meetings.tsx
2026-05-25 12:51:46 +00:00
riyadhafraa a131b2dc75 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: a1009a04-06b8-4ae1-9bb4-ba5a718c50c0
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/2UyHOi5
Replit-Helium-Checkpoint-Created: true
2026-05-25 12:45:26 +00:00
riyadhafraa eb25beec29 #639: Fix external-meeting toggle (save + layout)
Two issues reported on the new "اجتماع خارجي" toggle from #635:

1. "Doesn't save." Investigation: the server schema, PATCH/POST handlers,
   GET endpoint (full-row select), and DB column are all correct, and
   `docker/migrate.sh` runs `pnpm --filter @workspace/db run push-force`
   on every `docker compose up`, so the production schema does receive
   the `is_external` column. The likeliest real-world cause is a stale
   API image (column existed but the post-review API code that persists
   the flag wasn't deployed yet), or a transient stale-state render
   where `state.isExternal` was undefined and silently dropped from the
   PATCH body. Hardened the client so neither can happen again:
   - Both save sites (Manage dialog `save()` ~6700, inline Schedule
     edit save body ~3421) now send `Boolean(state.isExternal)` instead
     of the raw value, so an undefined state coerces to `false` rather
     than dropping the field.

2. "Overlaps other fields." The toggle row was sharing a row with the
   date input in the 2-col grid and used a fixed `h-9` wrapper that
   sat awkwardly next to the taller time pickers on narrow screens.
   - Made the FormRow `full` so it spans both columns on its own row,
     above the time pickers.
   - Dropped the fixed `h-9` and switched to `py-1` + `gap-3` + `text-sm`
     so it matches the form's vertical rhythm on iPhone, iPad portrait,
     iPad landscape, and desktop.

Out of scope / not changed
- No server changes (the server already accepts boolean | number and
  coerces to boolean; `Boolean(data.isExternal ?? false)` on POST and
  `if (data.isExternal !== undefined)` on PATCH are unchanged).
- No new badge / copy — that lives under separate proposed work.
- Postpone / cascade rules unchanged.
2026-05-25 12:19:48 +00:00
riyadhafraa d82f37b46c Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: c15f0cec-032c-4934-8d7b-1541df865fc6
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/2UyHOi5
Replit-Helium-Checkpoint-Created: true
2026-05-25 12:18:23 +00:00
riyadhafraa 736785e3d3 #635: External meetings + auto-numbering
User asked for three things in the executive-meetings module:
1. Remove the "daily number" input from the add/edit dialog — numbering
   is auto-assigned by the server already, so the field was just noise.
2. Add an "اجتماع خارجي" (external meeting) toggle. When ON, the row
   is force-tinted red in the schedule grid.
3. External meetings must be excluded from the auto-postpone flow:
   the alert "Postpone" button is disabled, and the cascade shift
   skips them as followers.

Changes
- lib/db/src/schema/executive-meetings.ts
  + `is_external boolean not null default false` column. Pushed via
    drizzle-kit (no destructive migration; defaults backfill).
- artifacts/api-server/src/routes/executive-meetings.ts
  + `isExternal` added to base zod fields, POST insert, PATCH update.
  + POST/PATCH force `rowColor='red'` when `isExternal=true`.
  + POST /:id/postpone-minutes rejects external meetings with
    HTTP 409 + code `external_meeting_no_auto_postpone`.
  + `computeCascadeShift` filters out external followers (preview +
    writer stay in lockstep, as the comment promises).
- artifacts/tx-os/src/pages/executive-meetings.tsx
  + Meeting type + MeetingFormState gain `isExternal`; dropped the
    `dailyNumber` field from the form state entirely.
  + `emptyMeetingForm` / `openEdit` updated; ManageSection.save() and
    the inline ScheduleSection save body now send `isExternal` and
    never send `dailyNumber`.
  + MeetingFormDialog: removed the daily-number FormRow and added a
    Switch-based external-meeting FormRow with localized hint.
  + `rowColors` memo coerces to "red" whenever `m.isExternal`.
  + Audit-diff "interesting" list now includes `isExternal`.
- artifacts/tx-os/src/components/executive-meetings/upcoming-meeting-alert.tsx
  + Meeting type gains optional `isExternal`.
  + "Postpone" button disabled + tooltip when meeting is external.
- locales: added `field.isExternal`, `field.isExternalHint`,
  `field.isExternalOn/Off`, and `alert.externalCannotPostpone` in
  both ar.json and en.json. Existing dailyNumber keys kept (still
  referenced by the manage-table column header / cell display).

Post-review hardening (from architect pass)
- PATCH now coerces rowColor → 'red' for any PATCH that touches a row
  that is (or becomes) external. Prevents PDF/export paths that read
  raw rowColor from showing a non-red tint for externals.
- Schedule row quick-actions popover: the "Postpone" button is now
  disabled with a localized tooltip when the meeting is external,
  matching the upcoming-meeting alert behavior.
- PostponeDialog.handleErr maps the 409 code
  `external_meeting_no_auto_postpone` to the localized
  `alert.externalCannotPostpone` toast so users see a real reason
  instead of the raw English error string.

Notes
- The `dailyNumber` column stays in DB (heavily used for slot
  persistence and the unique index); only the form input was removed.
  Server's `nextDailyNumber()` already auto-assigns when the field is
  absent on POST, and PATCH leaves it untouched when absent.
- Two pre-existing TS errors remain in api-server (`isHighlighted`
  type-inference quirk on `z.union(...).transform(...)` and a
  font_settings comparison) — not in scope for this task.
- Tests not added; verification by typecheck on changed surfaces and
  workflow-restart smoke. No e2e harness was wired.
2026-05-25 11:59:54 +00:00
riyadhafraa 5dc42fdb81 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: e83fea25-962d-4eb9-95bd-d2f39525752a
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/gIKdbC8
Replit-Helium-Checkpoint-Created: true
2026-05-25 11:44:31 +00:00
riyadhafraa 65bfe32e60 Task #634: fix SendNoteDialog centering on iPad PWA with keyboard open
User-reported regression from #630: opening "Send note" on iPad PWA
showed the recipient list pushed to the left side of the screen,
narrower than designed, with the dialog title + search input clipped
off the top. Dismissing the keyboard restored normal centered layout.

Root cause: the `keyboardFallback` branch (iPad PWA, where
visualViewport doesn't update) set `top: "6vh"` in *layout viewport*
coordinates. On iPad PWA Safari, opening the keyboard scrolls the
page down behind the keyboard, so layout-viewport `6vh` ends up
above the visible visual viewport — clipping the top half of the
dialog. Separately, the inline `transform` replaced Tailwind's
translate-x/y on Radix's content, and without an explicit `left:50%`
the animation/RTL combination shifted the box left.

Fix (artifacts/tx-os/src/components/notes/send-note-dialog.tsx):
- `keyboardFallback`: `top: calc(${vv.offsetTop || 0}px + 6vh)` so the
  anchor follows the visible visual viewport when Safari scrolls the
  page behind the keyboard. Add explicit `left: 50%`. Add
  `overflowY: auto` so if dialog content exceeds 50dvh, the dialog
  scrolls internally instead of clipping the header.
- `keyboardActive` branch: also add explicit `left: 50%` defensively
  for the same animation/RTL reason (no behavior change on devices
  where it was already working, but eliminates the asymmetry).

No changes to the shared `dialog.tsx`, composer, or executive-meetings
dialog — scope strictly limited to the regression site.

TypeScript: clean. Pre-existing errors in api-server/src/routes/push.ts
unrelated to this diff.
2026-05-25 11:36:29 +00:00
riyadhafraa e17eaa8986 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: e38cd10c-d814-4d2d-8a2d-246de925ebef
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/gIKdbC8
Replit-Helium-Checkpoint-Created: true
2026-05-25 11:34:03 +00:00
riyadhafraa be770081f8 Task #632: realtime order delivery for recipients on iPad PWA
Bug: order creator (services manager) saw new orders instantly with
sound, but other users holding orders.receive — even with the app
foregrounded on the Orders screen — got nothing until they force-quit
and reopened the PWA, at which point the orders appeared. Root cause:
Socket.IO silently drops behind Tailscale/NAT on iPad PWA and the
client neither detected it nor refetched missed state on reconnect.
The creator was unaffected because their POST mutation updates their
queries locally without depending on the realtime channel.

Client (artifacts/tx-os/src/hooks/use-notifications-socket.ts):
- Tighten io() options: reconnection {Delay 500, DelayMax 3000,
  Attempts Infinity, timeout 10s}.
- Track `wasDisconnected` flag; on `disconnect` flip it and log the
  reason (skipping the clean "io client disconnect" path).
- On `connect`, if previously disconnected, invalidate every realtime-
  driven query key: notifications, home stats, my/incoming orders,
  notes, note-folders, exec meetings (list/alert-state/notifications),
  apps, /me, roles, permissions. Warmup window is reset BEFORE the
  refetch so any flushed notification_created events post-reconnect
  don't chime.
- Add a `visibilitychange` listener: on foreground return, if the
  socket is disconnected, force `socket.connect()`; if it's "connected"
  but possibly half-open (silent drop), round-trip a 3s-timeout
  `client_health_probe` ack — on timeout, `disconnect().connect()`.
- `connect_error` logger for field debugging.

Server (artifacts/api-server/src/index.ts):
- Tighten Socket.IO pingInterval=10s, pingTimeout=5s (was default
  25s/20s) so dead-connection detection cycle drops from ~45s to ~15s.
- Add `client_health_probe` handler that acks immediately — pairs
  with the client-side half-open probe.

Deviations from plan: skipped the optional UI connection indicator
(point 5) — not necessary to fix the reported bug; can ship later if
users still feel uncertain about connection state.

Architect approved with one minor caveat: severe (>3s) transient
latency on foreground could trigger a one-off socket cycle. Acceptable
tradeoff and explicitly documented in the comment.

Pre-existing TS errors in api-server/src/routes/push.ts are unrelated
to this task and not touched by this diff.
2026-05-24 10:29:04 +00:00
riyadhafraa a68c95436d Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 737db90d-7f56-4a11-a382-013d09f4b5b7
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-24 10:22:18 +00:00
riyadhafraa 9c5e3a3f86 Task #630: keep recipients list visible above iPad keyboard in Send Note
Problem: opening Send Note on iPad, tapping the search field opened the
soft keyboard which covered the recipients list and the Send button —
the dialog stayed centered on the full layout viewport.

Fix (artifacts/tx-os/src/components/notes/send-note-dialog.tsx):

Two-tier keyboard detection:
  1. Primary — `vv.keyboardInset > 0` from useVisualViewport. Works on
     desktop touch laptops, iPad Safari (regular tab), Android Chrome.
     When true, override DialogContent style with
       top = vv.offsetTop + vv.height/2 − 48 (QuickType inset)
       transform: translate(-50%, -50%)
     so the dialog recenters around the visible viewport region.
  2. Fallback — `searchFocused && matchMedia('(pointer: coarse)')`.
     Only used when visualViewport does NOT report an inset, which is
     the iPad PWA (Add to Home Screen) case explicitly called out in
     components/ui/dialog.tsx comment. Top-anchors at 6vh with
     maxHeight 50dvh so the dialog never crosses the screen midpoint.
  3. Neither — pass NO style at all so Radix's default centered layout
     is fully restored (no leftover transition or top).

Touch-only fallback gating (matchMedia pointer:coarse) prevents the
earlier desktop-regression flagged by code review — focusing the
search on a desktop never repositions the dialog.

Other changes:
- onFocus/onBlur on the search input feed the fallback signal.
- Blur is debounced 150ms so tapping a recipient row mid-blur doesn't
  recenter the dialog out from under the finger.
- useEffect cleanup clears pending blur timeout on unmount.

Verification: tsc clean. Architect approved the touch-gated fallback;
follow-up review reconciled the diff with the spec's primary
visualViewport-driven path.
2026-05-24 09:48:10 +00:00
riyadhafraa 744b7814f5 Task #630: keep recipients list visible above iPad keyboard in Send Note
Problem: opening Send Note on iPad PWA, tapping the search field popped
up the soft keyboard which covered the entire people list and the Send
button. The previous fix relied on visualViewport to shrink the list,
but iPad PWAs don't reliably resize visualViewport when the keyboard
opens (see the note in components/ui/dialog.tsx referencing the
reverted #622–#624 global attempts).

Fix (artifacts/tx-os/src/components/notes/send-note-dialog.tsx):
- Track search-input focus directly — the most reliable "keyboard is
  about to open" signal on touch devices, independent of visualViewport.
- Gate the override behind `matchMedia('(pointer: coarse)')` so it
  only fires on touch-primary devices (iPad/iPhone/Android) and never
  on desktop or trackpad laptops — addressing the architect's
  cross-platform regression flag.
- When the gate is active, override DialogContent's Radix center
  anchor (top:50%; translate(-50%,-50%)) with `top:6vh;
  translate(-50%,0); maxHeight:50dvh`. The dialog grows downward from
  a fixed top edge so it always fits in the upper half of the screen,
  leaving the lower half free for the keyboard.
- Cap `listMaxHeight` to ~50% of innerHeight in the same gated
  condition, as a backstop where visualViewport stays full-height.
- Debounce blur by 150ms so a tap on a recipient row doesn't lose
  the row mid-tap to a center-jump animation; clear the timeout on
  unmount.
- Added 120ms ease transition on top/transform so the layout swap
  doesn't snap.

Deviations: original plan used vv.offsetTop+vv.height/2 to reposition,
but that depends on the same unreliable visualViewport. Switched to
a focus + coarse-pointer driven approach which works on iPad PWA.

Verification: tsc clean. Architect re-review pending after the touch
gate was added (first review flagged the missing platform guard,
which this revision addresses directly).
2026-05-24 09:45:38 +00:00
riyadhafraa f0f72cbd92 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: a561c1c0-9134-4e0f-917f-d00f833b9e1f
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-24 09:41:06 +00:00
riyadhafraa 96b8e0bcb9 Improve notification sound throttling and delivery reliability
Refactor notification sound playback to use per-bucket throttling, adjust socket warmup, and ensure push notifications are sent even if the client is considered connected.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 3dcee04b-6717-4c1f-a172-b1f9c2febbe0
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-24 08:33:53 +00:00
riyadhafraa 0c1251aaf1 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 6d2335b1-76d0-46ae-bcb5-9295dab12ff3
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-24 08:16:55 +00:00
riyadhafraa 305155a4fd Task #626: stop notifications after logout + tighten meeting reminder
- /auth/logout: delete all push_subscriptions rows for the user before
  destroying the session. Best-effort with logger.warn on failure so an
  operator can correlate any leaked-ring report to a real DB error.
- home.tsx handleLogout: call pushSub.disable() before the logout
  mutation, raced against a 1.5s timeout so a stalled service worker
  cannot block sign-out.
- executive-meeting-scheduler: switch the eligibility filter from
  denylist (ne cancelled + ne completed) to whitelist
  (eq status='scheduled'). Postponed / rescheduled / future statuses
  can no longer trigger false 5-minute reminders.
- docker-compose.yml: pin TZ=Asia/Riyadh on postgres, api, and web
  services so the scheduler's naive date/time math matches the
  operator's wall clock instead of UTC.

Gitea push failed with TLS error during this session — code committed
locally, needs manual `./scripts/publish-to-gitea.sh --push` retry
when the desktop-11cj93j tunnel recovers.
2026-05-23 08:25:04 +00:00
riyadhafraa 932681786b Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: f44fd507-9b35-490d-889e-eed85d20dc44
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-23 08:05:00 +00:00
riyadhafraa b402138464 Remove global dialog adjustments for soft keyboard
Revert global CSS and JavaScript hooks that attempted to manage dialog positioning with the soft keyboard, which caused issues on desktop.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 3ea26578-1c32-4300-8404-7ae727e33444
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 12:43:31 +00:00
riyadhafraa 218d7dac58 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 80fcbe81-ed83-4245-a43c-c4079f096dda
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 12:39:05 +00:00
riyadhafraa 338d80cf0a iOS keyboard fix v3 — visualViewport + touch-gate (#624)
Root causes the prior attempts missed:

1) Safari iOS/iPadOS ignores `interactive-widget=resizes-content`,
   so `100dvh` never shrinks when the soft keyboard opens. Every
   previous override that used `dvh` to size the dialog was sized
   to the full screen and ran behind the keyboard.

2) The CSS rule from #622 (`[role="dialog"]:has(:focus)`) was
   unconditional. On desktop, focusing any input inside a Radix
   DialogContent instantly stretched it to width:100vw + top:0,
   which collided with Radix's open-state slide-animation
   transforms and rendered the dialog as a broken narrow strip
   pinned in the top-left corner — visible in Tahani's laptop
   screenshot when opening "Add Meeting".

3) `AdminFormDialog` puts `role="dialog"` on a NON-fixed inner
   card, so the rule's `top/left/right` had no effect there
   anyway; the card stayed centred in a layout-viewport-sized
   wrapper which iOS does not shrink.

Fix:
- New `useVisualViewportVars` hook mounted in
  NotificationsSocketBridge. Writes `--vv-height` and
  `--vv-offset-top` on `<html>` from `window.visualViewport`,
  updated on resize / scroll / orientationchange. Falls back
  to `innerHeight`/0 if visualViewport is absent.
- Rewrote the index.css dialog rule:
  * Gated inside `@media (any-pointer: coarse)` so desktop is
    completely unaffected.
  * Uses `var(--vv-height, 100vh)` and `var(--vv-offset-top, 0px)`
    instead of `100dvh` / `0`, so dialogs actually track the
    visible band on iOS.
- New `.dialog-vv-wrapper` helper class that applies the same
  vv-sized top/height to bespoke full-screen overlay wrappers.
- Applied `.dialog-vv-wrapper` to AdminFormDialog and the admin
  ConfirmDialog wrappers; switched their `fixed inset-0` to
  `fixed inset-x-0 top-0 h-screen` and their inner cards from
  `max-h-[90vh]`/`max-h-[85vh]` to `max-h-full` so the card
  shrinks with the wrapper.

Kept `useScrollFocusedDialogField` unchanged — works correctly
once the dialog itself is sized to the visible band.

`tsc --noEmit` clean.
2026-05-21 12:04:12 +00:00
riyadhafraa 0a1c6b41de iPad keyboard scroll fix v2 (#623)
#622's `useScrollFocusedDialogField` still failed on Tahani's iPad
for two reasons:

1) Touch-gate too narrow: `pointer: coarse` is *primary* pointer.
   An iPad connected to a Magic Keyboard / trackpad reports primary
   as `fine`, so the hook returned early and never armed. Broadened
   to `(pointer: coarse) OR (any-pointer: coarse)` so any device
   with any touch input qualifies.

2) `scrollIntoView` doesn't work inside `position: fixed` on iOS
   Safari/PWA — the scroll silently no-ops. Replaced it with a
   manual walk: from the focused field, ascend to the nearest
   ancestor whose computed `overflow-y` is auto/scroll AND that
   actually has overflow, stopping at the dialog root. Compute the
   target's offset within that container's content and set
   `container.scrollTop` so the target sits centred in the visible
   band, clamped to [0, scrollHeight-clientHeight].

Also tightened cleanup per #622's reviewer note — timer IDs are
now removed from the tracking set inside the timeout callback as
well as on blur.

No CSS or dialog component changes. `tsc --noEmit` clean.
2026-05-21 11:21:58 +00:00
riyadhafraa 6896304981 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: b591d01c-8c2c-4e81-81d9-b67736dfaea9
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 11:21:10 +00:00
riyadhafraa c98bf56706 Scroll focused dialog field above iOS keyboard (#622)
The CSS `[role="dialog"]:has(:focus)` rule from #621 promotes any
focused dialog to a full-width sheet sized to `100dvh`, but Safari
does not auto-scroll the focused input into view inside the
dialog's own overflow container — it only tries to scroll the
document, which our position:fixed dialog ignores. The field stays
where it was, often behind the keyboard.

Added a global `useScrollFocusedDialogField` hook (in
artifacts/tx-os/src/hooks/) that listens to `document` focusin. If
the target is an input/textarea/select/contenteditable inside a
`closest('[role="dialog"]')`, it calls
`target.scrollIntoView({block:'center', behavior:'smooth'})` twice
(300ms and 600ms) to cover the iPad keyboard animation window and
the dialog's `max-height:100dvh` recalc. Timers are cleared on blur
and on unmount.

Mounted the hook once in `NotificationsSocketBridge` inside App.tsx
so it covers every page and every dialog kind we use (Radix
DialogContent, the bespoke AdminFormDialog, ad-hoc role="dialog"
wrappers) without touching their JSX.

No CSS or dialog component changes. `tsc --noEmit` clean.
2026-05-21 09:05:29 +00:00
riyadhafraa f352aa574d Scroll focused dialog field above iOS keyboard (#622)
The CSS `[role="dialog"]:has(:focus)` rule from #621 promotes any
focused dialog to a full-width sheet sized to `100dvh`, but Safari
does not auto-scroll the focused input into view inside the
dialog's own overflow container — it only tries to scroll the
document, which our position:fixed dialog ignores. The field stays
where it was, often behind the keyboard.

Added a global `useScrollFocusedDialogField` hook (in
artifacts/tx-os/src/hooks/) that listens to `document` focusin. If
the target is an input/textarea/select/contenteditable inside a
`closest('[role="dialog"]')`, it calls
`target.scrollIntoView({block:'center', behavior:'smooth'})` twice
(300ms and 600ms) to cover the iPad keyboard animation window and
the dialog's `max-height:100dvh` recalc. Timers are cleared on blur
and on unmount.

Mounted the hook once in `NotificationsSocketBridge` inside App.tsx
so it covers every page and every dialog kind we use (Radix
DialogContent, the bespoke AdminFormDialog, ad-hoc role="dialog"
wrappers) without touching their JSX.

No CSS or dialog component changes. `tsc --noEmit` clean.
2026-05-21 09:04:41 +00:00
riyadhafraa 958c40b5fb Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: fb89a8f2-a9db-43ed-943f-b147e6519687
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 09:03:51 +00:00
riyadhafraa 9e590b959e Unify edit-role dialog with AdminFormDialog (#621)
The "edit role" dialog in admin.tsx was hand-rolled as a bespoke
<div role-less wrapper> with its own close button, sticky footer and
full-width split buttons. That made it look different from every
other admin dialog (add role, add/edit group, add user), and on
iPad the action buttons floated mid-dialog because the content
exceeded max-h-[92vh]. The custom wrapper also lacked role="dialog",
so the new `:has(:focus)` CSS keyboard rule (index.css:492) never
applied to it.

Replaced the wrapper with AdminFormDialog (maxWidth="lg", KeyRound
icon, same title key). All inner content — name/desc fields, rename
warning, permissions list, removal impact, RolePermissionHistory,
RecentActivityForTarget — moved verbatim as children. Removed the
custom sticky footer; AdminFormDialog provides the unified footer
with cancel/save buttons. Preserved testIds `edit-role-dialog` and
`edit-role-submit`. Disabled logic translated 1:1 into
submitDisabled + isPending props (note: `impactError` coerced to
boolean via `!!` to satisfy the prop type).

No behavior change: same handlers (closeEditDialog, handleEdit),
same loading spinner, same disabled conditions. Bonus: the keyboard
override CSS now applies because AdminFormDialog already sets
role="dialog".

`tsc --noEmit` clean.
2026-05-21 08:57:08 +00:00
riyadhafraa 6a151393f5 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 57ab0c63-40b4-44e7-9bf3-7d71a7442473
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 08:56:06 +00:00
riyadhafraa 1e8f4435cd Improve dialog behavior when virtual keyboard is open
Update dialog component to use CSS :has(:focus) for keyboard detection, removing reliance on visual viewport for better cross-platform compatibility.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 144d5d9b-0d4f-4783-a2d4-8af91a180dd6
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 08:45:43 +00:00
riyadhafraa 27dea3f39e Add a temporary diagnostic display for keyboard inset calculations
Add a temporary debug overlay to the DialogContent component in `dialog.tsx` to display `keyboardInset`, `height`, and `offsetTop` values, and the keyboard open state.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: e4cbec37-342b-4d6e-9215-50c182eb1ed0
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 08:30:27 +00:00
riyadhafraa 0f7be86504 Improve dialog behavior and appearance when the keyboard is open
Refactor dialog styling to use global CSS with !important rules for keyboard open state, overriding inline styles and Tailwind classes.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 93a2c072-c3ed-47c7-99d1-75c48f36c85e
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 08:10:48 +00:00
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 f02305fe9f Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: af14f8d6-5fb9-40dd-b404-a1cc57afe3b2
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:42:19 +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 dd68923ba3 Allow relative URLs for upload destinations in API responses
Update OpenAPI spec and generated schemas to permit relative paths for upload URLs, resolving validation errors with the local storage driver.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 563d7ca2-281f-4d1e-bada-a5bbc9d9f061
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 09:30:21 +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 b84fe4e5c7 Update caching headers to ensure all devices get the latest site version
Modify Nginx configuration to include aggressive caching headers for service worker and index.html to prevent stale content on various devices.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 5c11d21b-1972-4651-a7a2-5deab7b263d1
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 20:17:47 +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