fix(plan): edit/add the clicked record + layer-aware add in exception mode

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-08 11:29:52 +02:00
parent 9370423fb0
commit 23ac924472
4 changed files with 151 additions and 22 deletions

View File

@@ -31,6 +31,7 @@ interface Project {
export type PlanCellModalMode =
| { kind: "closed" }
| { kind: "create"; userId: number; date: string }
| { kind: "create-override"; userId: number; date: string }
| {
kind: "edit-range";
entryId: number;
@@ -85,8 +86,14 @@ interface Props {
date: string,
) => Promise<void>;
onSwitchToEditRange: (entryId: number, userId: number, date: string) => void;
/** Open the create form for a brand-new record on (userId, date). */
onAddRecord: (userId: number, date: string) => void;
/** Open the create form for a brand-new record on (userId, date). The
* `source` picks the layer the new record lands in: "entry" in normal mode,
* "override" in exception mode (a day whose shown records are overrides). */
onAddRecord: (
userId: number,
date: string,
source: "entry" | "override",
) => void;
/** Open the right editor for one of the day's existing records. */
onEditRecord: (cell: ResolvedCell, userId: number, date: string) => void;
}
@@ -137,21 +144,26 @@ function EditForm(props: Props) {
const [confirmDelete, setConfirmDelete] = useState(false);
// Narrow mode to the kinds EditForm actually handles. The call site in
// PlanCellModal only passes "create" | "edit-range" | "edit-override" but
// the parameter type is the full union, so we narrow explicitly here.
// PlanCellModal only passes "create" | "create-override" | "edit-range" |
// "edit-override" but the parameter type is the full union, so we narrow
// explicitly here.
if (
mode.kind !== "create" &&
mode.kind !== "create-override" &&
mode.kind !== "edit-range" &&
mode.kind !== "edit-override"
) {
return null;
}
const isOverride = mode.kind === "edit-override";
// An override is a single-day record — both editing one ("edit-override")
// and creating one ("create-override") lock the date and hide the range UI.
const isOverride =
mode.kind === "edit-override" || mode.kind === "create-override";
const activeCategories = props.categories.filter((c) => c.is_active);
const initial = (() => {
if (mode.kind === "create") {
if (mode.kind === "create" || mode.kind === "create-override") {
return {
date_from: mode.date,
date_to: mode.date,
@@ -196,9 +208,11 @@ function EditForm(props: Props) {
const title =
mode.kind === "create"
? "Nový záznam plánu"
: mode.kind === "edit-range"
? "Upravit rozsah"
: "Upravit přepsání dne";
: mode.kind === "create-override"
? "Nové přepsání dne"
: mode.kind === "edit-range"
? "Upravit rozsah"
: "Upravit přepsání dne";
const handleSubmit = async () => {
setSubmitting(true);
@@ -213,6 +227,17 @@ function EditForm(props: Props) {
category,
note,
});
} else if (mode.kind === "create-override") {
// An override is a single day — lock it to mode.date regardless of
// any local dateFrom/isRange state (the date field is disabled for
// overrides, but be explicit).
await onSaveOverride({
user_id: mode.userId,
shift_date: mode.date,
project_id: projectId,
category,
note,
});
} else if (mode.kind === "edit-range") {
await onUpdateEntry(mode.entryId, {
date_from: dateFrom,
@@ -255,6 +280,10 @@ function EditForm(props: Props) {
const showRetiredCategory =
category && !activeCategories.some((c) => c.key === category);
// Both create flows ("create" entry, "create-override") show "Vytvořit" and
// have no Smazat button (there is no existing row to delete yet).
const isCreate = mode.kind === "create" || mode.kind === "create-override";
return (
<>
<Modal
@@ -262,10 +291,10 @@ function EditForm(props: Props) {
title={title}
onClose={onClose}
onSubmit={handleSubmit}
submitText={mode.kind === "create" ? "Vytvořit" : "Uložit"}
submitText={isCreate ? "Vytvořit" : "Uložit"}
loading={submitting}
>
{mode.kind !== "create" && (
{!isCreate && (
<Box sx={{ mb: 2 }}>
<Button
variant="outlined"
@@ -537,6 +566,12 @@ function DayPanel(
const catMap = Object.fromEntries(categories.map((x) => [x.key, x]));
const atCap = mode.cells.length >= 3;
const free = 3 - mode.cells.length;
// A day is in "exception mode" when its shown records are overrides. Cells
// are single-layer (all overrides OR all entries), so cells[0] is enough.
// "+ Přidat záznam" must add to the layer that's showing — an override here,
// otherwise resolveCell would hide a freshly-created entry behind the
// existing override after refetch.
const isOverrideMode = mode.cells[0]?.source === "override";
return (
<Modal
isOpen
@@ -601,7 +636,13 @@ function DayPanel(
variant="contained"
color="primary"
disabled={atCap}
onClick={() => onAddRecord(mode.userId, mode.date)}
onClick={() =>
onAddRecord(
mode.userId,
mode.date,
isOverrideMode ? "override" : "entry",
)
}
>
+ Přidat záznam
</Button>