192 lines
4.9 KiB
TypeScript
192 lines
4.9 KiB
TypeScript
import Box from "@mui/material/Box";
|
|
import Typography from "@mui/material/Typography";
|
|
import {
|
|
Modal,
|
|
Field,
|
|
DateField,
|
|
Select,
|
|
TextField,
|
|
CheckboxField,
|
|
} from "../ui";
|
|
import type { PlanUser, PlanCategory } from "../lib/queries/plan";
|
|
import type { Project } from "../lib/queries/projects";
|
|
|
|
export interface BulkPlanForm {
|
|
date_from: string;
|
|
date_to: string;
|
|
is_range: boolean;
|
|
user_ids: string[];
|
|
include_weekends: boolean;
|
|
project_id: string;
|
|
category: string;
|
|
note: string;
|
|
}
|
|
|
|
interface Props {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
form: BulkPlanForm;
|
|
setForm: (form: BulkPlanForm) => void;
|
|
users: PlanUser[];
|
|
projects: Project[];
|
|
categories: PlanCategory[];
|
|
onSubmit: () => void;
|
|
submitting: boolean;
|
|
toggleUser: (userId: number) => void;
|
|
toggleAllUsers: () => void;
|
|
}
|
|
|
|
export default function BulkPlanModal({
|
|
isOpen,
|
|
onClose,
|
|
form,
|
|
setForm,
|
|
users,
|
|
projects,
|
|
categories,
|
|
onSubmit,
|
|
submitting,
|
|
toggleUser,
|
|
toggleAllUsers,
|
|
}: Props) {
|
|
const activeCategories = categories.filter((c) => c.is_active);
|
|
return (
|
|
<Modal
|
|
isOpen={isOpen}
|
|
onClose={onClose}
|
|
title="Hromadné přiřazení"
|
|
maxWidth="lg"
|
|
loading={submitting}
|
|
onSubmit={onSubmit}
|
|
submitText="Vytvořit"
|
|
submitDisabled={form.user_ids.length === 0}
|
|
>
|
|
<Typography
|
|
variant="body2"
|
|
color="text.secondary"
|
|
sx={{ mt: 0.25, mb: 2 }}
|
|
>
|
|
Vytvoří záznamy pro vybrané dny u zvolených zaměstnanců. Dny, které už
|
|
mají 3 záznamy, se přeskočí.
|
|
</Typography>
|
|
|
|
<Field label="Datum od">
|
|
<DateField
|
|
value={form.date_from}
|
|
onChange={(val) => setForm({ ...form, date_from: val })}
|
|
/>
|
|
</Field>
|
|
<Field label="Rozsah dnů">
|
|
<CheckboxField
|
|
label="Více dní"
|
|
checked={form.is_range}
|
|
onChange={(checked) => setForm({ ...form, is_range: checked })}
|
|
/>
|
|
</Field>
|
|
{form.is_range && (
|
|
<Field label="Datum do">
|
|
<DateField
|
|
value={form.date_to}
|
|
onChange={(val) => setForm({ ...form, date_to: val })}
|
|
/>
|
|
</Field>
|
|
)}
|
|
<Field label="Víkendy">
|
|
<CheckboxField
|
|
label="Zahrnout víkendy"
|
|
checked={form.include_weekends}
|
|
onChange={(checked) =>
|
|
setForm({ ...form, include_weekends: checked })
|
|
}
|
|
/>
|
|
</Field>
|
|
|
|
<Box sx={{ mb: 2 }}>
|
|
<Box sx={{ display: "flex", alignItems: "center", gap: 1.5, mb: 0.5 }}>
|
|
<Typography
|
|
component="span"
|
|
variant="body2"
|
|
sx={{ fontWeight: 600, color: "text.secondary" }}
|
|
>
|
|
Zaměstnanci
|
|
</Typography>
|
|
<Typography
|
|
component="button"
|
|
type="button"
|
|
onClick={toggleAllUsers}
|
|
variant="caption"
|
|
sx={{
|
|
background: "none",
|
|
border: "none",
|
|
p: 0,
|
|
cursor: "pointer",
|
|
fontWeight: 500,
|
|
color: "primary.main",
|
|
}}
|
|
>
|
|
{users.length > 0 && form.user_ids.length === users.length
|
|
? "Odznačit vše"
|
|
: "Vybrat vše"}
|
|
</Typography>
|
|
</Box>
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
gap: 0.25,
|
|
maxHeight: 200,
|
|
overflowY: "auto",
|
|
p: 1.5,
|
|
bgcolor: "action.hover",
|
|
borderRadius: 2,
|
|
border: 1,
|
|
borderColor: "divider",
|
|
}}
|
|
>
|
|
{users.map((u) => (
|
|
<CheckboxField
|
|
key={u.id}
|
|
label={u.full_name}
|
|
checked={form.user_ids.includes(String(u.id))}
|
|
onChange={() => toggleUser(u.id)}
|
|
/>
|
|
))}
|
|
</Box>
|
|
<Typography variant="caption" color="text.secondary">
|
|
Vybráno: {form.user_ids.length} z {users.length}
|
|
</Typography>
|
|
</Box>
|
|
|
|
<Field label="Projekt">
|
|
<Select
|
|
value={form.project_id}
|
|
onChange={(val) => setForm({ ...form, project_id: val })}
|
|
options={[
|
|
{ value: "", label: "— bez projektu —" },
|
|
...projects.map((p) => ({ value: String(p.id), label: p.name })),
|
|
]}
|
|
/>
|
|
</Field>
|
|
<Field label="Kategorie">
|
|
<Select
|
|
value={form.category}
|
|
onChange={(val) => setForm({ ...form, category: val })}
|
|
options={activeCategories.map((c) => ({
|
|
value: c.key,
|
|
label: c.label,
|
|
}))}
|
|
/>
|
|
</Field>
|
|
<Field label="Text poznámky (volitelný)">
|
|
<TextField
|
|
multiline
|
|
minRows={2}
|
|
value={form.note}
|
|
onChange={(e) => setForm({ ...form, note: e.target.value })}
|
|
inputProps={{ maxLength: 500 }}
|
|
/>
|
|
</Field>
|
|
</Modal>
|
|
);
|
|
}
|