Files
nextjs-elysia-allaos/src/hooks/use-stepper.tsx
phaichayon 4702150af1 commit
2026-04-16 14:06:59 +07:00

101 lines
2.5 KiB
TypeScript

import type { AnyFormApi } from '@tanstack/react-form';
import { useCallback, useState } from 'react';
import type { ZodTypeAny } from 'zod';
/**
* Options for handling cancel/back actions
*/
type HandleCancelOrBackOpts = {
onBack?: VoidFunction;
onCancel?: VoidFunction;
};
/**
* State of the current step
*/
type StepState = {
value: number;
count: number;
goToNextStep: () => void;
goToPrevStep: () => void;
isCompleted: boolean;
};
/**
* Hook for managing multi-step form navigation and validation
*
* @param schemas - Array of Zod schemas for each step
* @returns Object with stepper state and methods
*/
export function useFormStepper(schemas: ZodTypeAny[]) {
const stepCount = schemas.length;
const [currentStep, setCurrentStep] = useState(1); // Start from 1
const goToNextStep = useCallback(() => {
setCurrentStep((prev) => Math.min(prev + 1, stepCount));
}, [stepCount]);
const goToPrevStep = useCallback(() => {
setCurrentStep((prev) => Math.max(prev - 1, 1));
}, []);
const step: StepState = {
value: currentStep,
count: stepCount,
goToNextStep,
goToPrevStep,
isCompleted: currentStep === stepCount
};
const currentValidator = schemas[currentStep - 1]; // Convert to 0-based for array access
const isFirstStep = currentStep === 1;
const triggerFormGroup = async (form: AnyFormApi) => {
const result = currentValidator.safeParse(form.state.values);
if (!result.success) {
await form.handleSubmit({ step: String(currentStep) });
return result;
}
return result;
};
const handleNextStepOrSubmit = async (form: AnyFormApi) => {
const result = await triggerFormGroup(form);
if (!result.success) {
return;
}
if (currentStep < stepCount) {
goToNextStep();
return;
}
if (currentStep === stepCount) {
form.handleSubmit();
}
};
const handleCancelOrBack = (opts?: HandleCancelOrBackOpts) => {
if (isFirstStep || step.isCompleted) {
opts?.onCancel?.();
return;
}
if (currentStep > 1) {
opts?.onBack?.();
goToPrevStep();
}
};
return {
step, // Current step state
currentStep, // Current step number (1-based)
isFirstStep, // Whether current step is the first step
currentValidator, // Zod schema for current step
triggerFormGroup, // Validate current step fields
handleNextStepOrSubmit, // Handle next/submit action
handleCancelOrBack // Handle back/cancel action
};
}