+
-
+
- {analysisList && analysisList.length > 0 ? (
-
+ {analysisResponses && analysisResponses.length > 0 ? (
+
) : (
-
+
)}
-
- {analysisList?.map((analysis) => (
-
- {analysis.elements.map((element) => (
-
- ))}
-
+ {analysisElementsWithResults.map(({ results }) => {
+ const analysisElement = analysisElements.find((element) => element.analysis_id_original === results.analysis_element_original_id);
+ if (!analysisElement) {
+ return null;
+ }
+ return (
+
+ );
+ })}
+ {analysisElementsWithoutResults.map((element) => (
+
))}
+ {hasNoAnalysisElements && (
+
+
+
+ )}
);
diff --git a/app/home/(user)/(dashboard)/cart/montonio-callback/actions.ts b/app/home/(user)/(dashboard)/cart/montonio-callback/actions.ts
index e48ac85..bede603 100644
--- a/app/home/(user)/(dashboard)/cart/montonio-callback/actions.ts
+++ b/app/home/(user)/(dashboard)/cart/montonio-callback/actions.ts
@@ -91,7 +91,7 @@ export async function processMontonioCallback(orderToken: string) {
const medusaOrder = await placeOrder(cartId, { revalidateCacheTags: false });
const orderedAnalysisElements = await getOrderedAnalysisElementsIds({ medusaOrder });
- await createOrder({ medusaOrder, orderedAnalysisElements });
+ const orderId = await createOrder({ medusaOrder, orderedAnalysisElements });
const { productTypes } = await listProductTypes();
const analysisPackagesType = productTypes.find(({ metadata }) => metadata?.handle === ANALYSIS_PACKAGES_TYPE_HANDLE);
@@ -119,10 +119,9 @@ export async function processMontonioCallback(orderToken: string) {
console.error("Missing email or analysisPackageName", orderResult);
}
- // Send order to Medipost (no await to avoid blocking)
sendOrderToMedipost({ medusaOrderId, orderedAnalysisElements });
- return { success: true };
+ return { success: true, orderId };
} catch (error) {
console.error("Failed to place order", error);
throw new Error(`Failed to place order, message=${error}`);
diff --git a/app/home/(user)/(dashboard)/cart/montonio-callback/client-component.tsx b/app/home/(user)/(dashboard)/cart/montonio-callback/client-component.tsx
index f90efa4..c388a6d 100644
--- a/app/home/(user)/(dashboard)/cart/montonio-callback/client-component.tsx
+++ b/app/home/(user)/(dashboard)/cart/montonio-callback/client-component.tsx
@@ -29,8 +29,8 @@ export default function MontonioCallbackClient({ orderToken, error }: {
setHasProcessed(true);
try {
- await processMontonioCallback(orderToken);
- router.push('/home/order');
+ const { orderId } = await processMontonioCallback(orderToken);
+ router.push(`/home/order/${orderId}/confirmed`);
} catch (error) {
console.error("Failed to place order", error);
router.push('/home/cart/montonio-callback/error');
diff --git a/app/home/(user)/(dashboard)/cart/montonio-callback/page.tsx b/app/home/(user)/(dashboard)/cart/montonio-callback/page.tsx
index 6893a97..d4f54f4 100644
--- a/app/home/(user)/(dashboard)/cart/montonio-callback/page.tsx
+++ b/app/home/(user)/(dashboard)/cart/montonio-callback/page.tsx
@@ -7,7 +7,6 @@ export default async function MontonioCallbackPage({ searchParams }: {
}) {
const orderToken = (await searchParams)['order-token'];
- console.log('orderToken', orderToken);
if (!orderToken) {
return
;
}
diff --git a/app/home/(user)/(dashboard)/order/[orderId]/confirmed/page.tsx b/app/home/(user)/(dashboard)/order/[orderId]/confirmed/page.tsx
index 2ca1b55..f49e5cb 100644
--- a/app/home/(user)/(dashboard)/order/[orderId]/confirmed/page.tsx
+++ b/app/home/(user)/(dashboard)/order/[orderId]/confirmed/page.tsx
@@ -1,13 +1,16 @@
-import { notFound } from 'next/navigation';
+import { redirect } from 'next/navigation';
+import { PageBody, PageHeader } from '@kit/ui/page';
-import { retrieveOrder } from '~/medusa/lib/data/orders';
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
-import OrderCompleted from '@/app/home/(user)/_components/order/order-completed';
import { withI18n } from '~/lib/i18n/with-i18n';
-
-type Props = {
- params: Promise<{ orderId: string }>;
-};
+import { getOrder } from '~/lib/services/order.service';
+import { retrieveOrder } from '@lib/data/orders';
+import pathsConfig from '~/config/paths.config';
+import Divider from "@modules/common/components/divider"
+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 { Trans } from '@kit/ui/trans';
export async function generateMetadata() {
const { t } = await createI18nServerInstance();
@@ -17,15 +20,33 @@ export async function generateMetadata() {
};
}
-async function OrderConfirmedPage(props: Props) {
+async function OrderConfirmedPage(props: {
+ params: Promise<{ orderId: string }>;
+}) {
const params = await props.params;
- const order = await retrieveOrder(params.orderId).catch(() => null);
+ const order = await getOrder({ orderId: Number(params.orderId) }).catch(() => null);
if (!order) {
- return notFound();
+ redirect(pathsConfig.app.myOrders);
}
- return
;
+ const medusaOrder = await retrieveOrder(order.medusa_order_id).catch(() => null);
+ if (!medusaOrder) {
+ redirect(pathsConfig.app.myOrders);
+ }
+
+ return (
+
+ } />
+
+
+
+ );
}
export default withI18n(OrderConfirmedPage);
diff --git a/app/home/(user)/(dashboard)/order/[orderId]/page.tsx b/app/home/(user)/(dashboard)/order/[orderId]/page.tsx
new file mode 100644
index 0000000..b9e8597
--- /dev/null
+++ b/app/home/(user)/(dashboard)/order/[orderId]/page.tsx
@@ -0,0 +1,52 @@
+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 { getOrder } from '~/lib/services/order.service';
+import { retrieveOrder } from '@lib/data/orders';
+import pathsConfig from '~/config/paths.config';
+import Divider from "@modules/common/components/divider"
+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 { Trans } from '@kit/ui/trans';
+
+export async function generateMetadata() {
+ const { t } = await createI18nServerInstance();
+
+ return {
+ title: t('cart:order.title'),
+ };
+}
+
+async function OrderConfirmedPage(props: {
+ params: Promise<{ orderId: string }>;
+}) {
+ const params = await props.params;
+
+ const order = await getOrder({ orderId: Number(params.orderId) }).catch(() => null);
+ if (!order) {
+ redirect(pathsConfig.app.myOrders);
+ }
+
+ const medusaOrder = await retrieveOrder(order.medusa_order_id).catch(() => null);
+ if (!medusaOrder) {
+ redirect(pathsConfig.app.myOrders);
+ }
+
+ return (
+
+ } />
+
+
+
+ );
+}
+
+export default withI18n(OrderConfirmedPage);
diff --git a/app/home/(user)/(dashboard)/order/page.tsx b/app/home/(user)/(dashboard)/order/page.tsx
index 98c1c4f..4b1d747 100644
--- a/app/home/(user)/(dashboard)/order/page.tsx
+++ b/app/home/(user)/(dashboard)/order/page.tsx
@@ -3,7 +3,6 @@ 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 { retrieveCustomer } from '@lib/data/customer';
import { PageBody } from '@kit/ui/makerkit/page';
import pathsConfig from '~/config/paths.config';
import { Trans } from '@kit/ui/trans';
@@ -11,6 +10,7 @@ import { HomeLayoutPageHeader } from '../../_components/home-page-header';
import OrdersTable from '../../_components/orders/orders-table';
import { withI18n } from '~/lib/i18n/with-i18n';
import type { IOrderLineItem } from '../../_components/orders/types';
+import { getAnalysisOrders } from '~/lib/services/order.service';
export async function generateMetadata() {
const { t } = await createI18nServerInstance();
@@ -21,24 +21,49 @@ export async function generateMetadata() {
}
async function OrdersPage() {
- const customer = await retrieveCustomer();
- const orders = await listOrders().catch(() => null);
+ const medusaOrders = await listOrders();
+ const analysisOrders = await getAnalysisOrders();
const { productTypes } = await listProductTypes();
- if (!customer || !orders || !productTypes) {
+ if (!medusaOrders || !productTypes) {
redirect(pathsConfig.auth.signIn);
}
const analysisPackagesType = productTypes.find(({ metadata }) => metadata?.handle === 'analysis-packages');
- const analysisPackageOrders: IOrderLineItem[] = orders.flatMap(({ id, items, payment_status, fulfillment_status }) => items
+ const analysisPackageOrders: IOrderLineItem[] = medusaOrders.flatMap(({ id, items, payment_status, fulfillment_status }) => items
?.filter((item) => item.product_type_id === analysisPackagesType?.id)
- .map((item) => ({ item, orderId: id, orderStatus: `${payment_status}/${fulfillment_status}` }))
+ .map((item) => {
+ const localOrder = analysisOrders.find((order) => order.medusa_order_id === id);
+ if (!localOrder) {
+ return null;
+ }
+ return {
+ item,
+ medusaOrderId: id,
+ orderId: localOrder?.id,
+ orderStatus: localOrder.status,
+ analysis_element_ids: localOrder.analysis_element_ids,
+ }
+ })
+ .filter((order) => order !== null)
|| []);
- const otherOrders: IOrderLineItem[] = orders
+ const otherOrders: IOrderLineItem[] = medusaOrders
.filter(({ items }) => items?.some((item) => item.product_type_id !== analysisPackagesType?.id))
.flatMap(({ id, items, payment_status, fulfillment_status }) => items
- ?.map((item) => ({ item, orderId: id, orderStatus: `${payment_status}/${fulfillment_status}` }))
+ ?.map((item) => {
+ const analysisOrder = analysisOrders.find((order) => order.medusa_order_id === id);
+ if (!analysisOrder) {
+ return null;
+ }
+ return {
+ item,
+ medusaOrderId: id,
+ orderId: analysisOrder.id,
+ orderStatus: analysisOrder.status,
+ }
+ })
+ .filter((order) => order !== null)
|| []);
return (
diff --git a/app/home/(user)/_components/order/cart-totals.tsx b/app/home/(user)/_components/order/cart-totals.tsx
index dc25aad..2df2237 100644
--- a/app/home/(user)/_components/order/cart-totals.tsx
+++ b/app/home/(user)/_components/order/cart-totals.tsx
@@ -6,8 +6,8 @@ import React from "react"
import { useTranslation } from "react-i18next"
import { Trans } from '@kit/ui/trans';
-export default function CartTotals({ order }: {
- order: StoreOrder
+export default function CartTotals({ medusaOrder }: {
+ medusaOrder: StoreOrder
}) {
const { i18n: { language } } = useTranslation()
const {
@@ -17,7 +17,7 @@ export default function CartTotals({ order }: {
tax_total,
discount_total,
gift_card_total,
- } = order
+ } = medusaOrder
return (
diff --git a/app/home/(user)/_components/order/order-completed.tsx b/app/home/(user)/_components/order/order-completed.tsx
deleted file mode 100644
index f7529a0..0000000
--- a/app/home/(user)/_components/order/order-completed.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Trans } from '@kit/ui/trans';
-import { PageBody, PageHeader } from '@kit/ui/page';
-import { StoreOrder } from "@medusajs/types"
-import Divider from "@modules/common/components/divider"
-
-import CartTotals from "./cart-totals"
-import OrderDetails from "./order-details"
-import OrderItems from "./order-items"
-
-export default async function OrderCompleted({
- order,
-}: {
- order: StoreOrder,
-}) {
- return (
-
- } />
-
-
-
- )
-}
diff --git a/app/home/(user)/_components/order/order-details.tsx b/app/home/(user)/_components/order/order-details.tsx
index e6bc6cf..b750c85 100644
--- a/app/home/(user)/_components/order/order-details.tsx
+++ b/app/home/(user)/_components/order/order-details.tsx
@@ -1,47 +1,21 @@
-import { StoreOrder } from "@medusajs/types"
import { Trans } from '@kit/ui/trans';
+import { formatDate } from 'date-fns';
+import { AnalysisOrder } from "~/lib/services/order.service";
-export default function OrderDetails({ order, showStatus }: {
- order: StoreOrder
- showStatus?: boolean
+export default function OrderDetails({ order }: {
+ order: AnalysisOrder
}) {
- const formatStatus = (str: string) => {
- const formatted = str.split("_").join(" ")
-
- return formatted.slice(0, 1).toUpperCase() + formatted.slice(1)
- }
-
return (
:{" "}
- {new Date(order.created_at).toLocaleDateString()}
+ {formatDate(order.created_at, 'dd.MM.yyyy HH:mm')}
- : {order.display_id}
+ : {order.medusa_order_id}
-
- {showStatus && (
- <>
-
- :{" "}
-
- {formatStatus(order.fulfillment_status)}
-
-
-
- :{" "}
-
- {formatStatus(order.payment_status)}
-
-
- >
- )}
)
}
diff --git a/app/home/(user)/_components/order/order-item.tsx b/app/home/(user)/_components/order/order-item.tsx
index 4cd4e7a..cad98e6 100644
--- a/app/home/(user)/_components/order/order-item.tsx
+++ b/app/home/(user)/_components/order/order-item.tsx
@@ -1,7 +1,7 @@
import { StoreCartLineItem, StoreOrderLineItem } from "@medusajs/types"
import { TableCell, TableRow } from "@kit/ui/table"
-import LineItemOptions from "@modules/common/components/line-item-options"
+// 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"
@@ -9,6 +9,7 @@ export default function OrderItem({ item, currencyCode }: {
item: StoreCartLineItem | StoreOrderLineItem
currencyCode: string
}) {
+ const partnerLocationName = item.metadata?.partner_location_name;
return (
{/*
@@ -22,9 +23,9 @@ export default function OrderItem({ item, currencyCode }: {
className="txt-medium-plus text-ui-fg-base"
data-testid="product-name"
>
- {item.product_title}{` (${item.metadata?.partner_location_name ?? "-"})`}
+ {item.product_title}{` ${partnerLocationName ? `(${partnerLocationName})` : ''}`}
-
+ {/* */}
diff --git a/app/home/(user)/_components/order/order-items.tsx b/app/home/(user)/_components/order/order-items.tsx
index 25dbe31..5375314 100644
--- a/app/home/(user)/_components/order/order-items.tsx
+++ b/app/home/(user)/_components/order/order-items.tsx
@@ -7,10 +7,10 @@ import OrderItem from "./order-item"
import { Heading } from "@kit/ui/heading"
import { Trans } from '@kit/ui/trans';
-export default function OrderItems({ order }: {
- order: StoreOrder
+export default function OrderItems({ medusaOrder }: {
+ medusaOrder: StoreOrder
}) {
- const items = order.items
+ const items = medusaOrder.items
return (
@@ -27,7 +27,7 @@ export default function OrderItems({ order }: {
))
: repeat(5).map((i) =>
)}
diff --git a/app/home/(user)/_components/orders/orders-item.tsx b/app/home/(user)/_components/orders/orders-item.tsx
index 2d80f7d..ea8943d 100644
--- a/app/home/(user)/_components/orders/orders-item.tsx
+++ b/app/home/(user)/_components/orders/orders-item.tsx
@@ -6,6 +6,7 @@ import { Eye } from "lucide-react";
import Link from "next/link";
import { formatDate } from "date-fns";
import { IOrderLineItem } from "./types";
+import { Trans } from '@kit/ui/trans';
export default function OrdersItem({ orderItem }: {
orderItem: IOrderLineItem,
@@ -22,15 +23,13 @@ export default function OrdersItem({ orderItem }: {
{formatDate(orderItem.item.created_at, 'dd.MM.yyyy HH:mm')}
- {orderItem.orderStatus && (
-
- {orderItem.orderStatus}
-
- )}
+
+
+
-
+
diff --git a/app/home/(user)/_components/orders/orders-table.tsx b/app/home/(user)/_components/orders/orders-table.tsx
index 2514aab..18f1872 100644
--- a/app/home/(user)/_components/orders/orders-table.tsx
+++ b/app/home/(user)/_components/orders/orders-table.tsx
@@ -9,8 +9,6 @@ import {
import OrdersItem from "./orders-item";
import { IOrderLineItem } from "./types";
-const IS_SHOWN_ORDER_STATUS = true as boolean;
-
export default function OrdersTable({ orderItems, title }: {
orderItems: IOrderLineItem[];
title: string;
@@ -29,10 +27,9 @@ export default function OrdersTable({ orderItems, title }: {
- {IS_SHOWN_ORDER_STATUS && (
-
-
- )}
+
+
+
diff --git a/app/home/(user)/_components/orders/types.ts b/app/home/(user)/_components/orders/types.ts
index 422043e..2c7140e 100644
--- a/app/home/(user)/_components/orders/types.ts
+++ b/app/home/(user)/_components/orders/types.ts
@@ -2,6 +2,7 @@ import { StoreOrderLineItem } from "@medusajs/types";
export interface IOrderLineItem {
item: StoreOrderLineItem;
- orderId: string;
+ medusaOrderId: string;
+ orderId: number;
orderStatus: string;
}
diff --git a/instrumentation.ts b/instrumentation.ts
index 7fb6d8f..c69cd21 100644
--- a/instrumentation.ts
+++ b/instrumentation.ts
@@ -1,9 +1,7 @@
-/**
- * This file is used to register monitoring instrumentation
- * for your Next.js application.
- */
import { type Instrumentation } from 'next';
+const isEnabledInDev = process.env.ENABLE_LOCAL_JOBS === 'true';
+
export async function register() {
const { registerMonitoringInstrumentation } = await import(
'@kit/monitoring/instrumentation'
@@ -12,6 +10,9 @@ export async function register() {
// Register monitoring instrumentation
// based on the MONITORING_PROVIDER environment variable.
await registerMonitoringInstrumentation();
+
+ // Register lightweight in-process job scheduler
+ await registerJobScheduler();
}
/**
@@ -28,3 +29,51 @@ export const onRequestError: Instrumentation.onRequestError = async (err) => {
await service.ready();
await service.captureException(err as Error);
};
+
+async function registerJobScheduler() {
+ const isProd = process.env.NODE_ENV === 'production';
+ if (!isProd && !isEnabledInDev) {
+ console.info('Job scheduler disabled');
+ return;
+ }
+
+ // Prevent duplicate intervals on hot reloads/dev
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const globalAny = globalThis as any;
+ if (globalAny.__mrJobSchedulerInitialized) {
+ console.info('Job scheduler already initialized');
+ return;
+ }
+ globalAny.__mrJobSchedulerInitialized = true;
+
+ let isRunning = false;
+
+ const runSyncAnalysisResults = async () => {
+ if (isRunning) {
+ console.info('Scheduled job syncAnalysisResults skipped: previous run still in progress');
+ return;
+ }
+ isRunning = true;
+ try {
+ try {
+ const { default: loadEnv } = await import('./app/api/job/handler/load-env');
+ loadEnv();
+ } catch {
+ // ignore if not available or already loaded
+ }
+
+ const { default: syncAnalysisResults } = await import(
+ './app/api/job/handler/sync-analysis-results'
+ );
+ await syncAnalysisResults();
+ } catch (error) {
+ console.error('Scheduled job syncAnalysisResults failed:', error);
+ } finally {
+ isRunning = false;
+ }
+ };
+
+ // Run every 10 minutes
+ setTimeout(runSyncAnalysisResults, 15_000);
+ setInterval(runSyncAnalysisResults, 10 * 60 * 1000);
+}
diff --git a/lib/i18n/i18n.settings.ts b/lib/i18n/i18n.settings.ts
index 2d9dad2..e41095f 100644
--- a/lib/i18n/i18n.settings.ts
+++ b/lib/i18n/i18n.settings.ts
@@ -39,6 +39,7 @@ export const defaultI18nNamespaces = [
'order-analysis',
'cart',
'orders',
+ 'analysis-results',
];
/**
diff --git a/lib/services/analysis-element.service.ts b/lib/services/analysis-element.service.ts
index 2777a77..635320c 100644
--- a/lib/services/analysis-element.service.ts
+++ b/lib/services/analysis-element.service.ts
@@ -1,4 +1,3 @@
-import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { Json, Tables } from '@kit/supabase/database';
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
import type { IMaterialGroup, IUuringElement } from './medipost.types';
@@ -9,10 +8,12 @@ export type AnalysisElement = Tables<{ schema: 'medreport' }, 'analysis_elements
export async function getAnalysisElements({
originalIds,
+ ids,
}: {
originalIds?: string[];
+ ids?: number[];
}): Promise {
- const query = getSupabaseServerClient()
+ const query = getSupabaseServerAdminClient()
.schema('medreport')
.from('analysis_elements')
.select(`*, analysis_groups(*)`)
@@ -22,6 +23,10 @@ export async function getAnalysisElements({
query.in('analysis_id_original', [...new Set(originalIds)]);
}
+ if (Array.isArray(ids)) {
+ query.in('id', ids);
+ }
+
const { data: analysisElements, error } = await query;
if (error) {
diff --git a/lib/services/audit/pageView.service.ts b/lib/services/audit/pageView.service.ts
new file mode 100644
index 0000000..719db6d
--- /dev/null
+++ b/lib/services/audit/pageView.service.ts
@@ -0,0 +1,35 @@
+import { getSupabaseServerClient } from '@kit/supabase/server-client';
+
+export const createPageViewLog = async ({
+ accountId,
+ action,
+}: {
+ accountId: string;
+ action: 'VIEW_ANALYSIS_RESULTS';
+}) => {
+ try {
+ const supabase = getSupabaseServerClient();
+
+ const {
+ data: { user },
+ error: userError,
+ } = await supabase.auth.getUser();
+
+ if (userError || !user) {
+ console.error('No authenticated user found; skipping audit insert');
+ return;
+ }
+
+ await supabase
+ .schema('audit')
+ .from('page_views')
+ .insert({
+ account_id: accountId,
+ action,
+ changed_by: user.id,
+ })
+ .throwOnError();
+ } catch (error) {
+ console.error('Failed to insert page view log', error);
+ }
+}
diff --git a/lib/services/medipost.service.ts b/lib/services/medipost.service.ts
index da08be8..e19e6db 100644
--- a/lib/services/medipost.service.ts
+++ b/lib/services/medipost.service.ts
@@ -36,7 +36,7 @@ import { uniqBy } from 'lodash';
import { Tables } from '@kit/supabase/database';
import { createAnalysisGroup } from './analysis-group.service';
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
-import { getOrder } from './order.service';
+import { getOrder, updateOrder } from './order.service';
import { getAnalysisElements, getAnalysisElementsAdmin } from './analysis-element.service';
import { getAnalyses } from './analyses.service';
import { getAccountAdmin } from './account.service';
@@ -235,6 +235,7 @@ export async function readPrivateMessageResponse({
const status = await syncPrivateMessage({ messageResponse, order });
if (status === 'COMPLETED') {
+ await updateOrder({ orderId: order.id, orderStatus: 'FULL_ANALYSIS_RESPONSE' });
await deletePrivateMessage(privateMessage.messageId);
messageIdProcessed = privateMessage.messageId;
}
@@ -658,6 +659,7 @@ export async function syncPrivateMessage({
);
}
+ console.info("status", AnalysisOrderStatus[messageResponse.TellimuseOlek], messageResponse.TellimuseOlek);
return AnalysisOrderStatus[messageResponse.TellimuseOlek];
}
@@ -686,6 +688,7 @@ export async function sendOrderToMedipost({
});
await sendPrivateMessage(orderXml);
+ await updateOrder({ orderId: medreportOrder.id, orderStatus: 'PROCESSING' });
}
export async function getOrderedAnalysisElementsIds({
diff --git a/lib/services/order.service.ts b/lib/services/order.service.ts
index 7702d1b..998d564 100644
--- a/lib/services/order.service.ts
+++ b/lib/services/order.service.ts
@@ -3,6 +3,8 @@ import type { Tables } from '@kit/supabase/database';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import type { StoreOrder } from '@medusajs/types';
+export type AnalysisOrder = Tables<{ schema: 'medreport' }, 'analysis_orders'>;
+
export async function createOrder({
medusaOrder,
orderedAnalysisElements,
@@ -32,6 +34,8 @@ export async function createOrder({
if (orderResult.error || !orderResult.data?.id) {
throw new Error(`Failed to create order, message=${orderResult.error}, data=${JSON.stringify(orderResult)}`);
}
+
+ return orderResult.data.id;
}
export async function updateOrder({
@@ -41,7 +45,8 @@ export async function updateOrder({
orderId: number;
orderStatus: Tables<{ schema: 'medreport' }, 'analysis_orders'>['status'];
}) {
- const { error } = await getSupabaseServerClient()
+ console.info(`Updating order id=${orderId} status=${orderStatus}`);
+ await getSupabaseServerAdminClient()
.schema('medreport')
.from('analysis_orders')
.update({
@@ -49,27 +54,32 @@ export async function updateOrder({
})
.eq('id', orderId)
.throwOnError();
- if (error) {
- throw new Error(`Failed to update order, message=${error}, data=${JSON.stringify(error)}`);
- }
}
export async function getOrder({
medusaOrderId,
+ orderId,
}: {
- medusaOrderId: string;
+ medusaOrderId?: string;
+ orderId?: number;
}) {
const query = getSupabaseServerAdminClient()
.schema('medreport')
.from('analysis_orders')
.select('*')
- .eq('medusa_order_id', medusaOrderId)
+ if (medusaOrderId) {
+ query.eq('medusa_order_id', medusaOrderId);
+ } else if (orderId) {
+ query.eq('id', orderId);
+ } else {
+ throw new Error('Either medusaOrderId or orderId must be provided');
+ }
const { data: order } = await query.single().throwOnError();
return order;
}
-export async function getOrders({
+export async function getAnalysisOrders({
orderStatus,
}: {
orderStatus?: Tables<{ schema: 'medreport' }, 'analysis_orders'>['status'];
diff --git a/packages/features/accounts/src/types/accounts.ts b/packages/features/accounts/src/types/accounts.ts
index 8048dea..bbc4ddb 100644
--- a/packages/features/accounts/src/types/accounts.ts
+++ b/packages/features/accounts/src/types/accounts.ts
@@ -1,6 +1,7 @@
import { Database } from '@kit/supabase/database';
-export type UserAnalysis =
- (Database['medreport']['Tables']['analysis_responses']['Row'] & {
- elements: Database['medreport']['Tables']['analysis_response_elements']['Row'][];
- })[];
+export type UserAnalysisElement = Database['medreport']['Tables']['analysis_response_elements']['Row'];
+export type UserAnalysisResponse = Database['medreport']['Tables']['analysis_responses']['Row'] & {
+ elements: UserAnalysisElement[];
+};
+export type UserAnalysis = UserAnalysisResponse[];
diff --git a/packages/supabase/src/database.types.ts b/packages/supabase/src/database.types.ts
index 94e7d39..6f92492 100644
--- a/packages/supabase/src/database.types.ts
+++ b/packages/supabase/src/database.types.ts
@@ -81,6 +81,30 @@ export type Database = {
}
Relationships: []
}
+ page_views: {
+ Row: {
+ account_id: string
+ action: string
+ changed_by: string
+ created_at: string
+ id: number
+ }
+ Insert: {
+ account_id: string
+ action: string
+ changed_by: string
+ created_at?: string
+ id?: number
+ }
+ Update: {
+ account_id?: string
+ action: string
+ changed_by?: string
+ created_at?: string
+ id?: number
+ }
+ Relationships: []
+ }
request_entries: {
Row: {
comment: string | null
@@ -1859,6 +1883,9 @@ export type Database = {
| "QUEUED"
| "ON_HOLD"
| "PROCESSING"
+ | "PARTIAL_ANALYSIS_RESPONSE"
+ | "FULL_ANALYSIS_RESPONSE"
+ | "WAITING_FOR_DOCTOR_RESPONSE"
| "COMPLETED"
| "REJECTED"
| "CANCELLED"
@@ -7745,12 +7772,15 @@ export const Constants = {
medreport: {
Enums: {
analysis_order_status: [
- "QUEUED",
- "ON_HOLD",
- "PROCESSING",
- "COMPLETED",
- "REJECTED",
- "CANCELLED",
+ "QUEUED", // makstud, ootab Synlabi saatmist
+ "ON_HOLD", //
+ "PROCESSING", // ootab proovide tulemusi
+ "PARTIAL_ANALYSIS_RESPONSE", // osalised tulemused
+ "FULL_ANALYSIS_RESPONSE", // kõik tulemused käes
+ "WAITING_FOR_DOCTOR_RESPONSE", // ootab arsti kokkuvõtet
+ "COMPLETED", // kinnitatud, lõplik
+ "REJECTED", // tagastatud
+ "CANCELLED", // tühistatud
],
app_permissions: [
"roles.manage",
diff --git a/packages/ui/src/makerkit/page.tsx b/packages/ui/src/makerkit/page.tsx
index 4f82a7b..e089171 100644
--- a/packages/ui/src/makerkit/page.tsx
+++ b/packages/ui/src/makerkit/page.tsx
@@ -42,7 +42,7 @@ function PageWithSidebar(props: PageProps) {
>
{MobileNavigation}
-
diff --git a/public/locales/en/account.json b/public/locales/en/account.json
index 95f7e2f..edbf616 100644
--- a/public/locales/en/account.json
+++ b/public/locales/en/account.json
@@ -122,11 +122,5 @@
"consentToAnonymizedCompanyData": {
"label": "Consent to be included in employer statistics",
"description": "Consent to be included in anonymized company statistics"
- },
- "analysisResults": {
- "pageTitle": "My analysis results",
- "description": "Super, you've already done your analysis. Here are your important results:",
- "descriptionEmpty": "If you've already done your analysis, your results will appear here soon.",
- "orderNewAnalysis": "Order new analyses"
}
}
diff --git a/public/locales/en/analysis-results.json b/public/locales/en/analysis-results.json
new file mode 100644
index 0000000..ada8eac
--- /dev/null
+++ b/public/locales/en/analysis-results.json
@@ -0,0 +1,14 @@
+{
+ "pageTitle": "My analysis results",
+ "description": "All analysis results will appear here within 1-3 business days after they have been done.",
+ "descriptionEmpty": "If you've already done your analysis, your results will appear here soon.",
+ "orderNewAnalysis": "Order new analyses",
+ "waitingForResults": "Waiting for results",
+ "noAnalysisElements": "No analysis orders found",
+ "analysisDate": "Analysis result date",
+ "results": {
+ "range": {
+ "normal": "Normal range"
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/locales/en/cart.json b/public/locales/en/cart.json
index 63cb930..3913a78 100644
--- a/public/locales/en/cart.json
+++ b/public/locales/en/cart.json
@@ -47,6 +47,9 @@
"error": "Failed to update location"
}
},
+ "order": {
+ "title": "Order"
+ },
"orderConfirmed": {
"title": "Order confirmed",
"summary": "Summary",
diff --git a/public/locales/en/orders.json b/public/locales/en/orders.json
index 33db1e6..cd36098 100644
--- a/public/locales/en/orders.json
+++ b/public/locales/en/orders.json
@@ -4,6 +4,18 @@
"table": {
"analysisPackage": "Analysis package",
"otherOrders": "Order",
- "createdAt": "Ordered at"
+ "createdAt": "Ordered at",
+ "status": "Status"
+ },
+ "status": {
+ "QUEUED": "Waiting to send to lab",
+ "ON_HOLD": "Waiting for analysis results",
+ "PROCESSING": "In progress",
+ "PARTIAL_ANALYSIS_RESPONSE": "Partial analysis response",
+ "FULL_ANALYSIS_RESPONSE": "All analysis responses",
+ "WAITING_FOR_DOCTOR_RESPONSE": "Waiting for doctor response",
+ "COMPLETED": "Completed",
+ "REJECTED": "Rejected",
+ "CANCELLED": "Cancelled"
}
}
\ No newline at end of file
diff --git a/public/locales/et/account.json b/public/locales/et/account.json
index 836c5e4..ade6520 100644
--- a/public/locales/et/account.json
+++ b/public/locales/et/account.json
@@ -145,11 +145,5 @@
"successTitle": "Tere, {{firstName}} {{lastName}}",
"successDescription": "Teie tervisekonto on aktiveeritud ja kasutamiseks valmis!",
"successButton": "Jätka"
- },
- "analysisResults": {
- "pageTitle": "Minu analüüside vastused",
- "description": "Super, oled käinud tervist kontrollimas. Siin on sinule olulised näitajad:",
- "descriptionEmpty": "Kui oled juba käinud analüüse andmas, siis varsti jõuavad siia sinu analüüside vastused.",
- "orderNewAnalysis": "Telli uued analüüsid"
}
}
diff --git a/public/locales/et/analysis-results.json b/public/locales/et/analysis-results.json
new file mode 100644
index 0000000..0acc140
--- /dev/null
+++ b/public/locales/et/analysis-results.json
@@ -0,0 +1,14 @@
+{
+ "pageTitle": "Minu analüüside vastused",
+ "description": "Kõikide analüüside tulemused ilmuvad 1-3 tööpäeva jooksul peale nende andmist.",
+ "descriptionEmpty": "Kui oled juba käinud analüüse andmas, siis varsti jõuavad siia sinu analüüside vastused.",
+ "orderNewAnalysis": "Telli uued analüüsid",
+ "waitingForResults": "Tulemuse ootel",
+ "noAnalysisElements": "Veel ei ole tellitud analüüse",
+ "analysisDate": "Analüüsi vastuse kuupäev",
+ "results": {
+ "range": {
+ "normal": "Normaalne vahemik"
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/locales/et/cart.json b/public/locales/et/cart.json
index d6026b9..06ef7b5 100644
--- a/public/locales/et/cart.json
+++ b/public/locales/et/cart.json
@@ -48,6 +48,9 @@
"error": "Asukoha uuendamine ebaõnnestus"
}
},
+ "order": {
+ "title": "Tellimus"
+ },
"orderConfirmed": {
"title": "Tellimus on edukalt esitatud",
"summary": "Teenused",
diff --git a/public/locales/et/orders.json b/public/locales/et/orders.json
index dcba485..04ba985 100644
--- a/public/locales/et/orders.json
+++ b/public/locales/et/orders.json
@@ -4,6 +4,18 @@
"table": {
"analysisPackage": "Analüüsi pakett",
"otherOrders": "Tellimus",
- "createdAt": "Tellitud"
+ "createdAt": "Tellitud",
+ "status": "Olek"
+ },
+ "status": {
+ "QUEUED": "Esitatud",
+ "ON_HOLD": "Makstud",
+ "PROCESSING": "Synlabile edastatud",
+ "PARTIAL_ANALYSIS_RESPONSE": "Osalised tulemused",
+ "FULL_ANALYSIS_RESPONSE": "Kõik tulemused käes",
+ "WAITING_FOR_DOCTOR_RESPONSE": "Ootab arsti kokkuvõtet",
+ "COMPLETED": "Lõplikud tulemused",
+ "REJECTED": "Tagastatud",
+ "CANCELLED": "Tühistatud"
}
}
\ No newline at end of file
diff --git a/styles/theme.css b/styles/theme.css
index 2b766a7..46641c3 100644
--- a/styles/theme.css
+++ b/styles/theme.css
@@ -135,8 +135,8 @@
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
- --breakpoint-xs: 30rem;
- --breakpoint-sm: 48rem;
+ --breakpoint-xs: 48rem;
+ --breakpoint-sm: 64rem;
--breakpoint-md: 70rem;
--breakpoint-lg: 80rem;
--breakpoint-xl: 96rem;
diff --git a/supabase/migrations/20250811065135_audit_page_views.sql b/supabase/migrations/20250811065135_audit_page_views.sql
new file mode 100644
index 0000000..ceab355
--- /dev/null
+++ b/supabase/migrations/20250811065135_audit_page_views.sql
@@ -0,0 +1,24 @@
+create table "audit"."page_views" (
+ "id" bigint generated by default as identity not null,
+ "account_id" text not null,
+ "action" text not null,
+ "created_at" timestamp with time zone not null default now(),
+ "changed_by" uuid not null
+);
+
+grant usage on schema audit to authenticated;
+grant select, insert, update, delete on table audit.page_views to authenticated;
+
+alter table "audit"."page_views" enable row level security;
+
+create policy "insert_own"
+on "audit"."page_views"
+as permissive
+for insert
+to authenticated
+with check (auth.uid() = changed_by);
+
+create policy "service_role_select" on "audit"."page_views" for select to service_role using (true);
+create policy "service_role_insert" on "audit"."page_views" for insert to service_role with check (true);
+create policy "service_role_update" on "audit"."page_views" for update to service_role using (true);
+create policy "service_role_delete" on "audit"."page_views" for delete to service_role using (true);
diff --git a/supabase/migrations/20250811101938_more_analysis_order_statuses.sql b/supabase/migrations/20250811101938_more_analysis_order_statuses.sql
new file mode 100644
index 0000000..66a3981
--- /dev/null
+++ b/supabase/migrations/20250811101938_more_analysis_order_statuses.sql
@@ -0,0 +1,3 @@
+alter type medreport.analysis_order_status add value 'PARTIAL_ANALYSIS_RESPONSE';
+alter type medreport.analysis_order_status add value 'FULL_ANALYSIS_RESPONSE';
+alter type medreport.analysis_order_status add value 'WAITING_FOR_DOCTOR_RESPONSE';
diff --git a/utils/medusa-product.ts b/utils/medusa-product.ts
index a93669b..ef4384f 100644
--- a/utils/medusa-product.ts
+++ b/utils/medusa-product.ts
@@ -5,7 +5,7 @@ export const getAnalysisElementMedusaProductIds = (products: ({ metadata?: { ana
const mapped = products
.flatMap((product) => {
- const value = product?.metadata?.analysisElementMedusaProductIds;
+ const value = product?.metadata?.analysisElementMedusaProductIds?.replaceAll("'", '"');
try {
return JSON.parse(value as string);
} catch (e) {