From b674640bd80dea78b074cbaa7094ad30b357a289 Mon Sep 17 00:00:00 2001 From: Danel Kungla Date: Fri, 26 Sep 2025 17:20:50 +0300 Subject: [PATCH] refactor time slots --- .../_components/booking/booking-container.tsx | 11 +- .../booking/booking-pagination.tsx | 113 ++++++++++++++ .../(user)/_components/booking/time-slots.tsx | 141 ++++-------------- lib/services/medusaCart.service.ts | 11 +- packages/ui/src/shadcn/skeleton.tsx | 16 +- 5 files changed, 173 insertions(+), 119 deletions(-) create mode 100644 app/home/(user)/_components/booking/booking-pagination.tsx diff --git a/app/home/(user)/_components/booking/booking-container.tsx b/app/home/(user)/_components/booking/booking-container.tsx index 9d3b6e8..67a9400 100644 --- a/app/home/(user)/_components/booking/booking-container.tsx +++ b/app/home/(user)/_components/booking/booking-container.tsx @@ -32,7 +32,16 @@ const BookingContainer = ({
- + { + if (product.metadata?.serviceIds) { + return Array.isArray( + JSON.parse(product.metadata.serviceIds as string), + ); + } + return false; + })} + />
diff --git a/app/home/(user)/_components/booking/booking-pagination.tsx b/app/home/(user)/_components/booking/booking-pagination.tsx new file mode 100644 index 0000000..f0c4631 --- /dev/null +++ b/app/home/(user)/_components/booking/booking-pagination.tsx @@ -0,0 +1,113 @@ +import React from 'react'; + +import { useTranslation } from 'react-i18next'; + +import { Trans } from '@kit/ui/makerkit/trans'; +import { cn } from '@kit/ui/shadcn'; +import { Button } from '@kit/ui/shadcn/button'; + +const BookingPagination = ({ + totalPages, + setCurrentPage, + currentPage, +}: { + totalPages: number; + setCurrentPage: (page: number) => void; + currentPage: number; +}) => { + const { t } = useTranslation(); + + const generatePageNumbers = () => { + const pages = []; + const maxVisiblePages = 5; + + if (totalPages <= maxVisiblePages) { + for (let i = 1; i <= totalPages; i++) { + pages.push(i); + } + } else { + if (currentPage <= 3) { + for (let i = 1; i <= 4; i++) { + pages.push(i); + } + pages.push('...'); + pages.push(totalPages); + } else if (currentPage >= totalPages - 2) { + pages.push(1); + pages.push('...'); + for (let i = totalPages - 3; i <= totalPages; i++) { + pages.push(i); + } + } else { + pages.push(1); + pages.push('...'); + for (let i = currentPage - 1; i <= currentPage + 1; i++) { + pages.push(i); + } + pages.push('...'); + pages.push(totalPages); + } + } + + return pages; + }; + + if (totalPages === 0) { + return ( +
+

{t('booking:noResults')}

+
+ ); + } + + return ( + totalPages > 1 && ( +
+
+ {t('common:pageOfPages', { + page: currentPage, + total: totalPages, + })} +
+ +
+ + + {generatePageNumbers().map((page, index) => ( + + ))} + + +
+
+ ) + ); +}; + +export default BookingPagination; diff --git a/app/home/(user)/_components/booking/time-slots.tsx b/app/home/(user)/_components/booking/time-slots.tsx index 220a79f..a88815c 100644 --- a/app/home/(user)/_components/booking/time-slots.tsx +++ b/app/home/(user)/_components/booking/time-slots.tsx @@ -11,6 +11,7 @@ import { pathsConfig } from '@kit/shared/config'; import { formatDateAndTime } from '@kit/shared/utils'; import { Button } from '@kit/ui/shadcn/button'; import { Card } from '@kit/ui/shadcn/card'; +import { Skeleton } from '@kit/ui/shadcn/skeleton'; import { toast } from '@kit/ui/sonner'; import { Trans } from '@kit/ui/trans'; import { cn } from '@kit/ui/utils'; @@ -19,6 +20,7 @@ import { updateReservationTime } from '~/lib/services/reservation.service'; import { createInitialReservationAction } from '../../_lib/server/actions'; import { EnrichedCartItem } from '../cart/types'; +import BookingPagination from './booking-pagination'; import { ServiceProvider, TimeSlot } from './booking.context'; import { useBooking } from './booking.provider'; @@ -68,57 +70,16 @@ const TimeSlots = ({ }) ?? [], 'StartTime', 'asc', - ), + ).filter(({ StartTime }) => isSameDay(StartTime, selectedDate)), [booking.timeSlots, selectedDate], ); - const totalPages = Math.ceil(filteredBookings.length / PAGE_SIZE); - const paginatedBookings = useMemo(() => { const startIndex = (currentPage - 1) * PAGE_SIZE; const endIndex = startIndex + PAGE_SIZE; return filteredBookings.slice(startIndex, endIndex); }, [filteredBookings, currentPage, PAGE_SIZE]); - const handlePageChange = (page: number) => { - setCurrentPage(page); - }; - - const generatePageNumbers = () => { - const pages = []; - const maxVisiblePages = 5; - - if (totalPages <= maxVisiblePages) { - for (let i = 1; i <= totalPages; i++) { - pages.push(i); - } - } else { - if (currentPage <= 3) { - for (let i = 1; i <= 4; i++) { - pages.push(i); - } - pages.push('...'); - pages.push(totalPages); - } else if (currentPage >= totalPages - 2) { - pages.push(1); - pages.push('...'); - for (let i = totalPages - 3; i <= totalPages; i++) { - pages.push(i); - } - } else { - pages.push(1); - pages.push('...'); - for (let i = currentPage - 1; i <= currentPage + 1; i++) { - pages.push(i); - } - pages.push('...'); - pages.push(totalPages); - } - } - - return pages; - }; - if (!booking?.timeSlots?.length) { return null; } @@ -143,12 +104,17 @@ const TimeSlots = ({ timeSlot.StartTime, booking.selectedLocationId ? booking.selectedLocationId : null, comments, - ).then(() => { - if (onComplete) { - onComplete(); - } - router.push(pathsConfig.app.cart); - }); + ) + .then(() => { + if (onComplete) { + onComplete(); + } + router.push(pathsConfig.app.cart); + }) + .catch((error) => { + console.error('Booking error: ', error); + throw error; + }); toast.promise(() => bookTimePromise, { success: , @@ -199,12 +165,15 @@ const TimeSlots = ({ return handleBookTime(timeSlot); }; - + console.log('paginatedBookings', booking.isLoadingTimeSlots); return ( -
+
{paginatedBookings.map((timeSlot, index) => { - const isEHIF = timeSlot.HKServiceID > 0; + const isHaigeKassa = timeSlot.HKServiceID > 0; const serviceProviderTitle = getServiceProviderTitle( currentLocale, timeSlot.serviceProvider, @@ -212,6 +181,7 @@ const TimeSlots = ({ const price = booking.selectedService?.variants?.[0]?.calculated_price ?.calculated_amount ?? cartItem?.unit_price; + return (
@@ -230,12 +200,14 @@ const TimeSlots = ({
{serviceProviderTitle && ( {serviceProviderTitle} )} - {isEHIF && {t('booking:ehifBooking')}} + {isHaigeKassa && {t('booking:ehifBooking')}}
{timeSlot.location?.address}
@@ -254,63 +226,14 @@ const TimeSlots = ({ ); })} - - {!paginatedBookings.length && ( -
-

{t('booking:noResults')}

-
- )}
- {totalPages > 1 && ( -
-
- {t('common:pageOfPages', { - page: currentPage, - total: totalPages, - })} -
- -
- - - {generatePageNumbers().map((page, index) => ( - - ))} - - -
-
- )} - + + ); }; diff --git a/lib/services/medusaCart.service.ts b/lib/services/medusaCart.service.ts index 87efe47..a94b5c8 100644 --- a/lib/services/medusaCart.service.ts +++ b/lib/services/medusaCart.service.ts @@ -31,8 +31,11 @@ const env = () => .min(1), }) .parse({ - medusaBackendPublicUrl: process.env.MEDUSA_BACKEND_PUBLIC_URL!, - siteUrl: process.env.NEXT_PUBLIC_SITE_URL!, + // Use for local testing + medusaBackendPublicUrl: 'http://webhook.site:3000', + siteUrl: 'http://webhook.site:3000', + // medusaBackendPublicUrl: process.env.MEDUSA_BACKEND_PUBLIC_URL!, + // siteUrl: process.env.NEXT_PUBLIC_SITE_URL!, }); export async function handleAddToCart({ @@ -42,6 +45,10 @@ export async function handleAddToCart({ selectedVariant: Pick; countryCode: string; }) { + try { + } catch (e) { + console.error('medusa card error: ', e); + } const { account } = await loadCurrentUserAccount(); if (!account) { throw new Error('Account not found'); diff --git a/packages/ui/src/shadcn/skeleton.tsx b/packages/ui/src/shadcn/skeleton.tsx index 5b0ac1e..2f3ba22 100644 --- a/packages/ui/src/shadcn/skeleton.tsx +++ b/packages/ui/src/shadcn/skeleton.tsx @@ -3,21 +3,23 @@ import { cn } from '../lib/utils'; function Skeleton({ className, children, + isLoading = true, ...props -}: React.HTMLAttributes) { +}: React.HTMLAttributes & { isLoading?: boolean }) { return (
-
+
{children ?? }
- -
+ {isLoading && ( +
+ )}
); }