add calendar & time picker
This commit is contained in:
parent
b6d7fabba1
commit
4db10a7f63
78
apps/web/components/orders/components/datetime-select.tsx
Normal file
78
apps/web/components/orders/components/datetime-select.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './contacts-grid';
|
||||
export * from './datetime-select';
|
||||
export * from './service-select';
|
||||
export * from './submit-button';
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user