Skip to content

Commit

Permalink
[#173] Update client pet details form and management
Browse files Browse the repository at this point in the history
- Allow editing and saving changes to pet details
- Add default example pet to provide guidance
- Refactor submission handling to match API requirements
- Enhance validation and UI feedback on form state

The client pet details form has been updated to enable editing and
persisting changes to a user's pet information. Key enhancements
include:

- Introducing a default example pet to guide users on expected input
format
- Refactoring form submission to match API payload requirements for pet
details
- Enhancing form validation with better error handling and success
feedback
- Improving UI with consistent styling and better guidance for input
fields
  • Loading branch information
delano committed Jun 30, 2024
1 parent 03d4329 commit 2063e6a
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 129 deletions.
201 changes: 109 additions & 92 deletions apps/ui/components/DeliveryInfoForm.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,110 @@
<template>
<div>
<UForm :state="state"
:validate="validate"
:validate-on="['submit']"
@submit="onSubmit"
ref="form$">

<UDashboardSection :title="title"
:description="description"
:icon="icon">
<template #links
v-if="cta">
<UButton type="submit"
label="Save changes"
class="block rounded-md bg-primary text-white dark:text-black" />
</template>

<UFormGroup name="branch"
label="AFB Branch"
description="The location that will fulfill your request."
required
class="grid grid-cols-2 gap-2"
autocomplete="nope"
:ui="{ container: '' }">

<USelect v-model="state.branch_selection"
name="branch_selection"
:options="parsedBranches"
placeholder="Select a branch"
icon="i-ph-map-pin"
size="md"
@change="updateInputAddressCenterPoint" />

<p class="text-gray-500 text-xs">
<NuxtLink :to="deliveryAreaLink"
class="text-secondary underline font-medium">See delivery area</NuxtLink>
</p>
<p class="text-gray-500 text-xs italic">Please contact [email protected] to update your branch.</p>
</UFormGroup>

<UFormGroup name="name"
label="Your Name"
description="Please enter your name."
required
class="grid grid-cols-2 gap-2 items-center"
:ui="{ container: '' }">
<UInput v-model="state.name"
autocomplete="off"
icon="i-heroicons-user"
size="md"
name="name" />
</UFormGroup>

<UFormGroup name="email"
label="Your Email"
description="The email address you use to sign in. We also use this for co-ordinating food requests."
class="grid grid-cols-2 gap-2 items-center"
:ui="{ container: '' }">

<UInput v-model="state.email"
autocomplete="off"
icon="i-heroicons-envelope"
size="md"
disabled />
</UFormGroup>

<UFormGroup name="phone_number"
label="Your Phone (optional)"
description="Please enter your phone number."
class="grid grid-cols-2 gap-2 items-center"
:ui="{ container: '' }">
<UInput v-model="state.phone_number"
autocomplete="off"
icon="i-heroicons-phone"
size="md"
name="phone_number" />
</UFormGroup>

<UFormGroup name="address"
label="Address"
description="The address for the pet food delivery."
required
class="grid grid-cols-2 gap-2"
:ui="{ container: '' }">

<UInput v-model="state.address"
type="address"
autocomplete="nope"
icon="i-heroicons-envelope"
size="md"
name="address"
ref="addressInput">
<template #trailing>
<span class="text-gray-500 dark:text-gray-400 text-sm">{{ state.zip }}</span>
</template>
</UInput>
</UFormGroup>

</UDashboardSection>
</UForm>

</div>

</template>


<script setup lang="ts">
import { Loader } from "@googlemaps/js-api-loader";
import { defineProps, ref } from 'vue';
Expand Down Expand Up @@ -82,7 +189,7 @@ const parsedBranches = computed(() => {
const toast = useToast();
function validate (state: any): FormError[] {
function validate(state: any): FormError[] {
const errors = []
if (!state.name) errors.push({ path: 'name', message: 'Please enter your name.' })
if (!state.address) errors.push({ path: 'address', message: 'Please enter your address.' })
Expand All @@ -91,6 +198,7 @@ function validate (state: any): FormError[] {
if (!state.branch_selection) errors.push({ path: 'branch_selection', message: 'Please doublecheck branch location.' })
return errors
}
async function onSubmit(event: FormSubmitEvent<any>) {
try {
Expand Down Expand Up @@ -242,94 +350,3 @@ const deliveryAreaLink = computed(() => {
});
</script>


<template>
<div>
<UForm :state="state" :validate="validate" :validate-on="['submit']" @submit="onSubmit" ref="form$">

<UDashboardSection :title="title" :description="description" :icon="icon">
<template #links v-if="cta">
<UButton type="submit" label="Save changes" class="block rounded-md bg-primary text-white dark:text-white"/>
</template>

<UFormGroup
name="branch"
label="AFB Branch"
description="The location that will fulfill your request."
required
class="grid grid-cols-2 gap-2"
autocomplete="nope"
:ui="{ container: '' }"
>

<USelect
v-model="state.branch_selection"
name="branch_selection"
:options="parsedBranches"
placeholder="Select a branch"
icon="i-ph-map-pin"
size="md"
@change="updateInputAddressCenterPoint"
/>

<p class="text-gray-500 text-xs">
<NuxtLink :to="deliveryAreaLink" class="text-secondary underline font-medium">See delivery area</NuxtLink>
</p>
<p class="text-gray-500 text-xs italic">Please contact [email protected] to update your branch.</p>
</UFormGroup>

<UFormGroup
name="name"
label="Your Name"
description="Please enter your name."
required
class="grid grid-cols-2 gap-2 items-center"
:ui="{ container: '' }"
>
<UInput v-model="state.name" autocomplete="off" icon="i-heroicons-user" size="md" name="name" />
</UFormGroup>

<UFormGroup
name="email"
label="Your Email"
description="The email address you use to sign in. We also use this for co-ordinating food requests."
class="grid grid-cols-2 gap-2 items-center"
:ui="{ container: '' }"
>

<UInput v-model="state.email" autocomplete="off" icon="i-heroicons-envelope" size="md" disabled />
</UFormGroup>

<UFormGroup
name="name"
label="Your Phone (optional)"
description="Please enter your name."
class="grid grid-cols-2 gap-2 items-center"
:ui="{ container: '' }"
>
<UInput v-model="state.phone_number" autocomplete="off" icon="i-heroicons-phone" size="md" name="phone_number" />
</UFormGroup>

<UFormGroup
name="address"
label="Address"
description="The address for the pet food delivery."
required
class="grid grid-cols-2 gap-2"
:ui="{ container: '' }"
>

<UInput v-model="state.address" type="address" autocomplete="nope" icon="i-heroicons-envelope" size="md" name="address" ref="addressInput">
<template #trailing>
<span class="text-gray-500 dark:text-gray-400 text-sm">{{ state.zip }}</span>
</template>
</UInput>
</UFormGroup>

</UDashboardSection>
</UForm>

</div>

</template>
99 changes: 98 additions & 1 deletion apps/ui/components/PetsForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,128 @@
size="lg"
display-errors
display-success
:endpoint="false"
@submit="onSubmit"
ref="form$" />
</template>

<script setup lang="ts">
// import type { PetFormState } from '@/types/forms/index';
import type { FormSubmitEvent } from "#ui/types";
import clientPetsSchema from '@/modules/requests/clientPetsSchema';
import type { PetInfo } from '@/types/index';
const toast = useToast()
const {
profileInfo,
userInfo,
authToken,
} = useProfile();
const props = defineProps<{
title?: String
description?: String
state?: Object
cta?: Boolean
icon?: String
user?: Object
profile?: Object
}>()
const schema = ref({})
const defaultPetExample: PetInfo = {
id: "3ef6ef2a-fd22-4082-a096-8bc95efa5a75",
pet_type: "Dog",
pet_name: "Buddy",
pet_dob: "2018",
food_details: {
allergies: "Chicken",
general_notes: "Loves to play fetch",
foodtype: "Dry"
},
dog_details: {
size: "20-50 lbs (Medium)"
},
spay_or_neutered: "Yes"
};
function validate(state: any): FormError[] {
const errors = []
if (!state.pets) errors.push({ path: 'name', message: 'Please enter at least one pet.' })
return errors
}
async function onSubmit(event: FormSubmitEvent<any>) {
try {
// Prepare the data to be sent
const profileData = {
id: props.profile.id,
user_id: props.user.id,
pets: event.data.pets,
}
const petsPath = `/api/v1/profiles/${profileData.id}/pets/`
// Make the API call
const response = await $fetch(petsPath, {
method: 'PUT',
body: JSON.stringify(profileData),
headers: {
'Content-Type': 'application/json',
'Authorization': `${authToken.value}`
}
})
// Handle successful response
console.log('Profile updated:', response)
toast.add({
title: `${props.title} updated`,
icon: 'i-heroicons-check-circle',
})
} catch (error) {
console.error('Error updating profile:', error)
toast.add({
title: 'Error updating profile',
description: 'Please try again later.',
icon: 'i-heroicons-exclamation-circle',
color: 'red'
})
}
}
onMounted(() => {
// console.log("FoodRequestFormState has been mounted");
const state = props.state;
const profilePets = props.profile?.pets || [defaultPetExample];
schema.value = {
client_pets: clientPetsSchema,
client_pets: clientPetsSchema(profilePets),
save: {
type: 'button',
submits: true,
buttonLabel: 'Update Pets',
full: true,
size: 'lg',
loading: false,
ui: {
variant: 'secondary',
icon: 'i-heroicons-check-circle',
},
onClick: (event: FormSubmitEvent<any>) => {
event.form.setLoading('save', true);
onSubmit(event);
},
},
}
});
Expand Down
Loading

0 comments on commit 2063e6a

Please sign in to comment.