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,65 @@
'use server';
import { StoreProductVariant } from '@medusajs/types';
import {
bookAppointment,
createInitialReservation,
} from '~/lib/services/connected-online.service';
import { handleAddToCart } from '~/lib/services/medusaCart.service';
import { updateLineItem } from '../../../../../packages/features/medusa-storefront/src/lib/data';
export async function bookTimeAction(
serviceId: number,
clinicId: number,
appointmentUserId: number,
syncUserId: number,
startTime: Date,
comments?: string,
) {
return bookAppointment(
serviceId,
clinicId,
appointmentUserId,
syncUserId,
startTime,
comments,
);
}
export async function createInitialReservationAction(
selectedVariant: Pick<StoreProductVariant, 'id'>,
countryCode: string,
serviceId: number,
clinicId: number,
appointmentUserId: number,
syncUserId: number,
startTime: Date,
locationId: number | null,
comments?: string,
) {
const { addedItem } = await handleAddToCart({
selectedVariant,
countryCode,
});
if (addedItem) {
const reservation = await createInitialReservation(
serviceId,
clinicId,
appointmentUserId,
syncUserId,
startTime,
addedItem.id,
locationId,
comments,
);
await updateLineItem({
lineId: addedItem.id,
quantity: addedItem.quantity,
metadata: { connectedOnlineReservationId: reservation.id },
});
}
}

View File

@@ -45,10 +45,6 @@ async function analysesLoader() {
})
: null;
const serviceCategories = productCategories.filter(
({ parent_category }) => parent_category?.handle === 'tto-categories',
);
return {
analyses:
categoryProducts?.response.products

View File

@@ -1,20 +1,30 @@
import { cache } from 'react';
import { getProductCategories } from '@lib/data';
import { getProductCategories, listProducts } from '@lib/data';
import { ServiceCategory } from '../../_components/service-categories';
async function categoryLoader({
handle,
}: {
handle: string;
}): Promise<{ category: ServiceCategory | null }> {
const response = await getProductCategories({
handle,
fields: '*products, is_active, metadata',
});
import { loadCountryCodes } from './load-analyses';
async function categoryLoader({ handle }: { handle: string }) {
const [response, countryCodes] = await Promise.all([
getProductCategories({
handle,
limit: 1,
}),
loadCountryCodes(),
]);
const category = response.product_categories[0];
const countryCode = countryCodes[0]!;
if (!response.product_categories?.[0]?.id) {
return { category: null };
}
const {
response: { products: categoryProducts },
} = await listProducts({
countryCode,
queryParams: { limit: 100, category_id: response.product_categories[0].id },
});
return {
category: {
@@ -25,7 +35,8 @@ async function categoryLoader({
description: category?.description || '',
handle: category?.handle || '',
name: category?.name || '',
products: category?.products || [],
countryCode,
products: categoryProducts,
},
};
}

View File

@@ -10,38 +10,36 @@ async function ttoServicesLoader() {
});
const heroCategories = response.product_categories?.filter(
({ parent_category, is_active, metadata }) =>
parent_category?.handle === 'tto-categories' &&
is_active &&
metadata?.isHero,
({ parent_category, metadata }) =>
parent_category?.handle === 'tto-categories' && metadata?.isHero,
);
const ttoCategories = response.product_categories?.filter(
({ parent_category, is_active, metadata }) =>
parent_category?.handle === 'tto-categories' &&
is_active &&
!metadata?.isHero,
({ parent_category, metadata }) =>
parent_category?.handle === 'tto-categories' && !metadata?.isHero,
);
return {
heroCategories:
heroCategories.map<ServiceCategory>(
({ name, handle, metadata, description }) => ({
heroCategories.map<Omit<ServiceCategory, 'countryCode'>>(
({ name, handle, metadata, description, products }) => ({
name,
handle,
color:
typeof metadata?.color === 'string' ? metadata.color : 'primary',
description,
products: products ?? [],
}),
) ?? [],
ttoCategories:
ttoCategories.map<ServiceCategory>(
({ name, handle, metadata, description }) => ({
ttoCategories.map<Omit<ServiceCategory, 'countryCode'>>(
({ name, handle, metadata, description, products }) => ({
name,
handle,
color:
typeof metadata?.color === 'string' ? metadata.color : 'primary',
description,
products: products ?? [],
}),
) ?? [],
};