@@ -23,12 +23,12 @@ const form = useForm(
2323 animal: {
2424 name: ' ' ,
2525 type: ' ' ,
26- ageYears : null ,
27- ageMonths : null ,
26+ age_years : null ,
27+ age_months : null ,
2828 },
2929 appointment: {
30- preferredDate : ' ' ,
31- preferredTime : [],
30+ preferred_date : ' ' ,
31+ preferred_time : [],
3232 symptoms: ' ' ,
3333 },
3434 },
@@ -42,6 +42,8 @@ const form = useForm(
4242const formRef = useTemplateRef <Form <any >>(' formRef' );
4343const formErrors = computed (() => Object .entries (form .errors ).map (([name , message ]) => ({ name , message })));
4444
45+ const submitted = ref (false );
46+
4547function showFormErrors() {
4648 formRef .value ?.setErrors (formErrors .value );
4749}
@@ -64,6 +66,10 @@ async function submitForm() {
6466 // Show errors after failed submission
6567 showFormErrors ();
6668 },
69+ onSuccess : () => {
70+ submitted .value = true ;
71+ form .reset ();
72+ },
6773 });
6874}
6975
@@ -79,121 +85,140 @@ function createAnimalType(item: string) {
7985 <UApp >
8086 <UContainer class =" flex h-full flex-col items-center justify-center p-4 sm:p-6" >
8187 <!-- Page header -->
82- <UIcon name =" i-lucide-hospital" class =" mt-8 size-32" />
83- <h1 class =" mt-6 text-5xl" >{{ page.props.name }}</h1 >
88+ <UIcon name =" i-lucide-hospital" class =" mt-12 size-32" />
89+ <h1 class =" mt-6 text-center text- 5xl font-black " >{{ page.props.name }}</h1 >
8490
8591 <!-- Appointment card -->
8692 <UCard class =" mt-16 sm:p-4" >
87- <!-- Appointment card: header-->
88- <div class =" mt-6 mb-12 px-4 text-center sm:mt-0" >
89- <h2 class =" text-3xl" >Schedule an appointment with us!</h2 >
90- <p class =" mt-2" >We'll get back to you as soon as possible.</p >
91- </div >
93+ <!-- Form -->
94+ <div v-if =" !submitted" >
95+ <!-- Appointment card: header-->
96+ <div class =" mt-6 mb-12 px-4 text-center sm:mt-0" >
97+ <h2 class =" text-4xl font-bold" >Schedule an appointment!</h2 >
98+ <p class =" mt-4" >We'll get back to you as soon as possible.</p >
99+ </div >
92100
93- <!-- Appointment card: form-->
94- <UForm
95- ref =" formRef"
96- :state =" form"
97- :validate =" validateForm"
98- :validate-on =" ['change']"
99- :validate-on-input-delay =" 0"
100- :disabled =" form.processing"
101- @submit =" submitForm"
102- class =" space-y-4"
103- >
104- <!-- Client -->
105- <p class =" mb-2 text-2xl/12" >About you</p >
106-
107- <!-- Client: name -->
108- <UFormField label =" Name" name =" client.name" class =" w-full" required >
109- <UInput v-model =" form.client.name" placeholder =" Your name" class =" w-full" />
110- </UFormField >
111- <!-- Client: email-->
112- <UFormField label =" Email" name =" client.email" description =" Used to contact you about your appointment" class =" w-full" required >
113- <UInput v-model =" form.client.email" type =" email" placeholder =" Your email" class =" w-full" />
114- </UFormField >
115-
116- <USeparator class =" mb-0 py-6" />
117-
118- <!-- Pet -->
119- <p class =" mb-2 pt-0 text-2xl/12" >About your pet</p >
120- <div class =" flex flex-col gap-4 md:flex-row" >
121- <!-- Pet: name-->
122- <UFormField label =" Name" name =" animal.name" class =" w-full" required >
123- <UInput v-model =" form.animal.name" class =" w-full" placeholder =" Your pet's name" />
101+ <!-- Appointment card: form-->
102+ <UForm
103+ ref =" formRef"
104+ :state =" form"
105+ :validate =" validateForm"
106+ :validate-on =" ['change']"
107+ :validate-on-input-delay =" 0"
108+ :disabled =" form.processing"
109+ @submit =" submitForm"
110+ class =" space-y-4"
111+ >
112+ <!-- Client -->
113+ <p class =" mb-2 text-2xl/12" >About you</p >
114+
115+ <!-- Client: name -->
116+ <UFormField label =" Name" name =" client.name" class =" w-full" required >
117+ <UInput v-model =" form.client.name" placeholder =" Your name" class =" w-full" />
124118 </UFormField >
125- <!-- Pet: type -->
126- <UFormField label =" Type" name =" animal.type" class =" w-full" required >
127- <UInputMenu
128- v-model =" form.animal.type"
129- placeholder =" Your pet type"
130- create-item =" always"
131- :items =" animalTypes"
132- @create =" createAnimalType"
133- class =" w-full"
134- />
119+ <!-- Client: email-->
120+ <UFormField
121+ label =" Email"
122+ name =" client.email"
123+ description =" Used to contact you about your appointment"
124+ class =" w-full"
125+ required
126+ >
127+ <UInput v-model =" form.client.email" type =" email" placeholder =" Your email" class =" w-full" />
135128 </UFormField >
136- </div >
137129
138- <!-- Pet: age -- >
139- < UFormField label = " Age " required >
140- <div class = " flex flex-col gap-2 sm:flex-row " >
141- < UFormField name = " animal.ageYears " >
142- <div class =" flex w-full gap-2 sm:items-center " >
143- < UInput v-model = " form.animal.ageYears " placeholder = " Age in years... " class = " w-full " / >
144- < span class =" whitespace-nowrap text-gray-400 " >year(s) and</ span >
145- </ div >
130+ < USeparator class = " mb-0 py-6 " / >
131+
132+ <!-- Pet -- >
133+ < p class = " mb-2 pt-0 text-2xl/12 " >About your pet</ p >
134+ <div class =" flex flex-col gap-4 md:flex-row " >
135+ <!-- Pet: name -- >
136+ < UFormField label = " Name " name = " animal.name " class =" w-full " required >
137+ <UInput v-model = " form.animal.name " class = " w-full " placeholder = " Your pet's name " / >
146138 </UFormField >
147- <UFormField name =" animal.ageMonths" >
148- <div class =" flex w-full items-center gap-2" >
149- <UInput v-model =" form.animal.ageMonths" placeholder =" ... and months" class =" w-full" />
150- <span class =" whitespace-nowrap text-gray-400" >month(s)</span >
151- </div >
139+ <!-- Pet: type -->
140+ <UFormField label =" Type" name =" animal.type" class =" w-full" required >
141+ <UInputMenu
142+ v-model =" form.animal.type"
143+ placeholder =" Your pet type"
144+ create-item =" always"
145+ :items =" animalTypes"
146+ @create =" createAnimalType"
147+ class =" w-full"
148+ />
152149 </UFormField >
153150 </div >
154- </UFormField >
155151
156- <USeparator class =" mb-0 py-6" />
152+ <!-- Pet: age -->
153+ <UFormField label =" Age" required >
154+ <div class =" flex flex-col gap-2 sm:flex-row" >
155+ <UFormField name =" animal.age_years" >
156+ <div class =" flex w-full gap-2 sm:items-center" >
157+ <UInput v-model =" form.animal.age_years" placeholder =" Age in years..." class =" w-full" />
158+ <span class =" whitespace-nowrap text-gray-400" >year(s) and</span >
159+ </div >
160+ </UFormField >
161+ <UFormField name =" animal.age_months" >
162+ <div class =" flex w-full items-center gap-2" >
163+ <UInput v-model =" form.animal.age_months" placeholder =" ... and months" class =" w-full" />
164+ <span class =" whitespace-nowrap text-gray-400" >month(s)</span >
165+ </div >
166+ </UFormField >
167+ </div >
168+ </UFormField >
157169
158- <!-- Appointment -->
159- <p class =" mb-2 pt-0 text-2xl/12" >About your visit</p >
160- <div class =" flex flex-col gap-4 md:flex-row" >
161- <div class =" space-y-2 md:w-1/3" >
162- <!-- Appointment: date + time -->
163- <UFormField label =" Preferred Time" name =" appointment.preferredDate" class =" w-full" required >
164- <UInput v-model =" form.appointment.preferredDate" type =" date" class =" w-full" />
165- </UFormField >
166- <UFormField name =" appointment.preferredTime" >
167- <UCheckboxGroup
168- v-model =" form.appointment.preferredTime"
169- orientation =" horizontal"
170- name =" appointment.preferredTime"
171- :items =" timeOfDay"
172- />
170+ <USeparator class =" mb-0 py-6" />
171+
172+ <!-- Appointment -->
173+ <p class =" mb-2 pt-0 text-2xl/12" >About your visit</p >
174+ <div class =" flex flex-col gap-4 md:flex-row" >
175+ <div class =" space-y-2 md:w-1/3" >
176+ <!-- Appointment: date + time -->
177+ <UFormField label =" Preferred Time" name =" appointment.preferred_date" class =" w-full" required >
178+ <UInput v-model =" form.appointment.preferred_date" type =" date" class =" w-full" />
179+ </UFormField >
180+ <UFormField name =" appointment.preferred_time" >
181+ <UCheckboxGroup
182+ v-model =" form.appointment.preferred_time"
183+ orientation =" horizontal"
184+ name =" appointment.preferredTime"
185+ :items =" timeOfDay"
186+ />
187+ </UFormField >
188+ </div >
189+ <!-- Appointment: symptoms-->
190+ <UFormField label =" Symptoms" name =" appointment.symptoms" class =" w-full md:w-2/3" required >
191+ <UTextarea v-model =" form.appointment.symptoms" placeholder =" Why are you visiting us?" :rows =" 4" class =" w-full" />
173192 </UFormField >
174193 </div >
175- <!-- Appointment: symptoms-->
176- <UFormField label =" Symptoms" name =" appointment.symptoms" class =" w-full md:w-2/3" required >
177- <UTextarea v-model =" form.appointment.symptoms" placeholder =" Why are you visiting us?" :rows =" 4" class =" w-full" />
178- </UFormField >
179- </div >
180194
181- <!-- Form: controls -->
182- <div class =" mt-12 flex flex-col-reverse items-center justify-end gap-3 sm:flex-row" >
183- <div v-if =" form.hasErrors" class =" text-sm text-red-400" >Please review and fix issues</div >
184- <UButton
185- type =" submit"
186- :disabled =" form.hasErrors"
187- :loading =" form.processing"
188- color =" primary"
189- size =" lg"
190- icon =" i-lucide-paw-print"
191- trailing
192- >
193- Schedule appointment
194- </UButton >
195+ <!-- Form: controls -->
196+ <div class =" mt-12 flex justify-center" >
197+ <UButton
198+ type =" submit"
199+ :disabled =" form.hasErrors"
200+ :loading =" form.processing"
201+ color =" primary"
202+ size =" lg"
203+ icon =" i-lucide-paw-print"
204+ trailing
205+ >
206+ Schedule appointment
207+ </UButton >
208+ </div >
209+ </UForm >
210+ </div >
211+ <!-- Success -->
212+ <div v-else >
213+ <div class =" flex flex-col items-center px-2 text-center sm:px-32" >
214+ <UIcon name =" i-lucide-circle-check-big" class =" mt-2 mb-6 size-32 text-green-400" />
215+ <h1 class =" text-5xl font-black" >Success</h1 >
216+ <p class =" mt-3 text-xl" >We got your appointment!</p >
217+
218+ <p class =" mt-12 text-sm" >You'll receive an email when your <br />appointment is confirmed.</p >
219+ <UButton class =" mt-8" variant =" soft" size =" sm" icon =" i-lucide-paw-print" @click =" submitted = false" >Go back</UButton >
195220 </div >
196- </UForm >
221+ </div >
197222 </UCard >
198223 </UContainer >
199224 </UApp >
0 commit comments