prettier fix
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
@@ -32,7 +33,7 @@ export default async function AnalysisResultsPage({
|
||||
]);
|
||||
|
||||
if (!account?.id) {
|
||||
return redirect("/");
|
||||
return redirect('/');
|
||||
}
|
||||
|
||||
await createPageViewLog({
|
||||
@@ -47,27 +48,31 @@ export default async function AnalysisResultsPage({
|
||||
title={<Trans i18nKey="analysis-results:pageTitle" />}
|
||||
description={<Trans i18nKey="analysis-results:descriptionEmpty" />}
|
||||
/>
|
||||
<PageBody className="gap-4">
|
||||
</PageBody>
|
||||
<PageBody className="gap-4"></PageBody>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const orderedAnalysisElements = analysisResponse.orderedAnalysisElements;
|
||||
const hasOrderedAnalysisElements = orderedAnalysisElements.length > 0;
|
||||
const isPartialStatus = analysisResponse.order.status === 'PARTIAL_ANALYSIS_RESPONSE';
|
||||
const isPartialStatus =
|
||||
analysisResponse.order.status === 'PARTIAL_ANALYSIS_RESPONSE';
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHeader
|
||||
title={<Trans i18nKey="analysis-results:pageTitle" />}
|
||||
description={hasOrderedAnalysisElements ? (
|
||||
isPartialStatus
|
||||
? <Trans i18nKey="analysis-results:descriptionPartial" />
|
||||
: <Trans i18nKey="analysis-results:description" />
|
||||
) : (
|
||||
<Trans i18nKey="analysis-results:descriptionEmpty" />
|
||||
)}
|
||||
description={
|
||||
hasOrderedAnalysisElements ? (
|
||||
isPartialStatus ? (
|
||||
<Trans i18nKey="analysis-results:descriptionPartial" />
|
||||
) : (
|
||||
<Trans i18nKey="analysis-results:description" />
|
||||
)
|
||||
) : (
|
||||
<Trans i18nKey="analysis-results:descriptionEmpty" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<Button asChild>
|
||||
@@ -106,13 +111,15 @@ export default async function AnalysisResultsPage({
|
||||
orderedAnalysisElements.map((element, index) => (
|
||||
<React.Fragment key={element.analysisIdOriginal}>
|
||||
<Analysis element={element} />
|
||||
{element.results?.nestedElements?.map((nestedElement, nestedIndex) => (
|
||||
<Analysis
|
||||
key={`nested-${nestedElement.analysisElementOriginalId}-${nestedIndex}`}
|
||||
nestedElement={nestedElement}
|
||||
isNestedElement
|
||||
/>
|
||||
))}
|
||||
{element.results?.nestedElements?.map(
|
||||
(nestedElement, nestedIndex) => (
|
||||
<Analysis
|
||||
key={`nested-${nestedElement.analysisElementOriginalId}-${nestedIndex}`}
|
||||
nestedElement={nestedElement}
|
||||
isNestedElement
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</React.Fragment>
|
||||
))
|
||||
) : (
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import type { AnalysisResultDetailsElementResults } from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
import { AnalysisResultLevel } from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
import { ArrowDown } from 'lucide-react';
|
||||
|
||||
import { cn } from '@kit/ui/utils';
|
||||
import type { AnalysisResultDetailsElementResults } from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
import { AnalysisResultLevel } from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
|
||||
type AnalysisResultLevelBarResults = Pick<AnalysisResultDetailsElementResults, 'normLower' | 'normUpper' | 'responseValue'>;
|
||||
type AnalysisResultLevelBarResults = Pick<
|
||||
AnalysisResultDetailsElementResults,
|
||||
'normLower' | 'normUpper' | 'responseValue'
|
||||
>;
|
||||
|
||||
const Level = ({
|
||||
isActive = false,
|
||||
@@ -34,22 +37,29 @@ const Level = ({
|
||||
{isActive && (
|
||||
<div
|
||||
className="absolute top-[-14px] left-1/2 -translate-x-1/2 rounded-[10px] bg-white p-[2px]"
|
||||
{...(arrowLocation ? {
|
||||
style: {
|
||||
left: `${arrowLocation}%`,
|
||||
...(arrowLocation > 92.5 && { left: '92.5%' }),
|
||||
...(arrowLocation < 7.5 && { left: '7.5%' }),
|
||||
}
|
||||
} : {})}
|
||||
{...(arrowLocation
|
||||
? {
|
||||
style: {
|
||||
left: `${arrowLocation}%`,
|
||||
...(arrowLocation > 92.5 && { left: '92.5%' }),
|
||||
...(arrowLocation < 7.5 && { left: '7.5%' }),
|
||||
},
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
<ArrowDown strokeWidth={2} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{color === 'success' && typeof normRangeText === 'string' && (
|
||||
<p className={cn("absolute bottom-[-18px] left-3/8 text-xs text-muted-foreground font-bold whitespace-nowrap", {
|
||||
'opacity-60': isActive,
|
||||
})}>
|
||||
<p
|
||||
className={cn(
|
||||
'text-muted-foreground absolute bottom-[-18px] left-3/8 text-xs font-bold whitespace-nowrap',
|
||||
{
|
||||
'opacity-60': isActive,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{normRangeText}
|
||||
</p>
|
||||
)}
|
||||
@@ -59,11 +69,7 @@ const Level = ({
|
||||
|
||||
const AnalysisLevelBar = ({
|
||||
level,
|
||||
results: {
|
||||
normLower: lower,
|
||||
normUpper: upper,
|
||||
responseValue: value,
|
||||
},
|
||||
results: { normLower: lower, normUpper: upper, responseValue: value },
|
||||
normRangeText,
|
||||
}: {
|
||||
level: AnalysisResultLevel;
|
||||
@@ -90,7 +96,7 @@ const AnalysisLevelBar = ({
|
||||
return 100; // Beyond upper bound
|
||||
}
|
||||
|
||||
// If only lower bound exists
|
||||
// If only lower bound exists
|
||||
if (upper === null && lower !== null) {
|
||||
if (value >= lower) {
|
||||
// Value is in normal range (above lower bound)
|
||||
@@ -127,7 +133,7 @@ const AnalysisLevelBar = ({
|
||||
// If pending results, show gray bar
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="mt-4 flex h-3 w-60% sm:w-[35%] max-w-[360px] gap-1 sm:mt-0">
|
||||
<div className="w-60% mt-4 flex h-3 max-w-[360px] gap-1 sm:mt-0 sm:w-[35%]">
|
||||
<Level color="gray-200" isFirst isLast />
|
||||
</div>
|
||||
);
|
||||
@@ -146,29 +152,25 @@ const AnalysisLevelBar = ({
|
||||
const [warning, normal, critical] = [
|
||||
{
|
||||
isActive: isWarning,
|
||||
color: "warning",
|
||||
color: 'warning',
|
||||
...(isWarning ? { arrowLocation } : {}),
|
||||
},
|
||||
{
|
||||
isActive: isNormal,
|
||||
color: "success",
|
||||
color: 'success',
|
||||
normRangeText,
|
||||
...(isNormal ? { arrowLocation } : {}),
|
||||
},
|
||||
{
|
||||
isActive: isCritical,
|
||||
color: "destructive",
|
||||
color: 'destructive',
|
||||
isLast: true,
|
||||
...(isCritical ? { arrowLocation } : {}),
|
||||
},
|
||||
] as const;
|
||||
|
||||
if (!hasLowerBound) {
|
||||
return [
|
||||
{ ...normal, isFirst: true },
|
||||
warning,
|
||||
critical,
|
||||
] as const;
|
||||
return [{ ...normal, isFirst: true }, warning, critical] as const;
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -176,16 +178,27 @@ const AnalysisLevelBar = ({
|
||||
normal,
|
||||
{ ...critical, isLast: true },
|
||||
] as const;
|
||||
}, [isValueBelowLower, isValueAboveUpper, isValueInNormalRange, arrowLocation, normRangeText, isNormal, isWarning, isCritical]);
|
||||
}, [
|
||||
isValueBelowLower,
|
||||
isValueAboveUpper,
|
||||
isValueInNormalRange,
|
||||
arrowLocation,
|
||||
normRangeText,
|
||||
isNormal,
|
||||
isWarning,
|
||||
isCritical,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={cn(
|
||||
"flex h-3 gap-1",
|
||||
"mt-4 sm:mt-0",
|
||||
"w-[60%] sm:w-[35%]",
|
||||
"min-w-[50vw] sm:min-w-auto",
|
||||
"max-w-[360px]",
|
||||
)}>
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-3 gap-1',
|
||||
'mt-4 sm:mt-0',
|
||||
'w-[60%] sm:w-[35%]',
|
||||
'min-w-[50vw] sm:min-w-auto',
|
||||
'max-w-[360px]',
|
||||
)}
|
||||
>
|
||||
<Level {...first} />
|
||||
<Level {...second} />
|
||||
<Level {...third} />
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
'use client';
|
||||
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { format } from 'date-fns';
|
||||
import { Info } from 'lucide-react';
|
||||
|
||||
import type {
|
||||
AnalysisResultDetailsElement,
|
||||
AnalysisResultsDetailsElementNested,
|
||||
} from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
import { AnalysisResultLevel } from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
import { format } from 'date-fns';
|
||||
import { Info } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
import { cn } from '@kit/ui/utils';
|
||||
|
||||
@@ -64,7 +65,11 @@ const Analysis = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const { responseValue, responseValueIsNegative, responseValueIsWithinNorm } = results;
|
||||
const {
|
||||
responseValue,
|
||||
responseValueIsNegative,
|
||||
responseValueIsWithinNorm,
|
||||
} = results;
|
||||
if (responseValue === null || responseValue === undefined) {
|
||||
if (hasIsNegative) {
|
||||
if (responseValueIsNegative) {
|
||||
@@ -107,7 +112,8 @@ const Analysis = ({
|
||||
|
||||
const isCancelled = Number(results?.status) === 5;
|
||||
const nestedElements = results?.nestedElements ?? null;
|
||||
const hasNestedElements = Array.isArray(nestedElements) && nestedElements.length > 0;
|
||||
const hasNestedElements =
|
||||
Array.isArray(nestedElements) && nestedElements.length > 0;
|
||||
|
||||
const normRangeText = (() => {
|
||||
if (normLower === null && normUpper === null) {
|
||||
@@ -118,9 +124,17 @@ const Analysis = ({
|
||||
const hasTextualResponse = hasIsNegative || hasIsWithinNorm;
|
||||
|
||||
return (
|
||||
<div className={cn("border-border rounded-lg border px-5", { 'ml-8': isNestedElement })}>
|
||||
<div className="flex flex-col items-center justify-between gap-2 pt-3 pb-6 sm:py-3 sm:h-[65px] sm:flex-row sm:gap-0">
|
||||
<div className={cn("flex items-center gap-2 font-semibold", { 'font-bold': isNestedElement })}>
|
||||
<div
|
||||
className={cn('border-border rounded-lg border px-5', {
|
||||
'ml-8': isNestedElement,
|
||||
})}
|
||||
>
|
||||
<div className="flex flex-col items-center justify-between gap-2 pt-3 pb-6 sm:h-[65px] sm:flex-row sm:gap-0 sm:py-3">
|
||||
<div
|
||||
className={cn('flex items-center gap-2 font-semibold', {
|
||||
'font-bold': isNestedElement,
|
||||
})}
|
||||
>
|
||||
{name}
|
||||
{results?.responseTime && (
|
||||
<div
|
||||
@@ -147,7 +161,7 @@ const Analysis = ({
|
||||
</div>
|
||||
|
||||
{isCancelled && (
|
||||
<div className="text-red-600 font-semibold text-sm">
|
||||
<div className="text-sm font-semibold text-red-600">
|
||||
<Trans i18nKey="analysis-results:cancelled" />
|
||||
</div>
|
||||
)}
|
||||
@@ -157,9 +171,15 @@ const Analysis = ({
|
||||
<div className="flex items-center gap-3 sm:ml-auto">
|
||||
<div
|
||||
className={cn('font-semibold', {
|
||||
'text-yellow-600': hasTextualResponse && analysisResultLevel === AnalysisResultLevel.WARNING,
|
||||
'text-red-600': hasTextualResponse && analysisResultLevel === AnalysisResultLevel.CRITICAL,
|
||||
'text-green-600': hasTextualResponse && analysisResultLevel === AnalysisResultLevel.NORMAL,
|
||||
'text-yellow-600':
|
||||
hasTextualResponse &&
|
||||
analysisResultLevel === AnalysisResultLevel.WARNING,
|
||||
'text-red-600':
|
||||
hasTextualResponse &&
|
||||
analysisResultLevel === AnalysisResultLevel.CRITICAL,
|
||||
'text-green-600':
|
||||
hasTextualResponse &&
|
||||
analysisResultLevel === AnalysisResultLevel.NORMAL,
|
||||
})}
|
||||
>
|
||||
{value}
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Modal from '@modules/common/components/modal';
|
||||
|
||||
import { PageBody, PageHeader } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
import { Button } from '@kit/ui/shadcn/button';
|
||||
import Modal from "@modules/common/components/modal"
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import Analysis from '../_components/analysis';
|
||||
import { analysisResponses } from './test-responses';
|
||||
@@ -19,16 +20,15 @@ export default function AnalysisResultsPage() {
|
||||
<PageBody className="gap-4">
|
||||
<div className="mt-8 flex flex-col justify-between gap-4 sm:flex-row sm:items-center sm:gap-0">
|
||||
<div>
|
||||
<h2>
|
||||
Analüüsi tulemused demo
|
||||
</h2>
|
||||
<h2>Analüüsi tulemused demo</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
{analysisResponses.map(({ id, orderedAnalysisElements }, index) => {
|
||||
const isOpen = openBlocks.includes(id);
|
||||
const closeModal = () => setOpenBlocks(openBlocks.filter((block) => block !== id));
|
||||
const closeModal = () =>
|
||||
setOpenBlocks(openBlocks.filter((block) => block !== id));
|
||||
return (
|
||||
<div key={index} className="flex flex-col gap-2 py-4">
|
||||
<div className="flex flex-col gap-2 pb-4">
|
||||
@@ -52,12 +52,21 @@ export default function AnalysisResultsPage() {
|
||||
{isOpen && (
|
||||
<Modal isOpen={isOpen} close={closeModal} size="large">
|
||||
<div className="overflow-y-auto">
|
||||
|
||||
<p>NormiStaatus</p>
|
||||
<ul>
|
||||
<li>0 - testi väärtus jääb normaalväärtuste piirkonda või on määramata,</li>
|
||||
<li>1 - testi väärtus jääb hoiatava (tähelepanu suunava) märkega piirkonda,</li>
|
||||
<li>2 - testi väärtus on normaalväärtuste piirkonnast väljas või kõrgendatud tähelepanu nõudvas piirkonnas.</li>
|
||||
<li>
|
||||
0 - testi väärtus jääb normaalväärtuste piirkonda
|
||||
või on määramata,
|
||||
</li>
|
||||
<li>
|
||||
1 - testi väärtus jääb hoiatava (tähelepanu
|
||||
suunava) märkega piirkonda,
|
||||
</li>
|
||||
<li>
|
||||
2 - testi väärtus on normaalväärtuste piirkonnast
|
||||
väljas või kõrgendatud tähelepanu nõudvas
|
||||
piirkonnas.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>UuringOlek</p>
|
||||
@@ -70,7 +79,7 @@ export default function AnalysisResultsPage() {
|
||||
<li>6 - Tühistatud,</li>
|
||||
</ul>
|
||||
|
||||
<pre className="text-sm bg-muted p-4 rounded-md">
|
||||
<pre className="bg-muted rounded-md p-4 text-sm">
|
||||
{JSON.stringify(orderedAnalysisElements, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
@@ -90,7 +99,7 @@ export default function AnalysisResultsPage() {
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</PageBody>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,52 @@
|
||||
'use server';
|
||||
|
||||
import { MontonioOrderToken } from '@/app/home/(user)/_components/cart/types';
|
||||
import { loadCurrentUserAccount } from '@/app/home/(user)/_lib/server/load-user-account';
|
||||
import { placeOrder, retrieveCart } from '@lib/data/cart';
|
||||
import { listProductTypes } from '@lib/data/products';
|
||||
import type { StoreOrder } from '@medusajs/types';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { z } from "zod";
|
||||
import { MontonioOrderToken } from "@/app/home/(user)/_components/cart/types";
|
||||
import { loadCurrentUserAccount } from "@/app/home/(user)/_lib/server/load-user-account";
|
||||
import { listProductTypes } from "@lib/data/products";
|
||||
import { placeOrder, retrieveCart } from "@lib/data/cart";
|
||||
import { createI18nServerInstance } from "~/lib/i18n/i18n.server";
|
||||
import { createAnalysisOrder, getAnalysisOrder } from '~/lib/services/order.service';
|
||||
import { sendOrderToMedipost } from '~/lib/services/medipost/medipostPrivateMessage.service';
|
||||
import { getOrderedAnalysisIds } from '~/lib/services/medusaOrder.service';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { AccountWithParams } from '@kit/accounts/types/accounts';
|
||||
import { createNotificationsApi } from '@kit/notifications/api';
|
||||
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
||||
import type { AccountWithParams } from '@kit/accounts/types/accounts';
|
||||
import type { StoreOrder } from '@medusajs/types';
|
||||
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { sendOrderToMedipost } from '~/lib/services/medipost/medipostPrivateMessage.service';
|
||||
import { getOrderedAnalysisIds } from '~/lib/services/medusaOrder.service';
|
||||
import {
|
||||
createAnalysisOrder,
|
||||
getAnalysisOrder,
|
||||
} from '~/lib/services/order.service';
|
||||
|
||||
const ANALYSIS_PACKAGES_TYPE_HANDLE = 'analysis-packages';
|
||||
const ANALYSIS_TYPE_HANDLE = 'synlab-analysis';
|
||||
const MONTONIO_PAID_STATUS = 'PAID';
|
||||
|
||||
const env = () => z
|
||||
.object({
|
||||
emailSender: z
|
||||
.string({
|
||||
error: 'EMAIL_SENDER is required',
|
||||
})
|
||||
.min(1),
|
||||
siteUrl: z
|
||||
.string({
|
||||
error: 'NEXT_PUBLIC_SITE_URL is required',
|
||||
})
|
||||
.min(1),
|
||||
isEnabledDispatchOnMontonioCallback: z
|
||||
.boolean({
|
||||
const env = () =>
|
||||
z
|
||||
.object({
|
||||
emailSender: z
|
||||
.string({
|
||||
error: 'EMAIL_SENDER is required',
|
||||
})
|
||||
.min(1),
|
||||
siteUrl: z
|
||||
.string({
|
||||
error: 'NEXT_PUBLIC_SITE_URL is required',
|
||||
})
|
||||
.min(1),
|
||||
isEnabledDispatchOnMontonioCallback: z.boolean({
|
||||
error: 'MEDIPOST_ENABLE_DISPATCH_ON_MONTONIO_CALLBACK is required',
|
||||
}),
|
||||
})
|
||||
.parse({
|
||||
emailSender: process.env.EMAIL_SENDER,
|
||||
siteUrl: process.env.NEXT_PUBLIC_SITE_URL!,
|
||||
isEnabledDispatchOnMontonioCallback: process.env.MEDIPOST_ENABLE_DISPATCH_ON_MONTONIO_CALLBACK === 'true',
|
||||
});
|
||||
})
|
||||
.parse({
|
||||
emailSender: process.env.EMAIL_SENDER,
|
||||
siteUrl: process.env.NEXT_PUBLIC_SITE_URL!,
|
||||
isEnabledDispatchOnMontonioCallback:
|
||||
process.env.MEDIPOST_ENABLE_DISPATCH_ON_MONTONIO_CALLBACK === 'true',
|
||||
});
|
||||
|
||||
const sendEmail = async ({
|
||||
account,
|
||||
@@ -49,15 +55,17 @@ const sendEmail = async ({
|
||||
partnerLocationName,
|
||||
language,
|
||||
}: {
|
||||
account: Pick<AccountWithParams, 'name' | 'id'>,
|
||||
email: string,
|
||||
analysisPackageName: string,
|
||||
partnerLocationName: string,
|
||||
language: string,
|
||||
account: Pick<AccountWithParams, 'name' | 'id'>;
|
||||
email: string;
|
||||
analysisPackageName: string;
|
||||
partnerLocationName: string;
|
||||
language: string;
|
||||
}) => {
|
||||
const client = getSupabaseServerAdminClient();
|
||||
try {
|
||||
const { renderSynlabAnalysisPackageEmail } = await import('@kit/email-templates');
|
||||
const { renderSynlabAnalysisPackageEmail } = await import(
|
||||
'@kit/email-templates'
|
||||
);
|
||||
const { getMailer } = await import('@kit/mailers');
|
||||
|
||||
const mailer = await getMailer();
|
||||
@@ -79,15 +87,14 @@ const sendEmail = async ({
|
||||
.catch((error) => {
|
||||
throw new Error(`Failed to send email, message=${error}`);
|
||||
});
|
||||
await createNotificationsApi(client)
|
||||
.createNotification({
|
||||
account_id: account.id,
|
||||
body: html,
|
||||
});
|
||||
await createNotificationsApi(client).createNotification({
|
||||
account_id: account.id,
|
||||
body: html,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to send email, message=${error}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function decodeOrderToken(orderToken: string) {
|
||||
const secretKey = process.env.MONTONIO_SECRET_KEY as string;
|
||||
@@ -97,7 +104,7 @@ async function decodeOrderToken(orderToken: string) {
|
||||
}) as MontonioOrderToken;
|
||||
|
||||
if (decoded.paymentStatus !== MONTONIO_PAID_STATUS) {
|
||||
throw new Error("Payment not successful");
|
||||
throw new Error('Payment not successful');
|
||||
}
|
||||
|
||||
return decoded;
|
||||
@@ -106,38 +113,49 @@ async function decodeOrderToken(orderToken: string) {
|
||||
async function getCartByOrderToken(decoded: MontonioOrderToken) {
|
||||
const [, , cartId] = decoded.merchantReferenceDisplay.split(':');
|
||||
if (!cartId) {
|
||||
throw new Error("Cart ID not found");
|
||||
throw new Error('Cart ID not found');
|
||||
}
|
||||
const cart = await retrieveCart(cartId);
|
||||
if (!cart) {
|
||||
throw new Error("Cart not found");
|
||||
throw new Error('Cart not found');
|
||||
}
|
||||
return cart;
|
||||
}
|
||||
|
||||
async function getOrderResultParameters(medusaOrder: StoreOrder) {
|
||||
const { productTypes } = await listProductTypes();
|
||||
const analysisPackagesType = productTypes.find(({ metadata }) => metadata?.handle === ANALYSIS_PACKAGES_TYPE_HANDLE);
|
||||
const analysisType = productTypes.find(({ metadata }) => metadata?.handle === ANALYSIS_TYPE_HANDLE);
|
||||
const analysisPackagesType = productTypes.find(
|
||||
({ metadata }) => metadata?.handle === ANALYSIS_PACKAGES_TYPE_HANDLE,
|
||||
);
|
||||
const analysisType = productTypes.find(
|
||||
({ metadata }) => metadata?.handle === ANALYSIS_TYPE_HANDLE,
|
||||
);
|
||||
|
||||
const analysisPackageOrderItem = medusaOrder.items?.find(({ product_type_id }) => product_type_id === analysisPackagesType?.id);
|
||||
const analysisItems = medusaOrder.items?.filter(({ product_type_id }) => product_type_id === analysisType?.id);
|
||||
const analysisPackageOrderItem = medusaOrder.items?.find(
|
||||
({ product_type_id }) => product_type_id === analysisPackagesType?.id,
|
||||
);
|
||||
const analysisItems = medusaOrder.items?.filter(
|
||||
({ product_type_id }) => product_type_id === analysisType?.id,
|
||||
);
|
||||
|
||||
return {
|
||||
medusaOrderId: medusaOrder.id,
|
||||
email: medusaOrder.email,
|
||||
analysisPackageOrder: analysisPackageOrderItem
|
||||
? {
|
||||
partnerLocationName: analysisPackageOrderItem?.metadata?.partner_location_name as string ?? '',
|
||||
analysisPackageName: analysisPackageOrderItem?.title ?? '',
|
||||
}
|
||||
: null,
|
||||
analysisItemsOrder: Array.isArray(analysisItems) && analysisItems.length > 0
|
||||
? analysisItems.map(({ product }) => ({
|
||||
analysisName: product?.title ?? '',
|
||||
analysisId: product?.metadata?.analysisIdOriginal as string ?? '',
|
||||
}))
|
||||
partnerLocationName:
|
||||
(analysisPackageOrderItem?.metadata
|
||||
?.partner_location_name as string) ?? '',
|
||||
analysisPackageName: analysisPackageOrderItem?.title ?? '',
|
||||
}
|
||||
: null,
|
||||
analysisItemsOrder:
|
||||
Array.isArray(analysisItems) && analysisItems.length > 0
|
||||
? analysisItems.map(({ product }) => ({
|
||||
analysisName: product?.title ?? '',
|
||||
analysisId: (product?.metadata?.analysisIdOriginal as string) ?? '',
|
||||
}))
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -146,12 +164,12 @@ async function sendAnalysisPackageOrderEmail({
|
||||
email,
|
||||
analysisPackageOrder,
|
||||
}: {
|
||||
account: AccountWithParams,
|
||||
email: string,
|
||||
account: AccountWithParams;
|
||||
email: string;
|
||||
analysisPackageOrder: {
|
||||
partnerLocationName: string,
|
||||
analysisPackageName: string,
|
||||
},
|
||||
partnerLocationName: string;
|
||||
analysisPackageName: string;
|
||||
};
|
||||
}) {
|
||||
const { language } = await createI18nServerInstance();
|
||||
const { analysisPackageName, partnerLocationName } = analysisPackageOrder;
|
||||
@@ -164,51 +182,69 @@ async function sendAnalysisPackageOrderEmail({
|
||||
language,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to send email", error);
|
||||
console.error('Failed to send email', error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function processMontonioCallback(orderToken: string) {
|
||||
const { account } = await loadCurrentUserAccount();
|
||||
if (!account) {
|
||||
throw new Error("Account not found in context");
|
||||
throw new Error('Account not found in context');
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = await decodeOrderToken(orderToken);
|
||||
const cart = await getCartByOrderToken(decoded);
|
||||
|
||||
const medusaOrder = await placeOrder(cart.id, { revalidateCacheTags: false });
|
||||
const orderedAnalysisElements = await getOrderedAnalysisIds({ medusaOrder });
|
||||
const medusaOrder = await placeOrder(cart.id, {
|
||||
revalidateCacheTags: false,
|
||||
});
|
||||
const orderedAnalysisElements = await getOrderedAnalysisIds({
|
||||
medusaOrder,
|
||||
});
|
||||
|
||||
try {
|
||||
const existingAnalysisOrder = await getAnalysisOrder({ medusaOrderId: medusaOrder.id });
|
||||
console.info(`Analysis order already exists for medusaOrderId=${medusaOrder.id}, orderId=${existingAnalysisOrder.id}`);
|
||||
const existingAnalysisOrder = await getAnalysisOrder({
|
||||
medusaOrderId: medusaOrder.id,
|
||||
});
|
||||
console.info(
|
||||
`Analysis order already exists for medusaOrderId=${medusaOrder.id}, orderId=${existingAnalysisOrder.id}`,
|
||||
);
|
||||
return { success: true, orderId: existingAnalysisOrder.id };
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
|
||||
const orderId = await createAnalysisOrder({ medusaOrder, orderedAnalysisElements });
|
||||
const orderId = await createAnalysisOrder({
|
||||
medusaOrder,
|
||||
orderedAnalysisElements,
|
||||
});
|
||||
const orderResult = await getOrderResultParameters(medusaOrder);
|
||||
|
||||
const { medusaOrderId, email, analysisPackageOrder, analysisItemsOrder } = orderResult;
|
||||
const { medusaOrderId, email, analysisPackageOrder, analysisItemsOrder } =
|
||||
orderResult;
|
||||
|
||||
if (email) {
|
||||
if (analysisPackageOrder) {
|
||||
await sendAnalysisPackageOrderEmail({ account, email, analysisPackageOrder });
|
||||
await sendAnalysisPackageOrderEmail({
|
||||
account,
|
||||
email,
|
||||
analysisPackageOrder,
|
||||
});
|
||||
} else {
|
||||
console.info(`Order has no analysis package, skipping email.`);
|
||||
}
|
||||
|
||||
if (analysisItemsOrder) {
|
||||
// @TODO send email for separate analyses
|
||||
console.warn(`Order has analysis items, but no email template exists yet`);
|
||||
console.warn(
|
||||
`Order has analysis items, but no email template exists yet`,
|
||||
);
|
||||
} else {
|
||||
console.info(`Order has no analysis items, skipping email.`);
|
||||
}
|
||||
} else {
|
||||
console.error("Missing email to send order result email", orderResult);
|
||||
console.error('Missing email to send order result email', orderResult);
|
||||
}
|
||||
|
||||
if (env().isEnabledDispatchOnMontonioCallback) {
|
||||
@@ -217,7 +253,7 @@ export async function processMontonioCallback(orderToken: string) {
|
||||
|
||||
return { success: true, orderId };
|
||||
} catch (error) {
|
||||
console.error("Failed to place order", error);
|
||||
console.error('Failed to place order', error);
|
||||
throw new Error(`Failed to place order, message=${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { processMontonioCallback } from './actions';
|
||||
|
||||
export default function MontonioCallbackClient({ orderToken, error }: {
|
||||
export default function MontonioCallbackClient({
|
||||
orderToken,
|
||||
error,
|
||||
}: {
|
||||
orderToken?: string;
|
||||
error?: string;
|
||||
}) {
|
||||
@@ -32,7 +37,7 @@ export default function MontonioCallbackClient({ orderToken, error }: {
|
||||
const { orderId } = await processMontonioCallback(orderToken);
|
||||
router.push(`/home/order/${orderId}/confirmed`);
|
||||
} catch (error) {
|
||||
console.error("Failed to place order", error);
|
||||
console.error('Failed to place order', error);
|
||||
router.push('/home/cart/montonio-callback/error');
|
||||
} finally {
|
||||
setIsProcessing(false);
|
||||
@@ -43,9 +48,9 @@ export default function MontonioCallbackClient({ orderToken, error }: {
|
||||
}, [orderToken, error, router, hasProcessed, isProcessing]);
|
||||
|
||||
return (
|
||||
<div className="flex mt-10 justify-center min-h-screen">
|
||||
<div className="mt-10 flex min-h-screen justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto mb-4"></div>
|
||||
<div className="border-primary mx-auto mb-4 h-12 w-12 animate-spin rounded-full border-b-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
import { PageBody, PageHeader } from '@/packages/ui/src/makerkit/page';
|
||||
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
import { PageBody, PageHeader } from '@/packages/ui/src/makerkit/page';
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { Alert, AlertDescription } from '@kit/ui/shadcn/alert';
|
||||
import { AlertTitle } from '@kit/ui/shadcn/alert';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
export async function generateMetadata() {
|
||||
const { t } = await createI18nServerInstance();
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import MontonioCallbackClient from './client-component';
|
||||
|
||||
export default async function MontonioCallbackPage({ searchParams }: {
|
||||
export default async function MontonioCallbackPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{
|
||||
'order-token'?: string;
|
||||
}>;
|
||||
}) {
|
||||
const orderToken = (await searchParams)['order-token'];
|
||||
|
||||
|
||||
if (!orderToken) {
|
||||
return <MontonioCallbackClient error="Order token is missing" />;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||
import { PageBody, PageHeader } from '@/packages/ui/src/makerkit/page';
|
||||
|
||||
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';
|
||||
import Cart from '../../_components/cart';
|
||||
import { listProductTypes } from '@lib/data/products';
|
||||
import CartTimer from '../../_components/cart/cart-timer';
|
||||
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
import Cart from '../../_components/cart';
|
||||
import CartTimer from '../../_components/cart/cart-timer';
|
||||
|
||||
export async function generateMetadata() {
|
||||
const { t } = await createI18nServerInstance();
|
||||
|
||||
@@ -20,34 +22,51 @@ export async function generateMetadata() {
|
||||
|
||||
async function CartPage() {
|
||||
const cart = await retrieveCart().catch((error) => {
|
||||
console.error("Failed to retrieve cart", error);
|
||||
console.error('Failed to retrieve cart', error);
|
||||
return notFound();
|
||||
});
|
||||
|
||||
const { productTypes } = await listProductTypes();
|
||||
const analysisPackagesType = productTypes.find(({ metadata }) => metadata?.handle === 'analysis-packages');
|
||||
const synlabAnalysisType = productTypes.find(({ metadata }) => metadata?.handle === 'synlab-analysis');
|
||||
const synlabAnalyses = analysisPackagesType && synlabAnalysisType && cart?.items
|
||||
? cart.items.filter((item) => {
|
||||
const productTypeId = item.product?.type_id;
|
||||
if (!productTypeId) {
|
||||
return false;
|
||||
}
|
||||
return [analysisPackagesType.id, synlabAnalysisType.id].includes(productTypeId);
|
||||
})
|
||||
: [];
|
||||
const ttoServiceItems = cart?.items?.filter((item) => !synlabAnalyses.some((analysis) => analysis.id === item.id)) ?? [];
|
||||
const analysisPackagesType = productTypes.find(
|
||||
({ metadata }) => metadata?.handle === 'analysis-packages',
|
||||
);
|
||||
const synlabAnalysisType = productTypes.find(
|
||||
({ metadata }) => metadata?.handle === 'synlab-analysis',
|
||||
);
|
||||
const synlabAnalyses =
|
||||
analysisPackagesType && synlabAnalysisType && cart?.items
|
||||
? cart.items.filter((item) => {
|
||||
const productTypeId = item.product?.type_id;
|
||||
if (!productTypeId) {
|
||||
return false;
|
||||
}
|
||||
return [analysisPackagesType.id, synlabAnalysisType.id].includes(
|
||||
productTypeId,
|
||||
);
|
||||
})
|
||||
: [];
|
||||
const ttoServiceItems =
|
||||
cart?.items?.filter(
|
||||
(item) => !synlabAnalyses.some((analysis) => analysis.id === item.id),
|
||||
) ?? [];
|
||||
|
||||
const otherItemsSorted = ttoServiceItems.sort((a, b) => (a.updated_at ?? "") > (b.updated_at ?? "") ? -1 : 1);
|
||||
const otherItemsSorted = ttoServiceItems.sort((a, b) =>
|
||||
(a.updated_at ?? '') > (b.updated_at ?? '') ? -1 : 1,
|
||||
);
|
||||
const item = otherItemsSorted[0];
|
||||
const isTimerShown = ttoServiceItems.length > 0 && !!item && !!item.updated_at;
|
||||
const isTimerShown =
|
||||
ttoServiceItems.length > 0 && !!item && !!item.updated_at;
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
<PageHeader title={<Trans i18nKey="cart:title" />}>
|
||||
{isTimerShown && <CartTimer cartItem={item} />}
|
||||
</PageHeader>
|
||||
<Cart cart={cart} synlabAnalyses={synlabAnalyses} ttoServiceItems={ttoServiceItems} />
|
||||
<Cart
|
||||
cart={cart}
|
||||
synlabAnalyses={synlabAnalyses}
|
||||
ttoServiceItems={ttoServiceItems}
|
||||
/>
|
||||
</PageBody>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Scale } from 'lucide-react';
|
||||
|
||||
import SelectAnalysisPackages from '@kit/shared/components/select-analysis-packages';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { PageBody } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
import SelectAnalysisPackages from '@kit/shared/components/select-analysis-packages';
|
||||
import { PageBody } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import ComparePackagesModal from '../../_components/compare-packages-modal';
|
||||
import { loadAnalysisPackages } from '../../_lib/server/load-analysis-packages';
|
||||
|
||||
@@ -21,7 +21,8 @@ export const generateMetadata = async () => {
|
||||
};
|
||||
|
||||
async function OrderAnalysisPackagePage() {
|
||||
const { analysisPackageElements, analysisPackages, countryCode } = await loadAnalysisPackages();
|
||||
const { analysisPackageElements, analysisPackages, countryCode } =
|
||||
await loadAnalysisPackages();
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
@@ -40,7 +41,10 @@ async function OrderAnalysisPackagePage() {
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<SelectAnalysisPackages analysisPackages={analysisPackages} countryCode={countryCode} />
|
||||
<SelectAnalysisPackages
|
||||
analysisPackages={analysisPackages}
|
||||
countryCode={countryCode}
|
||||
/>
|
||||
</PageBody>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
import { PageBody } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
import {
|
||||
PageViewAction,
|
||||
createPageViewLog,
|
||||
} from '~/lib/services/audit/pageView.service';
|
||||
|
||||
import { HomeLayoutPageHeader } from '../../_components/home-page-header';
|
||||
import { loadAnalyses } from '../../_lib/server/load-analyses';
|
||||
import OrderAnalysesCards from '../../_components/order-analyses-cards';
|
||||
import { createPageViewLog, PageViewAction } from '~/lib/services/audit/pageView.service';
|
||||
import { loadAnalyses } from '../../_lib/server/load-analyses';
|
||||
import { loadCurrentUserAccount } from '../../_lib/server/load-user-account';
|
||||
|
||||
export const generateMetadata = async () => {
|
||||
@@ -24,7 +28,7 @@ async function OrderAnalysisPage() {
|
||||
}
|
||||
|
||||
const { analyses, countryCode } = await loadAnalyses();
|
||||
|
||||
|
||||
await createPageViewLog({
|
||||
accountId: account.id,
|
||||
action: PageViewAction.VIEW_ORDER_ANALYSIS,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { PageBody } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
import { PageBody } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
import { HomeLayoutPageHeader } from '../../_components/home-page-header';
|
||||
|
||||
export const generateMetadata = async () => {
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
import { PageBody, PageHeader } from '@kit/ui/page';
|
||||
|
||||
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
import { getAnalysisOrder } from '~/lib/services/order.service';
|
||||
import { retrieveOrder } from '@lib/data/orders';
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
|
||||
import Divider from "@modules/common/components/divider"
|
||||
import CartTotals from '@/app/home/(user)/_components/order/cart-totals';
|
||||
import OrderDetails from '@/app/home/(user)/_components/order/order-details';
|
||||
import OrderItems from '@/app/home/(user)/_components/order/order-items';
|
||||
import CartTotals from '@/app/home/(user)/_components/order/cart-totals';
|
||||
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||
import { retrieveOrder } from '@lib/data/orders';
|
||||
import Divider from '@modules/common/components/divider';
|
||||
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
import { PageBody, PageHeader } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
import { getAnalysisOrder } from '~/lib/services/order.service';
|
||||
|
||||
export async function generateMetadata() {
|
||||
const { t } = await createI18nServerInstance();
|
||||
|
||||
@@ -27,12 +27,16 @@ async function OrderConfirmedPage(props: {
|
||||
}) {
|
||||
const params = await props.params;
|
||||
|
||||
const order = await getAnalysisOrder({ analysisOrderId: Number(params.orderId) }).catch(() => null);
|
||||
const order = await getAnalysisOrder({
|
||||
analysisOrderId: Number(params.orderId),
|
||||
}).catch(() => null);
|
||||
if (!order) {
|
||||
redirect(pathsConfig.app.myOrders);
|
||||
}
|
||||
|
||||
const medusaOrder = await retrieveOrder(order.medusa_order_id).catch(() => null);
|
||||
const medusaOrder = await retrieveOrder(order.medusa_order_id).catch(
|
||||
() => null,
|
||||
);
|
||||
if (!medusaOrder) {
|
||||
redirect(pathsConfig.app.myOrders);
|
||||
}
|
||||
@@ -41,7 +45,7 @@ async function OrderConfirmedPage(props: {
|
||||
<PageBody>
|
||||
<PageHeader title={<Trans i18nKey="cart:orderConfirmed.title" />} />
|
||||
<Divider />
|
||||
<div className="grid grid-cols-1 small:grid-cols-[1fr_360px] gap-x-40 lg:px-4 gap-y-6">
|
||||
<div className="small:grid-cols-[1fr_360px] grid grid-cols-1 gap-x-40 gap-y-6 lg:px-4">
|
||||
<OrderDetails order={order} />
|
||||
<Divider />
|
||||
<OrderItems medusaOrder={medusaOrder} />
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
import { PageBody, PageHeader } from '@kit/ui/page';
|
||||
|
||||
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
import { getAnalysisOrder } from '~/lib/services/order.service';
|
||||
import { retrieveOrder } from '@lib/data/orders';
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
|
||||
import Divider from "@modules/common/components/divider"
|
||||
import CartTotals from '@/app/home/(user)/_components/order/cart-totals';
|
||||
import OrderDetails from '@/app/home/(user)/_components/order/order-details';
|
||||
import OrderItems from '@/app/home/(user)/_components/order/order-items';
|
||||
import CartTotals from '@/app/home/(user)/_components/order/cart-totals';
|
||||
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||
import { retrieveOrder } from '@lib/data/orders';
|
||||
import Divider from '@modules/common/components/divider';
|
||||
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
import { PageBody, PageHeader } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
import { getAnalysisOrder } from '~/lib/services/order.service';
|
||||
|
||||
export async function generateMetadata() {
|
||||
const { t } = await createI18nServerInstance();
|
||||
|
||||
@@ -27,12 +27,16 @@ async function OrderConfirmedPage(props: {
|
||||
}) {
|
||||
const params = await props.params;
|
||||
|
||||
const order = await getAnalysisOrder({ analysisOrderId: Number(params.orderId) }).catch(() => null);
|
||||
const order = await getAnalysisOrder({
|
||||
analysisOrderId: Number(params.orderId),
|
||||
}).catch(() => null);
|
||||
if (!order) {
|
||||
redirect(pathsConfig.app.myOrders);
|
||||
}
|
||||
|
||||
const medusaOrder = await retrieveOrder(order.medusa_order_id).catch(() => null);
|
||||
const medusaOrder = await retrieveOrder(order.medusa_order_id).catch(
|
||||
() => null,
|
||||
);
|
||||
if (!medusaOrder) {
|
||||
redirect(pathsConfig.app.myOrders);
|
||||
}
|
||||
@@ -41,7 +45,7 @@ async function OrderConfirmedPage(props: {
|
||||
<PageBody>
|
||||
<PageHeader title={<Trans i18nKey="cart:order.title" />} />
|
||||
<Divider />
|
||||
<div className="grid grid-cols-1 small:grid-cols-[1fr_360px] gap-x-40 lg:px-4 gap-y-6">
|
||||
<div className="small:grid-cols-[1fr_360px] grid grid-cols-1 gap-x-40 gap-y-6 lg:px-4">
|
||||
<OrderDetails order={order} />
|
||||
<Divider />
|
||||
<OrderItems medusaOrder={medusaOrder} />
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { listOrders } from '~/medusa/lib/data/orders';
|
||||
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||
import { listProductTypes } from '@lib/data/products';
|
||||
import { PageBody } from '@kit/ui/makerkit/page';
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
import { HomeLayoutPageHeader } from '../../_components/home-page-header';
|
||||
import { getAnalysisOrders } from '~/lib/services/order.service';
|
||||
import OrderBlock from '../../_components/orders/order-block';
|
||||
import React from 'react';
|
||||
import { Divider } from '@medusajs/ui';
|
||||
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
import { PageBody } from '@kit/ui/makerkit/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
import { getAnalysisOrders } from '~/lib/services/order.service';
|
||||
import { listOrders } from '~/medusa/lib/data/orders';
|
||||
|
||||
import { HomeLayoutPageHeader } from '../../_components/home-page-header';
|
||||
import OrderBlock from '../../_components/orders/order-block';
|
||||
|
||||
export async function generateMetadata() {
|
||||
const { t } = await createI18nServerInstance();
|
||||
@@ -31,7 +34,9 @@ async function OrdersPage() {
|
||||
redirect(pathsConfig.auth.signIn);
|
||||
}
|
||||
|
||||
const analysisPackagesType = productTypes.find(({ metadata }) => metadata?.handle === 'analysis-packages')!;
|
||||
const analysisPackagesType = productTypes.find(
|
||||
({ metadata }) => metadata?.handle === 'analysis-packages',
|
||||
)!;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -41,14 +46,20 @@ async function OrdersPage() {
|
||||
/>
|
||||
<PageBody>
|
||||
{analysisOrders.map((analysisOrder) => {
|
||||
const medusaOrder = medusaOrders.find(({ id }) => id === analysisOrder.medusa_order_id);
|
||||
const medusaOrder = medusaOrders.find(
|
||||
({ id }) => id === analysisOrder.medusa_order_id,
|
||||
);
|
||||
if (!medusaOrder) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const medusaOrderItems = medusaOrder.items || [];
|
||||
const medusaOrderItemsAnalysisPackages = medusaOrderItems.filter((item) => item.product_type_id === analysisPackagesType?.id);
|
||||
const medusaOrderItemsOther = medusaOrderItems.filter((item) => item.product_type_id !== analysisPackagesType?.id);
|
||||
const medusaOrderItemsAnalysisPackages = medusaOrderItems.filter(
|
||||
(item) => item.product_type_id === analysisPackagesType?.id,
|
||||
);
|
||||
const medusaOrderItemsOther = medusaOrderItems.filter(
|
||||
(item) => item.product_type_id !== analysisPackagesType?.id,
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment key={analysisOrder.id}>
|
||||
@@ -59,7 +70,7 @@ async function OrdersPage() {
|
||||
itemsOther={medusaOrderItemsOther}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
);
|
||||
})}
|
||||
{analysisOrders.length === 0 && (
|
||||
<h5 className="mt-6">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { toTitleCase } from '@/lib/utils';
|
||||
import { createUserAnalysesApi } from '@kit/user-analyses/api';
|
||||
import { getSupabaseServerClient } from '@/packages/supabase/src/clients/server-client';
|
||||
|
||||
import { PageBody, PageHeader } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
import { createUserAnalysesApi } from '@kit/user-analyses/api';
|
||||
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
Reference in New Issue
Block a user