move getAvailableTimeSlots to server

This commit is contained in:
vchikalkin 2025-05-20 19:25:25 +03:00
parent 9314cdd1cb
commit b8880eedee
6 changed files with 69 additions and 33 deletions

View File

@ -17,6 +17,14 @@ export async function deleteSlot(...variables: Parameters<SlotsService['deleteSl
return service.deleteSlot(...variables);
}
export async function getAvailableTimeSlots(
...variables: Parameters<SlotsService['getAvailableTimeSlots']>
) {
const service = await getService();
return service.getAvailableTimeSlots(...variables);
}
export async function getSlot(...variables: Parameters<SlotsService['getSlot']>) {
const service = await getService();

View File

@ -1,32 +1,14 @@
/* eslint-disable canonical/id-match */
'use client';
import { useSlotsQuery } from '@/hooks/api/slots';
import { useAvailableTimeSlotsQuery } from '@/hooks/api/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';
const generateTimeSlots = (slots: SlotFieldsFragment[]): Array<{ slotId: string; time: Dayjs }> => {
const times: Array<{ slotId: string; time: Dayjs }> = [];
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({ slotId: slot.documentId, time: currentTime });
currentTime = currentTime.add(30, 'minute');
}
}
return times;
};
export function TimeSelect() {
const masterId = useOrderStore((store) => store.masterId);
const date = useOrderStore((store) => store.date);
const { data: { slots } = {} } = useSlotsQuery({
const { data: { times } = {}, isLoading } = useAvailableTimeSlotsQuery({
filters: {
date: {
eq: date,
@ -39,12 +21,14 @@ export function TimeSelect() {
},
});
const openedSlots = slots?.filter((slot) => slot?.state === Enum_Slot_State.Open);
const timeSlots = generateTimeSlots(openedSlots ? sift(openedSlots) : []);
if (isLoading || !times) return null;
const morning = timeSlots.filter((time) => time.time.hour() < 12);
const afternoon = timeSlots.filter((time) => time.time.hour() >= 12 && time.time.hour() < 18);
const evening = timeSlots.filter((time) => time.time.hour() >= 18);
const morning = times.filter(({ time }) => getHour(time) < 12);
const afternoon = times?.filter(({ time }) => {
const hour = getHour(time);
return hour >= 12 && hour < 18;
});
const evening = times?.filter(({ time }) => getHour(time) >= 18);
return (
<div className="space-y-2">
@ -55,10 +39,17 @@ export function TimeSelect() {
);
}
function getHour(time: string) {
const hour = time.split(':')[0];
if (hour) return Number.parseInt(hour, 10);
return -1;
}
function TimeSlotsButtons({
times,
title,
}: Readonly<{ times: Array<{ slotId: string; time: Dayjs }>; title: string }>) {
}: Readonly<{ times: Array<{ slotId: string; time: string }>; title: string }>) {
const setTime = useOrderStore((store) => store.setTime);
const setSlot = useOrderStore((store) => store.setSlotId);
@ -73,12 +64,12 @@ function TimeSlotsButtons({
className="mb-2"
key={time.toString()}
onClick={() => {
setTime(time.format('HH:mm'));
setTime(time);
setSlot(slotId);
}}
variant="outline"
>
{time.format('HH:mm')}
{time}
</Button>
))}
</div>

View File

@ -1,7 +1,14 @@
'use client';
import { useCustomerQuery } from './customers';
import { createSlot, deleteSlot, getSlot, getSlots, updateSlot } from '@/actions/api/slots';
import {
createSlot,
deleteSlot,
getAvailableTimeSlots,
getSlot,
getSlots,
updateSlot,
} from '@/actions/api/slots';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
export const useSlotsQuery = (variables: Parameters<typeof getSlots>[0]) => {
@ -25,6 +32,15 @@ export const useSlotQuery = (variables: Parameters<typeof getSlot>[0]) => {
});
};
export const useAvailableTimeSlotsQuery = (
variables: Parameters<typeof getAvailableTimeSlots>[0],
) => {
return useQuery({
queryFn: () => getAvailableTimeSlots(variables),
queryKey: ['available-time-slots', variables],
});
};
export const useSlotMutation = ({
documentId,
}: Pick<Parameters<typeof updateSlot>[0], 'documentId'>) => {

View File

@ -4,6 +4,7 @@ import { formatDate, formatTime } from '../utils/datetime-format';
import { BaseService } from './base';
import { CustomersService } from './customers';
import { type VariablesOf } from '@graphql-typed-document-node/core';
import dayjs from 'dayjs';
export class SlotsService extends BaseService {
async createSlot(variables: VariablesOf<typeof GQL.CreateSlotDocument>) {
@ -44,6 +45,27 @@ export class SlotsService extends BaseService {
return mutationResult.data;
}
async getAvailableTimeSlots(variables: VariablesOf<typeof GQL.GetSlotsDocument>) {
const { slots } = await this.getSlots(variables);
const openedSlots = slots.filter((x) => x?.state === GQL.Enum_Slot_State.Open);
const times: Array<{ slotId: string; time: string }> = [];
for (const slot of openedSlots)
if (slot?.time_start && slot?.time_end) {
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({ slotId: slot.documentId, time: currentTime.format('HH:mm') });
currentTime = currentTime.add(30, 'minute');
}
}
return { times };
}
async getSlot(variables: VariablesOf<typeof GQL.GetSlotDocument>) {
const { query } = await getClientWithToken();

View File

@ -20,7 +20,6 @@ query GetSlots($filters: SlotFiltersInput) {
query GetSlot($documentId: ID!) {
slot(documentId: $documentId) {
state
orders(sort: "time_start:asc") {
documentId
}

View File

@ -748,7 +748,7 @@ export type GetSlotQueryVariables = Exact<{
}>;
export type GetSlotQuery = { __typename?: 'Query', slot?: { __typename?: 'Slot', state?: Enum_Slot_State | null | undefined, documentId: string, date?: any | null | undefined, time_start: any, time_end: any, orders: Array<{ __typename?: 'Order', documentId: string } | null | undefined>, master?: { __typename?: 'Customer', documentId: string } | null | undefined } | null | undefined };
export type GetSlotQuery = { __typename?: 'Query', slot?: { __typename?: 'Slot', documentId: string, date?: any | null | undefined, time_start: any, time_end: any, state?: Enum_Slot_State | null | undefined, orders: Array<{ __typename?: 'Order', documentId: string } | null | undefined>, master?: { __typename?: 'Customer', documentId: string } | null | undefined } | null | undefined };
export type UpdateSlotMutationVariables = Exact<{
documentId: Scalars['ID']['input'];
@ -782,6 +782,6 @@ export const GetServicesDocument = {"kind":"Document","definitions":[{"kind":"Op
export const GetServiceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetService"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"service"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"documentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServiceFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServiceFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Service"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}}]} as unknown as DocumentNode<GetServiceQuery, GetServiceQueryVariables>;
export const CreateSlotDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateSlot"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SlotInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createSlot"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SlotFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SlotFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Slot"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"time_start"}},{"kind":"Field","name":{"kind":"Name","value":"time_end"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]} as unknown as DocumentNode<CreateSlotMutation, CreateSlotMutationVariables>;
export const GetSlotsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSlots"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filters"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SlotFiltersInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slots"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filters"}}},{"kind":"Argument","name":{"kind":"Name","value":"sort"},"value":{"kind":"StringValue","value":"time_start:asc","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SlotFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SlotFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Slot"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"time_start"}},{"kind":"Field","name":{"kind":"Name","value":"time_end"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]} as unknown as DocumentNode<GetSlotsQuery, GetSlotsQueryVariables>;
export const GetSlotDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSlot"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slot"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"documentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"orders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sort"},"value":{"kind":"StringValue","value":"time_start:asc","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"master"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}}]}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"SlotFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SlotFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Slot"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"time_start"}},{"kind":"Field","name":{"kind":"Name","value":"time_end"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]} as unknown as DocumentNode<GetSlotQuery, GetSlotQueryVariables>;
export const GetSlotDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSlot"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slot"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"documentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"orders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sort"},"value":{"kind":"StringValue","value":"time_start:asc","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"master"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}}]}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"SlotFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SlotFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Slot"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"time_start"}},{"kind":"Field","name":{"kind":"Name","value":"time_end"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]} as unknown as DocumentNode<GetSlotQuery, GetSlotQueryVariables>;
export const UpdateSlotDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSlot"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SlotInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateSlot"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"documentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SlotFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SlotFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Slot"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"time_start"}},{"kind":"Field","name":{"kind":"Name","value":"time_end"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]} as unknown as DocumentNode<UpdateSlotMutation, UpdateSlotMutationVariables>;
export const DeleteSlotDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteSlot"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteSlot"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"documentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"documentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documentId"}}]}}]}}]} as unknown as DocumentNode<DeleteSlotMutation, DeleteSlotMutationVariables>;