130 lines
3.8 KiB
TypeScript
130 lines
3.8 KiB
TypeScript
'use client';
|
|
|
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
import { StoreCart, StoreCartLineItem } from '@medusajs/types';
|
|
import { useForm } from 'react-hook-form';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { toast } from 'sonner';
|
|
import { z } from 'zod';
|
|
|
|
import { Form } from '@kit/ui/form';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectLabel,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@kit/ui/select';
|
|
import { Trans } from '@kit/ui/trans';
|
|
|
|
import { updateCartPartnerLocation } from '../../_lib/server/update-cart-partner-location';
|
|
import partnerLocations from './partner-locations.json';
|
|
|
|
const AnalysisLocationSchema = z.object({
|
|
locationId: z.string().min(1),
|
|
});
|
|
|
|
export default function AnalysisLocation({
|
|
cart,
|
|
synlabAnalyses,
|
|
}: {
|
|
cart: StoreCart;
|
|
synlabAnalyses: StoreCartLineItem[];
|
|
}) {
|
|
const { t } = useTranslation('cart');
|
|
|
|
const form = useForm<z.infer<typeof AnalysisLocationSchema>>({
|
|
defaultValues: {
|
|
locationId: (cart.metadata?.partner_location_id as string) ?? '',
|
|
},
|
|
resolver: zodResolver(AnalysisLocationSchema),
|
|
});
|
|
|
|
const getLocation = (locationId: string) =>
|
|
partnerLocations.find(({ name }) => name === locationId);
|
|
|
|
const selectedLocation = getLocation(form.watch('locationId'));
|
|
|
|
const onSubmit = async ({
|
|
locationId,
|
|
}: z.infer<typeof AnalysisLocationSchema>) => {
|
|
const promise = updateCartPartnerLocation({
|
|
cartId: cart.id,
|
|
lineIds: synlabAnalyses.map(({ id }) => id),
|
|
partnerLocationId: locationId,
|
|
partnerLocationName: getLocation(locationId)?.name ?? '',
|
|
});
|
|
|
|
toast.promise(promise, {
|
|
success: t(`cart:items.analysisLocation.success`),
|
|
loading: t(`cart:items.analysisLocation.loading`),
|
|
error: t(`cart:items.analysisLocation.error`),
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="txt-medium flex h-full w-full flex-col gap-y-4 bg-white">
|
|
<p className="text-muted-foreground text-sm">
|
|
<Trans i18nKey={'cart:locations.description'} />
|
|
</p>
|
|
|
|
<Form {...form}>
|
|
<form
|
|
onSubmit={form.handleSubmit((data) => onSubmit(data))}
|
|
className="mb-2 flex w-full flex-1 gap-x-2"
|
|
>
|
|
<Select
|
|
value={form.watch('locationId')}
|
|
onValueChange={(value) => {
|
|
form.setValue('locationId', value, {
|
|
shouldValidate: true,
|
|
shouldDirty: true,
|
|
shouldTouch: true,
|
|
});
|
|
|
|
return onSubmit(form.getValues());
|
|
}}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder={t('cart:locations.locationSelect')} />
|
|
</SelectTrigger>
|
|
|
|
<SelectContent>
|
|
{Object.entries(
|
|
partnerLocations.reduce(
|
|
(acc, curr) => ({
|
|
...acc,
|
|
[curr.city]: [
|
|
...((acc[curr.city] as typeof partnerLocations) ?? []),
|
|
curr,
|
|
],
|
|
}),
|
|
{} as Record<string, typeof partnerLocations>,
|
|
),
|
|
).map(([city, locations]) => (
|
|
<SelectGroup key={city}>
|
|
<SelectLabel>{city}</SelectLabel>
|
|
{locations.map((location) => (
|
|
<SelectItem key={location.name} value={location.name}>
|
|
{location.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectGroup>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</form>
|
|
</Form>
|
|
|
|
{selectedLocation && (
|
|
<div className="mb-4 flex flex-col gap-y-2">
|
|
<p className="text-sm">{selectedLocation.address}</p>
|
|
<p className="text-sm">{selectedLocation.hours}</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|