select time feature & get final order values
This commit is contained in:
parent
7fcf67eece
commit
3738c4e2a9
@ -6,6 +6,7 @@ import dayjs from 'dayjs';
|
|||||||
export function DateSelect() {
|
export function DateSelect() {
|
||||||
const selectedDate = useOrderStore((store) => store.date);
|
const selectedDate = useOrderStore((store) => store.date);
|
||||||
const setDate = useOrderStore((store) => store.setDate);
|
const setDate = useOrderStore((store) => store.setDate);
|
||||||
|
const setTime = useOrderStore((store) => store.setTime);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Calendar
|
<Calendar
|
||||||
@ -16,6 +17,7 @@ export function DateSelect() {
|
|||||||
mode="single"
|
mode="single"
|
||||||
onSelect={(date) => {
|
onSelect={(date) => {
|
||||||
if (date) setDate(date);
|
if (date) setDate(date);
|
||||||
|
setTime(null);
|
||||||
}}
|
}}
|
||||||
selected={selectedDate}
|
selected={selectedDate}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,31 +1,34 @@
|
|||||||
|
/* eslint-disable canonical/id-match */
|
||||||
'use client';
|
'use client';
|
||||||
|
import { useSlots } from '@/hooks/slots';
|
||||||
|
import { useOrderStore } from '@/stores/order';
|
||||||
|
import { Enum_Slot_State, type SlotFieldsFragment } from '@repo/graphql/types';
|
||||||
import { Button } from '@repo/ui/components/ui/button';
|
import { Button } from '@repo/ui/components/ui/button';
|
||||||
import dayjs, { type Dayjs } from 'dayjs';
|
import dayjs, { type Dayjs } from 'dayjs';
|
||||||
|
import { sift } from 'radash';
|
||||||
|
|
||||||
type TimeSlotsProps = {
|
const generateTimeSlots = (slots: SlotFieldsFragment[]): Dayjs[] => {
|
||||||
endTime?: string;
|
|
||||||
interval?: number;
|
|
||||||
startTime?: string;
|
|
||||||
};
|
|
||||||
const generateTimeSlots = (start: string, end: string, interval: number): Dayjs[] => {
|
|
||||||
const times: Dayjs[] = [];
|
const times: Dayjs[] = [];
|
||||||
let currentTime = dayjs(start, 'HH:mm');
|
for (const slot of slots) {
|
||||||
const endTime = dayjs(end, 'HH:mm');
|
let currentTime = dayjs(`${slot.date} ${slot.time_start}`);
|
||||||
|
const endTime = dayjs(`${slot.date} ${slot.time_end}`);
|
||||||
|
|
||||||
while (currentTime.isBefore(endTime) || currentTime.isSame(endTime)) {
|
while (currentTime.isBefore(endTime) || currentTime.isSame(endTime)) {
|
||||||
times.push(currentTime);
|
times.push(currentTime);
|
||||||
currentTime = currentTime.add(interval, 'minute');
|
currentTime = currentTime.add(30, 'minute');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return times;
|
return times;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TimeSelect({
|
export function TimeSelect() {
|
||||||
endTime = '2025-03-10T20:00:00',
|
const masterId = useOrderStore((store) => store.masterId);
|
||||||
interval = 30,
|
const date = useOrderStore((store) => store.date);
|
||||||
startTime = '2025-03-10T09:00:00',
|
const { data } = useSlots({ date, masterId });
|
||||||
}: Readonly<TimeSlotsProps>) {
|
|
||||||
const timeSlots = generateTimeSlots(startTime, endTime, interval);
|
const openedSlots = data?.data.slots.filter((slot) => slot?.state === Enum_Slot_State.Open);
|
||||||
|
const timeSlots = generateTimeSlots(openedSlots ? sift(openedSlots) : []);
|
||||||
|
|
||||||
const morning = timeSlots.filter((time) => time.hour() < 12);
|
const morning = timeSlots.filter((time) => time.hour() < 12);
|
||||||
const afternoon = timeSlots.filter((time) => time.hour() >= 12 && time.hour() < 18);
|
const afternoon = timeSlots.filter((time) => time.hour() >= 12 && time.hour() < 18);
|
||||||
@ -41,6 +44,8 @@ export function TimeSelect({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function TimeSlotsButtons({ times, title }: Readonly<{ times: Dayjs[]; title: string }>) {
|
function TimeSlotsButtons({ times, title }: Readonly<{ times: Dayjs[]; title: string }>) {
|
||||||
|
const setTime = useOrderStore((store) => store.setTime);
|
||||||
|
|
||||||
if (!times.length) return null;
|
if (!times.length) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -48,7 +53,12 @@ function TimeSlotsButtons({ times, title }: Readonly<{ times: Dayjs[]; title: st
|
|||||||
<h2 className="text-lg font-semibold">{title}</h2>
|
<h2 className="text-lg font-semibold">{title}</h2>
|
||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 gap-2">
|
||||||
{times.map((time) => (
|
{times.map((time) => (
|
||||||
<Button className="mb-2" key={time.toString()} variant="outline">
|
<Button
|
||||||
|
className="mb-2"
|
||||||
|
key={time.toString()}
|
||||||
|
onClick={() => setTime(time.format('HH:mm'))}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
{time.format('HH:mm')}
|
{time.format('HH:mm')}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export * from './back-button';
|
export * from './back-button';
|
||||||
export * from './contacts-grid';
|
export * from './contacts-grid';
|
||||||
export * from './datetime-select';
|
export * from './datetime-select';
|
||||||
|
export * from './next-button';
|
||||||
export * from './service-select';
|
export * from './service-select';
|
||||||
export * from './submit-button';
|
|
||||||
|
|||||||
@ -2,34 +2,38 @@
|
|||||||
import { useOrderStore } from '@/stores/order';
|
import { useOrderStore } from '@/stores/order';
|
||||||
import { Button } from '@repo/ui/components/ui/button';
|
import { Button } from '@repo/ui/components/ui/button';
|
||||||
|
|
||||||
export function SubmitButton() {
|
export function NextButton() {
|
||||||
const step = useOrderStore((store) => store.step);
|
const { clientId, date, masterId, nextStep, serviceId, step, time } = useOrderStore(
|
||||||
const nextStep = useOrderStore((store) => store.nextStep);
|
(store) => store,
|
||||||
|
);
|
||||||
function handleOnClick() {
|
|
||||||
if (step !== 'success') {
|
|
||||||
nextStep();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const disabled = useButtonDisabled();
|
const disabled = useButtonDisabled();
|
||||||
|
|
||||||
|
function handleOnClick() {
|
||||||
|
nextStep();
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log({ clientId, date, masterId, serviceId, step, time });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button className="w-full" disabled={disabled} onClick={() => handleOnClick()} type="button">
|
<Button className="w-full" disabled={disabled} onClick={() => handleOnClick()} type="button">
|
||||||
{step === 'success' ? 'Создать' : 'Продолжить'}
|
{step === 'datetime-select' ? 'Завершить' : 'Далее'}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useButtonDisabled() {
|
function useButtonDisabled() {
|
||||||
|
const step = useOrderStore((state) => state.step);
|
||||||
const clientId = useOrderStore((state) => state.clientId);
|
const clientId = useOrderStore((state) => state.clientId);
|
||||||
const masterId = useOrderStore((state) => state.masterId);
|
const masterId = useOrderStore((state) => state.masterId);
|
||||||
const serviceId = useOrderStore((state) => state.serviceId);
|
const serviceId = useOrderStore((state) => state.serviceId);
|
||||||
const step = useOrderStore((state) => state.step);
|
const date = useOrderStore((state) => state.date);
|
||||||
|
const time = useOrderStore((state) => state.time);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
(step === 'master-select' && !masterId) ||
|
(step === 'master-select' && !masterId) ||
|
||||||
(step === 'client-select' && !clientId) ||
|
(step === 'client-select' && !clientId) ||
|
||||||
(step === 'service-select' && !serviceId)
|
(step === 'service-select' && !serviceId) ||
|
||||||
|
(step === 'datetime-select' && (!date || !time))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -5,8 +5,8 @@ import {
|
|||||||
ClientsGrid,
|
ClientsGrid,
|
||||||
DateTimeSelect,
|
DateTimeSelect,
|
||||||
MastersGrid,
|
MastersGrid,
|
||||||
|
NextButton,
|
||||||
ServiceSelect,
|
ServiceSelect,
|
||||||
SubmitButton,
|
|
||||||
} from './components';
|
} from './components';
|
||||||
import { OrderStoreProvider, useOrderStore } from '@/stores/order';
|
import { OrderStoreProvider, useOrderStore } from '@/stores/order';
|
||||||
import { useInitOrderStore } from '@/stores/order/hooks';
|
import { useInitOrderStore } from '@/stores/order/hooks';
|
||||||
@ -30,7 +30,7 @@ export const OrderForm = withContext(OrderStoreProvider)(function () {
|
|||||||
<div className="space-y-4 [&>*]:px-4">
|
<div className="space-y-4 [&>*]:px-4">
|
||||||
{getStepComponent(step)}
|
{getStepComponent(step)}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<SubmitButton />
|
<NextButton />
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -18,7 +18,7 @@ type SlotMutationInput = {
|
|||||||
|
|
||||||
type SlotQueryInput = {
|
type SlotQueryInput = {
|
||||||
date: Date;
|
date: Date;
|
||||||
masterId?: string;
|
masterId?: null | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSlots = ({ date, masterId }: SlotQueryInput) => {
|
export const useSlots = ({ date, masterId }: SlotQueryInput) => {
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export type OrderStore = {
|
|||||||
export type Steps =
|
export type Steps =
|
||||||
| 'client-select'
|
| 'client-select'
|
||||||
| 'datetime-select'
|
| 'datetime-select'
|
||||||
|
| 'error'
|
||||||
| 'loading'
|
| 'loading'
|
||||||
| 'master-select'
|
| 'master-select'
|
||||||
| 'service-select'
|
| 'service-select'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user