MED-103: add booking functionality

This commit is contained in:
Helena
2025-09-17 18:11:13 +03:00
parent 7c92b787ce
commit 22f7fa134b
44 changed files with 1923 additions and 479 deletions

View File

@@ -0,0 +1,61 @@
import {
Body,
Head,
Html,
Preview,
Tailwind,
Text,
render,
} from '@react-email/components';
import { BodyStyle } from '../components/body-style';
import { EmailContent } from '../components/content';
import { EmailHeader } from '../components/header';
import { EmailHeading } from '../components/heading';
import { EmailWrapper } from '../components/wrapper';
export async function renderBookTimeFailedEmail({
reservationId,
error,
}: {
reservationId: number;
error: string;
}) {
const subject = 'Aja broneerimine ei õnnestunud';
const html = await render(
<Html>
<Head>
<BodyStyle />
</Head>
<Preview>{subject}</Preview>
<Tailwind>
<Body>
<EmailWrapper>
<EmailContent>
<EmailHeader>
<EmailHeading>{subject}</EmailHeading>
</EmailHeader>
<Text className="text-[16px] leading-[24px] text-[#242424]">
Tere
</Text>
<Text>
Broneeringu {reservationId} Connected Online'i saatmine ei
õnnestunud, kliendile tuleb teha tagasimakse.
</Text>
<Text>Saadud error: {error}</Text>
</EmailContent>
</EmailWrapper>
</Body>
</Tailwind>
</Html>,
);
return {
html,
subject,
};
}

View File

@@ -10,3 +10,4 @@ export * from './emails/all-results-received.email';
export * from './emails/order-processing.email';
export * from './emails/patient-first-results-received.email';
export * from './emails/patient-full-results-received.email';
export * from './emails/book-time-failed.email'

View File

@@ -15,6 +15,7 @@ import {
import { getRegion } from "./regions";
import { sdk } from "@lib/config";
import { retrieveOrder } from "./orders";
import { completeTtoCart } from "../../../../../../lib/services/connected-online.service";
/**
* Retrieves a cart by its ID. If no ID is provided, it will use the cart ID from the cookies.
@@ -89,7 +90,10 @@ export async function getOrSetCart(countryCode: string) {
export async function updateCart(
{ id, ...data }: HttpTypes.StoreUpdateCart & { id?: string },
{ onSuccess, onError }: { onSuccess: () => void, onError: () => void } = { onSuccess: () => {}, onError: () => {} },
{ onSuccess, onError }: { onSuccess: () => void; onError: () => void } = {
onSuccess: () => {},
onError: () => {},
}
) {
const cartId = id || (await getCartId());
@@ -163,7 +167,12 @@ export async function addToCart({
})
.catch(medusaError);
return cart;
const newCart = await getOrSetCart(countryCode);
const addedItem = newCart.items?.filter(
(item) => !cart.items?.some((oldCartItem) => oldCartItem.id === item.id)
)?.[0];
return { newCart, addedItem };
}
export async function updateLineItem({
@@ -268,7 +277,10 @@ export async function initiatePaymentSession(
export async function applyPromotions(
codes: string[],
{ onSuccess, onError }: { onSuccess: () => void, onError: () => void } = { onSuccess: () => {}, onError: () => {} },
{ onSuccess, onError }: { onSuccess: () => void; onError: () => void } = {
onSuccess: () => {},
onError: () => {},
}
) {
const cartId = await getCartId();
@@ -410,7 +422,10 @@ export async function setAddresses(currentState: unknown, formData: FormData) {
* @param cartId - optional - The ID of the cart to place an order for.
* @returns The cart object if the order was successful, or null if not.
*/
export async function placeOrder(cartId?: string, options: { revalidateCacheTags: boolean } = { revalidateCacheTags: true }) {
export async function placeOrder(
cartId?: string,
options: { revalidateCacheTags: boolean } = { revalidateCacheTags: true }
) {
const id = cartId || (await getCartId());
if (!id) {

View File

@@ -20,7 +20,6 @@ export const listCategories = async (query?: Record<string, any>) => {
...query,
},
next,
cache: "force-cache",
}
)
.then(({ product_categories }) => product_categories);
@@ -56,7 +55,6 @@ export const getProductCategories = async ({
limit,
},
next,
//cache: "force-cache",
}
);
};

View File

@@ -4,8 +4,8 @@ import { cookies } from 'next/headers';
import { createServerClient } from '@supabase/ssr';
import { Database } from '../database.types';
import { getSupabaseClientKeys } from '../get-supabase-client-keys';
import { Database } from '../database.types';
/**
* @name getSupabaseServerClient

View File

@@ -198,6 +198,7 @@ export type Database = {
action: string
changed_by: string
created_at: string
extra_data: Json | null
id: number
}
Insert: {
@@ -205,6 +206,7 @@ export type Database = {
action: string
changed_by: string
created_at?: string
extra_data?: Json | null
id?: number
}
Update: {
@@ -212,6 +214,7 @@ export type Database = {
action?: string
changed_by?: string
created_at?: string
extra_data?: Json | null
id?: number
}
Relationships: []
@@ -221,7 +224,6 @@ export type Database = {
comment: string | null
created_at: string
id: number
personal_code: number | null
request_api: string
request_api_method: string
requested_end_date: string | null
@@ -229,12 +231,12 @@ export type Database = {
service_id: number | null
service_provider_id: number | null
status: Database["audit"]["Enums"]["request_status"]
user_id: string | null
}
Insert: {
comment?: string | null
created_at?: string
id?: number
personal_code?: number | null
request_api: string
request_api_method: string
requested_end_date?: string | null
@@ -242,12 +244,12 @@ export type Database = {
service_id?: number | null
service_provider_id?: number | null
status: Database["audit"]["Enums"]["request_status"]
user_id?: string | null
}
Update: {
comment?: string | null
created_at?: string
id?: number
personal_code?: number | null
request_api?: string
request_api_method?: string
requested_end_date?: string | null
@@ -255,6 +257,7 @@ export type Database = {
service_id?: number | null
service_provider_id?: number | null
status?: Database["audit"]["Enums"]["request_status"]
user_id?: string | null
}
Relationships: []
}
@@ -990,32 +993,76 @@ export type Database = {
}
Relationships: []
}
connected_online_locations: {
Row: {
address: string | null
clinic_id: number
created_at: string
id: number
name: string
sync_id: number
updated_at: string | null
}
Insert: {
address?: string | null
clinic_id: number
created_at?: string
id?: number
name: string
sync_id: number
updated_at?: string | null
}
Update: {
address?: string | null
clinic_id?: number
created_at?: string
id?: number
name?: string
sync_id?: number
updated_at?: string | null
}
Relationships: [
{
foreignKeyName: "connected_online_locations_clinic_id_fkey"
columns: ["clinic_id"]
isOneToOne: false
referencedRelation: "connected_online_providers"
referencedColumns: ["id"]
},
]
}
connected_online_providers: {
Row: {
address: string
can_select_worker: boolean
created_at: string
email: string | null
id: number
key: string
name: string
personal_code_required: boolean
phone_number: string | null
updated_at: string | null
}
Insert: {
address?: string
can_select_worker: boolean
created_at?: string
email?: string | null
id: number
key: string
name: string
personal_code_required: boolean
phone_number?: string | null
updated_at?: string | null
}
Update: {
address?: string
can_select_worker?: boolean
created_at?: string
email?: string | null
id?: number
key?: string
name?: string
personal_code_required?: boolean
phone_number?: string | null
@@ -1025,55 +1072,117 @@ export type Database = {
}
connected_online_reservation: {
Row: {
booking_code: string
booking_code: string | null
clinic_id: number
comments: string | null
created_at: string
discount_code: string | null
id: number
lang: string
requires_payment: boolean
location_sync_id: number | null
medusa_cart_line_item_id: string | null
requires_payment: boolean | null
service_id: number
service_user_id: number | null
service_user_id: number
start_time: string
status: Database["medreport"]["Enums"]["connected_online_order_status"]
sync_user_id: number
updated_at: string | null
user_id: string
}
Insert: {
booking_code: string
booking_code?: string | null
clinic_id: number
comments?: string | null
created_at?: string
discount_code?: string | null
id?: number
lang: string
requires_payment: boolean
location_sync_id?: number | null
medusa_cart_line_item_id?: string | null
requires_payment?: boolean | null
service_id: number
service_user_id?: number | null
service_user_id: number
start_time: string
status: Database["medreport"]["Enums"]["connected_online_order_status"]
sync_user_id: number
updated_at?: string | null
user_id: string
}
Update: {
booking_code?: string
booking_code?: string | null
clinic_id?: number
comments?: string | null
created_at?: string
discount_code?: string | null
id?: number
lang?: string
requires_payment?: boolean
location_sync_id?: number | null
medusa_cart_line_item_id?: string | null
requires_payment?: boolean | null
service_id?: number
service_user_id?: number | null
service_user_id?: number
start_time?: string
status?: Database["medreport"]["Enums"]["connected_online_order_status"]
sync_user_id?: number
updated_at?: string | null
user_id?: string
}
Relationships: []
}
connected_online_service_providers: {
Row: {
clinic_id: number
created_at: string
id: number
is_deleted: boolean | null
job_title_en: string | null
job_title_et: string | null
job_title_id: number | null
job_title_ru: string | null
name: string
prefix: string | null
spoken_languages: string[] | null
updated_at: string | null
}
Insert: {
clinic_id: number
created_at?: string
id: number
is_deleted?: boolean | null
job_title_en?: string | null
job_title_et?: string | null
job_title_id?: number | null
job_title_ru?: string | null
name: string
prefix?: string | null
spoken_languages?: string[] | null
updated_at?: string | null
}
Update: {
clinic_id?: number
created_at?: string
id?: number
is_deleted?: boolean | null
job_title_en?: string | null
job_title_et?: string | null
job_title_id?: number | null
job_title_ru?: string | null
name?: string
prefix?: string | null
spoken_languages?: string[] | null
updated_at?: string | null
}
Relationships: [
{
foreignKeyName: "connected_online_service_providers_clinic_id_fkey"
columns: ["clinic_id"]
isOneToOne: false
referencedRelation: "connected_online_providers"
referencedColumns: ["id"]
},
]
}
connected_online_services: {
Row: {
clinic_id: number
@@ -1091,7 +1200,7 @@ export type Database = {
price: number
price_periods: string | null
requires_payment: boolean
sync_id: string
sync_id: number
updated_at: string | null
}
Insert: {
@@ -1110,7 +1219,7 @@ export type Database = {
price: number
price_periods?: string | null
requires_payment: boolean
sync_id: string
sync_id: number
updated_at?: string | null
}
Update: {
@@ -1129,7 +1238,7 @@ export type Database = {
price?: number
price_periods?: string | null
requires_payment?: boolean
sync_id?: string
sync_id?: number
updated_at?: string | null
}
Relationships: [
@@ -1150,7 +1259,7 @@ export type Database = {
doctor_user_id: string | null
id: number
status: Database["medreport"]["Enums"]["analysis_feedback_status"]
updated_at: string
updated_at: string | null
updated_by: string | null
user_id: string
value: string | null
@@ -1162,7 +1271,7 @@ export type Database = {
doctor_user_id?: string | null
id?: number
status?: Database["medreport"]["Enums"]["analysis_feedback_status"]
updated_at?: string
updated_at?: string | null
updated_by?: string | null
user_id: string
value?: string | null
@@ -1174,7 +1283,7 @@ export type Database = {
doctor_user_id?: string | null
id?: number
status?: Database["medreport"]["Enums"]["analysis_feedback_status"]
updated_at?: string
updated_at?: string | null
updated_by?: string | null
user_id?: string
value?: string | null
@@ -1259,23 +1368,36 @@ export type Database = {
}
medipost_actions: {
Row: {
created_at: string
id: number
action: string
xml: string
created_at: string | null
has_analysis_results: boolean
medusa_order_id: string
response_xml: string
has_error: boolean
id: string
medusa_order_id: string | null
response_xml: string | null
xml: string | null
}
Insert: {
action: string
xml: string
has_analysis_results: boolean
medusa_order_id: string
response_xml: string
has_error: boolean
created_at?: string | null
has_analysis_results?: boolean
has_error?: boolean
id?: string
medusa_order_id?: string | null
response_xml?: string | null
xml?: string | null
}
Update: {
action?: string
created_at?: string | null
has_analysis_results?: boolean
has_error?: boolean
id?: string
medusa_order_id?: string | null
response_xml?: string | null
xml?: string | null
}
Relationships: []
}
medreport_product_groups: {
Row: {
@@ -1944,6 +2066,13 @@ export type Database = {
personal_code: string
}[]
}
get_latest_medipost_dispatch_state_for_order: {
Args: { medusa_order_id: string }
Returns: {
action_date: string
has_success: boolean
}[]
}
get_medipost_dispatch_tries: {
Args: { p_medusa_order_id: string }
Returns: number
@@ -2036,9 +2165,9 @@ export type Database = {
Args: { account_id: string; user_id: string }
Returns: boolean
}
medipost_retry_dispatch: {
Args: { order_id: string }
Returns: Json
order_has_medipost_dispatch_error: {
Args: { medusa_order_id: string }
Returns: boolean
}
revoke_nonce: {
Args: { p_id: string; p_reason?: string }
@@ -2065,16 +2194,26 @@ export type Database = {
Returns: undefined
}
update_account: {
Args: {
p_city: string
p_has_consent_personal_data: boolean
p_last_name: string
p_name: string
p_personal_code: string
p_phone: string
p_uid: string
p_email: string
}
Args:
| {
p_city: string
p_email: string
p_has_consent_personal_data: boolean
p_last_name: string
p_name: string
p_personal_code: string
p_phone: string
p_uid: string
}
| {
p_city: string
p_has_consent_personal_data: boolean
p_last_name: string
p_name: string
p_personal_code: string
p_phone: string
p_uid: string
}
Returns: undefined
}
update_analysis_order_status: {
@@ -2182,6 +2321,11 @@ export type Database = {
| "invites.manage"
application_role: "user" | "doctor" | "super_admin"
billing_provider: "stripe" | "lemon-squeezy" | "paddle" | "montonio"
connected_online_order_status:
| "PENDING"
| "CONFIRMED"
| "REJECTED"
| "CANCELLED"
locale: "en" | "et" | "ru"
notification_channel: "in_app" | "email"
notification_type: "info" | "warning" | "error"
@@ -8099,6 +8243,12 @@ export const Constants = {
],
application_role: ["user", "doctor", "super_admin"],
billing_provider: ["stripe", "lemon-squeezy", "paddle", "montonio"],
connected_online_order_status: [
"PENDING",
"CONFIRMED",
"REJECTED",
"CANCELLED",
],
locale: ["en", "et", "ru"],
notification_channel: ["in_app", "email"],
notification_type: ["info", "warning", "error"],

View File

@@ -38,7 +38,7 @@ function Calendar({
head_cell:
'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
row: 'flex w-full mt-2',
cell: 'text-center text-sm p-0 relative [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
cell: 'text-center text-sm p-0 relative [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-md focus-within:relative focus-within:z-20',
day: cn(
buttonVariants({ variant: 'ghost' }),
'h-9 w-9 p-0 font-normal aria-selected:opacity-100',