diff --git a/CHANGELOG.md b/CHANGELOG.md index 191007c0..6ff85a31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project uses a user-facing changelog format. ### Changed +- Ajokoetuloksen lisäyslomakkeen avattavat kortit noudattavat virallisen pöytäkirjan aihealueita ilman pöytäkirjan taulukkoasettelun kopiointia. Lisätietoja muokataan pöytäkirjan mukaisissa yksittäin avattavissa ryhmissä myös mobiilissa. - Viimeisen koetuloksen poistaminen säilyttää ajokoetapahtuman tyhjänä, kunnes ylläpitäjä poistaa tapahtuman erikseen. - Uuden ajokoetapahtuman luomisen jälkeen siirrytään suoraan lisäämään tapahtuman ensimmäistä koetulosta. - Ajokoetuloksen lisäyslomake näyttää 1.8.2023 alkaen käytössä olevan sääntökauden mukaiset kentät. Vanhemmilla tai tunnistamattomilla sääntökausilla kaikki yhteensopivuuskentät säilyvät näkyvissä varoituksen kanssa. diff --git a/apps/web/components/admin/trials/admin-trial-entry-create-page-client.tsx b/apps/web/components/admin/trials/admin-trial-entry-create-page-client.tsx index e9876c1a..0ddcf530 100644 --- a/apps/web/components/admin/trials/admin-trial-entry-create-page-client.tsx +++ b/apps/web/components/admin/trials/admin-trial-entry-create-page-client.tsx @@ -28,9 +28,18 @@ import { } from "@/queries/admin/trials"; import { EntryMetaSection } from "./internal/entry-meta-section"; import { EraSection } from "./internal/era-section"; -import { LisatiedotMatrix } from "./internal/lisatiedot-matrix"; +import { LisatiedotWorkspace } from "./internal/lisatiedot-workspace"; +import { ResultCreateCard } from "./internal/result-create-card"; type SaveIntent = "another" | "finish"; +type CardId = + | "basic" + | "time" + | "merit" + | "loss" + | "result" + | "judges" + | "additional"; export function AdminTrialEntryCreatePageClient({ trialEventId, @@ -123,6 +132,10 @@ function ResultCreateForm({ [event, fieldSet], ); const [draft, setDraft] = React.useState(initial); + const [openCards, setOpenCards] = React.useState>( + new Set(["basic"]), + ); + const [workspaceResetKey, setWorkspaceResetKey] = React.useState(0); const [errorText, setErrorText] = React.useState(null); const submittingRef = React.useRef(false); const dirty = !areAdminTrialEntryCreateDraftsEqual(initial, draft); @@ -157,6 +170,17 @@ function ResultCreateForm({ setErrorText(null); const parsed = toCreateAdminTrialEntryRequest(event.trialEventId, draft); if (!parsed.ok) { + setOpenCards( + (current) => + new Set([ + ...current, + parsed.section === "registration" + ? "basic" + : parsed.section === "eras" + ? "time" + : "result", + ]), + ); setErrorText( t( `admin.trials.manage.resultCreate.validation.${parsed.section}` as never, @@ -168,9 +192,11 @@ function ResultCreateForm({ try { await mutation.mutateAsync(parsed.request); toast.success(t("admin.trials.manage.resultCreate.success")); - if (intent === "another") + if (intent === "another") { setDraft(createAdminTrialEntryCreateDraft(event, fieldSet)); - else router.replace(workspaceHref); + setOpenCards(new Set(["basic"])); + setWorkspaceResetKey((current) => current + 1); + } else router.replace(workspaceHref); } catch (error) { const code = error instanceof AdminMutationError ? error.errorCode : undefined; @@ -192,6 +218,7 @@ function ResultCreateForm({ ? (error.details as AdminTrialEntryValidationIssue | undefined) : undefined; if (issue?.area === "additional_info" && issue.koodi) { + setOpenCards((current) => new Set([...current, "additional"])); const row = `${issue.koodi}${issue.osa ? issue.osa : ""}`; const issueKey = issue.reason === "invalid_lisatieto_order" @@ -199,6 +226,18 @@ function ResultCreateForm({ : "admin.trials.manage.resultCreate.error.additionalInfoRow"; setErrorText(`${t(issueKey)}: ${row}.`); } else { + const errorCard: Partial> = { + INVALID_REGISTRATION_NUMBER: "basic", + TRIAL_ENTRY_REGISTRATION_CONFLICT: "basic", + INVALID_TRIAL_ENTRY: "result", + INVALID_TRIAL_ERAS: "time", + INVALID_TRIAL_ADDITIONAL_INFO: "additional", + }; + if (code && errorCard[code]) { + setOpenCards( + (current) => new Set([...current, errorCard[code] as CardId]), + ); + } setErrorText( t( `admin.trials.manage.resultCreate.error.${map[code ?? ""] ?? "generic"}` as never, @@ -210,6 +249,50 @@ function ResultCreateForm({ } } + function toggleCard(id: CardId) { + setOpenCards((current) => { + const next = new Set(current); + if (next.has(id)) next.delete(id); + else next.add(id); + return next; + }); + } + const displaySummary = (...values: string[]) => + values + .filter((value) => value.trim()) + .slice(0, 3) + .join(" • ") || t("admin.trials.manage.resultCreate.summary.empty"); + const entryGroups = Object.fromEntries( + fieldSet.presentationGroups.map((group) => [ + group.id, + new Set(group.entryFields), + ]), + ); + const eraGroups = Object.fromEntries( + fieldSet.presentationGroups.map((group) => [ + group.id, + new Set(group.eraFields), + ]), + ); + const changeEntry = ( + update: (current: typeof draft.entry) => typeof draft.entry, + ) => + setDraft((current) => ({ + ...current, + entry: update(current.entry), + })); + const changeEra = ( + era: number, + field: Exclude, + value: string, + ) => + setDraft((current) => ({ + ...current, + eras: current.eras.map((item) => + item.era === era ? { ...item, [field]: value } : item, + ), + })); + return (
@@ -229,13 +312,27 @@ function ResultCreateForm({

) : null}
- - - {errorText ? ( -

- {errorText} -

- ) : null} + {errorText ? ( +

+ {errorText} +

+ ) : null} + toggleCard("basic")} + > +
+
+ toggleCard("time")} + > +
- setDraft((current) => ({ - ...current, - eras: current.eras.map((item) => - item.era === era ? { ...item, [field]: value } : item, - ), - })) - } - visibleFields={fieldSet.eraFields} + onChangeEraField={changeEra} + visibleFields={eraGroups.time} yvaLabel={fieldSet.yvaLabels?.era} /> - +
+
+ toggleCard("merit")} + > +
+ - setDraft((current) => ({ - ...current, - lisatiedotRows: current.lisatiedotRows.map((row) => - row.koodi === koodi && row.osa === osa - ? { ...row, eraValues: { ...row.eraValues, [era]: value } } - : row, - ), - })) - } + onAddEra={addEra} + onRemoveEra={removeEra} + onChangeEraField={changeEra} + visibleFields={eraGroups.merit} + yvaLabel={fieldSet.yvaLabels?.era} + showControls={false} + /> + +
+
+ toggleCard("loss")} + > +
+ + +
+
+ toggleCard("result")} + > +
+ + {eraGroups.result.size ? ( + + ) : null} +
+
+ toggleCard("judges")} + > + + + toggleCard("additional")} + > + + setDraft((current) => ({ + ...current, + lisatiedotRows: current.lisatiedotRows.map((row) => + row.koodi === koodi && row.osa === osa + ? { ...row, eraValues: { ...row.eraValues, [era]: value } } + : row, + ), + })) + } + onRemoveRow={(koodi, osa) => + setDraft((current) => ({ + ...current, + lisatiedotRows: current.lisatiedotRows.map((row) => + row.koodi === koodi && row.osa === osa + ? { + ...row, + eraValues: Object.fromEntries( + Object.keys(row.eraValues).map((era) => [era, ""]), + ), + } + : row, + ), + })) + } + /> + + +