From b9f40d6a2da57a0d757265ef23a2fee71ff5dffe Mon Sep 17 00:00:00 2001 From: k4rli Date: Thu, 24 Jul 2025 08:04:25 +0300 Subject: [PATCH] feat(MED-100): analysis location select in cart --- app/home/(user)/(dashboard)/cart/page.tsx | 15 ++- .../_components/cart/analysis-location.tsx | 99 +++++++++++++++++++ app/home/(user)/_components/cart/index.tsx | 21 +++- public/locales/en/cart.json | 10 ++ public/locales/et/cart.json | 10 ++ 5 files changed, 145 insertions(+), 10 deletions(-) create mode 100644 app/home/(user)/_components/cart/analysis-location.tsx diff --git a/app/home/(user)/(dashboard)/cart/page.tsx b/app/home/(user)/(dashboard)/cart/page.tsx index cdb0918..bac927a 100644 --- a/app/home/(user)/(dashboard)/cart/page.tsx +++ b/app/home/(user)/(dashboard)/cart/page.tsx @@ -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]; diff --git a/app/home/(user)/_components/cart/analysis-location.tsx b/app/home/(user)/_components/cart/analysis-location.tsx new file mode 100644 index 0000000..89da90c --- /dev/null +++ b/app/home/(user)/_components/cart/analysis-location.tsx @@ -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>({ + defaultValues: { + locationId: cart.metadata?.partner_location_id as string ?? '', + }, + resolver: zodResolver(AnalysisLocationSchema), + }); + + const onSubmit = async ({ locationId }: z.infer) => { + 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 ( +
+
+ onSubmit(data))} + className="w-full mb-2 flex gap-x-2" + > + +
+ + +

+ +

+ +
+ ) +} diff --git a/app/home/(user)/_components/cart/index.tsx b/app/home/(user)/_components/cart/index.tsx index f6a4a95..fc05d7c 100644 --- a/app/home/(user)/_components/cart/index.tsx +++ b/app/home/(user)/_components/cart/index.tsx @@ -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 (
- {Array.isArray(cart.items) && cart.items.length > 0 && ( + {hasCartItems && (

@@ -106,6 +110,21 @@ export default function Cart({ )} + + {isLocationsShown && ( + + +

+ +
+ + + + + + )}
diff --git a/public/locales/en/cart.json b/public/locales/en/cart.json index 8f83aa1..63cb930 100644 --- a/public/locales/en/cart.json +++ b/public/locales/en/cart.json @@ -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" } } \ No newline at end of file diff --git a/public/locales/et/cart.json b/public/locales/et/cart.json index f5bcc75..d6026b9 100644 --- a/public/locales/et/cart.json +++ b/public/locales/et/cart.json @@ -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" } } \ No newline at end of file