From db38e602aad8805a17e53c161ad642b17e53caf2 Mon Sep 17 00:00:00 2001 From: Karli Date: Fri, 26 Sep 2025 13:24:09 +0300 Subject: [PATCH] feat(MED-97): update cart flow for using benefits --- app/home/(user)/(dashboard)/cart/page.tsx | 26 +++- app/home/(user)/_components/cart/index.tsx | 71 +++++++--- .../(user)/_components/order/cart-totals.tsx | 52 +++++++- .../_components/order/order-details.tsx | 2 +- .../(user)/_lib/server/balance-actions.ts | 13 ++ app/home/(user)/_lib/server/cart-actions.ts | 2 +- lib/services/medusaCart.service.ts | 21 +-- lib/services/order.service.ts | 42 ------ lib/types/account-balance-entry.ts | 3 + packages/features/accounts/package.json | 1 + .../services/account-balance.service.ts | 125 ++++++++++++++++++ .../src/types/account-balance-entry.ts | 3 + .../medusa-storefront/src/lib/data/cart.ts | 31 +++++ packages/supabase/src/database.types.ts | 49 +++++++ .../20250926040043_update_consume_balance.sql | 59 +++++++++ 15 files changed, 419 insertions(+), 81 deletions(-) create mode 100644 app/home/(user)/_lib/server/balance-actions.ts create mode 100644 lib/types/account-balance-entry.ts create mode 100644 packages/features/accounts/src/server/services/account-balance.service.ts create mode 100644 packages/features/accounts/src/types/account-balance-entry.ts create mode 100644 supabase/migrations/20250926040043_update_consume_balance.sql diff --git a/app/home/(user)/(dashboard)/cart/page.tsx b/app/home/(user)/(dashboard)/cart/page.tsx index 41dca03..a514cad 100644 --- a/app/home/(user)/(dashboard)/cart/page.tsx +++ b/app/home/(user)/(dashboard)/cart/page.tsx @@ -1,5 +1,3 @@ -import { notFound } from 'next/navigation'; - import { createI18nServerInstance } from '@/lib/i18n/i18n.server'; import { PageBody, PageHeader } from '@/packages/ui/src/makerkit/page'; import { retrieveCart } from '@lib/data/cart'; @@ -11,6 +9,8 @@ import { withI18n } from '~/lib/i18n/with-i18n'; import Cart from '../../_components/cart'; import CartTimer from '../../_components/cart/cart-timer'; +import { loadCurrentUserAccount } from '../../_lib/server/load-user-account'; +import { AccountBalanceService } from '~/lib/services/accountBalance.service'; export async function generateMetadata() { const { t } = await createI18nServerInstance(); @@ -21,12 +21,22 @@ export async function generateMetadata() { } async function CartPage() { - const cart = await retrieveCart().catch((error) => { - console.error('Failed to retrieve cart', error); - return notFound(); - }); + const [ + cart, + { productTypes }, + { account }, + ] = await Promise.all([ + retrieveCart(), + listProductTypes(), + loadCurrentUserAccount(), + ]); + + if (!account) { + return null; + } + + const balanceSummary = await new AccountBalanceService().getBalanceSummary(account.id); - const { productTypes } = await listProductTypes(); const analysisPackagesType = productTypes.find( ({ metadata }) => metadata?.handle === 'analysis-packages', ); @@ -63,9 +73,11 @@ async function CartPage() { {isTimerShown && } ); diff --git a/app/home/(user)/_components/cart/index.tsx b/app/home/(user)/_components/cart/index.tsx index 7887040..328dbdf 100644 --- a/app/home/(user)/_components/cart/index.tsx +++ b/app/home/(user)/_components/cart/index.tsx @@ -2,9 +2,7 @@ import { useState } from 'react'; -import { handleNavigateToPayment } from '@/lib/services/medusaCart.service'; import { formatCurrency } from '@/packages/shared/src/utils'; -import { initiatePaymentSession } from '@lib/data/cart'; import { StoreCart, StoreCartLineItem } from '@medusajs/types'; import { Loader2 } from 'lucide-react'; import { useTranslation } from 'react-i18next'; @@ -16,27 +14,35 @@ import { Trans } from '@kit/ui/trans'; import AnalysisLocation from './analysis-location'; import CartItems from './cart-items'; import DiscountCode from './discount-code'; +import { initiatePayment } from '../../_lib/server/cart-actions'; +import { useRouter } from 'next/navigation'; +import { AccountBalanceSummary } from '@kit/accounts/services/account-balance.service'; const IS_DISCOUNT_SHOWN = true as boolean; export default function Cart({ + accountId, cart, synlabAnalyses, ttoServiceItems, + balanceSummary, }: { + accountId: string; cart: StoreCart | null; synlabAnalyses: StoreCartLineItem[]; ttoServiceItems: StoreCartLineItem[]; + balanceSummary: AccountBalanceSummary | null; }) { const { i18n: { language }, } = useTranslation(); const [isInitiatingSession, setIsInitiatingSession] = useState(false); - + const router = useRouter(); const items = cart?.items ?? []; + const hasCartItems = cart && Array.isArray(items) && items.length > 0; - if (!cart || items.length === 0) { + if (!hasCartItems) { return (
@@ -56,24 +62,35 @@ export default function Cart({ ); } - async function initiatePayment() { + async function initiateSession() { setIsInitiatingSession(true); - const response = await initiatePaymentSession(cart!, { - provider_id: 'pp_montonio_montonio', - }); - if (response.payment_collection) { - const { payment_sessions } = response.payment_collection; - const paymentSessionId = payment_sessions![0]!.id; - const url = await handleNavigateToPayment({ language, paymentSessionId }); - window.location.href = url; - } else { + + try { + const { url, isFullyPaidByBenefits, orderId } = await initiatePayment({ + accountId, + balanceSummary: balanceSummary!, + cart: cart!, + language, + }); + if (url) { + window.location.href = url; + } else if (isFullyPaidByBenefits) { + if (typeof orderId !== 'number') { + throw new Error('Order ID is missing'); + } + router.push(`/home/order/${orderId}/confirmed`); + } + } catch (error) { + console.error('Failed to initiate payment', error); setIsInitiatingSession(false); } } - const hasCartItems = Array.isArray(cart.items) && cart.items.length > 0; const isLocationsShown = synlabAnalyses.length > 0; + const companyBenefitsTotal = balanceSummary?.totalBalance ?? 0; + const montonioTotal = cart && companyBenefitsTotal > 0 ? cart.total - companyBenefitsTotal : cart.total; + return (
@@ -106,7 +123,7 @@ export default function Cart({

-
+

@@ -122,6 +139,24 @@ export default function Cart({

+ {companyBenefitsTotal > 0 && ( +
+
+

+ +

+
+
+

+ {formatCurrency({ + value: (companyBenefitsTotal > cart.total ? cart.total : companyBenefitsTotal), + currencyCode: cart.currency_code, + locale: language, + })} +

+
+
+ )}

@@ -131,7 +166,7 @@ export default function Cart({

{formatCurrency({ - value: cart.total, + value: montonioTotal < 0 ? 0 : montonioTotal, currencyCode: cart.currency_code, locale: language, })} @@ -175,7 +210,7 @@ export default function Cart({