import { useMemo, useState } from 'react'; import { useRouter } from 'next/navigation'; import { formatCurrency } from '@/packages/shared/src/utils'; import { addHours, isAfter, isSameDay } from 'date-fns'; import { orderBy } from 'lodash'; import { useTranslation } from 'react-i18next'; 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'; 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'; const getServiceProviderTitle = ( currentLocale: string, serviceProvider?: ServiceProvider, ) => { if (!serviceProvider) return null; if (currentLocale === 'en') return serviceProvider.jobTitleEn; if (currentLocale === 'ru') return serviceProvider.jobTitleRu; return serviceProvider.jobTitleEt; }; const PAGE_SIZE = 7; const TimeSlots = ({ countryCode, cartItem, onComplete, }: { countryCode: string; cartItem?: EnrichedCartItem; onComplete?: () => void; }) => { const [currentPage, setCurrentPage] = useState(1); const { t, i18n: { language: currentLocale }, } = useTranslation(); const booking = useBooking(); const router = useRouter(); const selectedDate = booking.selectedDate ?? new Date(); const filteredBookings = useMemo( () => orderBy( booking?.timeSlots?.filter(({ StartTime }) => { const firstAvailableTimeToSelect = isSameDay(selectedDate, new Date()) ? addHours(new Date(), 0.5) : selectedDate; return isAfter(StartTime, firstAvailableTimeToSelect); }) ?? [], 'StartTime', 'asc', ).filter(({ StartTime }) => isSameDay(StartTime, selectedDate)), [booking.timeSlots, selectedDate], ); const paginatedBookings = useMemo(() => { const startIndex = (currentPage - 1) * PAGE_SIZE; const endIndex = startIndex + PAGE_SIZE; return filteredBookings.slice(startIndex, endIndex); }, [filteredBookings, currentPage, PAGE_SIZE]); if (!booking?.timeSlots?.length) { return null; } const handleBookTime = async (timeSlot: TimeSlot, comments?: string) => { const selectedService = booking.selectedService; const selectedVariant = selectedService?.variants?.[0]; const syncedService = timeSlot.syncedService; if (!syncedService || !selectedVariant) { return toast.error(t('booking:serviceNotFound')); } const bookTimePromise = createInitialReservationAction( selectedVariant, countryCode, Number(syncedService.id), syncedService?.clinic_id, timeSlot.UserID, timeSlot.SyncUserID, timeSlot.StartTime, booking.selectedLocationId ? booking.selectedLocationId : null, comments, ) .then(() => { if (onComplete) { onComplete(); } router.push(pathsConfig.app.cart); }) .catch((error) => { console.error('Booking error: ', error); throw error; }); toast.promise(() => bookTimePromise, { success: , error: , loading: , }); }; const handleChangeTime = async ( timeSlot: TimeSlot, reservationId: number, cartId: string, ) => { const syncedService = timeSlot.syncedService; if (!syncedService) { return toast.error(t('booking:serviceNotFound')); } const bookTimePromise = updateReservationTime( reservationId, timeSlot.StartTime, Number(syncedService.id), timeSlot.UserID, timeSlot.SyncUserID, booking.selectedLocationId ? booking.selectedLocationId : null, cartId, ); toast.promise(() => bookTimePromise, { success: , error: , loading: , }); if (onComplete) { onComplete(); } }; const handleTimeSelect = async (timeSlot: TimeSlot) => { if (cartItem?.reservation.id) { return handleChangeTime( timeSlot, cartItem.reservation.id, cartItem.cart_id, ); } return handleBookTime(timeSlot); }; console.log('paginatedBookings', booking.isLoadingTimeSlots); return (
{paginatedBookings.map((timeSlot, index) => { const isHaigeKassa = timeSlot.HKServiceID > 0; const serviceProviderTitle = getServiceProviderTitle( currentLocale, timeSlot.serviceProvider, ); const price = booking.selectedService?.variants?.[0]?.calculated_price ?.calculated_amount ?? cartItem?.unit_price; return (
{formatDateAndTime(timeSlot.StartTime.toString())}
{timeSlot.serviceProvider?.name}
{serviceProviderTitle && ( {serviceProviderTitle} )} {isHaigeKassa && {t('booking:ehifBooking')}}
{timeSlot.location?.address}
{formatCurrency({ currencyCode: 'EUR', locale: 'et-EE', value: price ?? '', })}
); })}
); }; export default TimeSlots;