add calendar & time picker

This commit is contained in:
vchikalkin 2025-03-10 18:58:04 +03:00
parent b6d7fabba1
commit 4db10a7f63
4 changed files with 84 additions and 14 deletions

View File

@ -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 (
<div className="space-y-4">
<Calendar
className="bg-background"
disabled={(date) => {
return dayjs().isAfter(dayjs(date), 'day');
}}
mode="single"
// onSelect={(date) => {
// if (date) setSelectedDate(date);
// }}
// selected={selectedDate}
/>
<TimeSlots endTime="2025-03-10T20:00:00" interval={30} startTime="2025-03-10T09:00:00" />
</div>
);
}
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<TimeSlotsProps>) {
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 (
<div className="space-y-2">
<TimeSlotsButtons times={morning} title="Утро" />
<TimeSlotsButtons times={afternoon} title="День" />
<TimeSlotsButtons times={evening} title="Вечер" />
</div>
);
}
function TimeSlotsButtons({ times, title }: Readonly<{ times: Dayjs[]; title: string }>) {
return (
<div className="space-y-2">
<h2 className="text-lg font-semibold">{title}</h2>
<div className="grid grid-cols-3 gap-2">
{times.map((time) => (
<Button className="mb-2" key={time.toString()} variant="outline">
{time.format('HH:mm')}
</Button>
))}
</div>
</div>
);
}

View File

@ -1,3 +1,4 @@
export * from './contacts-grid';
export * from './datetime-select';
export * from './service-select';
export * from './submit-button';

View File

@ -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() {
<OrderContextProvider>
<ContactsGrid />
<ServiceSelect />
<DateTimeSelect />
<SubmitButton />
</OrderContextProvider>
</div>

View File

@ -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 | string>(null);
return { orderId, setOrderId };
}
function useStep() {
const [state, dispatch] = useReducer(stepsReducer, { step: 'customer-select' });
@ -60,20 +53,17 @@ export const OrderContext = createContext<ContextType>({} as ContextType);
export function OrderContextProvider({ children }: Readonly<PropsWithChildren>) {
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 <OrderContext.Provider value={value}>{children}</OrderContext.Provider>;