From 4db10a7f634675d1d3b75c844effc4c6382113c2 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Mon, 10 Mar 2025 18:58:04 +0300 Subject: [PATCH] add calendar & time picker --- .../orders/components/datetime-select.tsx | 78 +++++++++++++++++++ .../web/components/orders/components/index.ts | 1 + apps/web/components/orders/order-form.tsx | 3 +- apps/web/context/order.tsx | 16 +--- 4 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 apps/web/components/orders/components/datetime-select.tsx diff --git a/apps/web/components/orders/components/datetime-select.tsx b/apps/web/components/orders/components/datetime-select.tsx new file mode 100644 index 0000000..8a40a2e --- /dev/null +++ b/apps/web/components/orders/components/datetime-select.tsx @@ -0,0 +1,78 @@ +'use client'; +import { OrderContext } from '@/context/order'; +import { Button } from '@repo/ui/components/ui/button'; +import { Calendar } from '@repo/ui/components/ui/calendar'; +import dayjs, { type Dayjs } from 'dayjs'; +import { use } from 'react'; + +type TimeSlotsProps = { + endTime: string; + interval?: number; + startTime: string; +}; +export function DateTimeSelect() { + const { step } = use(OrderContext); + + if (step !== 'datetime-select') return null; + + return ( +
+ { + return dayjs().isAfter(dayjs(date), 'day'); + }} + mode="single" + // onSelect={(date) => { + // if (date) setSelectedDate(date); + // }} + // selected={selectedDate} + /> + +
+ ); +} + +const generateTimeSlots = (start: string, end: string, interval: number): Dayjs[] => { + const times: Dayjs[] = []; + let currentTime = dayjs(start, 'HH:mm'); + const endTime = dayjs(end, 'HH:mm'); + + while (currentTime.isBefore(endTime) || currentTime.isSame(endTime)) { + times.push(currentTime); + currentTime = currentTime.add(interval, 'minute'); + } + + return times; +}; + +function TimeSlots({ endTime, interval = 30, startTime }: Readonly) { + const timeSlots = generateTimeSlots(startTime, endTime, interval); + + const morning = timeSlots.filter((time) => time.hour() < 12); + const afternoon = timeSlots.filter((time) => time.hour() >= 12 && time.hour() < 18); + const evening = timeSlots.filter((time) => time.hour() >= 18); + + return ( +
+ + + +
+ ); +} + +function TimeSlotsButtons({ times, title }: Readonly<{ times: Dayjs[]; title: string }>) { + return ( +
+

{title}

+
+ {times.map((time) => ( + + ))} +
+
+ ); +} diff --git a/apps/web/components/orders/components/index.ts b/apps/web/components/orders/components/index.ts index c2329ff..e362dd9 100644 --- a/apps/web/components/orders/components/index.ts +++ b/apps/web/components/orders/components/index.ts @@ -1,3 +1,4 @@ export * from './contacts-grid'; +export * from './datetime-select'; export * from './service-select'; export * from './submit-button'; diff --git a/apps/web/components/orders/order-form.tsx b/apps/web/components/orders/order-form.tsx index 5a5b53b..c53b282 100644 --- a/apps/web/components/orders/order-form.tsx +++ b/apps/web/components/orders/order-form.tsx @@ -1,4 +1,4 @@ -import { ContactsGrid, ServiceSelect, SubmitButton } from './components'; +import { ContactsGrid, DateTimeSelect, ServiceSelect, SubmitButton } from './components'; import { OrderContextProvider } from '@/context/order'; export function OrderForm() { @@ -7,6 +7,7 @@ export function OrderForm() { + diff --git a/apps/web/context/order.tsx b/apps/web/context/order.tsx index 1f46177..b37eb6d 100644 --- a/apps/web/context/order.tsx +++ b/apps/web/context/order.tsx @@ -6,17 +6,15 @@ type Action = { payload: Steps; type: 'SET_STEP' } | { type: 'NEXT_STEP' }; type ContextType = { customerId: null | string; nextStep: () => void; - orderId: null | string; setCustomerId: (customerId: string) => void; - setOrderId: (orderId: string) => void; setStep: (step: Steps) => void; step: Steps; }; type State = { step: Steps }; -type Steps = 'customer-select' | 'service-select' | 'success' | 'time-select'; +type Steps = 'customer-select' | 'datetime-select' | 'service-select' | 'success'; -const stepsSequence: Steps[] = ['customer-select', 'service-select', 'time-select', 'success']; +const stepsSequence: Steps[] = ['customer-select', 'service-select', 'datetime-select', 'success']; function stepsReducer(state: State, action: Action): State { switch (action.type) { @@ -42,11 +40,6 @@ function useCustomerState() { return { customerId, setCustomerId }; } -function useOrderState() { - const [orderId, setOrderId] = useState(null); - return { orderId, setOrderId }; -} - function useStep() { const [state, dispatch] = useReducer(stepsReducer, { step: 'customer-select' }); @@ -60,20 +53,17 @@ export const OrderContext = createContext({} as ContextType); export function OrderContextProvider({ children }: Readonly) { const { customerId, setCustomerId } = useCustomerState(); - const { orderId, setOrderId } = useOrderState(); const { nextStep, setStep, step } = useStep(); const value = useMemo( () => ({ customerId, nextStep, - orderId, setCustomerId, - setOrderId, setStep, step, }), - [customerId, nextStep, orderId, setCustomerId, setOrderId, setStep, step], + [customerId, nextStep, setCustomerId, setStep, step], ); return {children};