init import projet

This commit is contained in:
2026-05-03 21:53:59 +02:00
parent f3756fdf8d
commit f4795e538c
179 changed files with 37694 additions and 132 deletions
@@ -0,0 +1,145 @@
import { useCallback, useMemo, useState } from "react";
import {
areDraftValuesEqual,
getDraftValuesFromEntry,
serializeChangedDraftToUpsertPayload,
validateDraft,
} from "@/features/predictions/domain/prediction-serializers";
import type {
PredictionCard,
PredictionDraftValue,
PredictionEntry,
UpsertPredictionPayload,
} from "@/types/predictions";
type SaveHandler = (cardId: string, body: UpsertPredictionPayload) => Promise<PredictionEntry>;
type ControllerInput = {
card: PredictionCard;
entry?: PredictionEntry;
onSave: SaveHandler;
disabled?: boolean;
};
export type PredictionTileController = {
draftValues: PredictionDraftValue[];
persistedValues: PredictionDraftValue[];
dirty: boolean;
saving: boolean;
errorMessage: string;
successMessage: string;
setText: (fieldId: string, value: string) => void;
setNumber: (fieldId: string, value: number | null) => void;
setDate: (fieldId: string, value: string) => void;
submit: () => Promise<boolean>;
resetFromEntry: (nextEntry?: PredictionEntry) => void;
};
function updateDraftValue(
draftValues: PredictionDraftValue[],
fieldId: string,
updater: (current: PredictionDraftValue) => PredictionDraftValue,
) {
return draftValues.map((value) => (value.fieldId === fieldId ? updater(value) : value));
}
export function usePredictionTileController({
card,
entry,
onSave,
disabled = false,
}: ControllerInput): PredictionTileController {
const initialValues = useMemo(() => getDraftValuesFromEntry(card, entry), [card, entry]);
const [draftValues, setDraftValues] = useState<PredictionDraftValue[]>(initialValues);
const [persistedValues, setPersistedValues] = useState<PredictionDraftValue[]>(initialValues);
const [saving, setSaving] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const [successMessage, setSuccessMessage] = useState("");
const dirty = useMemo(
() => !areDraftValuesEqual(draftValues, persistedValues),
[draftValues, persistedValues],
);
const setText = useCallback((fieldId: string, value: string) => {
setDraftValues((current) =>
updateDraftValue(current, fieldId, (draft) => ({ ...draft, valueText: value })),
);
}, []);
const setNumber = useCallback((fieldId: string, value: number | null) => {
setDraftValues((current) =>
updateDraftValue(current, fieldId, (draft) => ({ ...draft, valueNumber: value })),
);
}, []);
const setDate = useCallback((fieldId: string, value: string) => {
setDraftValues((current) =>
updateDraftValue(current, fieldId, (draft) => ({ ...draft, valueDate: value })),
);
}, []);
const submit = useCallback(async () => {
if (disabled) {
setErrorMessage("Le jeu est cloture. Les pronostics sont verrouilles.");
return false;
}
const validation = validateDraft(card, draftValues);
if (!validation.valid) {
setErrorMessage(validation.message);
setSuccessMessage("");
return false;
}
const payload = serializeChangedDraftToUpsertPayload(card, draftValues, persistedValues);
if (payload.values.length === 0) {
setErrorMessage("");
setSuccessMessage("Aucun changement a enregistrer");
return true;
}
setSaving(true);
setErrorMessage("");
setSuccessMessage("");
try {
const updatedEntry = await onSave(card.id, payload);
const nextValues = getDraftValuesFromEntry(card, updatedEntry);
setDraftValues(nextValues);
setPersistedValues(nextValues);
setSuccessMessage("Pronostic enregistre");
return true;
} catch (error) {
setErrorMessage(error instanceof Error ? error.message : "Erreur de sauvegarde");
return false;
} finally {
setSaving(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [card, disabled, draftValues, persistedValues, onSave]);
const resetFromEntry = useCallback((nextEntry?: PredictionEntry) => {
const nextValues = getDraftValuesFromEntry(card, nextEntry);
setDraftValues(nextValues);
setPersistedValues(nextValues);
setErrorMessage("");
setSuccessMessage("");
}, [card]);
return useMemo(() => ({
draftValues,
persistedValues,
dirty,
saving,
errorMessage,
successMessage,
setText,
setNumber,
setDate,
submit,
resetFromEntry,
}), [draftValues, persistedValues, dirty, saving, errorMessage, successMessage, setText, setNumber, setDate, submit, resetFromEntry]);
}