Migrate Calendar interface patterns

This commit is contained in:
2026-08-03 15:08:18 +02:00
parent a125b666da
commit d7fd9447a2
13 changed files with 486 additions and 42 deletions
@@ -5,12 +5,16 @@ import {
} from "react";
import { Trash2 } from "lucide-react";
import {
ActionBlockerHint,
Button,
ConfirmDialog,
DateField,
Dialog,
DocumentationHelpLink,
SegmentedControl,
TimeField,
ToggleSwitch,
i18nMessage,
useUnsavedDraftGuard,
} from "@govoplan/core-webui";
import type {
@@ -29,6 +33,10 @@ import {
toInputDate,
toInputTime,
} from "./calendarViewModel";
import {
CALENDAR_DOCUMENTATION,
CALENDAR_I18N,
} from "./interfacePatterns";
type CalendarEventEndMode = "end" | "duration";
type CalendarEventEditScope = "occurrence" | "series";
@@ -160,6 +168,13 @@ export function CalendarEventDialog({
};
const initialEventDraftKey = useMemo(() => calendarDraftKey(eventDraft), []);
const eventDirty = calendarDraftKey(eventDraft) !== initialEventDraftKey;
const saveDisabledReason = saving
? CALENDAR_I18N.saving
: !canWrite
? CALENDAR_I18N.readOnly
: !summary.trim()
? CALENDAR_I18N.eventTitleRequired
: undefined;
useUnsavedDraftGuard({
dirty: eventDirty,
@@ -258,14 +273,11 @@ export function CalendarEventDialog({
function requestDelete() {
if (!event) return;
if (!confirmingDelete) {
setConfirmingDelete(true);
return;
}
void onDelete(event, editScope);
setConfirmingDelete(true);
}
return (
<>
<Dialog
open
title={event ? "i18n:govoplan-calendar.edit_event.a7028454" : "i18n:govoplan-calendar.new_event.2ef3795c"}
@@ -277,19 +289,32 @@ export function CalendarEventDialog({
<>
<div>
{event && canDelete &&
<Button type="button" variant="danger" onClick={requestDelete} disabled={saving}>
<Trash2 size={16} /> {confirmingDelete ? "i18n:govoplan-calendar.confirm_delete.c9f2829e" : "i18n:govoplan-calendar.delete.f6fdbe48"}
<Button type="button" variant="danger" onClick={requestDelete} disabled={saving} disabledReason={saving ? CALENDAR_I18N.saving : undefined}>
<Trash2 size={16} /> i18n:govoplan-calendar.delete.f6fdbe48
</Button>
}
</div>
<div className="calendar-dialog-actions">
<Button type="button" onClick={onCancel} disabled={saving}>i18n:govoplan-calendar.cancel.77dfd213</Button>
<Button type="submit" form={formId} variant="primary" disabled={saving || !canWrite}>{saving ? "i18n:govoplan-calendar.saving.ae7e8875" : "i18n:govoplan-calendar.save.efc007a3"}</Button>
<Button type="submit" form={formId} variant="primary" disabled={Boolean(saveDisabledReason)} disabledReason={saveDisabledReason}>{saving ? "i18n:govoplan-calendar.saving.ae7e8875" : "i18n:govoplan-calendar.save.efc007a3"}</Button>
</div>
</>
}>
<form id={formId} className="calendar-dialog-form" onSubmit={submit}>
<div className="calendar-dialog-documentation">
<DocumentationHelpLink reference={CALENDAR_DOCUMENTATION} />
</div>
{!canWrite && (
<ActionBlockerHint
tone="info"
reason={{
summary: CALENDAR_I18N.readOnly,
requiredAction: "Ask a calendar manager for event write permission."
}}
documentation={CALENDAR_DOCUMENTATION}
/>
)}
{canChooseSeries && (
<SegmentedControl
ariaLabel="Recurring event edit scope"
@@ -503,7 +528,22 @@ export function CalendarEventDialog({
</section>
</details>
</form>
</Dialog>);
</Dialog>
<ConfirmDialog
open={Boolean(event && confirmingDelete)}
title="i18n:govoplan-calendar.delete_event_title"
message={i18nMessage(editScope === "occurrence"
? "i18n:govoplan-calendar.delete_event_occurrence_message"
: "i18n:govoplan-calendar.delete_event_series_message", {
value0: event?.summary || "Event"
})}
confirmLabel="i18n:govoplan-calendar.delete.f6fdbe48"
tone="danger"
busy={saving}
onCancel={() => setConfirmingDelete(false)}
onConfirm={() => event && void onDelete(event, editScope)}
/>
</>);
}