MED-198: add notification for new analysis result
This commit is contained in:
@@ -3,6 +3,9 @@ import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { createNotificationsApi } from '@/packages/features/notifications/src/server/api';
|
||||
import { getSupabaseServerClient } from '@/packages/supabase/src/clients/server-client';
|
||||
|
||||
import { ButtonTooltip } from '@kit/shared/components/ui/button-tooltip';
|
||||
import { pathsConfig } from '@kit/shared/config';
|
||||
import { Button } from '@kit/ui/button';
|
||||
@@ -25,7 +28,9 @@ export default async function AnalysisResultsPage({
|
||||
id: string;
|
||||
}>;
|
||||
}) {
|
||||
const supabaseClient = getSupabaseServerClient();
|
||||
const { id: analysisOrderId } = await params;
|
||||
const notificationsApi = createNotificationsApi(supabaseClient);
|
||||
|
||||
const [{ account }, analysisResponse] = await Promise.all([
|
||||
loadCurrentUserAccount(),
|
||||
@@ -41,6 +46,11 @@ export default async function AnalysisResultsPage({
|
||||
action: PageViewAction.VIEW_ANALYSIS_RESULTS,
|
||||
});
|
||||
|
||||
await notificationsApi.dismissNotification(
|
||||
`/home/analysis-results/${analysisOrderId}`,
|
||||
'link',
|
||||
);
|
||||
|
||||
if (!analysisResponse) {
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -90,6 +90,14 @@ async function OrdersPage() {
|
||||
),
|
||||
);
|
||||
|
||||
if (
|
||||
medusaOrderItemsAnalysisPackages.length === 0 &&
|
||||
medusaOrderItemsOther.length === 0 &&
|
||||
medusaOrderItemsTtoServices.length === 0
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment key={medusaOrder.id}>
|
||||
<Divider className="my-6" />
|
||||
|
||||
@@ -32,6 +32,7 @@ import { Trans } from '@kit/ui/trans';
|
||||
|
||||
// home imports
|
||||
import type { UserWorkspace } from '../_lib/server/load-user-workspace';
|
||||
import { UserNotifications } from './user-notifications';
|
||||
|
||||
const PERSONAL_ACCOUNT_SLUG = 'personal';
|
||||
|
||||
@@ -90,7 +91,7 @@ export function HomeMobileNavigation(props: {
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<div className="flex justify-between gap-4">
|
||||
<div className="flex justify-between gap-3">
|
||||
<Link href={pathsConfig.app.cart}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -108,6 +109,9 @@ export function HomeMobileNavigation(props: {
|
||||
)}
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<UserNotifications userId={user.id} />
|
||||
|
||||
<DropdownMenuTrigger>
|
||||
<Menu className="h-6 w-6" />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
@@ -61,6 +61,7 @@ export default function OrderBlock({
|
||||
id: analysisOrder.id,
|
||||
status: analysisOrder.status,
|
||||
}}
|
||||
isPackage
|
||||
/>
|
||||
)}
|
||||
{itemsTtoService && (
|
||||
|
||||
@@ -32,11 +32,13 @@ export default function OrderItemsTable({
|
||||
title,
|
||||
order,
|
||||
type = 'analysisOrder',
|
||||
isPackage = false,
|
||||
}: {
|
||||
items: StoreOrderLineItem[];
|
||||
title: string;
|
||||
order: Order;
|
||||
type?: OrderItemType;
|
||||
isPackage?: boolean;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
|
||||
@@ -100,9 +102,15 @@ export default function OrderItemsTable({
|
||||
</TableCell>
|
||||
)}
|
||||
<TableCell className="min-w-[180px] px-6">
|
||||
<Trans
|
||||
i18nKey={`orders:status.${type}.${order?.status ?? 'CONFIRMED'}`}
|
||||
/>
|
||||
{isPackage ? (
|
||||
<Trans
|
||||
i18nKey={`orders:status.analysisPackageOrder.${order?.status ?? 'CONFIRMED'}`}
|
||||
/>
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey={`orders:status.${type}.${order?.status ?? 'CONFIRMED'}`}
|
||||
/>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
<TableCell className="px-6 text-right">
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
'use server';
|
||||
|
||||
import { AccountWithParams } from '@/packages/features/accounts/src/types/accounts';
|
||||
import { createNotificationsApi } from '@/packages/features/notifications/src/server/api';
|
||||
import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client';
|
||||
import { listProductTypes } from '@lib/data';
|
||||
import { initiateMultiPaymentSession, placeOrder } from '@lib/data/cart';
|
||||
import type { StoreCart, StoreOrder } from '@medusajs/types';
|
||||
@@ -327,7 +325,6 @@ const sendEmail = async ({
|
||||
partnerLocationName: string;
|
||||
language: string;
|
||||
}) => {
|
||||
const client = getSupabaseServerAdminClient();
|
||||
try {
|
||||
const { renderSynlabAnalysisPackageEmail } = await import(
|
||||
'@kit/email-templates'
|
||||
@@ -353,10 +350,6 @@ const sendEmail = async ({
|
||||
.catch((error) => {
|
||||
throw new Error(`Failed to send email, message=${error}`);
|
||||
});
|
||||
await createNotificationsApi(client).createNotification({
|
||||
account_id: account.id,
|
||||
body: html,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to send email, message=${error}`);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
import type { PostgrestError } from '@supabase/supabase-js';
|
||||
|
||||
import { GetMessageListResponse, MedipostAction } from '@/lib/types/medipost';
|
||||
import { createNotificationsApi } from '@/packages/features/notifications/src/server/api';
|
||||
import { createUserAnalysesApi } from '@/packages/features/user-analyses/src/server/api';
|
||||
import { pathsConfig } from '@/packages/shared/src/config';
|
||||
import { AnalysisOrderStatus } from '@/packages/shared/src/types/medipost-analysis';
|
||||
import type {
|
||||
MedipostOrderResponse,
|
||||
@@ -16,6 +18,7 @@ import axios from 'axios';
|
||||
import { toArray } from '@kit/shared/utils';
|
||||
import { Tables } from '@kit/supabase/database';
|
||||
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import type { AnalysisResponseElement } from '~/lib/types/analysis-response-element';
|
||||
import type { AnalysisOrder } from '~/lib/types/order';
|
||||
|
||||
@@ -268,6 +271,7 @@ export async function syncPrivateMessage({
|
||||
order: Tables<{ schema: 'medreport' }, 'analysis_orders'>;
|
||||
}) {
|
||||
const supabase = getSupabaseServerAdminClient();
|
||||
const { t } = await createI18nServerInstance();
|
||||
|
||||
const orderStatus = AnalysisOrderStatus[TellimuseOlek];
|
||||
|
||||
@@ -300,6 +304,7 @@ export async function syncPrivateMessage({
|
||||
log,
|
||||
});
|
||||
|
||||
let newElementsAdded = 0;
|
||||
for (const element of newElements) {
|
||||
try {
|
||||
await upsertAnalysisResponseElement({
|
||||
@@ -308,6 +313,7 @@ export async function syncPrivateMessage({
|
||||
analysis_response_id: analysisResponseId,
|
||||
},
|
||||
});
|
||||
newElementsAdded++;
|
||||
} catch (e) {
|
||||
log(
|
||||
`Failed to create order response element for response id ${analysisResponseId}, element id '${element.analysis_element_original_id}' (order id: ${order.id})`,
|
||||
@@ -316,6 +322,16 @@ export async function syncPrivateMessage({
|
||||
}
|
||||
}
|
||||
|
||||
log(`Added ${newElementsAdded} new elements`);
|
||||
|
||||
if (newElementsAdded !== 0) {
|
||||
await createNotificationsApi(supabase).createNotification({
|
||||
account_id: analysisOrder.user_id,
|
||||
body: t('analysis-results:notification.body'),
|
||||
link: `${pathsConfig.app.analysisResults}/${order.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
return (await hasAllAnalysisResponseElements({ analysisResponseId, order }))
|
||||
? { isCompleted: orderStatus === 'COMPLETED' }
|
||||
: { isPartial: true };
|
||||
@@ -371,8 +387,13 @@ export async function readPrivateMessageResponse({
|
||||
const hasInvalidOrderId = isNaN(analysisOrderId);
|
||||
|
||||
if (hasInvalidOrderId || !messageResponse || !patientPersonalCode) {
|
||||
console.log({
|
||||
privateMessageContent,
|
||||
saadetis: privateMessageContent?.Saadetis,
|
||||
messageResponse,
|
||||
});
|
||||
console.error(
|
||||
`Invalid order id or message response or patient personal code, medipostExternalOrderId=${medipostExternalOrderId}, privateMessageId=${privateMessageId}`,
|
||||
`Invalid !order id or message response or patient personal code, medipostExternalOrderId=${medipostExternalOrderId}, privateMessageId=${privateMessageId}`,
|
||||
);
|
||||
await upsertMedipostActionLog({
|
||||
action: 'sync_analysis_results_from_medipost',
|
||||
|
||||
@@ -62,7 +62,10 @@ export const listOrders = async (
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(({ orders }) => orders)
|
||||
.catch((err) => medusaError(err));
|
||||
.catch((err) => {
|
||||
console.error('Error receiving orders', { err });
|
||||
return medusaError(err);
|
||||
});
|
||||
};
|
||||
|
||||
export const listOrdersByIds = async (ids: string[]) => {
|
||||
|
||||
@@ -50,4 +50,13 @@ class NotificationsApi {
|
||||
createNotification(params: Notification['Insert']) {
|
||||
return this.service.createNotification(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name createNotification
|
||||
* @description Create a new notification in the database
|
||||
* @param params
|
||||
*/
|
||||
dismissNotification(eqValue: string, eqColumn?: string) {
|
||||
return this.service.dismissNotification(eqColumn, eqValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,4 +29,21 @@ class NotificationsService {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async dismissNotification(eqColumn = 'id', eqValue: string) {
|
||||
const logger = await getLogger();
|
||||
const { error } = await this.client
|
||||
.schema('medreport')
|
||||
.from('notifications')
|
||||
.update({ dismissed: true })
|
||||
.eq(eqColumn, eqValue);
|
||||
|
||||
if (error) {
|
||||
logger.error(
|
||||
{ eqColumn, eqValue },
|
||||
`Could not dismiss notification: ${error.message}`,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,5 +21,8 @@
|
||||
}
|
||||
},
|
||||
"orderTitle": "Order number {{orderNumber}}",
|
||||
"view": "View results"
|
||||
"view": "View results",
|
||||
"notification": {
|
||||
"body": "You have new analysis results"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,15 @@
|
||||
"REJECTED": "Rejected",
|
||||
"CANCELLED": "Cancelled",
|
||||
"analysisOrder": {
|
||||
"QUEUED": "Queued",
|
||||
"PROCESSING": "Sent to Synlab",
|
||||
"PARTIAL_ANALYSIS_RESPONSE": "Partial results",
|
||||
"FULL_ANALYSIS_RESPONSE": "All results received",
|
||||
"COMPLETED": "Confirmed",
|
||||
"REJECTED": "Rejected",
|
||||
"CANCELLED": "Cancelled"
|
||||
},
|
||||
"analysisPackageOrder": {
|
||||
"QUEUED": "Queued",
|
||||
"PROCESSING": "Sent to Synlab",
|
||||
"PARTIAL_ANALYSIS_RESPONSE": "Partial results",
|
||||
|
||||
@@ -21,5 +21,8 @@
|
||||
}
|
||||
},
|
||||
"orderTitle": "Tellimus {{orderNumber}}",
|
||||
"view": "Vaata tulemusi"
|
||||
"view": "Vaata tulemusi",
|
||||
"notification": {
|
||||
"body": "Teil on valmis uued analüüsi tulemused"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
"REJECTED": "Tagastatud",
|
||||
"CANCELLED": "Tühistatud",
|
||||
"analysisOrder": {
|
||||
"QUEUED": "Esitatud",
|
||||
"PROCESSING": "Synlabile edastatud",
|
||||
"PARTIAL_ANALYSIS_RESPONSE": "Osalised tulemused",
|
||||
"FULL_ANALYSIS_RESPONSE": "Kõik tulemused käes",
|
||||
"COMPLETED": "Kinnitatud",
|
||||
"REJECTED": "Tagastatud",
|
||||
"CANCELLED": "Tühistatud"
|
||||
},
|
||||
"analysisPackageOrder": {
|
||||
"QUEUED": "Esitatud",
|
||||
"PROCESSING": "Synlabile edastatud",
|
||||
"PARTIAL_ANALYSIS_RESPONSE": "Osalised tulemused",
|
||||
|
||||
@@ -20,5 +20,8 @@
|
||||
"isNotWithinNorm": "Не в норме"
|
||||
}
|
||||
},
|
||||
"orderTitle": "Заказ {{orderNumber}}"
|
||||
"orderTitle": "Заказ {{orderNumber}}",
|
||||
"notification": {
|
||||
"body": "Teil on valmis uued analüüsi tulemused"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,15 @@
|
||||
"REJECTED": "Отклонено",
|
||||
"CANCELLED": "Отменено",
|
||||
"analysisOrder": {
|
||||
"QUEUED": "Отправлено",
|
||||
"PROCESSING": "Отправлено в Synlab",
|
||||
"PARTIAL_ANALYSIS_RESPONSE": "Частичные результаты",
|
||||
"FULL_ANALYSIS_RESPONSE": "Все результаты получены",
|
||||
"COMPLETED": "Подтверждено",
|
||||
"REJECTED": "Отклонено",
|
||||
"CANCELLED": "Отменено"
|
||||
},
|
||||
"analysisPackageOrder": {
|
||||
"QUEUED": "Отправлено",
|
||||
"PROCESSING": "Отправлено в Synlab",
|
||||
"PARTIAL_ANALYSIS_RESPONSE": "Частичные результаты",
|
||||
|
||||
Reference in New Issue
Block a user