Merge branch 'main' into MED-85

This commit is contained in:
2025-08-28 14:57:09 +03:00
23 changed files with 561 additions and 179 deletions

View File

@@ -0,0 +1,35 @@
import { Database } from '@kit/supabase/database';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
export enum NotificationAction {
DOCTOR_FEEDBACK_RECEIVED = 'DOCTOR_FEEDBACK_RECEIVED',
}
export const createNotificationLog = async ({
action,
status,
comment,
relatedRecordId,
}: {
action: NotificationAction;
status: Database['audit']['Enums']['action_status'];
comment?: string;
relatedRecordId?: string | number;
}) => {
try {
const supabase = getSupabaseServerClient();
await supabase
.schema('audit')
.from('notification_entries')
.insert({
action,
status,
comment,
related_record_key: relatedRecordId?.toString(),
})
.throwOnError();
} catch (error) {
console.error('Failed to insert doctor page view log', error);
}
};

View File

@@ -1,10 +1,33 @@
'use server';
import { CompanySubmitData } from '@/lib/types/company';
import { emailSchema } from '@/lib/validations/email.schema';
import { renderDoctorSummaryReceivedEmail } from '@kit/email-templates';
import { getMailer } from '@kit/mailers';
import { enhanceAction } from '@kit/next/actions';
import { CompanySubmitData } from '../types/company';
import { emailSchema } from '../validations/email.schema';
export const sendDoctorSummaryCompletedEmail = async (
language: string,
recipientName: string,
recipientEmail: string,
orderNr: string,
orderId: number,
) => {
const { html, subject } = await renderDoctorSummaryReceivedEmail({
language,
recipientName,
recipientEmail,
orderNr,
orderId,
});
await sendEmail({
subject,
html,
to: recipientEmail,
});
};
export const sendCompanyOfferEmail = async (
data: CompanySubmitData,
@@ -26,7 +49,6 @@ export const sendCompanyOfferEmail = async (
export const sendEmail = enhanceAction(
async ({ subject, html, to }) => {
const mailer = await getMailer();
await mailer.sendEmail({
to,
subject,

View File

@@ -1,42 +1,45 @@
'use server';
import { z } from 'zod';
import { loadCurrentUserAccount } from '@/app/home/(user)/_lib/server/load-user-account';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { MontonioOrderHandlerService } from '@/packages/billing/montonio/src';
import { addToCart, deleteLineItem, retrieveCart } from '@lib/data/cart';
import { getCartId } from '@lib/data/cookies';
import { StoreCartLineItem, StoreProductVariant } from '@medusajs/types';
import { MontonioOrderHandlerService } from '@/packages/billing/montonio/src';
import { z } from 'zod';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { requireUserInServerComponent } from '../server/require-user-in-server-component';
const env = () => z
.object({
medusaBackendPublicUrl: z
.string({
required_error: 'MEDUSA_BACKEND_PUBLIC_URL is required',
})
.min(1),
siteUrl: z
.string({
required_error: 'NEXT_PUBLIC_SITE_URL is required',
})
.min(1),
})
.parse({
medusaBackendPublicUrl: process.env.MEDUSA_BACKEND_PUBLIC_URL!,
siteUrl: process.env.NEXT_PUBLIC_SITE_URL!,
});
const env = () =>
z
.object({
medusaBackendPublicUrl: z
.string({
required_error: 'MEDUSA_BACKEND_PUBLIC_URL is required',
})
.min(1),
siteUrl: z
.string({
required_error: 'NEXT_PUBLIC_SITE_URL is required',
})
.min(1),
})
.parse({
medusaBackendPublicUrl: process.env.MEDUSA_BACKEND_PUBLIC_URL!,
siteUrl: process.env.NEXT_PUBLIC_SITE_URL!,
});
export async function handleAddToCart({
selectedVariant,
countryCode,
}: {
selectedVariant: Pick<StoreProductVariant, 'id'>
countryCode: string
selectedVariant: Pick<StoreProductVariant, 'id'>;
countryCode: string;
}) {
const supabase = getSupabaseServerClient();
const user = await requireUserInServerComponent();
const account = await loadCurrentUserAccount()
const account = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');
}
@@ -48,16 +51,13 @@ export async function handleAddToCart({
countryCode,
});
const { error } = await supabase
.schema('audit')
.from('cart_entries')
.insert({
variant_id: selectedVariant.id,
operation: 'ADD_TO_CART',
account_id: account.id,
cart_id: cart.id,
changed_by: user.id,
});
const { error } = await supabase.schema('audit').from('cart_entries').insert({
variant_id: selectedVariant.id,
operation: 'ADD_TO_CART',
account_id: account.id,
cart_id: cart.id,
changed_by: user.id,
});
if (error) {
throw new Error('Error logging cart entry: ' + error.message);
}
@@ -65,68 +65,65 @@ export async function handleAddToCart({
return cart;
}
export async function handleDeleteCartItem({
lineId,
}: {
lineId: string;
}) {
export async function handleDeleteCartItem({ lineId }: { lineId: string }) {
await deleteLineItem(lineId);
const supabase = getSupabaseServerClient();
const cartId = await getCartId();
const user = await requireUserInServerComponent();
const account = await loadCurrentUserAccount()
const account = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');
}
const { error } = await supabase
.schema('audit')
.from('cart_entries')
.insert({
variant_id: lineId,
operation: 'REMOVE_FROM_CART',
account_id: account.id,
cart_id: cartId!,
changed_by: user.id,
});
const { error } = await supabase.schema('audit').from('cart_entries').insert({
variant_id: lineId,
operation: 'REMOVE_FROM_CART',
account_id: account.id,
cart_id: cartId!,
changed_by: user.id,
});
if (error) {
throw new Error('Error logging cart entry: ' + error.message);
}
}
export async function handleNavigateToPayment({ language, paymentSessionId }: { language: string, paymentSessionId: string }) {
export async function handleNavigateToPayment({
language,
paymentSessionId,
}: {
language: string;
paymentSessionId: string;
}) {
const supabase = getSupabaseServerClient();
const user = await requireUserInServerComponent();
const account = await loadCurrentUserAccount()
const account = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');
}
const cart = await retrieveCart();
if (!cart) {
throw new Error("No cart found");
throw new Error('No cart found');
}
const paymentLink = await new MontonioOrderHandlerService().getMontonioPaymentLink({
notificationUrl: `${env().medusaBackendPublicUrl}/hooks/payment/montonio_montonio`,
returnUrl: `${env().siteUrl}/home/cart/montonio-callback`,
amount: cart.total,
currency: cart.currency_code.toUpperCase(),
description: `Order from Medreport`,
locale: language,
merchantReference: `${account.id}:${paymentSessionId}:${cart.id}`,
});
const { error } = await supabase
.schema('audit')
.from('cart_entries')
.insert({
operation: 'NAVIGATE_TO_PAYMENT',
account_id: account.id,
cart_id: cart.id,
changed_by: user.id,
const paymentLink =
await new MontonioOrderHandlerService().getMontonioPaymentLink({
notificationUrl: `${env().medusaBackendPublicUrl}/hooks/payment/montonio_montonio`,
returnUrl: `${env().siteUrl}/home/cart/montonio-callback`,
amount: cart.total,
currency: cart.currency_code.toUpperCase(),
description: `Order from Medreport`,
locale: language,
merchantReference: `${account.id}:${paymentSessionId}:${cart.id}`,
});
const { error } = await supabase.schema('audit').from('cart_entries').insert({
operation: 'NAVIGATE_TO_PAYMENT',
account_id: account.id,
cart_id: cart.id,
changed_by: user.id,
});
if (error) {
throw new Error('Error logging cart entry: ' + error.message);
}
@@ -137,26 +134,23 @@ export async function handleNavigateToPayment({ language, paymentSessionId }: {
export async function handleLineItemTimeout({
lineItem,
}: {
lineItem: StoreCartLineItem
lineItem: StoreCartLineItem;
}) {
const supabase = getSupabaseServerClient();
const user = await requireUserInServerComponent();
const account = await loadCurrentUserAccount()
const account = await loadCurrentUserAccount();
if (!account) {
throw new Error('Account not found');
}
await deleteLineItem(lineItem.id);
const { error } = await supabase
.schema('audit')
.from('cart_entries')
.insert({
operation: 'LINE_ITEM_TIMEOUT',
account_id: account.id,
cart_id: lineItem.cart_id,
changed_by: user.id,
});
const { error } = await supabase.schema('audit').from('cart_entries').insert({
operation: 'LINE_ITEM_TIMEOUT',
account_id: account.id,
cart_id: lineItem.cart_id,
changed_by: user.id,
});
if (error) {
throw new Error('Error logging cart entry: ' + error.message);
}