#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.
This commit is contained in:
@@ -3412,8 +3412,10 @@ function ScheduleSection({
|
||||
sortOrder: idx,
|
||||
kind: a.kind ?? "person",
|
||||
})),
|
||||
// #635: external meeting flag.
|
||||
isExternal: editingMeeting.isExternal,
|
||||
// #635/#639: external meeting flag — coerce to real
|
||||
// boolean so an undefined state never silently drops
|
||||
// the field from the PATCH body.
|
||||
isExternal: Boolean(editingMeeting.isExternal),
|
||||
};
|
||||
try {
|
||||
await apiJson(
|
||||
@@ -6691,9 +6693,12 @@ function ManageSection({
|
||||
// schedule survive a save through the Manage dialog.
|
||||
kind: a.kind ?? "person",
|
||||
})),
|
||||
// #635: send the external flag so the server can force rowColor='red'
|
||||
// and the cascade/postpone rules know to skip it.
|
||||
isExternal: editing.isExternal,
|
||||
// #635/#639: send the external flag as a real boolean so the
|
||||
// server can force rowColor='red' and the cascade/postpone rules
|
||||
// know to skip it. Coerce defensively — a stale render where
|
||||
// state.isExternal is undefined would otherwise silently send
|
||||
// `undefined` and the server PATCH would skip the column.
|
||||
isExternal: Boolean(editing.isExternal),
|
||||
};
|
||||
try {
|
||||
if (editing.id == null) {
|
||||
@@ -7571,21 +7576,26 @@ function MeetingFormDialog({
|
||||
onChange={(e) => update("meetingDate", e.target.value)}
|
||||
/>
|
||||
</FormRow>
|
||||
{/* #635: external-meeting toggle replaces the daily-number
|
||||
input (numbering is now fully auto-assigned by the
|
||||
server). When ON the row is force-tinted red and the
|
||||
alert-postpone button is disabled. */}
|
||||
{/* #635/#639: external-meeting toggle replaces the
|
||||
daily-number input (numbering is now fully auto-assigned
|
||||
by the server). When ON the row is force-tinted red and
|
||||
the alert-postpone button is disabled.
|
||||
`full` so it spans both grid columns on its own row —
|
||||
prevents the toggle from sharing a row with the date
|
||||
input and colliding with the time pickers below on
|
||||
narrow screens. */}
|
||||
<FormRow
|
||||
label={t("executiveMeetings.manage.field.isExternal")}
|
||||
hint={t("executiveMeetings.manage.field.isExternalHint")}
|
||||
full
|
||||
>
|
||||
<div className="flex items-center gap-2 h-9">
|
||||
<div className="flex items-center gap-3 py-1">
|
||||
<Switch
|
||||
checked={state.isExternal}
|
||||
onCheckedChange={(v) => update("isExternal", Boolean(v))}
|
||||
data-testid="em-form-isExternal"
|
||||
/>
|
||||
<span className="text-xs text-gray-700">
|
||||
<span className="text-sm text-gray-700">
|
||||
{state.isExternal
|
||||
? t("executiveMeetings.manage.field.isExternalOn")
|
||||
: t("executiveMeetings.manage.field.isExternalOff")}
|
||||
|
||||
Reference in New Issue
Block a user