Files
fotospiel-app/resources/js/pages/marketing/checkout/WizardContext.tsx
2025-10-05 20:39:30 +02:00

111 lines
3.4 KiB
TypeScript

import React, { createContext, useCallback, useContext, useMemo, useState } from "react";
import type { CheckoutPackage, CheckoutStepId, CheckoutWizardContextValue, CheckoutWizardState } from "./types";
interface CheckoutWizardProviderProps {
initialPackage: CheckoutPackage;
packageOptions: CheckoutPackage[];
initialStep?: CheckoutStepId;
initialAuthUser?: CheckoutWizardState['authUser'];
initialIsAuthenticated?: boolean;
children: React.ReactNode;
}
const CheckoutWizardContext = createContext<CheckoutWizardContextValue | undefined>(undefined);
export const CheckoutWizardProvider: React.FC<CheckoutWizardProviderProps> = ({
initialPackage,
packageOptions,
initialStep = 'package',
initialAuthUser = null,
initialIsAuthenticated,
children,
}) => {
const [state, setState] = useState<CheckoutWizardState>(() => ({
currentStep: initialStep,
selectedPackage: initialPackage,
packageOptions,
isAuthenticated: Boolean(initialIsAuthenticated || initialAuthUser),
authUser: initialAuthUser ?? null,
paymentProvider: undefined,
isProcessing: false,
}));
const setStep = useCallback((step: CheckoutStepId) => {
setState((prev) => ({ ...prev, currentStep: step }));
}, []);
const nextStep = useCallback(() => {
setState((prev) => {
const order: CheckoutStepId[] = ['package', 'auth', 'payment', 'confirmation'];
const currentIndex = order.indexOf(prev.currentStep);
const nextIndex = currentIndex === -1 ? 0 : Math.min(order.length - 1, currentIndex + 1);
return { ...prev, currentStep: order[nextIndex] };
});
}, []);
const previousStep = useCallback(() => {
setState((prev) => {
const order: CheckoutStepId[] = ['package', 'auth', 'payment', 'confirmation'];
const currentIndex = order.indexOf(prev.currentStep);
const nextIndex = currentIndex <= 0 ? 0 : currentIndex - 1;
return { ...prev, currentStep: order[nextIndex] };
});
}, []);
const setSelectedPackage = useCallback((pkg: CheckoutPackage) => {
setState((prev) => ({
...prev,
selectedPackage: pkg,
paymentProvider: undefined,
}));
}, []);
const markAuthenticated = useCallback<CheckoutWizardContextValue['markAuthenticated']>((user) => {
setState((prev) => ({
...prev,
isAuthenticated: Boolean(user),
authUser: user ?? null,
}));
}, []);
const setPaymentProvider = useCallback<CheckoutWizardContextValue['setPaymentProvider']>((provider) => {
setState((prev) => ({
...prev,
paymentProvider: provider,
}));
}, []);
const resetPaymentState = useCallback(() => {
setState((prev) => ({
...prev,
paymentProvider: undefined,
isProcessing: false,
}));
}, []);
const value = useMemo<CheckoutWizardContextValue>(() => ({
...state,
setStep,
nextStep,
previousStep,
setSelectedPackage,
markAuthenticated,
setPaymentProvider,
resetPaymentState,
}), [state, setStep, nextStep, previousStep, setSelectedPackage, markAuthenticated, setPaymentProvider, resetPaymentState]);
return (
<CheckoutWizardContext.Provider value={value}>
{children}
</CheckoutWizardContext.Provider>
);
};
export const useCheckoutWizard = () => {
const context = useContext(CheckoutWizardContext);
if (!context) {
throw new Error('useCheckoutWizard must be used within CheckoutWizardProvider');
}
return context;
};