select time feature & get final order values

This commit is contained in:
vchikalkin 2025-05-07 17:33:35 +03:00
parent 7fcf67eece
commit 3738c4e2a9
7 changed files with 51 additions and 34 deletions

View File

@ -6,6 +6,7 @@ import dayjs from 'dayjs';
export function DateSelect() {
const selectedDate = useOrderStore((store) => store.date);
const setDate = useOrderStore((store) => store.setDate);
const setTime = useOrderStore((store) => store.setTime);
return (
<Calendar
@ -16,6 +17,7 @@ export function DateSelect() {
mode="single"
onSelect={(date) => {
if (date) setDate(date);
setTime(null);
}}
selected={selectedDate}
/>

View File

@ -1,31 +1,34 @@
/* eslint-disable canonical/id-match */
'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 dayjs, { type Dayjs } from 'dayjs';
import { sift } from 'radash';
type TimeSlotsProps = {
endTime?: string;
interval?: number;
startTime?: string;
};
const generateTimeSlots = (start: string, end: string, interval: number): Dayjs[] => {
const generateTimeSlots = (slots: SlotFieldsFragment[]): Dayjs[] => {
const times: Dayjs[] = [];
let currentTime = dayjs(start, 'HH:mm');
const endTime = dayjs(end, 'HH:mm');
for (const slot of slots) {
let currentTime = dayjs(`${slot.date} ${slot.time_start}`);
const endTime = dayjs(`${slot.date} ${slot.time_end}`);
while (currentTime.isBefore(endTime) || currentTime.isSame(endTime)) {
times.push(currentTime);
currentTime = currentTime.add(interval, 'minute');
while (currentTime.isBefore(endTime) || currentTime.isSame(endTime)) {
times.push(currentTime);
currentTime = currentTime.add(30, 'minute');
}
}
return times;
};
export function TimeSelect({
endTime = '2025-03-10T20:00:00',
interval = 30,
startTime = '2025-03-10T09:00:00',
}: Readonly<TimeSlotsProps>) {
const timeSlots = generateTimeSlots(startTime, endTime, interval);
export function TimeSelect() {
const masterId = useOrderStore((store) => store.masterId);
const date = useOrderStore((store) => store.date);
const { data } = useSlots({ date, masterId });
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 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 }>) {
const setTime = useOrderStore((store) => store.setTime);
if (!times.length) return null;
return (
@ -48,7 +53,12 @@ function TimeSlotsButtons({ times, title }: Readonly<{ times: Dayjs[]; title: st
<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">
<Button
className="mb-2"
key={time.toString()}
onClick={() => setTime(time.format('HH:mm'))}
variant="outline"
>
{time.format('HH:mm')}
</Button>
))}

View File

@ -1,5 +1,5 @@
export * from './back-button';
export * from './contacts-grid';
export * from './datetime-select';
export * from './next-button';
export * from './service-select';
export * from './submit-button';

View File

@ -2,34 +2,38 @@
import { useOrderStore } from '@/stores/order';
import { Button } from '@repo/ui/components/ui/button';
export function SubmitButton() {
const step = useOrderStore((store) => store.step);
const nextStep = useOrderStore((store) => store.nextStep);
function handleOnClick() {
if (step !== 'success') {
nextStep();
}
}
export function NextButton() {
const { clientId, date, masterId, nextStep, serviceId, step, time } = useOrderStore(
(store) => store,
);
const disabled = useButtonDisabled();
function handleOnClick() {
nextStep();
// eslint-disable-next-line no-console
console.log({ clientId, date, masterId, serviceId, step, time });
}
return (
<Button className="w-full" disabled={disabled} onClick={() => handleOnClick()} type="button">
{step === 'success' ? 'Создать' : 'Продолжить'}
{step === 'datetime-select' ? 'Завершить' : 'Далее'}
</Button>
);
}
function useButtonDisabled() {
const step = useOrderStore((state) => state.step);
const clientId = useOrderStore((state) => state.clientId);
const masterId = useOrderStore((state) => state.masterId);
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 (
(step === 'master-select' && !masterId) ||
(step === 'client-select' && !clientId) ||
(step === 'service-select' && !serviceId)
(step === 'service-select' && !serviceId) ||
(step === 'datetime-select' && (!date || !time))
);
}

View File

@ -5,8 +5,8 @@ import {
ClientsGrid,
DateTimeSelect,
MastersGrid,
NextButton,
ServiceSelect,
SubmitButton,
} from './components';
import { OrderStoreProvider, useOrderStore } from '@/stores/order';
import { useInitOrderStore } from '@/stores/order/hooks';
@ -30,7 +30,7 @@ export const OrderForm = withContext(OrderStoreProvider)(function () {
<div className="space-y-4 [&>*]:px-4">
{getStepComponent(step)}
<div className="space-y-2">
<SubmitButton />
<NextButton />
<BackButton />
</div>
</div>

View File

@ -18,7 +18,7 @@ type SlotMutationInput = {
type SlotQueryInput = {
date: Date;
masterId?: string;
masterId?: null | string;
};
export const useSlots = ({ date, masterId }: SlotQueryInput) => {

View File

@ -20,6 +20,7 @@ export type OrderStore = {
export type Steps =
| 'client-select'
| 'datetime-select'
| 'error'
| 'loading'
| 'master-select'
| 'service-select'