From 307997d67f0531b69157bfae43bb5b9006cf44c0 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Wed, 16 Jul 2025 13:27:41 +0300 Subject: [PATCH] feat(order-form): implement date selection with event highlighting and monthly view for available time slots --- .../orders/order-form/datetime-select.tsx | 37 +++++++++++++++++++ packages/graphql/api/slots.ts | 8 ++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/apps/web/components/orders/order-form/datetime-select.tsx b/apps/web/components/orders/order-form/datetime-select.tsx index 7411206..5d179ad 100644 --- a/apps/web/components/orders/order-form/datetime-select.tsx +++ b/apps/web/components/orders/order-form/datetime-select.tsx @@ -6,12 +6,40 @@ import { Button } from '@repo/ui/components/ui/button'; import { Calendar } from '@repo/ui/components/ui/calendar'; import { formatDate } from '@repo/utils/datetime-format'; import dayjs from 'dayjs'; +import { useState } from 'react'; export function DateSelect() { const selectedDate = useOrderStore((store) => store.date); const setDate = useOrderStore((store) => store.setDate); const setTime = useOrderStore((store) => store.setTime); const setSlot = useOrderStore((store) => store.setSlotId); + const masterId = useOrderStore((store) => store.masterId); + const serviceId = useOrderStore((store) => store.serviceId); + + const [currentMonthDate, setCurrentMonthDate] = useState(new Date()); + + const { data: { slots } = {} } = useAvailableTimeSlotsQuery( + { + filters: { + date: { + gte: dayjs(currentMonthDate).startOf('month').format('YYYY-MM-DD'), + lte: dayjs(currentMonthDate).endOf('month').format('YYYY-MM-DD'), + }, + master: { + documentId: { + eq: masterId, + }, + }, + }, + }, + { + service: { + documentId: { + eq: serviceId, + }, + }, + }, + ); return ( { + return slots?.some((slot) => dayjs(slot?.date).isSame(date, 'day')) || false; + }, + }} + modifiersClassNames={{ + hasEvent: 'border-primary border-2 rounded-xl', + }} + onMonthChange={(date) => setCurrentMonthDate(date)} onSelect={(date) => { if (date) setDate(date); setTime(null); diff --git a/packages/graphql/api/slots.ts b/packages/graphql/api/slots.ts index c1a50d5..b5ed134 100644 --- a/packages/graphql/api/slots.ts +++ b/packages/graphql/api/slots.ts @@ -50,6 +50,8 @@ export class SlotsService extends BaseService { variables: VariablesOf, context: { service: GQL.ServiceFiltersInput }, ) { + if (!variables.filters?.date) throw new Error('Missing date'); + const { query } = await getClientWithToken(); const getSlotsResult = await query({ @@ -76,10 +78,10 @@ export class SlotsService extends BaseService { const serviceDuration = getMinutes(service.duration); - const openedSlots = getSlotsResult.data.slots; + const slots = getSlotsResult.data.slots; const times: Array<{ slotId: string; time: string }> = []; - for (const slot of openedSlots) { + for (const slot of slots) { if (!slot?.time_start || !slot?.time_end) continue; let startTime = dayjs(`${slot.date} ${slot.time_start}`); @@ -107,7 +109,7 @@ export class SlotsService extends BaseService { } } - return { times }; + return { slots, times }; } async getSlot(variables: VariablesOf) {