Add subcription feature 2

This commit is contained in:
Urtzi Alfaro
2026-01-14 13:15:48 +01:00
parent 6ddf608d37
commit a4c3b7da3f
32 changed files with 4240 additions and 965 deletions

View File

@@ -188,6 +188,39 @@ export const useAuthStore = create<AuthState>()(
const response = await authService.registerWithSubscription(userData);
// NEW ARCHITECTURE: Check if SetupIntent verification is required
if (response && response.requires_action) {
// SetupIntent required - NO user created yet, NO tokens returned
// Store registration data for post-3DS completion
const pendingRegistrationData = {
email: userData.email,
password: userData.password,
full_name: userData.full_name,
setup_intent_id: response.setup_intent_id,
plan_id: response.plan_id,
payment_method_id: response.payment_method_id,
billing_interval: response.billing_interval,
coupon_code: response.coupon_code,
customer_id: response.customer_id,
payment_customer_id: response.payment_customer_id,
trial_period_days: response.trial_period_days,
client_secret: response.client_secret
};
// Store in session storage for post-3DS completion
sessionStorage.setItem('pending_registration_data', JSON.stringify(pendingRegistrationData));
set({
isLoading: false,
error: null,
pendingRegistrationData,
});
// Return the SetupIntent data for frontend to handle 3DS
return response;
}
// OLD FLOW: No SetupIntent required - user created and authenticated
if (response && response.access_token) {
// Set the auth tokens on the API client immediately
apiClient.setAuthToken(response.access_token);
@@ -223,6 +256,60 @@ export const useAuthStore = create<AuthState>()(
}
},
completeRegistrationAfterSetupIntent: async (completionData: {
email: string;
password: string;
full_name: string;
setup_intent_id: string;
plan_id: string;
payment_method_id: string;
billing_interval: 'monthly' | 'yearly';
coupon_code?: string;
}) => {
try {
set({ isLoading: true, error: null });
const response = await authService.completeRegistrationAfterSetupIntent(completionData);
if (response && response.access_token) {
// Set the auth tokens on the API client immediately
apiClient.setAuthToken(response.access_token);
if (response.refresh_token) {
apiClient.setRefreshToken(response.refresh_token);
}
// Store subscription ID in state for onboarding flow
const pendingSubscriptionId = response.subscription_id || null;
// Clear pending registration data from session storage
sessionStorage.removeItem('pending_registration_data');
set({
user: response.user || null,
token: response.access_token,
refreshToken: response.refresh_token || null,
isAuthenticated: true,
isLoading: false,
error: null,
pendingSubscriptionId,
pendingRegistrationData: null,
});
} else {
throw new Error('Registration completion failed');
}
} catch (error) {
set({
user: null,
token: null,
refreshToken: null,
isAuthenticated: false,
isLoading: false,
error: error instanceof Error ? error.message : 'Error completando el registro',
});
throw error;
}
},
logout: () => {
// Clear the auth tokens from API client
apiClient.setAuthToken(null);
@@ -446,6 +533,7 @@ export const useAuthActions = () => useAuthStore((state) => ({
login: state.login,
register: state.register,
registerWithSubscription: state.registerWithSubscription,
completeRegistrationAfterSetupIntent: state.completeRegistrationAfterSetupIntent,
logout: state.logout,
refreshAuth: state.refreshAuth,
updateUser: state.updateUser,