From eaba29095e5fa195322adbbb78d86257fd2216fa Mon Sep 17 00:00:00 2001 From: riyadhafraa <49757212-riyadhafraa@users.noreply.replit.com> Date: Wed, 29 Apr 2026 12:04:43 +0000 Subject: [PATCH] Task #137: Polish Executive Meetings schedule table (5 refinements + post-review fixes) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original 5 refinements: 1. Time displayed on a single line (TimeRangeCell with whitespace-nowrap). 2. Time inline-editable with two HH:MM inputs. 3. Reliable attendee inline-edit with placeholder + dir handling. 4. Floating formatting toolbar via portal so it never clips the table. 5. Inline "Add row" tr at the bottom of the table. Follow-up fixes from architect reviews: - Add row scrolls the new row into view (requestAnimationFrame + scrollIntoView center) and auto-opens the title cell in edit mode (createRow captures POST response id, threads autoEditTitleId through ScheduleSection -> MeetingRow -> EditableCell.startInEditMode). autoEditTitleId hardened with a 1.5s fallback clear so it can't go stale if the title cell never mounts. - Time editor explicit Save/Cancel buttons (Check/X icons, em-time-save-/ em-time-cancel- testids, onMouseDown preventDefault to survive blur). - Invalid time order (start > end) raises a destructive toast with i18n key executiveMeetings.schedule.timeOrderError (AR + EN), keeps the editor open, and refocuses the start input. Equal start/end is valid per spec. Server errors also toasted. - Toolbar always placed BELOW the editing cell (no flip-above) so it never sits on top of the row above the active cell. - Toolbar horizontally clamped inside the table's scroll container (nearest overflowX:auto/scroll ancestor), not just the viewport, so it never escapes the table visually. - Add-row label uses spec-mandated copy ("+ Add meeting" / "+ أضف اجتماعًا جديدًا") via i18n key. - Removed duplicate error toast on time save: TimeRangeCell now only rolls back local state in its catch; the parent saveTimes is the single source for surfacing the destructive error toast. Files touched: - artifacts/tx-os/src/pages/executive-meetings.tsx - artifacts/tx-os/src/components/editable-cell.tsx - artifacts/tx-os/src/locales/{ar,en}.json Verification: - E2E (Playwright): all 5 features + post-review fixes pass. * Toolbar measured BELOW the cell at top and bottom of viewport (delta ~4px, isBelow=true in both cases). * Toolbar measured INSIDE the table scroll container's left/right. * Equal start/end (14:00–14:00) saved without validation toast. - Manual API: POST 201, PATCH 200, validation 400, DELETE 204. - Tasks #122 and #125 still functional. - Pre-existing failing tests (admin.tsx codegen drift from #96 + 3 api-server tests) are unrelated and untouched. --- artifacts/tx-os/src/locales/ar.json | 2 +- artifacts/tx-os/src/locales/en.json | 2 +- artifacts/tx-os/src/pages/executive-meetings.tsx | 13 +++++-------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/artifacts/tx-os/src/locales/ar.json b/artifacts/tx-os/src/locales/ar.json index 6f39a6d3..3e72cfef 100644 --- a/artifacts/tx-os/src/locales/ar.json +++ b/artifacts/tx-os/src/locales/ar.json @@ -771,7 +771,7 @@ "dragRow": "اسحب لإعادة الترتيب", "editMeetingTitle": "تعديل عنوان الاجتماع", "schedule": { - "addRow": "إضافة سطر", + "addRow": "+ أضف اجتماعًا جديدًا", "newMeetingDefaultAr": "اجتماع جديد", "newMeetingDefaultEn": "New meeting", "timeStart": "وقت البداية", diff --git a/artifacts/tx-os/src/locales/en.json b/artifacts/tx-os/src/locales/en.json index a7526a57..bfabe442 100644 --- a/artifacts/tx-os/src/locales/en.json +++ b/artifacts/tx-os/src/locales/en.json @@ -723,7 +723,7 @@ "label": "Row color" }, "schedule": { - "addRow": "Add row", + "addRow": "+ Add meeting", "newMeetingDefaultAr": "اجتماع جديد", "newMeetingDefaultEn": "New meeting", "timeStart": "Start time", diff --git a/artifacts/tx-os/src/pages/executive-meetings.tsx b/artifacts/tx-os/src/pages/executive-meetings.tsx index 9e242ae2..d8ba3f84 100644 --- a/artifacts/tx-os/src/pages/executive-meetings.tsx +++ b/artifacts/tx-os/src/pages/executive-meetings.tsx @@ -1792,17 +1792,14 @@ function TimeRangeCell({ setEditing(false); try { await onSaveTimes(newStart, newEnd); - } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - toast({ - title: t("common.error"), - description: msg, - variant: "destructive", - }); + } catch { + // The parent `saveTimes` handler is responsible for surfacing the + // error toast; we only need to roll back the local draft state so + // the cell shows the previously-saved values. setStart(startSaved); setEnd(endSaved); } - }, [start, end, startSaved, endSaved, onSaveTimes, toast, t]); + }, [start, end, startSaved, endSaved, onSaveTimes]); const onFocusOut = (e: React.FocusEvent) => { if (!editing) return;