feature: edit slot time
This commit is contained in:
parent
05c6d72801
commit
adbd07600c
@ -40,6 +40,21 @@ export async function getSlots(input: GQL.GetSlotsQueryVariables) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateSlot(input: GQL.UpdateSlotMutationVariables) {
|
||||
const customer = await getProfile();
|
||||
|
||||
if (!customer?.documentId) throw new Error('Customer not found');
|
||||
|
||||
return api.updateSlot({
|
||||
...input,
|
||||
data: {
|
||||
...input.data,
|
||||
date: input.data?.date ? formatDate(input.data.date).db() : undefined,
|
||||
time_end: input.data?.time_end ? formatTime(input.data.time_end).db() : undefined,
|
||||
time_start: input.data?.time_start ? formatTime(input.data.time_start).db() : undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const getSlot = api.getSlot;
|
||||
export const updateSlot = api.updateSlot;
|
||||
export const deleteSlot = api.deleteSlot;
|
||||
|
||||
75
apps/web/components/schedule/components/slot-time.tsx
Normal file
75
apps/web/components/schedule/components/slot-time.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
'use client';
|
||||
import { ScheduleTimeContext } from '../context';
|
||||
import { type SlotComponentProps } from '../types';
|
||||
import { AddTimeRange, ReadonlyTimeRange } from './time-range';
|
||||
import { useSlotMutation, useSlotQuery } from '@/hooks/slots';
|
||||
import { Button } from '@repo/ui/components/ui/button';
|
||||
import { PencilLine } from 'lucide-react';
|
||||
import { use, useEffect } from 'react';
|
||||
|
||||
export function SlotTime(props: Readonly<SlotComponentProps>) {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Time {...props} />
|
||||
<EditSaveButton {...props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function EditSaveButton({ documentId }: Readonly<SlotComponentProps>) {
|
||||
const { editMode, endTime, resetTime, setEditMode, startTime } = use(ScheduleTimeContext);
|
||||
const { mutate: updateSlot } = useSlotMutation({ documentId });
|
||||
|
||||
const { data } = useSlotQuery({ documentId });
|
||||
const slot = data?.data?.slot;
|
||||
|
||||
if (editMode) {
|
||||
function handleOnSave() {
|
||||
updateSlot({ data: { time_end: endTime, time_start: startTime }, documentId });
|
||||
resetTime();
|
||||
setEditMode(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button className="rounded-full text-xs" onClick={() => handleOnSave()}>
|
||||
Сохранить
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
const hasOrders = Boolean(slot?.orders.length);
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="rounded-full text-xs"
|
||||
disabled={hasOrders}
|
||||
onClick={() => setEditMode(true)}
|
||||
size="icon"
|
||||
variant="outline"
|
||||
>
|
||||
<PencilLine className="size-4" />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
function Time(props: Readonly<SlotComponentProps>) {
|
||||
const { editMode, setEndTime, setStartTime } = use(ScheduleTimeContext);
|
||||
|
||||
const { data } = useSlotQuery(props);
|
||||
const slot = data?.data?.slot;
|
||||
|
||||
const { isPending } = useSlotMutation(props);
|
||||
|
||||
useEffect(() => {
|
||||
if (editMode) {
|
||||
if (slot?.time_start) setStartTime(slot.time_start);
|
||||
if (slot?.time_end) setEndTime(slot.time_end);
|
||||
}
|
||||
}, [editMode, setEndTime, setStartTime, slot]);
|
||||
|
||||
if (!slot) return null;
|
||||
|
||||
if (editMode) return <AddTimeRange disabled={isPending} />;
|
||||
|
||||
return <ReadonlyTimeRange {...slot} className="text-3xl" />;
|
||||
}
|
||||
@ -1,11 +1,14 @@
|
||||
'use client';
|
||||
import { ScheduleTimeContext } from '../context';
|
||||
import { useSlotAdd } from '@/hooks/slots';
|
||||
import { formatTime } from '@/utils/date';
|
||||
import { Input } from '@repo/ui/components/ui/input';
|
||||
import { cn } from '@repo/ui/lib/utils';
|
||||
import { use } from 'react';
|
||||
|
||||
type AddTimeRangeProps = {
|
||||
readonly disabled?: boolean;
|
||||
};
|
||||
|
||||
type TimeRangeProps = {
|
||||
readonly className?: string;
|
||||
readonly delimiter?: boolean;
|
||||
@ -13,16 +16,15 @@ type TimeRangeProps = {
|
||||
readonly time_start: string;
|
||||
};
|
||||
|
||||
export function AddTimeRange() {
|
||||
export function AddTimeRange({ disabled = false }: AddTimeRangeProps) {
|
||||
const { endTime, setEndTime, setStartTime, startTime } = use(ScheduleTimeContext);
|
||||
const { isPending } = useSlotAdd();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex-1">
|
||||
<Input
|
||||
className="rounded-xl"
|
||||
disabled={isPending}
|
||||
disabled={disabled}
|
||||
id="start-time"
|
||||
onChange={(event) => setStartTime?.(event.target.value)}
|
||||
required
|
||||
@ -33,7 +35,7 @@ export function AddTimeRange() {
|
||||
<div className="flex-1">
|
||||
<Input
|
||||
className="rounded-xl"
|
||||
disabled={isPending}
|
||||
disabled={disabled}
|
||||
id="end-time"
|
||||
onChange={(event) => setEndTime?.(event.target.value)}
|
||||
required
|
||||
|
||||
@ -1,12 +1,20 @@
|
||||
'use client';
|
||||
import { createContext, type PropsWithChildren, useMemo, useState } from 'react';
|
||||
import {
|
||||
createContext,
|
||||
type Dispatch,
|
||||
type PropsWithChildren,
|
||||
type SetStateAction,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
export type ContextType = {
|
||||
editMode: boolean;
|
||||
endTime: string;
|
||||
setEditMode: (value: boolean) => void;
|
||||
setEndTime: (value: string) => void;
|
||||
setStartTime: (value: string) => void;
|
||||
resetTime: () => void;
|
||||
setEditMode: Dispatch<SetStateAction<boolean>>;
|
||||
setEndTime: Dispatch<SetStateAction<string>>;
|
||||
setStartTime: Dispatch<SetStateAction<string>>;
|
||||
startTime: string;
|
||||
};
|
||||
export const ScheduleTimeContext = createContext<ContextType>({} as ContextType);
|
||||
@ -16,10 +24,16 @@ export function ScheduleTimeContextProvider({ children }: Readonly<PropsWithChil
|
||||
const [startTime, setStartTime] = useState('');
|
||||
const [endTime, setEndTime] = useState('');
|
||||
|
||||
function resetTime() {
|
||||
setStartTime('');
|
||||
setEndTime('');
|
||||
}
|
||||
|
||||
const value = useMemo(() => {
|
||||
return {
|
||||
editMode,
|
||||
endTime,
|
||||
resetTime,
|
||||
setEditMode,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
|
||||
@ -11,11 +11,11 @@ import { PlusSquare } from 'lucide-react';
|
||||
import { type FormEvent, use } from 'react';
|
||||
|
||||
export const DaySlotAddForm = withContext(ScheduleTimeContextProvider)(function () {
|
||||
const { endTime, setEndTime, setStartTime, startTime } = use(ScheduleTimeContext);
|
||||
const { endTime, resetTime, startTime } = use(ScheduleTimeContext);
|
||||
|
||||
const { selectedDate } = use(ScheduleContext);
|
||||
|
||||
const { mutate: addSlot } = useSlotAdd();
|
||||
const { isPending, mutate: addSlot } = useSlotAdd();
|
||||
|
||||
const handleSubmit = (event: FormEvent) => {
|
||||
event.preventDefault();
|
||||
@ -27,15 +27,14 @@ export const DaySlotAddForm = withContext(ScheduleTimeContextProvider)(function
|
||||
time_start: startTime,
|
||||
});
|
||||
|
||||
setStartTime('');
|
||||
setEndTime('');
|
||||
resetTime();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="px-4">
|
||||
<form className="grid grid-cols-[1fr_1fr_auto] items-center gap-2" onSubmit={handleSubmit}>
|
||||
<AddTimeRange />
|
||||
<AddTimeRange disabled={isPending} />
|
||||
<Button className="rounded-full" type="submit">
|
||||
<PlusSquare className="mr-1 size-4" />
|
||||
Добавить
|
||||
|
||||
@ -14,14 +14,14 @@ export function SlotButtons({ documentId }: Readonly<SlotComponentProps>) {
|
||||
const isOpened = slot?.state === Enum_Slot_State.Open;
|
||||
const isClosed = slot?.state === Enum_Slot_State.Closed;
|
||||
|
||||
const { mutate: mutateSlot } = useSlotMutation({ documentId });
|
||||
const { mutate: updateSlot } = useSlotMutation({ documentId });
|
||||
|
||||
function handleOpenSlot() {
|
||||
return mutateSlot({ data: { state: Enum_Slot_State.Open }, documentId });
|
||||
return updateSlot({ data: { state: Enum_Slot_State.Open }, documentId });
|
||||
}
|
||||
|
||||
function handleCloseSlot() {
|
||||
return mutateSlot({ data: { state: Enum_Slot_State.Closed }, documentId });
|
||||
return updateSlot({ data: { state: Enum_Slot_State.Closed }, documentId });
|
||||
}
|
||||
|
||||
const { mutate: deleteSlot } = useSlotDelete({ documentId });
|
||||
@ -32,6 +32,8 @@ export function SlotButtons({ documentId }: Readonly<SlotComponentProps>) {
|
||||
return deleteSlot();
|
||||
}
|
||||
|
||||
const hasOrders = Boolean(slot?.orders.length);
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-[2fr_1fr]">
|
||||
{isOpened && (
|
||||
@ -54,7 +56,7 @@ export function SlotButtons({ documentId }: Readonly<SlotComponentProps>) {
|
||||
)}
|
||||
<Button
|
||||
className="rounded-l-none rounded-r-2xl bg-red-100 p-6 text-red-500 dark:bg-red-700 dark:text-red-100"
|
||||
disabled={Boolean(slot?.orders.length)}
|
||||
disabled={hasOrders}
|
||||
onClick={handleDeleteSlot}
|
||||
variant="ghost"
|
||||
>
|
||||
|
||||
@ -1,19 +1,17 @@
|
||||
'use client';
|
||||
import { SlotDate } from './components/slot-date';
|
||||
import { ReadonlyTimeRange } from './components/time-range';
|
||||
import { SlotTime } from './components/slot-time';
|
||||
import { ScheduleTimeContextProvider } from './context';
|
||||
import { type SlotComponentProps } from './types';
|
||||
import { useSlotQuery } from '@/hooks/slots';
|
||||
|
||||
export function SlotDateTime(props: Readonly<SlotComponentProps>) {
|
||||
const { data } = useSlotQuery(props);
|
||||
const slot = data?.data?.slot;
|
||||
|
||||
if (!slot) return null;
|
||||
import { withContext } from '@/utils/context';
|
||||
|
||||
export const SlotDateTime = withContext(ScheduleTimeContextProvider)(function (
|
||||
props: Readonly<SlotComponentProps>,
|
||||
) {
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<SlotDate {...props} />
|
||||
<ReadonlyTimeRange {...slot} className="text-3xl" />
|
||||
<SlotTime {...props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user