order: add repeat button

This commit is contained in:
vchikalkin 2025-06-26 18:28:44 +03:00
parent 1fb3b67d79
commit 9beee9902e
5 changed files with 102 additions and 16 deletions

View File

@ -1,12 +1,16 @@
/* eslint-disable canonical/id-match */
'use client';
import FloatingActionPanel from '../shared/action-panel';
import { type OrderComponentProps } from './types';
import { useIsMaster } from '@/hooks/api/customers';
import { useOrderMutation, useOrderQuery } from '@/hooks/api/orders';
import { usePushWithData } from '@/hooks/url';
import { Enum_Order_State } from '@repo/graphql/types';
export function OrderButtons({ documentId }: Readonly<OrderComponentProps>) {
const push = usePushWithData();
const isMaster = useIsMaster();
const { data: { order } = {} } = useOrderQuery({ documentId });
@ -34,6 +38,10 @@ export function OrderButtons({ documentId }: Readonly<OrderComponentProps>) {
}
}
function handleOnRepeat() {
push('/orders/add', order);
}
return (
<FloatingActionPanel
isLoading={isPending}
@ -49,6 +57,7 @@ export function OrderButtons({ documentId }: Readonly<OrderComponentProps>) {
? undefined
: () => handleApprove()
}
onRepeat={isCancelled || isCompleted ? handleOnRepeat : undefined}
/>
);
}

View File

@ -7,8 +7,10 @@ import { NextButton } from './next-button';
import { ErrorPage, SuccessPage } from './result';
import { ServiceSelect } from './service-select';
import { SubmitButton } from './submit-button';
import { useGetUrlData } from '@/hooks/url';
import { OrderStoreProvider, useInitOrderStore, useOrderStore } from '@/stores/order';
import { withContext } from '@/utils/context';
import { type OrderFieldsFragment } from '@repo/graphql/types';
import { LoadingSpinner } from '@repo/ui/components/ui/spinner';
import { type JSX } from 'react';
@ -35,7 +37,9 @@ function getButtonComponent(step: string) {
}
export const OrderForm = withContext(OrderStoreProvider)(function () {
useInitOrderStore();
const data = useGetUrlData<OrderFieldsFragment>();
useInitOrderStore(data);
const step = useOrderStore((store) => store.step);
if (step === 'loading') return <LoadingSpinner />;

View File

@ -0,0 +1 @@
export * from './parameters';

View File

@ -0,0 +1,35 @@
/* eslint-disable canonical/id-match */
/* eslint-disable @typescript-eslint/naming-convention */
'use client';
import { useRouter, useSearchParams } from 'next/navigation';
export function useGetUrlData<T>(): null | T {
const searchParameters = useSearchParams();
const data = searchParameters.get('_data_');
if (!data) return null;
try {
const decoded = decodeURIComponent(atob(data));
return JSON.parse(decoded) as T;
} catch (error) {
throw new Error('Failed to parse data parameters', { cause: error });
}
}
export function usePushWithData() {
const router = useRouter();
const searchParameters = useSearchParams();
return <T>(url: string, parameters: T) => {
try {
const base64 = btoa(encodeURIComponent(JSON.stringify(parameters)));
const parameters_ = new URLSearchParams(searchParameters);
parameters_.set('_data_', base64);
router.push(`${url}?${parameters_.toString()}`);
} catch (error) {
throw new Error('Failed to serialize data parameters', { cause: error });
}
};
}

View File

@ -1,8 +1,10 @@
/* eslint-disable sonarjs/cognitive-complexity */
'use client';
import { useOrderStore } from './context';
import { type Steps } from './types';
import { useCustomerQuery, useIsMaster } from '@/hooks/api/customers';
import { useEffect } from 'react';
import { type OrderFieldsFragment } from '@repo/graphql/types';
import { useCallback, useEffect, useRef } from 'react';
const STEPS: Steps[] = [
'master-select',
@ -14,28 +16,63 @@ const STEPS: Steps[] = [
export const MASTER_STEPS: Steps[] = STEPS.filter((step) => step !== 'master-select');
export const CLIENT_STEPS: Steps[] = STEPS.filter((step) => step !== 'client-select');
export function useInitOrderStore() {
export function useInitOrderStore(initData: null | OrderFieldsFragment) {
const initialized = useRef(false);
const { data: { customer } = {} } = useCustomerQuery();
const isMaster = useIsMaster();
const setMasterId = useOrderStore((store) => store.setMasterId);
const setClientId = useOrderStore((store) => store.setClientId);
const setServiceId = useOrderStore((store) => store.setServiceId);
const setStep = useOrderStore((store) => store.setStep);
const setStepsSequence = useOrderStore((store) => store._setStepSequence);
const isMaster = useIsMaster();
const step = useOrderStore((store) => store.step);
const setFirstStep = useCallback(() => {
const steps = isMaster ? MASTER_STEPS : CLIENT_STEPS;
setStepsSequence(steps);
setStep(steps[0] as Steps);
}, [isMaster, setStep, setStepsSequence]);
useEffect(() => {
if (isMaster && customer) {
setMasterId(customer?.documentId);
if (initialized.current || !customer || step !== 'loading') return;
if (initData) {
const masterId = initData.slot?.master?.documentId;
const clientId = initData.client?.documentId;
const serviceId = initData.services[0]?.documentId;
if (masterId) setMasterId(masterId);
if (clientId) setClientId(clientId);
if (serviceId) setServiceId(serviceId);
if (masterId && clientId && serviceId) {
setStep('datetime-select');
} else {
setFirstStep();
}
} else {
if (isMaster) {
setMasterId(customer.documentId);
} else {
setClientId(customer.documentId);
}
setFirstStep();
}
if (!isMaster && customer) {
setClientId(customer?.documentId);
}
const steps = isMaster ? MASTER_STEPS : CLIENT_STEPS;
const initialStep = steps[0] as Steps;
setStepsSequence(steps);
setStep(initialStep);
}, [customer, isMaster, setClientId, setMasterId, setStep, setStepsSequence]);
initialized.current = true;
}, [
customer,
initData,
isMaster,
setClientId,
setFirstStep,
setMasterId,
setServiceId,
setStep,
setStepsSequence,
step,
]);
}