Bug fixes

This commit is contained in:
2026-07-05 17:52:43 +02:00
parent fb6108bd0c
commit c40531b6ae
12 changed files with 1196 additions and 946 deletions

View File

@@ -50,14 +50,14 @@ interface AppState {
deletePlant: (id: string) => Promise<void>;
updatePlant: (plant: Plant) => void;
refreshPlants: () => void;
refreshBillingSummary: () => Promise<void>;
refreshBillingSummary: () => Promise<BillingSummary | null>;
syncRevenueCatState: (customerInfo: RevenueCatCustomerInfo, source?: RevenueCatSyncSource) => Promise<BillingSummary | null>;
simulatePurchase: (productId: PurchaseProductId) => Promise<void>;
simulateWebhookEvent: (event: SimulatedWebhookEvent, payload?: { credits?: number }) => Promise<void>;
getLexiconSearchHistory: () => string[];
saveLexiconSearchQuery: (query: string) => void;
clearLexiconSearchHistory: () => void;
hydrateSession: (session: AuthSession) => Promise<void>;
hydrateSession: (session: AuthSession) => Promise<BillingSummary | null>;
signOut: () => Promise<void>;
setPendingPlant: (result: IdentificationResult, imageUri: string) => void;
getPendingPlant: () => { result: IdentificationResult; imageUri: string } | null;
@@ -166,13 +166,19 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
const isDarkMode = resolvedScheme === 'dark';
const t = getTranslation(language);
const refreshBillingSummary = useCallback(async () => {
const refreshBillingSummary = useCallback(async (): Promise<BillingSummary | null> => {
setIsLoadingBilling(true);
try {
const summary = await backendApiClient.getBillingSummary();
setBillingSummary(summary);
return summary;
} catch (e) {
console.error('Failed to refresh billing summary', e);
// Transient failure: keep the last-known summary so a network blip
// doesn't wipe a paying user's entitlement mid-session. Session
// transitions (hydrateSession/sign-out) clear the summary themselves,
// so a stale summary can never leak across accounts.
return null;
} finally {
setIsLoadingBilling(false);
}
@@ -180,6 +186,8 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
const resetStateForSignedOutUser = useCallback(() => {
setSession(null);
// Old account's billing must not survive into the guest/next session.
setBillingSummary(null);
setPlants([]);
setLanguage(getDeviceLanguage());
setAppearanceModeState('system');
@@ -292,6 +300,10 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
setProfileNameState(nextSession.name);
setIsLoadingPlants(true);
setIsLoadingBilling(true);
// The previous (guest or prior account) summary is meaningless for this
// session — clear it so the entitlement gate treats it as "unknown"
// instead of bouncing on stale data if the fetch below fails.
setBillingSummary(null);
// Settings aus SQLite
try {
@@ -318,18 +330,11 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
}
// Billing laden
try {
await refreshBillingSummary();
} catch (e) {
console.error('Initial billing summary check failed', e);
setIsLoadingBilling(false);
let summary = await refreshBillingSummary();
if (!summary) {
// Einmaliger Retry nach 2s
setTimeout(async () => {
try {
await refreshBillingSummary();
} catch {
// silent — user can retry manually
}
setTimeout(() => {
refreshBillingSummary();
}, 2000);
}
@@ -348,6 +353,8 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
}
}, 800);
}
return summary;
}, [refreshBillingSummary, pendingPlant, savePlant]);
const signOut = useCallback(async () => {