prettier fix

This commit is contained in:
Danel Kungla
2025-09-19 17:22:36 +03:00
parent efa94b3322
commit 0c2cfe6d18
509 changed files with 17988 additions and 9920 deletions

View File

@@ -1,13 +1,13 @@
"use client"
'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 { useForm } from "react-hook-form";
import { z } from "zod";
import { StoreCart, StoreCartLineItem } 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 { z } from 'zod';
import { Form } from '@kit/ui/form';
import {
Select,
SelectContent,
@@ -17,29 +17,39 @@ import {
SelectTrigger,
SelectValue,
} from '@kit/ui/select';
import { updateCartPartnerLocation } from '../../_lib/server/update-cart-partner-location';
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[] }) {
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 ?? '',
locationId: (cart.metadata?.partner_location_id as string) ?? '',
},
resolver: zodResolver(AnalysisLocationSchema),
});
const getLocation = (locationId: string) => partnerLocations.find(({ name }) => name === locationId);
const getLocation = (locationId: string) =>
partnerLocations.find(({ name }) => name === locationId);
const selectedLocation = getLocation(form.watch('locationId'));
const onSubmit = async ({ locationId }: z.infer<typeof AnalysisLocationSchema>) => {
const onSubmit = async ({
locationId,
}: z.infer<typeof AnalysisLocationSchema>) => {
const promise = updateCartPartnerLocation({
cartId: cart.id,
lineIds: synlabAnalyses.map(({ id }) => id),
@@ -52,18 +62,18 @@ export default function AnalysisLocation({ cart, synlabAnalyses }: { cart: Store
loading: t(`cart:items.analysisLocation.loading`),
error: t(`cart:items.analysisLocation.error`),
});
}
};
return (
<div className="w-full h-full bg-white flex flex-col txt-medium gap-y-4">
<p className="text-sm text-muted-foreground">
<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="w-full mb-2 flex gap-x-2 flex-1"
className="mb-2 flex w-full flex-1 gap-x-2"
>
<Select
value={form.watch('locationId')}
@@ -82,34 +92,38 @@ export default function AnalysisLocation({ cart, synlabAnalyses }: { cart: Store
</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>
))}
{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="flex flex-col gap-y-2 mb-4">
<p className="text-sm">
{selectedLocation.address}
</p>
<p className="text-sm">
{selectedLocation.hours}
</p>
<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>
)
);
}

View File

@@ -1,12 +1,13 @@
"use client";
'use client';
import { Trash } from "lucide-react";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useState } from 'react';
import { Spinner } from '@medusajs/icons';
import { Trash } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';
import { Spinner } from "@medusajs/icons";
import { handleDeleteCartItem } from "~/lib/services/medusaCart.service";
import { handleDeleteCartItem } from '~/lib/services/medusaCart.service';
const CartItemDelete = ({
id,
@@ -33,9 +34,9 @@ const CartItemDelete = ({
};
return (
<div className="flex items-center justify-between text-small-regular">
<div className="text-small-regular flex items-center justify-between">
<button
className="flex gap-x-1 text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer"
className="text-ui-fg-subtle hover:text-ui-fg-base flex cursor-pointer gap-x-1"
onClick={() => handleDelete()}
>
{isDeleting ? <Spinner className="animate-spin" /> : <Trash />}

View File

@@ -1,23 +1,27 @@
"use client"
'use client';
import { HttpTypes } from "@medusajs/types"
import { useTranslation } from "react-i18next"
import {
TableCell,
TableRow,
} from '@kit/ui/table';
import { formatCurrency } from "@/packages/shared/src/utils"
import CartItemDelete from "./cart-item-delete";
import { formatCurrency } from '@/packages/shared/src/utils';
import { HttpTypes } from '@medusajs/types';
import { useTranslation } from 'react-i18next';
export default function CartItem({ item, currencyCode }: {
item: HttpTypes.StoreCartLineItem
currencyCode: string
import { TableCell, TableRow } from '@kit/ui/table';
import CartItemDelete from './cart-item-delete';
export default function CartItem({
item,
currencyCode,
}: {
item: HttpTypes.StoreCartLineItem;
currencyCode: string;
}) {
const { i18n: { language } } = useTranslation();
const {
i18n: { language },
} = useTranslation();
return (
<TableRow className="w-full" data-testid="product-row">
<TableCell className="text-left w-[100%] px-4 sm:px-6">
<TableCell className="w-[100%] px-4 text-left sm:px-6">
<p
className="txt-medium-plus text-ui-fg-base"
data-testid="product-title"
@@ -26,9 +30,7 @@ export default function CartItem({ item, currencyCode }: {
</p>
</TableCell>
<TableCell className="px-4 sm:px-6">
{item.quantity}
</TableCell>
<TableCell className="px-4 sm:px-6">{item.quantity}</TableCell>
<TableCell className="min-w-[80px] px-4 sm:px-6">
{formatCurrency({
@@ -38,7 +40,7 @@ export default function CartItem({ item, currencyCode }: {
})}
</TableCell>
<TableCell className="min-w-[80px] px-4 sm:px-6 text-right">
<TableCell className="min-w-[80px] px-4 text-right sm:px-6">
{formatCurrency({
value: item.total,
currencyCode,
@@ -46,11 +48,11 @@ export default function CartItem({ item, currencyCode }: {
})}
</TableCell>
<TableCell className="text-right px-4 sm:px-6">
<span className="flex gap-x-1 justify-end w-[60px]">
<TableCell className="px-4 text-right sm:px-6">
<span className="flex w-[60px] justify-end gap-x-1">
<CartItemDelete id={item.id} />
</span>
</TableCell>
</TableRow>
)
);
}

View File

@@ -1,15 +1,21 @@
import { StoreCart, StoreCartLineItem } from "@medusajs/types"
import { Trans } from '@kit/ui/trans';
import CartItem from "./cart-item";
import { StoreCart, StoreCartLineItem } from '@medusajs/types';
import {
Table,
TableBody,
TableHead,
TableRow,
TableHeader,
TableRow,
} from '@kit/ui/table';
import { Trans } from '@kit/ui/trans';
export default function CartItems({ cart, items, productColumnLabelKey }: {
import CartItem from './cart-item';
export default function CartItems({
cart,
items,
productColumnLabelKey,
}: {
cart: StoreCart;
items: StoreCartLineItem[];
productColumnLabelKey: string;
@@ -19,7 +25,7 @@ export default function CartItems({ cart, items, productColumnLabelKey }: {
}
return (
<Table className="rounded-lg border border-separate">
<Table className="border-separate rounded-lg border">
<TableHeader className="text-ui-fg-subtle txt-medium-plus">
<TableRow>
<TableHead className="px-4 sm:px-6">
@@ -28,19 +34,20 @@ export default function CartItems({ cart, items, productColumnLabelKey }: {
<TableHead className="px-4 sm:px-6">
<Trans i18nKey="cart:table.quantity" />
</TableHead>
<TableHead className="px-4 sm:px-6 min-w-[100px]">
<TableHead className="min-w-[100px] px-4 sm:px-6">
<Trans i18nKey="cart:table.price" />
</TableHead>
<TableHead className="px-4 sm:px-6 min-w-[100px] text-right">
<TableHead className="min-w-[100px] px-4 text-right sm:px-6">
<Trans i18nKey="cart:table.total" />
</TableHead>
<TableHead className="px-4 sm:px-6">
</TableHead>
<TableHead className="px-4 sm:px-6"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{items
.sort((a, b) => (a.created_at ?? "") > (b.created_at ?? "") ? -1 : 1)
.sort((a, b) =>
(a.created_at ?? '') > (b.created_at ?? '') ? -1 : 1,
)
.map((item) => (
<CartItem
key={item.id}
@@ -50,5 +57,5 @@ export default function CartItems({ cart, items, productColumnLabelKey }: {
))}
</TableBody>
</Table>
)
);
}

View File

@@ -1,6 +1,12 @@
"use client";
'use client';
import { useEffect, useState } from 'react';
import { handleLineItemTimeout } from '@/lib/services/medusaCart.service';
import { StoreCartLineItem } from '@medusajs/types';
import { Timer } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { Button } from '@kit/ui/button';
import {
AlertDialog,
AlertDialogAction,
@@ -8,18 +14,17 @@ import {
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle
} from "@kit/ui/alert-dialog";
import { Timer } from 'lucide-react';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { StoreCartLineItem } from '@medusajs/types';
import { handleLineItemTimeout } from '@/lib/services/medusaCart.service';
AlertDialogTitle,
} from '@kit/ui/alert-dialog';
import { Button } from '@kit/ui/button';
const TIMEOUT_MINUTES = 15;
export default function CartTimer({ cartItem }: { cartItem: StoreCartLineItem }) {
export default function CartTimer({
cartItem,
}: {
cartItem: StoreCartLineItem;
}) {
const { t } = useTranslation();
const [timeLeft, setTimeLeft] = useState<number | null>(null);
const [isDialogOpen, setDialogOpen] = useState(false);
@@ -39,7 +44,9 @@ export default function CartTimer({ cartItem }: { cartItem: StoreCartLineItem })
return () => clearInterval(interval);
}, [updatedAt]);
const minutes = timeLeft ? Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60)) : 0;
const minutes = timeLeft
? Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60))
: 0;
const seconds = timeLeft ? Math.floor((timeLeft % (1000 * 60)) / 1000) : 0;
const isTimeLeftPositive = timeLeft === null || timeLeft > 0;
@@ -53,13 +60,16 @@ export default function CartTimer({ cartItem }: { cartItem: StoreCartLineItem })
}, [isTimeLeftPositive, cartItem.id]);
if (timeLeft === null) {
return <div className='min-h-[40px]' />;
return <div className="min-h-[40px]" />;
}
return (
<>
<div className="ml-auto">
<Button variant="outline" className="flex items-center gap-x-2 bg-accent hover:bg-accent px-4 cursor-default">
<Button
variant="outline"
className="bg-accent hover:bg-accent flex cursor-default items-center gap-x-2 px-4"
>
<Timer />
<span className="text-sm">
{t('cart:checkout.timeLeft', {
@@ -76,7 +86,9 @@ export default function CartTimer({ cartItem }: { cartItem: StoreCartLineItem })
{t('cart:checkout.timeoutTitle')}
</AlertDialogTitle>
<AlertDialogDescription>
{t('cart:checkout.timeoutDescription', { productTitle: cartItem.product?.title })}
{t('cart:checkout.timeoutDescription', {
productTitle: cartItem.product?.title,
})}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
@@ -87,5 +99,5 @@ export default function CartTimer({ cartItem }: { cartItem: StoreCartLineItem })
</AlertDialogContent>
</AlertDialog>
</>
)
);
}

View File

@@ -1,6 +1,6 @@
"use server"
'use server';
import { applyPromotions } from "@lib/data/cart"
import { applyPromotions } from '@lib/data/cart';
export async function addPromotionCodeAction(code: string) {
try {
@@ -12,9 +12,14 @@ export async function addPromotionCodeAction(code: string) {
}
}
export async function removePromotionCodeAction(codeToRemove: string, appliedCodes: string[]) {
export async function removePromotionCodeAction(
codeToRemove: string,
appliedCodes: string[],
) {
try {
const updatedCodes = appliedCodes.filter((appliedCode) => appliedCode !== codeToRemove);
const updatedCodes = appliedCodes.filter(
(appliedCode) => appliedCode !== codeToRemove,
);
await applyPromotions(updatedCodes);
return { success: true, message: 'Discount code removed successfully' };
} catch (error) {

View File

@@ -1,30 +1,37 @@
"use client"
'use client';
import { Badge, Text } from "@medusajs/ui"
import { toast } from '@kit/ui/sonner';
import React from "react";
import React from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { convertToLocale } from '@lib/util/money';
import { StoreCart, StorePromotion } from '@medusajs/types';
import { Badge, Text } from '@medusajs/ui';
import Trash from '@modules/common/icons/trash';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import { convertToLocale } from "@lib/util/money"
import { StoreCart, StorePromotion } from "@medusajs/types"
import Trash from "@modules/common/icons/trash"
import { Button } from '@kit/ui/button';
import { Form, FormControl, FormField, FormItem } from "@kit/ui/form";
import { Form, FormControl, FormField, FormItem } from '@kit/ui/form';
import { Input } from '@kit/ui/input';
import { toast } from '@kit/ui/sonner';
import { Trans } from '@kit/ui/trans';
import { Input } from "@kit/ui/input";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { addPromotionCodeAction, removePromotionCodeAction } from "./discount-code-actions";
import {
addPromotionCodeAction,
removePromotionCodeAction,
} from './discount-code-actions';
const DiscountCodeSchema = z.object({
code: z.string().min(1),
})
});
export default function DiscountCode({ cart }: {
export default function DiscountCode({
cart,
}: {
cart: StoreCart & {
promotions: StorePromotion[]
}
promotions: StorePromotion[];
};
}) {
const { t } = useTranslation('cart');
@@ -33,11 +40,11 @@ export default function DiscountCode({ cart }: {
const removePromotionCode = async (code: string) => {
const appliedCodes = promotions
.filter((p) => p.code !== undefined)
.map((p) => p.code!)
.map((p) => p.code!);
const loading = toast.loading(t('cart:discountCode.removeLoading'));
const result = await removePromotionCodeAction(code, appliedCodes)
const result = await removePromotionCodeAction(code, appliedCodes);
toast.dismiss(loading);
if (result.success) {
@@ -45,21 +52,20 @@ export default function DiscountCode({ cart }: {
} else {
toast.error(t('cart:discountCode.removeError'));
}
}
};
const addPromotionCode = async (code: string) => {
const loading = toast.loading(t('cart:discountCode.addLoading'));
const result = await addPromotionCodeAction(code)
const result = await addPromotionCodeAction(code);
toast.dismiss(loading);
if (result.success) {
toast.success(t('cart:discountCode.addSuccess'));
form.reset()
form.reset();
} else {
toast.error(t('cart:discountCode.addError'));
}
}
};
const form = useForm<z.infer<typeof DiscountCodeSchema>>({
defaultValues: {
@@ -69,40 +75,41 @@ export default function DiscountCode({ cart }: {
});
return (
<div className="w-full h-full bg-white flex flex-col txt-medium gap-y-4">
<p className="text-sm text-muted-foreground">
<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:discountCode.subtitle'} />
</p>
<Form {...form}>
<form
onSubmit={form.handleSubmit((data) => addPromotionCode(data.code))}
className="w-full mb-2 flex gap-x-2 sm:flex-row flex-col gap-y-2 flex-1"
className="mb-2 flex w-full flex-1 flex-col gap-x-2 gap-y-2 sm:flex-row"
>
<FormField
name={'code'}
render={({ field }) => (
<FormItem className="flex-1">
<FormControl>
<Input required type="text" {...field} placeholder={t('cart:discountCode.placeholder')} />
<Input
required
type="text"
{...field}
placeholder={t('cart:discountCode.placeholder')}
/>
</FormControl>
</FormItem>
)}
/>
<Button
type="submit"
variant="secondary"
className="h-min"
>
<Button type="submit" variant="secondary" className="h-min">
<Trans i18nKey={'cart:discountCode.apply'} />
</Button>
</form>
</Form>
{promotions.length > 0 && (
<div className="w-full flex items-center mt-4">
<div className="flex flex-col w-full gap-y-2">
<div className="mt-4 flex w-full items-center">
<div className="flex w-full flex-col gap-y-2">
<p>
<Trans i18nKey={'cart:discountCode.appliedCodes'} />
</p>
@@ -111,32 +118,32 @@ export default function DiscountCode({ cart }: {
return (
<div
key={promotion.id}
className="flex items-center justify-between w-full max-w-full mb-2"
className="mb-2 flex w-full max-w-full items-center justify-between"
data-testid="discount-row"
>
<Text className="flex gap-x-1 items-baseline text-sm w-4/5 pr-1">
<Text className="flex w-4/5 items-baseline gap-x-1 pr-1 text-sm">
<span className="truncate" data-testid="discount-code">
<Badge
color={promotion.is_automatic ? "green" : "grey"}
color={promotion.is_automatic ? 'green' : 'grey'}
size="small"
className="px-4 text-sm"
>
{promotion.code}
</Badge>{" "}
</Badge>{' '}
(
{promotion.application_method?.value !== undefined &&
promotion.application_method.currency_code !==
undefined && (
undefined && (
<>
{promotion.application_method.type ===
"percentage"
{promotion.application_method.type === 'percentage'
? `${promotion.application_method.value}%`
: convertToLocale({
amount: Number(promotion.application_method.value),
currency_code:
promotion.application_method
.currency_code,
})}
amount: Number(
promotion.application_method.value,
),
currency_code:
promotion.application_method.currency_code,
})}
</>
)}
)
@@ -152,10 +159,10 @@ export default function DiscountCode({ cart }: {
className="flex items-center"
onClick={() => {
if (!promotion.code) {
return
return;
}
removePromotionCode(promotion.code)
removePromotionCode(promotion.code);
}}
data-testid="remove-discount-button"
>
@@ -166,11 +173,11 @@ export default function DiscountCode({ cart }: {
</button>
)}
</div>
)
);
})}
</div>
</div>
)}
</div>
)
);
}

View File

@@ -1,22 +1,21 @@
"use client";
'use client';
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';
import { useState } from "react";
import { Loader2 } from "lucide-react";
import { StoreCart, StoreCartLineItem } from "@medusajs/types"
import CartItems from "./cart-items"
import { Trans } from '@kit/ui/trans';
import { Button } from '@kit/ui/button';
import {
Card,
CardContent,
CardHeader,
} from '@kit/ui/card';
import DiscountCode from "./discount-code";
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";
import { Card, CardContent, CardHeader } from '@kit/ui/card';
import { Trans } from '@kit/ui/trans';
import AnalysisLocation from './analysis-location';
import CartItems from './cart-items';
import DiscountCode from './discount-code';
const IS_DISCOUNT_SHOWN = true as boolean;
@@ -25,11 +24,13 @@ export default function Cart({
synlabAnalyses,
ttoServiceItems,
}: {
cart: StoreCart | null
cart: StoreCart | null;
synlabAnalyses: StoreCartLineItem[];
ttoServiceItems: StoreCartLineItem[];
}) {
const { i18n: { language } } = useTranslation();
const {
i18n: { language },
} = useTranslation();
const [isInitiatingSession, setIsInitiatingSession] = useState(false);
@@ -39,7 +40,10 @@ export default function Cart({
return (
<div className="content-container py-5 lg:px-4">
<div>
<div className="flex flex-col justify-center items-center" data-testid="empty-cart-message">
<div
className="flex flex-col items-center justify-center"
data-testid="empty-cart-message"
>
<h4 className="text-center">
<Trans i18nKey="cart:emptyCartMessage" />
</h4>
@@ -71,21 +75,29 @@ export default function Cart({
const isLocationsShown = synlabAnalyses.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={synlabAnalyses} productColumnLabelKey="cart:items.synlabAnalyses.productColumnLabel" />
<CartItems cart={cart} items={ttoServiceItems} productColumnLabelKey="cart:items.ttoServices.productColumnLabel" />
<div className="small:grid-cols-[1fr_360px] grid grid-cols-1 gap-x-40 lg:px-4">
<div className="flex flex-col gap-y-6 bg-white">
<CartItems
cart={cart}
items={synlabAnalyses}
productColumnLabelKey="cart:items.synlabAnalyses.productColumnLabel"
/>
<CartItems
cart={cart}
items={ttoServiceItems}
productColumnLabelKey="cart:items.ttoServices.productColumnLabel"
/>
</div>
{hasCartItems && (
<>
<div className="flex sm:justify-end gap-x-4 px-4 sm:px-6 pt-2 sm:pt-4">
<div className="w-full sm:w-auto sm:mr-[42px]">
<p className="ml-0 font-bold text-sm text-muted-foreground">
<div className="flex gap-x-4 px-4 pt-2 sm:justify-end sm:px-6 sm:pt-4">
<div className="w-full sm:mr-[42px] sm:w-auto">
<p className="text-muted-foreground ml-0 text-sm font-bold">
<Trans i18nKey="cart:order.subtotal" />
</p>
</div>
<div className={`sm:mr-[112px] sm:w-[50px]`}>
<p className="text-sm text-right">
<p className="text-right text-sm">
{formatCurrency({
value: cart.subtotal,
currencyCode: cart.currency_code,
@@ -94,14 +106,14 @@ export default function Cart({
</p>
</div>
</div>
<div className="flex sm:justify-end gap-x-4 px-4 sm:px-6 py-2 sm:py-4">
<div className="w-full sm:w-auto sm:mr-[42px]">
<p className="ml-0 font-bold text-sm text-muted-foreground">
<div className="flex gap-x-4 px-4 py-2 sm:justify-end sm:px-6 sm:py-4">
<div className="w-full sm:mr-[42px] sm:w-auto">
<p className="text-muted-foreground ml-0 text-sm font-bold">
<Trans i18nKey="cart:order.promotionsTotal" />
</p>
</div>
<div className={`sm:mr-[112px] sm:w-[50px]`}>
<p className="text-sm text-right">
<p className="text-right text-sm">
{formatCurrency({
value: cart.discount_total,
currencyCode: cart.currency_code,
@@ -110,14 +122,14 @@ export default function Cart({
</p>
</div>
</div>
<div className="flex sm:justify-end gap-x-4 px-4 sm:px-6">
<div className="w-full sm:w-auto sm:mr-[42px]">
<p className="ml-0 font-bold text-sm">
<div className="flex gap-x-4 px-4 sm:justify-end sm:px-6">
<div className="w-full sm:mr-[42px] sm:w-auto">
<p className="ml-0 text-sm font-bold">
<Trans i18nKey="cart:order.total" />
</p>
</div>
<div className={`sm:mr-[112px] sm:w-[50px]`}>
<p className="text-sm text-right">
<p className="text-right text-sm">
{formatCurrency({
value: cart.total,
currencyCode: cart.currency_code,
@@ -129,11 +141,9 @@ export default function Cart({
</>
)}
<div className="flex sm:flex-row flex-col gap-y-6 py-4 sm:py-8 gap-x-4">
<div className="flex flex-col gap-x-4 gap-y-6 py-4 sm:flex-row sm:py-8">
{IS_DISCOUNT_SHOWN && (
<Card
className="flex flex-col justify-between w-full sm:w-1/2"
>
<Card className="flex w-full flex-col justify-between sm:w-1/2">
<CardHeader className="pb-4">
<h5>
<Trans i18nKey="cart:discountCode.title" />
@@ -146,24 +156,31 @@ export default function Cart({
)}
{isLocationsShown && (
<Card
className="flex flex-col justify-between w-full sm:w-1/2"
>
<Card className="flex w-full flex-col justify-between sm:w-1/2">
<CardHeader className="pb-4">
<h5>
<Trans i18nKey="cart:locations.title" />
</h5>
</CardHeader>
<CardContent className="h-full">
<AnalysisLocation cart={{ ...cart }} synlabAnalyses={synlabAnalyses} />
<AnalysisLocation
cart={{ ...cart }}
synlabAnalyses={synlabAnalyses}
/>
</CardContent>
</Card>
)}
</div>
<div>
<Button className="h-10" onClick={initiatePayment} disabled={isInitiatingSession}>
{isInitiatingSession && <Loader2 className="w-4 h-4 mr-2 animate-spin" />}
<Button
className="h-10"
onClick={initiatePayment}
disabled={isInitiatingSession}
>
{isInitiatingSession && (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
)}
<Trans i18nKey="cart:checkout.goToCheckout" />
</Button>
</div>

View File

@@ -119,4 +119,4 @@
"hours": "Verevõtt tööpäeviti 8.00-12.00",
"city": "Otepää"
}
]
]

View File

@@ -4,12 +4,12 @@ export interface MontonioOrderToken {
merchantReference: string;
merchantReferenceDisplay: string;
paymentStatus:
| 'PAID'
| 'FAILED'
| 'CANCELLED'
| 'PENDING'
| 'EXPIRED'
| 'REFUNDED';
| 'PAID'
| 'FAILED'
| 'CANCELLED'
| 'PENDING'
| 'EXPIRED'
| 'REFUNDED';
paymentMethod: string;
grandTotal: number;
currency: string;
@@ -19,4 +19,4 @@ export interface MontonioOrderToken {
paymentLinkUuid: string;
iat: number;
exp: number;
}
}

View File

@@ -1,9 +1,13 @@
import { JSX } from 'react';
import { StoreProduct } from '@medusajs/types';
import { QuestionMarkCircledIcon } from '@radix-ui/react-icons';
import { VisuallyHidden } from '@radix-ui/react-visually-hidden';
import { Check, X } from 'lucide-react';
import { PackageHeader } from '@kit/shared/components/package-header';
import { AnalysisPackageWithVariant } from '@kit/shared/components/select-analysis-package';
import { InfoTooltip } from '@kit/shared/components/ui/info-tooltip';
import {
Dialog,
DialogContent,
@@ -18,14 +22,14 @@ import {
TableHeader,
TableRow,
} from '@kit/ui/table';
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 { AnalysisPackageWithVariant } from '@kit/shared/components/select-analysis-package';
import { withI18n } from '~/lib/i18n/with-i18n';
export type AnalysisPackageElement = Pick<StoreProduct, 'title' | 'id' | 'description'> & {
export type AnalysisPackageElement = Pick<
StoreProduct,
'title' | 'id' | 'description'
> & {
isIncludedInStandard: boolean;
isIncludedInStandardPlus: boolean;
isIncludedInPremium: boolean;
@@ -39,7 +43,11 @@ const CheckWithBackground = () => {
);
};
const PackageTableHead = async ({ product }: { product: AnalysisPackageWithVariant }) => {
const PackageTableHead = async ({
product,
}: {
product: AnalysisPackageWithVariant;
}) => {
const { t, language } = await createI18nServerInstance();
const { title, price, nrOfAnalyses } = product;
@@ -48,14 +56,14 @@ const PackageTableHead = async ({ product }: { product: AnalysisPackageWithVaria
<TableHead className="py-2">
<PackageHeader
title={t(title)}
tagColor='bg-cyan'
tagColor="bg-cyan"
analysesNr={t('product:nrOfAnalyses', { nr: nrOfAnalyses })}
language={language}
price={price}
/>
</TableHead>
)
}
);
};
const ComparePackagesModal = async ({
analysisPackages,
@@ -69,7 +77,9 @@ const ComparePackagesModal = async ({
const { t } = await createI18nServerInstance();
const standardPackage = analysisPackages.find(({ isStandard }) => isStandard);
const standardPlusPackage = analysisPackages.find(({ isStandardPlus }) => isStandardPlus);
const standardPlusPackage = analysisPackages.find(
({ isStandardPlus }) => isStandardPlus,
);
const premiumPackage = analysisPackages.find(({ isPremium }) => isPremium);
if (!standardPackage || !standardPlusPackage || !premiumPackage) {
@@ -100,7 +110,7 @@ const ComparePackagesModal = async ({
<p className="text-muted-foreground mx-auto w-3/5 text-sm">
{t('product:healthPackageComparison.description')}
</p>
<div className="rounded-md border max-h-[80vh] overflow-y-auto">
<div className="max-h-[80vh] overflow-y-auto rounded-md border">
<Table>
<TableHeader>
<TableRow>
@@ -112,16 +122,14 @@ const ComparePackagesModal = async ({
</TableHeader>
<TableBody>
{analysisPackageElements.map(
(
{
title,
id,
description,
isIncludedInStandard,
isIncludedInStandardPlus,
isIncludedInPremium,
},
) => {
({
title,
id,
description,
isIncludedInStandard,
isIncludedInStandardPlus,
isIncludedInPremium,
}) => {
if (!title) {
return null;
}
@@ -130,20 +138,28 @@ const ComparePackagesModal = async ({
<TableRow key={id}>
<TableCell className="py-6 sm:max-w-[30vw]">
{title}{' '}
{description && (<InfoTooltip content={description} icon={<QuestionMarkCircledIcon />} />)}
{description && (
<InfoTooltip
content={description}
icon={<QuestionMarkCircledIcon />}
/>
)}
</TableCell>
<TableCell align="center" className="py-6">
{isIncludedInStandard && <CheckWithBackground />}
</TableCell>
<TableCell align="center" className="py-6">
{isIncludedInStandardPlus && <CheckWithBackground />}
{isIncludedInStandardPlus && (
<CheckWithBackground />
)}
</TableCell>
<TableCell align="center" className="py-6">
{isIncludedInPremium && <CheckWithBackground />}
</TableCell>
</TableRow>
);
})}
},
)}
</TableBody>
</Table>
</div>

View File

@@ -11,7 +11,7 @@ export default function DashboardCards() {
<div className="flex gap-4">
<Card
variant="gradient-success"
className="xs:w-1/2 sm:w-auto flex w-full flex-col justify-between"
className="xs:w-1/2 flex w-full flex-col justify-between sm:w-auto"
>
<CardHeader className="flex-row">
<div

View File

@@ -3,17 +3,11 @@
import Link from 'next/link';
import { BlendingModeIcon } from '@radix-ui/react-icons';
import {
Droplets,
} from 'lucide-react';
import { Droplets } from 'lucide-react';
import { InfoTooltip } from '@kit/shared/components/ui/info-tooltip';
import { Button } from '@kit/ui/button';
import {
Card,
CardContent,
CardHeader,
} from '@kit/ui/card';
import { Card, CardContent, CardHeader } from '@kit/ui/card';
import { Trans } from '@kit/ui/trans';
import { cn } from '@kit/ui/utils';

View File

@@ -2,9 +2,9 @@
import Link from 'next/link';
import type { AccountWithParams } from '@kit/accounts/types/accounts';
import { Database } from '@/packages/supabase/src/database.types';
import { BlendingModeIcon, RulerHorizontalIcon } from '@radix-ui/react-icons';
import { isNil } from 'lodash';
import {
Activity,
ChevronRight,
@@ -15,6 +15,7 @@ import {
User,
} from 'lucide-react';
import type { AccountWithParams } from '@kit/accounts/types/accounts';
import { pathsConfig } from '@kit/shared/config';
import { Button } from '@kit/ui/button';
import {
@@ -27,13 +28,13 @@ import {
import { Trans } from '@kit/ui/trans';
import { cn } from '@kit/ui/utils';
import { isNil } from 'lodash';
import { BmiCategory } from '~/lib/types/bmi';
import PersonalCode, {
bmiFromMetric,
getBmiBackgroundColor,
getBmiStatus,
} from '~/lib/utils';
import DashboardRecommendations from './dashboard-recommendations';
const getCardVariant = (isSuccess: boolean | null): CardProps['variant'] => {
@@ -57,80 +58,78 @@ const cards = ({
bmiStatus: BmiCategory | null;
smoking?: boolean | null;
}) => [
{
title: 'dashboard:gender',
description: gender ?? '-',
icon: <User />,
iconBg: 'bg-success',
},
{
title: 'dashboard:age',
description: age ? `${age}` : '-',
icon: <Clock9 />,
iconBg: 'bg-success',
},
{
title: 'dashboard:height',
description: height ? `${height}cm` : '-',
icon: <RulerHorizontalIcon className="size-4" />,
iconBg: 'bg-success',
},
{
title: 'dashboard:weight',
description: weight ? `${weight}kg` : '-',
icon: <Scale />,
iconBg: 'bg-success',
},
{
title: 'dashboard:bmi',
description: bmiFromMetric(weight || 0, height || 0)?.toString() ?? '-',
icon: <TrendingUp />,
iconBg: getBmiBackgroundColor(bmiStatus),
},
{
title: 'dashboard:bloodPressure',
description: '-',
icon: <Activity />,
iconBg: 'bg-warning',
},
{
title: 'dashboard:cholesterol',
description: '-',
icon: <BlendingModeIcon className="size-4" />,
iconBg: 'bg-destructive',
},
{
title: 'dashboard:ldlCholesterol',
description: '-',
icon: <Pill />,
iconBg: 'bg-warning',
},
// {
// title: 'Score 2',
// description: 'Normis',
// icon: <LineChart />,
// iconBg: 'bg-success',
// },
{
title: 'dashboard:smoking',
description:
isNil(smoking)
? 'dashboard:respondToQuestion'
: !!smoking
? 'common:yes'
: 'common:no',
descriptionColor: 'text-primary',
icon:
isNil(smoking) ? (
<Link href={pathsConfig.app.personalAccountSettings}>
<Button size="icon" variant="outline" className="px-2 text-black">
<ChevronRight className="size-4 stroke-2" />
</Button>
</Link>
) : null,
cardVariant: getCardVariant(isNil(smoking) ? null : !smoking),
},
];
{
title: 'dashboard:gender',
description: gender ?? '-',
icon: <User />,
iconBg: 'bg-success',
},
{
title: 'dashboard:age',
description: age ? `${age}` : '-',
icon: <Clock9 />,
iconBg: 'bg-success',
},
{
title: 'dashboard:height',
description: height ? `${height}cm` : '-',
icon: <RulerHorizontalIcon className="size-4" />,
iconBg: 'bg-success',
},
{
title: 'dashboard:weight',
description: weight ? `${weight}kg` : '-',
icon: <Scale />,
iconBg: 'bg-success',
},
{
title: 'dashboard:bmi',
description: bmiFromMetric(weight || 0, height || 0)?.toString() ?? '-',
icon: <TrendingUp />,
iconBg: getBmiBackgroundColor(bmiStatus),
},
{
title: 'dashboard:bloodPressure',
description: '-',
icon: <Activity />,
iconBg: 'bg-warning',
},
{
title: 'dashboard:cholesterol',
description: '-',
icon: <BlendingModeIcon className="size-4" />,
iconBg: 'bg-destructive',
},
{
title: 'dashboard:ldlCholesterol',
description: '-',
icon: <Pill />,
iconBg: 'bg-warning',
},
// {
// title: 'Score 2',
// description: 'Normis',
// icon: <LineChart />,
// iconBg: 'bg-success',
// },
{
title: 'dashboard:smoking',
description: isNil(smoking)
? 'dashboard:respondToQuestion'
: smoking
? 'common:yes'
: 'common:no',
descriptionColor: 'text-primary',
icon: isNil(smoking) ? (
<Link href={pathsConfig.app.personalAccountSettings}>
<Button size="icon" variant="outline" className="px-2 text-black">
<ChevronRight className="size-4 stroke-2" />
</Button>
</Link>
) : null,
cardVariant: getCardVariant(isNil(smoking) ? null : !smoking),
},
];
const IS_SHOWN_RECOMMENDATIONS = false as boolean;
@@ -146,13 +145,15 @@ export default function Dashboard({
}) {
const height = account.accountParams?.height || 0;
const weight = account.accountParams?.weight || 0;
let age: number = 0;
let gender: { label: string; value: string } | null = null;
try {
({ age = 0, gender } = PersonalCode.parsePersonalCode(account.personal_code!));
({ age = 0, gender } = PersonalCode.parsePersonalCode(
account.personal_code!,
));
} catch (e) {
console.error("Failed to parse personal code", e);
console.error('Failed to parse personal code', e);
}
const bmiStatus = getBmiStatus(bmiThresholds, { age, height, weight });

View File

@@ -5,11 +5,9 @@ import { useContext } from 'react';
import { useRouter } from 'next/navigation';
import { AccountSelector } from '@kit/accounts/account-selector';
import { featureFlagsConfig, pathsConfig } from '@kit/shared/config';
import { SidebarContext } from '@kit/ui/shadcn-sidebar';
import { pathsConfig, featureFlagsConfig } from '@kit/shared/config';
const features = {
enableTeamCreation: featureFlagsConfig.enableTeamCreation,
};

View File

@@ -7,6 +7,8 @@ export function HomeLayoutPageHeader(
}>,
) {
return (
<PageHeader description={props.description} title={props.title}>{props.children}</PageHeader>
<PageHeader description={props.description} title={props.title}>
{props.children}
</PageHeader>
);
}

View File

@@ -1,25 +1,23 @@
"use client";
'use client';
import { useState } from 'react';
import { formatCurrency } from '@/packages/shared/src/utils';
import { StoreProduct } from '@medusajs/types';
import { HeartPulse, Loader2, ShoppingCart } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { Button } from '@kit/ui/button';
import {
Card,
CardHeader,
CardFooter,
CardDescription,
} from '@kit/ui/card';
import { StoreProduct } from '@medusajs/types';
import { useState } from 'react';
import { handleAddToCart } from '~/lib/services/medusaCart.service';
import { InfoTooltip } from '@kit/shared/components/ui/info-tooltip';
import { Trans } from '@kit/ui/trans';
import { Button } from '@kit/ui/button';
import { Card, CardDescription, CardFooter, CardHeader } from '@kit/ui/card';
import { toast } from '@kit/ui/sonner';
import { formatCurrency } from '@/packages/shared/src/utils';
import { Trans } from '@kit/ui/trans';
import { handleAddToCart } from '~/lib/services/medusaCart.service';
export type OrderAnalysisCard = Pick<
StoreProduct, 'title' | 'description' | 'subtitle'
StoreProduct,
'title' | 'description' | 'subtitle'
> & {
variant: { id: string };
price: number | null;
@@ -32,10 +30,13 @@ export default function OrderAnalysesCards({
analyses: OrderAnalysisCard[];
countryCode: string;
}) {
const {
i18n: { language },
} = useTranslation();
const { i18n: { language } } = useTranslation()
const [variantAddingToCart, setVariantAddingToCart] = useState<string | null>(null);
const [variantAddingToCart, setVariantAddingToCart] = useState<string | null>(
null,
);
const handleSelect = async (variantId: string) => {
if (variantAddingToCart) {
return null;
@@ -54,24 +55,19 @@ export default function OrderAnalysesCards({
setVariantAddingToCart(null);
console.error(e);
}
}
};
return (
<div className="grid xs:grid-cols-3 gap-6 mt-4">
{analyses.map(({
title,
variant,
description,
subtitle,
price,
}) => {
const formattedPrice = typeof price === 'number'
? formatCurrency({
currencyCode: 'eur',
locale: language,
value: price,
})
: null;
<div className="xs:grid-cols-3 mt-4 grid gap-6">
{analyses.map(({ title, variant, description, subtitle, price }) => {
const formattedPrice =
typeof price === 'number'
? formatCurrency({
currencyCode: 'eur',
locale: language,
value: price,
})
: null;
return (
<Card
key={title}
@@ -80,23 +76,29 @@ export default function OrderAnalysesCards({
>
<CardHeader className="flex-row">
<div
className={'flex size-8 items-center-safe justify-center-safe rounded-full text-white bg-primary\/10 mb-6'}
className={
'bg-primary/10 mb-6 flex size-8 items-center-safe justify-center-safe rounded-full text-white'
}
>
<HeartPulse className="size-4 fill-green-500" />
</div>
<div className='ml-auto flex size-8 items-center-safe justify-center-safe rounded-full text-white bg-warning'>
<div className="bg-warning ml-auto flex size-8 items-center-safe justify-center-safe rounded-full text-white">
<Button
size="icon"
variant="outline"
className="px-2 text-black"
onClick={() => handleSelect(variant.id)}
>
{variantAddingToCart === variant.id ? <Loader2 className="size-4 stroke-2 animate-spin" /> : <ShoppingCart className="size-4 stroke-2" />}
{variantAddingToCart === variant.id ? (
<Loader2 className="size-4 animate-spin stroke-2" />
) : (
<ShoppingCart className="size-4 stroke-2" />
)}
</Button>
</div>
</CardHeader>
<CardFooter className="flex gap-2">
<div className="flex flex-col items-start gap-2 flex-1">
<div className="flex flex-1 flex-col items-start gap-2">
<h5>
{title}
{description && (
@@ -104,7 +106,7 @@ export default function OrderAnalysesCards({
{' '}
<InfoTooltip
content={
<div className='flex flex-col gap-2'>
<div className="flex flex-col gap-2">
<span>{formattedPrice}</span>
<span>{description}</span>
</div>
@@ -113,11 +115,7 @@ export default function OrderAnalysesCards({
</>
)}
</h5>
{subtitle && (
<CardDescription>
{subtitle}
</CardDescription>
)}
{subtitle && <CardDescription>{subtitle}</CardDescription>}
</div>
<div className="flex flex-col items-end gap-2 self-end text-sm">
<span>{formattedPrice}</span>

View File

@@ -1,15 +1,21 @@
"use client"
'use client';
import React from 'react';
import { formatCurrency } from '@/packages/shared/src/utils';
import { StoreOrder } from '@medusajs/types';
import { useTranslation } from 'react-i18next';
import { formatCurrency } from "@/packages/shared/src/utils"
import { StoreOrder } from "@medusajs/types"
import React from "react"
import { useTranslation } from "react-i18next"
import { Trans } from '@kit/ui/trans';
export default function CartTotals({ medusaOrder }: {
medusaOrder: StoreOrder
export default function CartTotals({
medusaOrder,
}: {
medusaOrder: StoreOrder;
}) {
const { i18n: { language } } = useTranslation()
const {
i18n: { language },
} = useTranslation();
const {
currency_code,
total,
@@ -17,29 +23,39 @@ export default function CartTotals({ medusaOrder }: {
tax_total,
discount_total,
gift_card_total,
} = medusaOrder
} = medusaOrder;
return (
<div>
<div className="flex flex-col gap-y-2 txt-medium text-ui-fg-subtle ">
<div className="txt-medium text-ui-fg-subtle flex flex-col gap-y-2">
<div className="flex items-center justify-between">
<span className="flex gap-x-1 items-center">
<span className="flex items-center gap-x-1">
<Trans i18nKey="cart:order.subtotal" />
</span>
<span data-testid="cart-subtotal" data-value={subtotal || 0}>
{formatCurrency({ value: subtotal ?? 0, currencyCode: currency_code, locale: language })}
{formatCurrency({
value: subtotal ?? 0,
currencyCode: currency_code,
locale: language,
})}
</span>
</div>
{!!discount_total && (
<div className="flex items-center justify-between">
<span><Trans i18nKey="cart:order.promotionsTotal" /></span>
<span>
<Trans i18nKey="cart:order.promotionsTotal" />
</span>
<span
className="text-ui-fg-interactive"
data-testid="cart-discount"
data-value={discount_total || 0}
>
-{" "}
{formatCurrency({ value: discount_total ?? 0, currencyCode: currency_code, locale: language })}
-{' '}
{formatCurrency({
value: discount_total ?? 0,
currencyCode: currency_code,
locale: language,
})}
</span>
</div>
)}
@@ -53,30 +69,42 @@ export default function CartTotals({ medusaOrder }: {
</div> */}
{!!gift_card_total && (
<div className="flex items-center justify-between">
<span><Trans i18nKey="cart:order.giftCard" /></span>
<span>
<Trans i18nKey="cart:order.giftCard" />
</span>
<span
className="text-ui-fg-interactive"
data-testid="cart-gift-card-amount"
data-value={gift_card_total || 0}
>
-{" "}
{formatCurrency({ value: gift_card_total ?? 0, currencyCode: currency_code, locale: language })}
-{' '}
{formatCurrency({
value: gift_card_total ?? 0,
currencyCode: currency_code,
locale: language,
})}
</span>
</div>
)}
</div>
<div className="h-px w-full border-b border-gray-200 my-4" />
<div className="flex items-center justify-between text-ui-fg-base mb-2 txt-medium ">
<span className="font-bold"><Trans i18nKey="cart:order.total" /></span>
<div className="my-4 h-px w-full border-b border-gray-200" />
<div className="text-ui-fg-base txt-medium mb-2 flex items-center justify-between">
<span className="font-bold">
<Trans i18nKey="cart:order.total" />
</span>
<span
className="txt-xlarge-plus"
data-testid="cart-total"
data-value={total || 0}
>
{formatCurrency({ value: total ?? 0, currencyCode: currency_code, locale: language })}
{formatCurrency({
value: total ?? 0,
currencyCode: currency_code,
locale: language,
})}
</span>
</div>
<div className="h-px w-full border-b border-gray-200 mt-4" />
<div className="mt-4 h-px w-full border-b border-gray-200" />
</div>
)
);
}

View File

@@ -1,29 +1,25 @@
import { Trans } from '@kit/ui/trans';
import { formatDate } from 'date-fns';
import type { AnalysisOrder } from "~/lib/types/analysis-order";
export default function OrderDetails({ order }: {
order: AnalysisOrder
}) {
import { Trans } from '@kit/ui/trans';
import type { AnalysisOrder } from '~/lib/types/analysis-order';
export default function OrderDetails({ order }: { order: AnalysisOrder }) {
return (
<div className="flex flex-col gap-y-2">
<div>
<span className="font-bold">
<Trans i18nKey="cart:orderConfirmed.orderNumber" />:{" "}
</span>
<span>
{order.medusa_order_id}
<Trans i18nKey="cart:orderConfirmed.orderNumber" />:{' '}
</span>
<span>{order.medusa_order_id}</span>
</div>
<div>
<span className="font-bold">
<Trans i18nKey="cart:orderConfirmed.orderDate" />:{" "}
</span>
<span>
{formatDate(order.created_at, 'dd.MM.yyyy HH:mm')}
<Trans i18nKey="cart:orderConfirmed.orderDate" />:{' '}
</span>
<span>{formatDate(order.created_at, 'dd.MM.yyyy HH:mm')}</span>
</div>
</div>
)
);
}

View File

@@ -1,13 +1,16 @@
import { StoreCartLineItem, StoreOrderLineItem } from "@medusajs/types"
import { TableCell, TableRow } from "@kit/ui/table"
import { StoreCartLineItem, StoreOrderLineItem } from '@medusajs/types';
// import LineItemOptions from "@modules/common/components/line-item-options"
import LineItemPrice from "@modules/common/components/line-item-price"
import LineItemUnitPrice from "@modules/common/components/line-item-unit-price"
import LineItemPrice from '@modules/common/components/line-item-price';
import LineItemUnitPrice from '@modules/common/components/line-item-unit-price';
export default function OrderItem({ item, currencyCode }: {
item: StoreCartLineItem | StoreOrderLineItem
currencyCode: string
import { TableCell, TableRow } from '@kit/ui/table';
export default function OrderItem({
item,
currencyCode,
}: {
item: StoreCartLineItem | StoreOrderLineItem;
currencyCode: string;
}) {
const partnerLocationName = item.metadata?.partner_location_name;
return (
@@ -18,22 +21,21 @@ export default function OrderItem({ item, currencyCode }: {
</div>
</TableCell> */}
<TableCell className="text-left px-6">
<TableCell className="px-6 text-left">
<span
className="txt-medium-plus text-ui-fg-base"
data-testid="product-name"
>
{item.product_title}{` ${partnerLocationName ? `(${partnerLocationName})` : ''}`}
{item.product_title}
{` ${partnerLocationName ? `(${partnerLocationName})` : ''}`}
</span>
{/* <LineItemOptions variant={item.variant} data-testid="product-variant" /> */}
</TableCell>
<TableCell className="px-6">
<span className="flex flex-col items-end h-full justify-center">
<span className="flex gap-x-1 ">
<span className="text-ui-fg-muted">
{item.quantity}x{" "}
</span>
<span className="flex h-full flex-col items-end justify-center">
<span className="flex gap-x-1">
<span className="text-ui-fg-muted">{item.quantity}x </span>
<LineItemUnitPrice
item={item}
style="tight"
@@ -49,5 +51,5 @@ export default function OrderItem({ item, currencyCode }: {
</span>
</TableCell>
</TableRow>
)
);
}

View File

@@ -1,39 +1,44 @@
import repeat from "@lib/util/repeat"
import { StoreOrder } from "@medusajs/types"
import { Table, TableBody } from "@kit/ui/table"
import repeat from '@lib/util/repeat';
import { StoreOrder } from '@medusajs/types';
import SkeletonLineItem from '@modules/skeletons/components/skeleton-line-item';
import SkeletonLineItem from "@modules/skeletons/components/skeleton-line-item"
import OrderItem from "./order-item"
import { Heading } from "@kit/ui/heading"
import { Heading } from '@kit/ui/heading';
import { Table, TableBody } from '@kit/ui/table';
import { Trans } from '@kit/ui/trans';
export default function OrderItems({ medusaOrder }: {
medusaOrder: StoreOrder
import OrderItem from './order-item';
export default function OrderItems({
medusaOrder,
}: {
medusaOrder: StoreOrder;
}) {
const items = medusaOrder.items
const items = medusaOrder.items;
return (
<div className="flex flex-col gap-y-4">
<Heading level={5} className="flex flex-row text-3xl-regular">
<Heading level={5} className="text-3xl-regular flex flex-row">
<Trans i18nKey="cart:orderConfirmed.summary" />
</Heading>
<div className="flex flex-col">
<Table className="rounded-lg border border-separate">
<Table className="border-separate rounded-lg border">
<TableBody data-testid="products-table">
{items?.length
? items
.sort((a, b) => (a.created_at ?? "") > (b.created_at ?? "") ? -1 : 1)
.map((item) => (
<OrderItem
key={item.id}
item={item}
currencyCode={medusaOrder.currency_code}
/>
))
.sort((a, b) =>
(a.created_at ?? '') > (b.created_at ?? '') ? -1 : 1,
)
.map((item) => (
<OrderItem
key={item.id}
item={item}
currencyCode={medusaOrder.currency_code}
/>
))
: repeat(5).map((i) => <SkeletonLineItem key={i} />)}
</TableBody>
</Table>
</div>
</div>
)
);
}

View File

@@ -1,9 +1,15 @@
'use server';
import { createPageViewLog, PageViewAction } from "~/lib/services/audit/pageView.service";
import { loadCurrentUserAccount } from "../../_lib/server/load-user-account";
import {
PageViewAction,
createPageViewLog,
} from '~/lib/services/audit/pageView.service';
export async function logAnalysisResultsNavigateAction(analysisOrderId: string) {
import { loadCurrentUserAccount } from '../../_lib/server/load-user-account';
export async function logAnalysisResultsNavigateAction(
analysisOrderId: string,
) {
const { account } = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');

View File

@@ -1,37 +1,57 @@
import type { AnalysisOrder } from "~/lib/types/analysis-order";
import { Trans } from '@kit/ui/makerkit/trans';
import { StoreOrderLineItem } from "@medusajs/types";
import OrderItemsTable from "./order-items-table";
import Link from "next/link";
import { Eye } from "lucide-react";
import Link from 'next/link';
export default function OrderBlock({ analysisOrder, itemsAnalysisPackage, itemsOther }: {
analysisOrder: AnalysisOrder,
itemsAnalysisPackage: StoreOrderLineItem[],
itemsOther: StoreOrderLineItem[],
import { StoreOrderLineItem } from '@medusajs/types';
import { Eye } from 'lucide-react';
import { Trans } from '@kit/ui/makerkit/trans';
import type { AnalysisOrder } from '~/lib/types/analysis-order';
import OrderItemsTable from './order-items-table';
export default function OrderBlock({
analysisOrder,
itemsAnalysisPackage,
itemsOther,
}: {
analysisOrder: AnalysisOrder;
itemsAnalysisPackage: StoreOrderLineItem[];
itemsOther: StoreOrderLineItem[];
}) {
return (
<div className="flex flex-col gap-4">
<h4>
<Trans i18nKey="analysis-results:orderTitle" values={{ orderNumber: analysisOrder.medusa_order_id }} />
<Trans
i18nKey="analysis-results:orderTitle"
values={{ orderNumber: analysisOrder.medusa_order_id }}
/>
{` (${analysisOrder.id})`}
</h4>
<div className="flex gap-2">
<h5>
<Trans i18nKey={`orders:status.${analysisOrder.status}`} />
</h5>
<Link href={`/home/order/${analysisOrder.id}`} className="flex items-center justify-between text-small-regular">
<button
className="flex gap-x-1 text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer"
>
<Link
href={`/home/order/${analysisOrder.id}`}
className="text-small-regular flex items-center justify-between"
>
<button className="text-ui-fg-subtle hover:text-ui-fg-base flex cursor-pointer gap-x-1">
<Eye />
</button>
</Link>
</div>
<div className="flex flex-col gap-4">
<OrderItemsTable items={itemsAnalysisPackage} title="orders:table.analysisPackage" analysisOrder={analysisOrder} />
<OrderItemsTable items={itemsOther} title="orders:table.otherOrders" analysisOrder={analysisOrder} />
<OrderItemsTable
items={itemsAnalysisPackage}
title="orders:table.analysisPackage"
analysisOrder={analysisOrder}
/>
<OrderItemsTable
items={itemsOther}
title="orders:table.otherOrders"
analysisOrder={analysisOrder}
/>
</div>
</div>
)
);
}

View File

@@ -65,7 +65,7 @@ export default function OrderItemsTable({
)
.map((orderItem) => (
<TableRow className="w-full" key={orderItem.id}>
<TableCell className="text-left w-[100%] px-6">
<TableCell className="w-[100%] px-6 text-left">
<p className="txt-medium-plus text-ui-fg-base">
{orderItem.product_title}
</p>