init import projet
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
Reference in New Issue
Block a user