feat(MED-100): analysis location select in cart
This commit is contained in:
@@ -5,7 +5,7 @@ import { notFound } from 'next/navigation';
|
||||
|
||||
import { retrieveCart } from '~/medusa/lib/data/cart';
|
||||
import Cart from '../../_components/cart';
|
||||
import { listCollections } from '@lib/data';
|
||||
import { listProductTypes } from '@lib/data';
|
||||
import CartTimer from '../../_components/cart/cart-timer';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
@@ -23,15 +23,12 @@ export default async function CartPage() {
|
||||
return notFound();
|
||||
});
|
||||
|
||||
const { collections } = await listCollections({
|
||||
limit: "100",
|
||||
});
|
||||
|
||||
const analysisPackagesCollection = collections.find(({ handle }) => handle === 'analysis-packages');
|
||||
const analysisPackages = analysisPackagesCollection && cart?.items
|
||||
? cart.items.filter((item) => item.product?.collection_id === analysisPackagesCollection.id)
|
||||
const { productTypes } = await listProductTypes();
|
||||
const analysisPackagesType = productTypes.find(({ metadata }) => metadata?.handle === 'analysis-packages');
|
||||
const analysisPackages = analysisPackagesType && cart?.items
|
||||
? cart.items.filter((item) => item.product?.type_id === analysisPackagesType.id)
|
||||
: [];
|
||||
const otherItems = cart?.items?.filter((item) => item.product?.collection_id !== analysisPackagesCollection?.id) ?? [];
|
||||
const otherItems = cart?.items?.filter((item) => item.product?.type_id !== analysisPackagesType?.id) ?? [];
|
||||
|
||||
const otherItemsSorted = otherItems.sort((a, b) => (a.updated_at ?? "") > (b.updated_at ?? "") ? -1 : 1);
|
||||
const item = otherItemsSorted[0];
|
||||
|
||||
99
app/home/(user)/_components/cart/analysis-location.tsx
Normal file
99
app/home/(user)/_components/cart/analysis-location.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
"use client"
|
||||
|
||||
import { toast } from 'sonner';
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import { updateCart } from "@lib/data/cart"
|
||||
import { StoreCart } from "@medusajs/types"
|
||||
import { Form } from "@kit/ui/form";
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@kit/ui/select';
|
||||
|
||||
const AnalysisLocationSchema = z.object({
|
||||
locationId: z.string().min(1),
|
||||
});
|
||||
|
||||
const MOCK_LOCATIONS: { id: string, name: string }[] = [
|
||||
{ id: "synlab-tallinn-1", name: "SYNLAB - Tallinn" },
|
||||
{ id: "synlab-tartu-1", name: "SYNLAB - Tartu" },
|
||||
{ id: "synlab-parnu-1", name: "SYNLAB - Pärnu" },
|
||||
]
|
||||
|
||||
export default function AnalysisLocation({ cart }: { cart: StoreCart }) {
|
||||
const { t } = useTranslation('cart');
|
||||
|
||||
const form = useForm<z.infer<typeof AnalysisLocationSchema>>({
|
||||
defaultValues: {
|
||||
locationId: cart.metadata?.partner_location_id as string ?? '',
|
||||
},
|
||||
resolver: zodResolver(AnalysisLocationSchema),
|
||||
});
|
||||
|
||||
const onSubmit = async ({ locationId }: z.infer<typeof AnalysisLocationSchema>) => {
|
||||
const promise = updateCart({
|
||||
metadata: {
|
||||
partner_location_name: MOCK_LOCATIONS.find(({ id }) => id === locationId)?.name ?? '',
|
||||
partner_location_id: locationId,
|
||||
},
|
||||
});
|
||||
|
||||
toast.promise(promise, {
|
||||
success: t(`cart:items.analysisLocation.success`),
|
||||
loading: t(`cart:items.analysisLocation.loading`),
|
||||
error: t(`cart:items.analysisLocation.error`),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full bg-white flex flex-col txt-medium">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit((data) => onSubmit(data))}
|
||||
className="w-full mb-2 flex 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>
|
||||
<SelectGroup>
|
||||
<SelectLabel>{t('cart:locations.locationSelect')}</SelectLabel>
|
||||
|
||||
{MOCK_LOCATIONS.map((location) => (
|
||||
<SelectItem key={location.id} value={location.id}>{location.name}</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
<p className="text-sm text-muted-foreground">
|
||||
<Trans i18nKey={'cart:locations.description'} />
|
||||
</p>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import { initiatePaymentSession } from "@lib/data/cart";
|
||||
import { formatCurrency } from "@/packages/shared/src/utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { handleNavigateToPayment } from "@/lib/services/medusaCart.service";
|
||||
import AnalysisLocation from "./analysis-location";
|
||||
|
||||
const IS_DISCOUNT_SHOWN = false as boolean;
|
||||
|
||||
@@ -66,13 +67,16 @@ export default function Cart({
|
||||
}
|
||||
}
|
||||
|
||||
const hasCartItems = Array.isArray(cart.items) && cart.items.length > 0;
|
||||
const isLocationsShown = analysisPackages.length > 0;
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 small:grid-cols-[1fr_360px] gap-x-40 lg:px-4">
|
||||
<div className="flex flex-col bg-white gap-y-6">
|
||||
<CartItems cart={cart} items={analysisPackages} productColumnLabelKey="cart:items.analysisPackages.productColumnLabel" />
|
||||
<CartItems cart={cart} items={otherItems} productColumnLabelKey="cart:items.services.productColumnLabel" />
|
||||
</div>
|
||||
{Array.isArray(cart.items) && cart.items.length > 0 && (
|
||||
{hasCartItems && (
|
||||
<div className="flex justify-end gap-x-4 px-6 py-4">
|
||||
<div className="mr-[36px]">
|
||||
<p className="ml-0 font-bold text-sm">
|
||||
@@ -106,6 +110,21 @@ export default function Cart({
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{isLocationsShown && (
|
||||
<Card
|
||||
className="flex flex-col justify-between w-1/2"
|
||||
>
|
||||
<CardHeader className="pb-4">
|
||||
<h5>
|
||||
<Trans i18nKey="cart:locations.title" />
|
||||
</h5>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<AnalysisLocation cart={{ ...cart }} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -40,6 +40,11 @@
|
||||
"success": "Item removed from cart",
|
||||
"loading": "Removing item from cart",
|
||||
"error": "Failed to remove item from cart"
|
||||
},
|
||||
"analysisLocation": {
|
||||
"success": "Location updated",
|
||||
"loading": "Updating location",
|
||||
"error": "Failed to update location"
|
||||
}
|
||||
},
|
||||
"orderConfirmed": {
|
||||
@@ -57,5 +62,10 @@
|
||||
"montonioCallback": {
|
||||
"title": "Montonio checkout",
|
||||
"description": "Please wait while we process your payment."
|
||||
},
|
||||
"locations": {
|
||||
"title": "Location for analysis",
|
||||
"description": "If you are unable to go to the lab to collect the sample, you can go to any other suitable collection point.",
|
||||
"locationSelect": "Select location"
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,11 @@
|
||||
"success": "Toode eemaldatud ostukorvist",
|
||||
"loading": "Toote eemaldamine ostukorvist",
|
||||
"error": "Toote eemaldamine ostukorvist ebaõnnestus"
|
||||
},
|
||||
"analysisLocation": {
|
||||
"success": "Asukoht uuendatud",
|
||||
"loading": "Asukoha uuendamine",
|
||||
"error": "Asukoha uuendamine ebaõnnestus"
|
||||
}
|
||||
},
|
||||
"orderConfirmed": {
|
||||
@@ -58,5 +63,10 @@
|
||||
"montonioCallback": {
|
||||
"title": "Montonio makseprotsess",
|
||||
"description": "Palun oodake, kuni me töötleme sinu makseprotsessi lõpuni."
|
||||
},
|
||||
"locations": {
|
||||
"title": "Asukoht analüüside andmiseks",
|
||||
"description": "Kui Teil ei ole võimalik valitud asukohta minna analüüse andma, siis võite minna Teile sobivasse verevõtupunkti.",
|
||||
"locationSelect": "Vali asukoht"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user