113 lines
3.9 KiB
Vue
113 lines
3.9 KiB
Vue
<template>
|
|
<form @submit.prevent="validate">
|
|
<div class="grid grid-cols-1 items-start gap-8 mb-16">
|
|
<h1 class="font-bold text-5xl uppercase">Réception</h1>
|
|
<div class="flex flex-col">
|
|
<label for="license-plate" class="font-bold uppercase text-xl mb-4">Immatriculation</label>
|
|
<input
|
|
id="license-plate"
|
|
v-model="form.licensePlate"
|
|
type="text"
|
|
class="border-b border-black justify-self-start text-xl pb-[6px] uppercase"
|
|
/>
|
|
<p v-if="fieldErrors.licensePlate" class="text-red-600 text-sm">{{ fieldErrors.licensePlate }}</p>
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<label for="reception-date" class="font-bold uppercase text-xl mb-4">Date de reception</label>
|
|
<input
|
|
id="reception-date"
|
|
v-model="form.receptionDate"
|
|
type="date"
|
|
class="border-b border-black justify-self-start text-xl pb-[6px] uppercase"
|
|
/>
|
|
<p v-if="fieldErrors.receptionDate" class="text-red-600 text-sm">{{ fieldErrors.receptionDate }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex justify-center">
|
|
<button
|
|
type="submit"
|
|
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end"
|
|
>Peser
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { z } from 'zod'
|
|
import { mapZodErrors } from '~/utils/zod-errors'
|
|
import { useReceptionStore } from '~/stores/reception'
|
|
|
|
type ReceptionFormData = {
|
|
licensePlate: string
|
|
receptionDate: string
|
|
}
|
|
|
|
const router = useRouter()
|
|
const receptionStore = useReceptionStore()
|
|
const form = reactive<ReceptionFormData>({
|
|
licensePlate: '',
|
|
receptionDate: new Date().toISOString().slice(0, 10)
|
|
})
|
|
const fieldErrors = reactive<Partial<Record<keyof ReceptionFormData, string>>>({
|
|
licensePlate: undefined,
|
|
receptionDate: undefined
|
|
})
|
|
const formSchema = z.object({
|
|
licensePlate: z
|
|
.string()
|
|
.min(1, 'Immatriculation requise.')
|
|
.max(20, 'Immatriculation trop longue (20 caracteres max).'),
|
|
receptionDate: z
|
|
.string()
|
|
.min(1, 'Date de reception requise.')
|
|
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date de reception invalide.')
|
|
})
|
|
|
|
watch(
|
|
() => receptionStore.current,
|
|
(reception) => {
|
|
form.licensePlate = reception?.licensePlate ?? ''
|
|
form.receptionDate = reception?.receptionDate ?? new Date().toISOString().slice(0, 10)
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
|
|
async function validate() {
|
|
fieldErrors.licensePlate = undefined
|
|
fieldErrors.receptionDate = undefined
|
|
const normalizedLicensePlate = form.licensePlate.trim()
|
|
const normalizedReceptionDate = form.receptionDate.trim()
|
|
const result = formSchema.safeParse({
|
|
licensePlate: normalizedLicensePlate,
|
|
receptionDate: normalizedReceptionDate
|
|
})
|
|
if (!result.success) {
|
|
const errors = mapZodErrors<ReceptionFormData>(result.error)
|
|
fieldErrors.licensePlate = errors.licensePlate ?? 'Formulaire invalide.'
|
|
fieldErrors.receptionDate = errors.receptionDate ?? 'Formulaire invalide.'
|
|
return
|
|
}
|
|
|
|
if (!receptionStore.current) {
|
|
const created = await receptionStore.createReception({
|
|
currentStep: 1,
|
|
licensePlate: normalizedLicensePlate || null,
|
|
receptionDate: normalizedReceptionDate || null
|
|
})
|
|
if (created) {
|
|
await router.push(`/reception/${created.id}`)
|
|
}
|
|
return
|
|
}
|
|
|
|
const nextStep = receptionStore.current.currentStep + 1
|
|
await receptionStore.updateReception(receptionStore.current.id, {
|
|
currentStep: nextStep,
|
|
licensePlate: normalizedLicensePlate || null,
|
|
receptionDate: normalizedReceptionDate || null
|
|
})
|
|
}
|
|
|
|
</script>
|