#324 Make the Add/Edit Meeting dialog fit on a phone screen

After #322 trimmed the dialog, the Save/Cancel footer slid below
the visible 90vh sheet on phones because the whole DialogContent
was a single overflow-y-auto block.

Changes in artifacts/tx-os/src/pages/executive-meetings.tsx:

MeetingFormDialog
- Rebuilt DialogContent as a flex column: shrink-0 header,
  flex-1 min-h-0 overflow-y-auto middle (the only scroller),
  shrink-0 footer. Save/Cancel now stay pinned at the bottom
  even after many attendees are added.
- Reduced mobile padding/gaps (`p-4 sm:p-6`,
  `gap-3 sm:gap-4`, grid `gap-2 sm:gap-3`). Desktop spacing
  unchanged.
- Switched the field grid from `grid-cols-1 sm:grid-cols-2`
  to a flat `grid-cols-2` so the two short fields (التاريخ,
  الرقم اليومي) share a row even on mobile. Title spans both
  columns; time pickers span both on mobile and one each on
  sm+ via the new mobileFull variant.
- Inner scroll wrapper uses negative margins + matching padding
  so scroll content can extend edge-to-edge without losing the
  dialog's gutter.

FormRow helper
- Broadened `full` from `sm:col-span-2` to `col-span-2`
  (works in both 1-col and 2-col grids; only callers using
  `full` are in this file).
- Added `mobileFull` prop → `col-span-2 sm:col-span-1` for
  the time pickers, so AM/PM controls don't get squeezed on
  phones.

Out of scope (untouched): validation, save logic, attendee
model, removed-field defaults from #322, duplicate dialog,
audit, schedule view, translations.
This commit is contained in:
riyadhafraa
2026-05-03 10:09:29 +00:00
parent cfd2a46d39
commit d2dda556d6
2 changed files with 39 additions and 13 deletions
@@ -5399,20 +5399,25 @@ function MeetingFormDialog({
return (
<Dialog open={true} onOpenChange={(o) => !o && onClose()}>
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
{/* #324: rebuild DialogContent as a flex column so the header,
a single scrollable middle, and the footer stack predictably
on mobile. Without this the whole sheet scrolled and the
Save/Cancel buttons slid below the visible 90vh viewport on
phones. Reduced mobile padding/gaps; desktop unchanged. */}
<DialogContent className="max-w-3xl max-h-[90vh] p-4 sm:p-6 flex flex-col gap-3 sm:gap-4 overflow-hidden">
<DialogHeader className="shrink-0">
<DialogTitle>
{state.id == null
? t("executiveMeetings.manage.addMeeting")
: t("executiveMeetings.manage.editMeeting")}
</DialogTitle>
</DialogHeader>
{/* #322 polish: arrange the trimmed form into a tidy grid that
avoids dangling cells. Title spans full width on every
breakpoint so it gets enough room. Date + daily number sit
on one row on tablet/desktop, then start + end times share
the next row. On mobile each field stacks. */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div className="flex-1 min-h-0 overflow-y-auto -mx-4 px-4 sm:-mx-6 sm:px-6 space-y-3 sm:space-y-4">
{/* #322 polish (grid): title spans full width. Date + daily
number always share one row (both are short). Time pickers
are full-width on mobile so the AM/PM controls don't get
cramped, but share a row on tablet/desktop. */}
<div className="grid grid-cols-2 gap-2 sm:gap-3">
<FormRow
label={t("executiveMeetings.manage.field.titleAr")}
full
@@ -5441,7 +5446,10 @@ function MeetingFormDialog({
onChange={(e) => update("dailyNumber", e.target.value)}
/>
</FormRow>
<FormRow label={t("executiveMeetings.manage.field.startTime")}>
<FormRow
label={t("executiveMeetings.manage.field.startTime")}
mobileFull
>
<TimePicker12h
ref={startPickerRef}
value={state.startTime}
@@ -5457,7 +5465,10 @@ function MeetingFormDialog({
pmTestId="em-form-startTime-pm"
/>
</FormRow>
<FormRow label={t("executiveMeetings.manage.field.endTime")}>
<FormRow
label={t("executiveMeetings.manage.field.endTime")}
mobileFull
>
<TimePicker12h
ref={endPickerRef}
value={state.endTime}
@@ -5480,7 +5491,7 @@ function MeetingFormDialog({
preserved for meetings being edited. */}
</div>
<div className="border-t border-gray-200 pt-3 mt-1">
<div className="border-t border-gray-200 pt-3">
<div className="flex items-center justify-between mb-2 gap-2 flex-wrap">
<h4 className="font-semibold text-sm text-[#0B1E3F]">
{t("executiveMeetings.manage.attendees.label")} (
@@ -5569,8 +5580,12 @@ function MeetingFormDialog({
)}
</div>
</div>
</div>
<DialogFooter>
{/* #324: footer sits outside the scroll area so it stays
pinned to the bottom of the dialog even after many
attendees are added. */}
<DialogFooter className="shrink-0">
<Button variant="ghost" onClick={onClose} disabled={saving}>
{t("executiveMeetings.common.cancel")}
</Button>
@@ -5592,15 +5607,26 @@ function FormRow({
label,
children,
full,
mobileFull,
hint,
}: {
label: string;
children: React.ReactNode;
/** Always span both columns of a 2-col grid. Safe in single-column
* grids too (col-span-2 just clamps to the available width). */
full?: boolean;
/** Span both columns on mobile but a single column from sm+. Used
* by #324 so the time pickers don't get squeezed on phones. */
mobileFull?: boolean;
hint?: string;
}) {
const span = full
? "col-span-2"
: mobileFull
? "col-span-2 sm:col-span-1"
: "";
return (
<div className={full ? "sm:col-span-2" : ""}>
<div className={span}>
<Label className="text-xs text-gray-700">{label}</Label>
<div className="mt-1">{children}</div>
{hint && <p className="text-[11px] text-gray-500 mt-0.5">{hint}</p>}
Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB