Sep 7, 2023
0
Level 2
How can I use haseErrors from useForm in a function ?
Hello everyone,
I'm trying to use the hasErrors from the useForm of Inertia.js to apply a condition to close my sheet (I'm using Shadcn for the components).
But as I can see, useForm are asynchronous and I can't use hasErrors directly in my handleSubmit function.
I was thinking of using useEffect but I didn't see how to do that.
Here is my code :
import MarkerSummaryTable from '@/Components/MarkerSummaryTable';
import { IMarkerSheetState, useMarkerSheetContext } from '@/Sheets/MarkerSheet/useMarkerSheetContext';
import { MarkerData, OperationData, ValidateMarkerFormRequestData } from '@/types/generated';
import { useForm } from '@inertiajs/react';
import MarkerOperationSelector from '@/Sheets/MarkerSheet/Components/MarkerOperationSelector';
import { FormEvent, useEffect, useState } from 'react';
import { Button } from '@/Components/UI/button';
import FormGroup from '@/Components/FormGroup';
import TextInput from '@/Components/TextInput';
import { useLocations } from '@/hooks/useLocations';
import SelectInput from '@/Components/SelectInput';
import { useMarkerOperations } from '@/hooks/useMarkerOperations';
import SplitButton from '@/Components/SplitButton';
interface IMarkerSheetValidationTab {
marker: MarkerData;
state: IMarkerSheetState;
reload: (id: number) => void;
}
type ITrackerNumberByQuantity = {
quantity: number;
tracking_numbers: string[];
};
export function MarkerSheetValidationTab({ marker, state, reload }: IMarkerSheetValidationTab) {
const { close } = useMarkerSheetContext();
const { data: locations, processing: processingLocations } = useLocations();
const { data: operations, processing: processingMarkerOperations } = useMarkerOperations(marker.id);
const processing = processingLocations || processingMarkerOperations;
const [operation, setOperation] = useState<OperationData | null>(null);
const validationForm = useForm<ValidateMarkerFormRequestData>({
marker_id: marker.id,
location_id: null,
operation_id: state.operationId ?? -1,
quantity: 1,
tracking_numbers: [],
});
useEffect(() => {
const currentOperation = operations.find(operation => operation.id === validationForm.data.operation_id) ?? null;
setOperation(currentOperation);
if (currentOperation) {
validationForm.setData('quantity', currentOperation?.processing_markers_count ?? 1);
}
}, [validationForm.data.operation_id, operations]);
const saveResponseToLocalStorage = (response: string) => {
localStorage.setItem('continueAfterValidation', response);
};
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
validationForm.post(e.currentTarget.action);
if (localStorage.getItem('continueAfterValidation') === 'true') {
validationForm.reset();
reload(marker.id);
saveResponseToLocalStorage('false');
}
if (validationForm.hasErrors) {
close();
}
};
return (
<div className="flex h-full w-full flex-col gap-2">
<div className={'px-1'}>
<MarkerSummaryTable marker={marker} />
</div>
{processing ? (
<div className={'flex flex-1 items-center justify-center'}>Chargement...</div>
) : (
<>
<div className={'px-1'}>
<MarkerOperationSelector
operations={operations ?? []}
value={validationForm.data.operation_id}
onValueChange={operationId => {
validationForm.setData({
...validationForm.data,
operation_id: operationId,
});
}}
/>
</div>
<form
id="form-validation"
action={route('workflow.markers.validation')}
method="POST"
onSubmit={handleSubmit}
className={'flex flex-col gap-4 px-1'}
>
<div className="grid grid-cols-12 gap-2">
<FormGroup label="Quantité" labelProps={{ htmlFor: 'quantity' }} className="col-span-3">
<TextInput
type="number"
name="quantity"
id="quantity"
min="1"
max={operation?.processing_markers_count ?? 0}
className="block w-full"
value={validationForm.data.quantity}
onChange={e => validationForm.setData('quantity', e.target.valueAsNumber)}
/>
</FormGroup>
<FormGroup label="Numéro de lot" labelProps={{ htmlFor: 'tracking_codes' }} className="col-span-9">
<TextInput
type="text"
name="tracking_codes"
id="tracking_codes"
className="block w-full"
value={validationForm.data.tracking_numbers?.join(', ')}
onChange={e => validationForm.setData('tracking_numbers', e.target.value.split(', '))}
/>
</FormGroup>
{validationForm.errors.tracking_numbers && (
<div className="col-span-12 text-right text-red-500">{validationForm.errors.tracking_numbers}</div>
)}
</div>
<FormGroup label="Localisation" labelProps={{ htmlFor: 'location_id' }}>
<SelectInput
className={'w-full'}
onChange={e =>
validationForm.setData('location_id', e.currentTarget.value ? parseInt(e.currentTarget.value) : null)
}
defaultValue={validationForm.data.location_id?.toString()}
>
<option value="">Sélectionnez l'endroit où vous déposez le repère</option>
{locations.map(location => (
<option key={location.id} value={location.id.toString()}>
{location.label}
</option>
))}
</SelectInput>
</FormGroup>
</form>
<div className={'mt-auto flex items-center justify-end gap-4 border-t bg-zinc-50 px-1 py-2'}>
<SplitButton
asChild
menu={[
{
key: 'validate-and-continue',
label: 'Valider et continuer',
props: {
children: (
<Button
form={'form-validation'}
type={'submit'}
size={'lg'}
processing={validationForm.processing}
onClick={() => saveResponseToLocalStorage('true')}
variant={'ghost'}
>
Valider et continuer
</Button>
),
},
},
{
key: 'cancel',
label: 'Annuler',
props: {
children: (
<Button onClick={() => validationForm.reset()} size={'lg'} variant={'ghost'}>
Annuler
</Button>
),
},
},
]}
>
<Button form={'form-validation'} type={'submit'} processing={validationForm.processing} variant="outline">
Valider
</Button>
</SplitButton>
</div>
</>
)}
</div>
);
}
Thank you in advanced for your help
Please or to participate in this conversation.