feat(app): buffer onboarding answers before auth, flush to profile after sign-up/login
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import { AuthService } from '../../services/authService';
|
|||||||
import * as AppleAuthentication from 'expo-apple-authentication';
|
import * as AppleAuthentication from 'expo-apple-authentication';
|
||||||
import Constants from 'expo-constants';
|
import Constants from 'expo-constants';
|
||||||
import { useSafeAnalytics } from '../../services/analytics';
|
import { useSafeAnalytics } from '../../services/analytics';
|
||||||
|
import { PreAuthOnboardingService } from '../../services/preAuthOnboardingService';
|
||||||
|
|
||||||
const ONBOARDING_AUTH_BACKGROUND = {
|
const ONBOARDING_AUTH_BACKGROUND = {
|
||||||
light: '#fbfaf3',
|
light: '#fbfaf3',
|
||||||
@@ -70,6 +71,9 @@ export default function LoginScreen() {
|
|||||||
try {
|
try {
|
||||||
const session = await AuthService.login(email, password);
|
const session = await AuthService.login(email, password);
|
||||||
const billing = await hydrateSession(session);
|
const billing = await hydrateSession(session);
|
||||||
|
if (session?.userId) {
|
||||||
|
await PreAuthOnboardingService.flushToProfile(session.userId).catch(() => {});
|
||||||
|
}
|
||||||
const isPro = billing?.entitlement?.plan === 'pro' && billing?.entitlement?.status === 'active';
|
const isPro = billing?.entitlement?.plan === 'pro' && billing?.entitlement?.status === 'active';
|
||||||
// Non-pro accounts land on the paywall with context instead of being
|
// Non-pro accounts land on the paywall with context instead of being
|
||||||
// bounced through the root redirect (which looks like an app restart).
|
// bounced through the root redirect (which looks like an app restart).
|
||||||
@@ -118,6 +122,9 @@ export default function LoginScreen() {
|
|||||||
name: fullName || undefined,
|
name: fullName || undefined,
|
||||||
});
|
});
|
||||||
const billing = await hydrateSession(session);
|
const billing = await hydrateSession(session);
|
||||||
|
if (session?.userId) {
|
||||||
|
await PreAuthOnboardingService.flushToProfile(session.userId).catch(() => {});
|
||||||
|
}
|
||||||
if (session.isNewUser) {
|
if (session.isNewUser) {
|
||||||
await AsyncStorage.setItem('greenlens_show_tour', 'true');
|
await AsyncStorage.setItem('greenlens_show_tour', 'true');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
|||||||
import * as AppleAuthentication from 'expo-apple-authentication';
|
import * as AppleAuthentication from 'expo-apple-authentication';
|
||||||
import Constants from 'expo-constants';
|
import Constants from 'expo-constants';
|
||||||
import { useSafeAnalytics } from '../../services/analytics';
|
import { useSafeAnalytics } from '../../services/analytics';
|
||||||
|
import { PreAuthOnboardingService } from '../../services/preAuthOnboardingService';
|
||||||
|
|
||||||
const ONBOARDING_AUTH_BACKGROUND = {
|
const ONBOARDING_AUTH_BACKGROUND = {
|
||||||
light: '#fbfaf3',
|
light: '#fbfaf3',
|
||||||
@@ -83,6 +84,9 @@ export default function SignupScreen() {
|
|||||||
try {
|
try {
|
||||||
const session = await AuthService.signUp(email, name, password);
|
const session = await AuthService.signUp(email, name, password);
|
||||||
await hydrateSession(session);
|
await hydrateSession(session);
|
||||||
|
if (session?.userId) {
|
||||||
|
await PreAuthOnboardingService.flushToProfile(session.userId).catch(() => {});
|
||||||
|
}
|
||||||
// Flag setzen: Tour beim nächsten App-Öffnen anzeigen
|
// Flag setzen: Tour beim nächsten App-Öffnen anzeigen
|
||||||
await AsyncStorage.setItem('greenlens_show_tour', 'true');
|
await AsyncStorage.setItem('greenlens_show_tour', 'true');
|
||||||
router.replace('/onboarding/source');
|
router.replace('/onboarding/source');
|
||||||
@@ -132,6 +136,9 @@ export default function SignupScreen() {
|
|||||||
name: fullName || undefined,
|
name: fullName || undefined,
|
||||||
});
|
});
|
||||||
const billing = await hydrateSession(session);
|
const billing = await hydrateSession(session);
|
||||||
|
if (session?.userId) {
|
||||||
|
await PreAuthOnboardingService.flushToProfile(session.userId).catch(() => {});
|
||||||
|
}
|
||||||
await AsyncStorage.setItem('greenlens_show_tour', 'true');
|
await AsyncStorage.setItem('greenlens_show_tour', 'true');
|
||||||
posthog.capture('apple_login_succeeded', { surface: 'signup' });
|
posthog.capture('apple_login_succeeded', { surface: 'signup' });
|
||||||
const isPro = billing?.entitlement?.plan === 'pro' && billing?.entitlement?.status === 'active';
|
const isPro = billing?.entitlement?.plan === 'pro' && billing?.entitlement?.status === 'active';
|
||||||
|
|||||||
36
services/preAuthOnboardingService.ts
Normal file
36
services/preAuthOnboardingService.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
import { OnboardingProgressService } from './onboardingProgressService';
|
||||||
|
|
||||||
|
const STORAGE_KEY = 'greenlens_preauth_onboarding_v1';
|
||||||
|
|
||||||
|
export type PreAuthAnswers = {
|
||||||
|
acquisitionSource?: string;
|
||||||
|
primaryGoal?: string;
|
||||||
|
experienceLevel?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PreAuthOnboardingService = {
|
||||||
|
async setAnswer<K extends keyof PreAuthAnswers>(key: K, value: PreAuthAnswers[K]): Promise<void> {
|
||||||
|
const answers = await this.getAnswers();
|
||||||
|
answers[key] = value;
|
||||||
|
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(answers));
|
||||||
|
},
|
||||||
|
|
||||||
|
async getAnswers(): Promise<PreAuthAnswers> {
|
||||||
|
try {
|
||||||
|
const raw = await AsyncStorage.getItem(STORAGE_KEY);
|
||||||
|
return raw ? (JSON.parse(raw) as PreAuthAnswers) : {};
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Persist buffered answers into the per-user profile after sign-up/login.
|
||||||
|
async flushToProfile(userId: number): Promise<void> {
|
||||||
|
const answers = await this.getAnswers();
|
||||||
|
if (answers.acquisitionSource) OnboardingProgressService.setAcquisitionSource(userId, answers.acquisitionSource);
|
||||||
|
if (answers.primaryGoal) OnboardingProgressService.setPrimaryGoal(userId, answers.primaryGoal);
|
||||||
|
if (answers.experienceLevel) OnboardingProgressService.setExperienceLevel(userId, answers.experienceLevel);
|
||||||
|
await AsyncStorage.removeItem(STORAGE_KEY);
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user