feat(MED-121): use age+sex specific analysis package variants

This commit is contained in:
2025-08-25 11:50:03 +03:00
parent 195af1db3d
commit 38d73e27ad
8 changed files with 237 additions and 106 deletions

View File

@@ -22,8 +22,14 @@ import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
import { PackageHeader } from '@kit/shared/components/package-header';
import { InfoTooltip } from '@kit/shared/components/ui/info-tooltip';
import { StoreProduct } from '@medusajs/types';
import { getAnalysisElementMedusaProductIds } from '@/utils/medusa-product';
import { withI18n } from '@/lib/i18n/with-i18n';
import { AnalysisPackageWithVariant } from '@kit/shared/components/select-analysis-package';
import { withI18n } from '~/lib/i18n/with-i18n';
export type AnalysisPackageElement = Pick<StoreProduct, 'title' | 'id' | 'description'> & {
isIncludedInStandard: boolean;
isIncludedInStandardPlus: boolean;
isIncludedInPremium: boolean;
};
const CheckWithBackground = () => {
return (
@@ -33,15 +39,15 @@ const CheckWithBackground = () => {
);
};
const PackageTableHead = async ({ product, nrOfAnalyses }: { product: StoreProduct, nrOfAnalyses: number }) => {
const PackageTableHead = async ({ product }: { product: AnalysisPackageWithVariant }) => {
const { t, language } = await createI18nServerInstance();
const variant = product.variants?.[0];
const titleKey = product.title;
const price = variant?.calculated_price?.calculated_amount ?? 0;
const { title, price, nrOfAnalyses } = product;
return (
<TableHead className="py-2">
<PackageHeader
title={t(titleKey)}
title={t(title)}
tagColor='bg-cyan'
analysesNr={t('product:nrOfAnalyses', { nr: nrOfAnalyses })}
language={language}
@@ -56,24 +62,20 @@ const ComparePackagesModal = async ({
analysisPackageElements,
triggerElement,
}: {
analysisPackages: StoreProduct[];
analysisPackageElements: StoreProduct[];
analysisPackages: AnalysisPackageWithVariant[];
analysisPackageElements: AnalysisPackageElement[];
triggerElement: JSX.Element;
}) => {
const { t } = await createI18nServerInstance();
const standardPackage = analysisPackages.find(({ metadata }) => metadata?.analysisPackageTier === 'standard')!;
const standardPlusPackage = analysisPackages.find(({ metadata }) => metadata?.analysisPackageTier === 'standard-plus')!;
const premiumPackage = analysisPackages.find(({ metadata }) => metadata?.analysisPackageTier === 'premium')!;
const standardPackage = analysisPackages.find(({ isStandard }) => isStandard);
const standardPlusPackage = analysisPackages.find(({ isStandardPlus }) => isStandardPlus);
const premiumPackage = analysisPackages.find(({ isPremium }) => isPremium);
if (!standardPackage || !standardPlusPackage || !premiumPackage) {
return null;
}
const standardPackageAnalyses = getAnalysisElementMedusaProductIds([standardPackage]);
const standardPlusPackageAnalyses = getAnalysisElementMedusaProductIds([standardPlusPackage]);
const premiumPackageAnalyses = getAnalysisElementMedusaProductIds([premiumPackage]);
return (
<Dialog>
<DialogTrigger asChild>{triggerElement}</DialogTrigger>
@@ -103,9 +105,9 @@ const ComparePackagesModal = async ({
<TableHeader>
<TableRow>
<TableHead></TableHead>
<PackageTableHead product={standardPackage} nrOfAnalyses={standardPackageAnalyses.length} />
<PackageTableHead product={standardPlusPackage} nrOfAnalyses={standardPlusPackageAnalyses.length} />
<PackageTableHead product={premiumPackage} nrOfAnalyses={premiumPackageAnalyses.length} />
<PackageTableHead product={standardPackage} />
<PackageTableHead product={standardPlusPackage} />
<PackageTableHead product={premiumPackage} />
</TableRow>
</TableHeader>
<TableBody>
@@ -115,29 +117,29 @@ const ComparePackagesModal = async ({
title,
id,
description,
isIncludedInStandard,
isIncludedInStandardPlus,
isIncludedInPremium,
},
index,
) => {
if (!title) {
return null;
}
const includedInStandard = standardPackageAnalyses.includes(id);
const includedInStandardPlus = standardPlusPackageAnalyses.includes(id);
const includedInPremium = premiumPackageAnalyses.includes(id);
return (
<TableRow key={index}>
<TableRow key={id}>
<TableCell className="py-6">
{title}{' '}
{description && (<InfoTooltip content={description} icon={<QuestionMarkCircledIcon />} />)}
</TableCell>
<TableCell align="center" className="py-6">
{includedInStandard && <CheckWithBackground />}
{isIncludedInStandard && <CheckWithBackground />}
</TableCell>
<TableCell align="center" className="py-6">
{(includedInStandard || includedInStandardPlus) && <CheckWithBackground />}
{(isIncludedInStandard || isIncludedInStandardPlus) && <CheckWithBackground />}
</TableCell>
<TableCell align="center" className="py-6">
{(includedInStandard || includedInStandardPlus || includedInPremium) && <CheckWithBackground />}
{(isIncludedInStandard || isIncludedInStandardPlus || isIncludedInPremium) && <CheckWithBackground />}
</TableCell>
</TableRow>
);

View File

@@ -9,30 +9,39 @@ import {
CardFooter,
CardDescription,
} from '@kit/ui/card';
import { StoreProduct, StoreProductVariant } from '@medusajs/types';
import { StoreProduct } from '@medusajs/types';
import { useState } from 'react';
import { handleAddToCart } from '~/lib/services/medusaCart.service';
import { useRouter } from 'next/navigation';
import { InfoTooltip } from '@kit/shared/components/ui/info-tooltip';
import { Trans } from '@kit/ui/trans';
export type OrderAnalysisCard = Pick<
StoreProduct, 'title' | 'description' | 'subtitle'
> & {
isAvailable: boolean;
variant: { id: string };
};
export default function OrderAnalysesCards({
analyses,
countryCode,
}: {
analyses: StoreProduct[];
analyses: OrderAnalysisCard[];
countryCode: string;
}) {
const router = useRouter();
const [isAddingToCart, setIsAddingToCart] = useState(false);
const handleSelect = async (selectedVariant: StoreProductVariant) => {
if (!selectedVariant?.id || isAddingToCart) return null
const handleSelect = async (variantId: string) => {
if (isAddingToCart) {
return null;
}
setIsAddingToCart(true);
try {
await handleAddToCart({
selectedVariant,
selectedVariant: { id: variantId },
countryCode,
});
setIsAddingToCart(false);
@@ -47,13 +56,11 @@ export default function OrderAnalysesCards({
<div className="grid grid-cols-3 gap-6 mt-4">
{analyses.map(({
title,
variants,
variant,
description,
subtitle,
status,
metadata,
isAvailable,
}) => {
const isAvailable = status === 'published' && !!metadata?.analysisIdOriginal;
return (
<Card
key={title}
@@ -72,7 +79,7 @@ export default function OrderAnalysesCards({
size="icon"
variant="outline"
className="px-2 text-black"
onClick={() => handleSelect(variants![0]!)}
onClick={() => handleSelect(variant.id)}
>
{isAddingToCart ? <Loader2 className="size-4 stroke-2 animate-spin" /> : <ShoppingCart className="size-4 stroke-2" />}
</Button>