various fixes for checkout

This commit is contained in:
Codex Agent
2025-12-22 21:51:34 +01:00
parent c8f0f880d2
commit 0f2604309d
12 changed files with 681 additions and 277 deletions

View File

@@ -11,6 +11,7 @@ interface CheckoutState {
loading: boolean;
error: string | null;
paymentCompleted: boolean;
checkoutSessionId: string | null;
}
interface CheckoutWizardContextType {
@@ -25,6 +26,7 @@ interface CheckoutWizardContextType {
client_token?: string | null;
} | null;
paymentCompleted: boolean;
checkoutSessionId: string | null;
selectPackage: (pkg: CheckoutPackage) => void;
setSelectedPackage: (pkg: CheckoutPackage) => void;
setAuthUser: (user: unknown) => void;
@@ -38,6 +40,8 @@ interface CheckoutWizardContextType {
setError: (error: string | null) => void;
resetPaymentState: () => void;
setPaymentCompleted: (completed: boolean) => void;
setCheckoutSessionId: (sessionId: string | null) => void;
clearCheckoutSessionId: () => void;
}
const CheckoutWizardContext = createContext<CheckoutWizardContextType | null>(null);
@@ -52,6 +56,7 @@ const initialState: CheckoutState = {
loading: false,
error: null,
paymentCompleted: false,
checkoutSessionId: null,
};
type CheckoutAction =
@@ -63,7 +68,8 @@ type CheckoutAction =
| { type: 'UPDATE_PAYMENT_INTENT'; payload: string | null }
| { type: 'SET_LOADING'; payload: boolean }
| { type: 'SET_ERROR'; payload: string | null }
| { type: 'SET_PAYMENT_COMPLETED'; payload: boolean };
| { type: 'SET_PAYMENT_COMPLETED'; payload: boolean }
| { type: 'SET_CHECKOUT_SESSION_ID'; payload: string | null };
function checkoutReducer(state: CheckoutState, action: CheckoutAction): CheckoutState {
switch (action.type) {
@@ -99,6 +105,8 @@ function checkoutReducer(state: CheckoutState, action: CheckoutAction): Checkout
return { ...state, error: action.payload };
case 'SET_PAYMENT_COMPLETED':
return { ...state, paymentCompleted: action.payload };
case 'SET_CHECKOUT_SESSION_ID':
return { ...state, checkoutSessionId: action.payload };
default:
return state;
}
@@ -135,6 +143,7 @@ export function CheckoutWizardProvider({
isAuthenticated: initialIsAuthenticated || Boolean(initialAuthUser),
};
const checkoutSessionStorageKey = 'checkout-session-id';
const [state, dispatch] = useReducer(checkoutReducer, customInitialState);
@@ -151,10 +160,15 @@ export function CheckoutWizardProvider({
if (parsed.currentStep) dispatch({ type: 'GO_TO_STEP', payload: parsed.currentStep });
} else {
localStorage.removeItem('checkout-wizard-state');
}
} catch (error) {
console.error('Failed to restore checkout state:', error);
}
} catch (error) {
console.error('Failed to restore checkout state:', error);
}
}
const storedSession = localStorage.getItem(checkoutSessionStorageKey);
if (storedSession) {
dispatch({ type: 'SET_CHECKOUT_SESSION_ID', payload: storedSession });
}
}, [initialPackage]);
@@ -173,6 +187,14 @@ export function CheckoutWizardProvider({
}
}, [state.currentStep]);
useEffect(() => {
if (state.checkoutSessionId) {
localStorage.setItem(checkoutSessionStorageKey, state.checkoutSessionId);
} else {
localStorage.removeItem(checkoutSessionStorageKey);
}
}, [state.checkoutSessionId]);
const selectPackage = useCallback((pkg: CheckoutPackage) => {
dispatch({ type: 'SELECT_PACKAGE', payload: pkg });
}, []);
@@ -214,12 +236,21 @@ export function CheckoutWizardProvider({
dispatch({ type: 'SET_LOADING', payload: false });
dispatch({ type: 'SET_ERROR', payload: null });
dispatch({ type: 'SET_PAYMENT_COMPLETED', payload: false });
dispatch({ type: 'SET_CHECKOUT_SESSION_ID', payload: null });
}, []);
const setPaymentCompleted = useCallback((completed: boolean) => {
dispatch({ type: 'SET_PAYMENT_COMPLETED', payload: completed });
}, []);
const setCheckoutSessionId = useCallback((sessionId: string | null) => {
dispatch({ type: 'SET_CHECKOUT_SESSION_ID', payload: sessionId });
}, []);
const clearCheckoutSessionId = useCallback(() => {
dispatch({ type: 'SET_CHECKOUT_SESSION_ID', payload: null });
}, []);
const cancelCheckout = useCallback(() => {
// Track abandoned checkout (fire and forget)
if (state.authUser || state.selectedPackage) {
@@ -241,9 +272,10 @@ export function CheckoutWizardProvider({
// State aus localStorage entfernen
localStorage.removeItem('checkout-wizard-state');
localStorage.removeItem(checkoutSessionStorageKey);
// Zur Package-Übersicht zurückleiten
window.location.href = '/packages';
}, [state]);
}, [state, checkoutSessionStorageKey]);
const value: CheckoutWizardContextType = {
state,
@@ -254,6 +286,7 @@ export function CheckoutWizardProvider({
authUser: state.authUser,
paddleConfig: paddle ?? null,
paymentCompleted: state.paymentCompleted,
checkoutSessionId: state.checkoutSessionId,
selectPackage,
setSelectedPackage,
setAuthUser,
@@ -267,6 +300,8 @@ export function CheckoutWizardProvider({
setError,
resetPaymentState,
setPaymentCompleted,
setCheckoutSessionId,
clearCheckoutSessionId,
};
return (