feat(plan): day panel — list/add/edit up to 3 records per cell
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -64,7 +64,8 @@ export type PlanCellModalMode =
|
||||
note: string;
|
||||
};
|
||||
}
|
||||
| { kind: "view"; userId: number; date: string; cell: ResolvedCell };
|
||||
| { kind: "view"; userId: number; date: string; cell: ResolvedCell }
|
||||
| { kind: "day"; userId: number; date: string; cells: ResolvedCell[] };
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@@ -84,6 +85,10 @@ 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 right editor for one of the day's existing records. */
|
||||
onEditRecord: (cell: ResolvedCell, userId: number, date: string) => void;
|
||||
}
|
||||
|
||||
const TrashIcon = (
|
||||
@@ -112,6 +117,7 @@ export default function PlanCellModal(props: Props) {
|
||||
if (mode.kind === "view") return <ViewModal {...props} />;
|
||||
if (mode.kind === "day-in-range")
|
||||
return <DayInRangeModal {...props} mode={mode} />;
|
||||
if (mode.kind === "day") return <DayPanel {...props} mode={mode} />;
|
||||
return <EditForm {...props} />;
|
||||
}
|
||||
|
||||
@@ -506,3 +512,105 @@ function ViewModal(props: Props) {
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const EditIcon = (
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-hidden
|
||||
>
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
||||
<path d="M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
function DayPanel(
|
||||
props: Props & { mode: Extract<PlanCellModalMode, { kind: "day" }> },
|
||||
) {
|
||||
const { mode, onClose, onAddRecord, onEditRecord, categories } = props;
|
||||
const catMap = Object.fromEntries(categories.map((x) => [x.key, x]));
|
||||
const atCap = mode.cells.length >= 3;
|
||||
const free = 3 - mode.cells.length;
|
||||
return (
|
||||
<Modal
|
||||
isOpen
|
||||
title={`Plán — ${formatDate(mode.date)}`}
|
||||
onClose={onClose}
|
||||
onSubmit={onClose}
|
||||
submitText="Zavřít"
|
||||
hideCancel
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: 1.25, mb: 2 }}>
|
||||
{mode.cells.map((c, i) => {
|
||||
const color =
|
||||
catMap[c.category]?.color || "var(--mui-palette-divider)";
|
||||
const projectLabel = cellProjectLabel(c);
|
||||
return (
|
||||
<Card
|
||||
key={
|
||||
c.entryId != null
|
||||
? c.entryId
|
||||
: c.overrideId != null
|
||||
? `o${c.overrideId}`
|
||||
: i
|
||||
}
|
||||
variant="outlined"
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1.5 }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 4,
|
||||
alignSelf: "stretch",
|
||||
minHeight: 28,
|
||||
borderRadius: 2,
|
||||
bgcolor: color,
|
||||
}}
|
||||
/>
|
||||
<Box sx={{ flex: 1, minWidth: 0 }}>
|
||||
<Typography sx={{ fontWeight: 600, fontSize: "0.85rem" }}>
|
||||
{planCategoryLabel(c.category, catMap)}
|
||||
{projectLabel ? ` · ${projectLabel}` : ""}
|
||||
</Typography>
|
||||
{c.note && (
|
||||
<Typography variant="body2" color="text.secondary" noWrap>
|
||||
{c.note}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="inherit"
|
||||
startIcon={EditIcon}
|
||||
onClick={() => onEditRecord(c, mode.userId, mode.date)}
|
||||
>
|
||||
Upravit
|
||||
</Button>
|
||||
</Box>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1.5 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={atCap}
|
||||
onClick={() => onAddRecord(mode.userId, mode.date)}
|
||||
>
|
||||
+ Přidat záznam
|
||||
</Button>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{atCap
|
||||
? "Maximum 3 záznamy na den"
|
||||
: `${free} ${free === 1 ? "volné místo" : "volná místa"}`}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user