fix(01-03): defer species/breed Select render until data loads — fixes CUID showing in trigger
This commit is contained in:
1 parent
63ec6637b1
commit
c4588098ca
1 file changed
+76
-71
@@ -19,6 +19,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
/**
|
||||
* PetForm — reusable create/edit form for pet profiles.
|
||||
@@ -98,12 +99,12 @@ export function PetForm({
|
||||
initialValues?.speciesId ?? ""
|
||||
);
|
||||
|
||||
const { data: speciesList = [] } = useQuery({
|
||||
const { data: speciesList = [], isLoading: speciesLoading } = useQuery({
|
||||
...trpc.pets.listSpecies.queryOptions(),
|
||||
staleTime: Infinity,
|
||||
});
|
||||
|
||||
const { data: breedList = [] } = useQuery({
|
||||
const { data: breedList = [], isLoading: breedsLoading } = useQuery({
|
||||
...trpc.pets.listBreeds.queryOptions(
|
||||
{ speciesId: selectedSpeciesId || "__none__" },
|
||||
),
|
||||
@@ -201,40 +202,42 @@ export function PetForm({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Species selector */}
|
||||
{/* Species selector — defer render until list loaded so SelectValue resolves names */}
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label htmlFor="species">Species</Label>
|
||||
<Controller
|
||||
name="speciesId"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={field.value || null}
|
||||
onValueChange={(val) => {
|
||||
const newVal = val ?? "";
|
||||
field.onChange(newVal);
|
||||
setSelectedSpeciesId(newVal);
|
||||
// Reset breed when species changes (species and breed are coupled)
|
||||
setValue("breedId", null);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger
|
||||
id="species"
|
||||
className="w-full"
|
||||
aria-invalid={!!errors.speciesId}
|
||||
{speciesLoading ? (
|
||||
<Skeleton className="h-9 w-full" />
|
||||
) : (
|
||||
<Controller
|
||||
name="speciesId"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={field.value || undefined}
|
||||
onValueChange={(val) => {
|
||||
field.onChange(val);
|
||||
setSelectedSpeciesId(val);
|
||||
setValue("breedId", null);
|
||||
}}
|
||||
>
|
||||
<SelectValue placeholder="Select species" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{speciesList.map((species) => (
|
||||
<SelectItem key={species.id} value={species.id}>
|
||||
{species.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
<SelectTrigger
|
||||
id="species"
|
||||
className="w-full"
|
||||
aria-invalid={!!errors.speciesId}
|
||||
>
|
||||
<SelectValue placeholder="Select species" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{speciesList.map((species) => (
|
||||
<SelectItem key={species.id} value={species.id}>
|
||||
{species.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{errors.speciesId && (
|
||||
<p className="text-xs text-destructive">
|
||||
{errors.speciesId.message}
|
||||
@@ -242,49 +245,51 @@ export function PetForm({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Breed selector */}
|
||||
{/* Breed selector — defer render until list loaded so SelectValue resolves names */}
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label htmlFor="breed">Breed</Label>
|
||||
<Controller
|
||||
name="breedId"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={field.value ?? null}
|
||||
onValueChange={(val) => {
|
||||
field.onChange(val ?? null);
|
||||
}}
|
||||
disabled={!selectedSpeciesId}
|
||||
>
|
||||
<SelectTrigger
|
||||
id="breed"
|
||||
className="w-full"
|
||||
{selectedSpeciesId && breedsLoading ? (
|
||||
<Skeleton className="h-9 w-full" />
|
||||
) : (
|
||||
<Controller
|
||||
name="breedId"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={field.value ?? undefined}
|
||||
onValueChange={(val) => field.onChange(val ?? null)}
|
||||
disabled={!selectedSpeciesId}
|
||||
>
|
||||
<SelectValue
|
||||
placeholder={
|
||||
selectedSpeciesId
|
||||
? "Select breed (optional)"
|
||||
: "Select a species first"
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{breedList.length === 0 ? (
|
||||
<SelectItem value="__empty__" disabled>
|
||||
No breeds found for this species.
|
||||
</SelectItem>
|
||||
) : (
|
||||
breedList.map((breed) => (
|
||||
<SelectItem key={breed.id} value={breed.id}>
|
||||
{breed.name}
|
||||
<SelectTrigger
|
||||
id="breed"
|
||||
className="w-full"
|
||||
disabled={!selectedSpeciesId}
|
||||
>
|
||||
<SelectValue
|
||||
placeholder={
|
||||
selectedSpeciesId
|
||||
? "Select breed (optional)"
|
||||
: "Select a species first"
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{breedList.length === 0 ? (
|
||||
<SelectItem value="__empty__" disabled>
|
||||
No breeds found for this species.
|
||||
</SelectItem>
|
||||
))
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
breedList.map((breed) => (
|
||||
<SelectItem key={breed.id} value={breed.id}>
|
||||
{breed.name}
|
||||
</SelectItem>
|
||||
))
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{errors.breedId && (
|
||||
<p className="text-xs text-destructive">{errors.breedId.message}</p>
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user