Initial commit
This commit is contained in:
218
resources/js/components/RoundEvaluationLogOverridesModal.tsx
Normal file
218
resources/js/components/RoundEvaluationLogOverridesModal.tsx
Normal file
@@ -0,0 +1,218 @@
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
Select,
|
||||
SelectItem,
|
||||
Textarea,
|
||||
type Selection,
|
||||
} from "@heroui/react";
|
||||
import type {
|
||||
LogOverride,
|
||||
LogResult,
|
||||
OverrideForm,
|
||||
} from "@/components/RoundEvaluationLogOverrides.types";
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
onOpenChange: (isOpen: boolean) => void;
|
||||
onClose: () => void;
|
||||
activeItem: LogResult | null;
|
||||
override?: LogOverride;
|
||||
form?: OverrideForm;
|
||||
bands: { id: number; name: string }[];
|
||||
categories: { id: number; name: string }[];
|
||||
powerCategories: { id: number; name: string }[];
|
||||
onFieldChange: (logId: number, field: keyof OverrideForm, value: string) => void;
|
||||
onSave: (logId: number) => void;
|
||||
resolveName: (list: { id: number; name: string }[], id?: number | null) => string;
|
||||
};
|
||||
|
||||
const statusOptions = [
|
||||
{ value: "AUTO", label: "AUTO" },
|
||||
{ value: "OK", label: "OK" },
|
||||
{ value: "CHECK", label: "CHECK" },
|
||||
{ value: "DQ", label: "DQ" },
|
||||
{ value: "IGNORED", label: "IGNORED" },
|
||||
];
|
||||
|
||||
const getFirstSelection = (keys: Selection) => {
|
||||
if (keys === "all") return "";
|
||||
const [first] = Array.from(keys);
|
||||
return typeof first === "string" || typeof first === "number" ? String(first) : "";
|
||||
};
|
||||
|
||||
export default function RoundEvaluationLogOverridesModal({
|
||||
isOpen,
|
||||
onOpenChange,
|
||||
onClose,
|
||||
activeItem,
|
||||
override,
|
||||
form,
|
||||
bands,
|
||||
categories,
|
||||
powerCategories,
|
||||
onFieldChange,
|
||||
onSave,
|
||||
resolveName,
|
||||
}: Props) {
|
||||
return (
|
||||
<Modal isOpen={isOpen} onOpenChange={onOpenChange} size="2xl" scrollBehavior="inside">
|
||||
<ModalContent>
|
||||
<ModalHeader className="flex flex-col gap-1">
|
||||
Upravit log #{activeItem?.log_id ?? "—"}
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
{activeItem && (
|
||||
<>
|
||||
<div className="text-xs text-foreground-500 mb-2">
|
||||
<div>
|
||||
{activeItem.log?.pcall ?? "—"} | {activeItem.band?.name ?? "—"} /{" "}
|
||||
{activeItem.category?.name ?? "—"} /{" "}
|
||||
{activeItem.powerCategory?.name ?? activeItem.power_category?.name ?? "—"}
|
||||
</div>
|
||||
<div>
|
||||
Score: {activeItem.official_score ?? "—"} | Rank:{" "}
|
||||
{activeItem.rank_overall ?? "—"} | Status: {activeItem.status ?? "—"}
|
||||
</div>
|
||||
</div>
|
||||
{override && (
|
||||
<div className="text-xs text-foreground-500 mb-2">
|
||||
Override: {override.forced_log_status ?? "AUTO"} /{" "}
|
||||
{resolveName(bands, override.forced_band_id)} /{" "}
|
||||
{resolveName(categories, override.forced_category_id)} /{" "}
|
||||
{resolveName(powerCategories, override.forced_power_category_id)}
|
||||
</div>
|
||||
)}
|
||||
<div className="grid gap-2 md:grid-cols-2">
|
||||
<Select
|
||||
aria-label="Status"
|
||||
size="sm"
|
||||
variant="bordered"
|
||||
label="Status"
|
||||
selectedKeys={new Set([form?.status ?? "AUTO"])}
|
||||
onSelectionChange={(keys) =>
|
||||
onFieldChange(
|
||||
activeItem.log_id,
|
||||
"status",
|
||||
getFirstSelection(keys) || "AUTO"
|
||||
)
|
||||
}
|
||||
selectionMode="single"
|
||||
disallowEmptySelection={true}
|
||||
>
|
||||
{statusOptions.map((opt) => (
|
||||
<SelectItem key={opt.value} textValue={opt.label}>
|
||||
{opt.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
<Select
|
||||
aria-label="Band"
|
||||
size="sm"
|
||||
variant="bordered"
|
||||
label="Band"
|
||||
selectedKeys={new Set([form?.bandId || "auto"])}
|
||||
onSelectionChange={(keys) =>
|
||||
onFieldChange(
|
||||
activeItem.log_id,
|
||||
"bandId",
|
||||
getFirstSelection(keys) === "auto" ? "" : getFirstSelection(keys)
|
||||
)
|
||||
}
|
||||
selectionMode="single"
|
||||
disallowEmptySelection={true}
|
||||
>
|
||||
<SelectItem key="auto" textValue="AUTO">
|
||||
AUTO
|
||||
</SelectItem>
|
||||
{bands.map((band) => (
|
||||
<SelectItem key={String(band.id)} textValue={band.name}>
|
||||
{band.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
<Select
|
||||
aria-label="Kategorie"
|
||||
size="sm"
|
||||
variant="bordered"
|
||||
label="Kategorie"
|
||||
selectedKeys={new Set([form?.categoryId || "auto"])}
|
||||
onSelectionChange={(keys) =>
|
||||
onFieldChange(
|
||||
activeItem.log_id,
|
||||
"categoryId",
|
||||
getFirstSelection(keys) === "auto" ? "" : getFirstSelection(keys)
|
||||
)
|
||||
}
|
||||
selectionMode="single"
|
||||
disallowEmptySelection={true}
|
||||
>
|
||||
<SelectItem key="auto" textValue="AUTO">
|
||||
AUTO
|
||||
</SelectItem>
|
||||
{categories.map((cat) => (
|
||||
<SelectItem key={String(cat.id)} textValue={cat.name}>
|
||||
{cat.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
<Select
|
||||
aria-label="Výkon"
|
||||
size="sm"
|
||||
variant="bordered"
|
||||
label="Výkon"
|
||||
selectedKeys={new Set([form?.powerCategoryId || "auto"])}
|
||||
onSelectionChange={(keys) =>
|
||||
onFieldChange(
|
||||
activeItem.log_id,
|
||||
"powerCategoryId",
|
||||
getFirstSelection(keys) === "auto" ? "" : getFirstSelection(keys)
|
||||
)
|
||||
}
|
||||
selectionMode="single"
|
||||
disallowEmptySelection={true}
|
||||
>
|
||||
<SelectItem key="auto" textValue="AUTO">
|
||||
AUTO
|
||||
</SelectItem>
|
||||
{powerCategories.map((cat) => (
|
||||
<SelectItem key={String(cat.id)} textValue={cat.name}>
|
||||
{cat.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
<Textarea
|
||||
label="Důvod změny"
|
||||
size="sm"
|
||||
variant="bordered"
|
||||
minRows={2}
|
||||
value={form?.reason ?? ""}
|
||||
onChange={(e) => onFieldChange(activeItem.log_id, "reason", e.target.value)}
|
||||
placeholder="Krátce popiš, proč zasahuješ."
|
||||
/>
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Button
|
||||
size="sm"
|
||||
color="primary"
|
||||
onPress={() => onSave(activeItem.log_id)}
|
||||
isDisabled={form?.saving}
|
||||
>
|
||||
{form?.saving ? "Ukládám…" : "Uložit"}
|
||||
</Button>
|
||||
<Button size="sm" variant="light" onPress={onClose}>
|
||||
Zavřít
|
||||
</Button>
|
||||
{form?.error && <span className="text-red-600">{form.error}</span>}
|
||||
{form?.success && <span className="text-green-600">{form.success}</span>}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user