fix(mobile): auth-gated hydrates and telemetry flush on background
- Run notes/workspace/inbox hydrate, broadcast/survey polling, and offline queue flush timers only when hasBootstrapped && isAuthenticated - Split effects: kill switch, bootstrap, initPlatform, global AppState flush - Avoid pre-auth 401s from parallel API hydrates Made-with: Cursor
This commit is contained in:
parent
e920d724e4
commit
6620e5dabb
@ -3,10 +3,10 @@ import { Stack } from 'expo-router';
|
|||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import { AppState, Modal, Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native';
|
import { AppState, Modal, Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native';
|
||||||
import { useAuthStore, type AuthState } from '../store/auth-store';
|
import { useAuthStore, type AuthState } from '../store/auth-store';
|
||||||
import { useInboxStore, type InboxState } from '../store/inbox-store';
|
import { useInboxStore } from '../store/inbox-store';
|
||||||
import { useNotesStore, type NotesState } from '../store/notes-store';
|
import { useNotesStore } from '../store/notes-store';
|
||||||
import { useWorkspaceStore, type WorkspaceState } from '../store/workspace-store';
|
import { useWorkspaceStore } from '../store/workspace-store';
|
||||||
import { checkKillSwitch, initPlatform } from '../lib/platform';
|
import { checkKillSwitch, flushTelemetry, initPlatform } from '../lib/platform';
|
||||||
import { getBroadcastClient } from '../lib/broadcast-client';
|
import { getBroadcastClient } from '../lib/broadcast-client';
|
||||||
import { getSurveyClient } from '../lib/survey-client';
|
import { getSurveyClient } from '../lib/survey-client';
|
||||||
import { flushNoteQueue, getNoteQueueSize } from '../lib/offline-queue';
|
import { flushNoteQueue, getNoteQueueSize } from '../lib/offline-queue';
|
||||||
@ -37,9 +37,8 @@ export default function RootLayout() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const bootstrapAuth = useAuthStore((state: AuthState) => state.bootstrap);
|
const bootstrapAuth = useAuthStore((state: AuthState) => state.bootstrap);
|
||||||
const hydrateInbox = useInboxStore((state: InboxState) => state.hydrate);
|
const hasBootstrapped = useAuthStore((state: AuthState) => state.hasBootstrapped);
|
||||||
const hydrateNotes = useNotesStore((state: NotesState) => state.hydrate);
|
const isAuthenticated = useAuthStore((state: AuthState) => state.isAuthenticated);
|
||||||
const hydrateWorkspaces = useWorkspaceStore((state: WorkspaceState) => state.hydrate);
|
|
||||||
|
|
||||||
function toSurveyAnswer(question: Question, value: string): QuestionAnswer {
|
function toSurveyAnswer(question: Question, value: string): QuestionAnswer {
|
||||||
if (question.type === 'single_choice' || question.type === 'dropdown') {
|
if (question.type === 'single_choice' || question.type === 'dropdown') {
|
||||||
@ -99,15 +98,45 @@ export default function RootLayout() {
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
setKillSwitchState({ checked: true, disabled: false, message: null });
|
setKillSwitchState({ checked: true, disabled: false, message: null });
|
||||||
});
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
void bootstrapAuth();
|
void bootstrapAuth();
|
||||||
|
}, [bootstrapAuth]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
void initPlatform();
|
void initPlatform();
|
||||||
void hydrateNotes();
|
}, []);
|
||||||
void hydrateWorkspaces();
|
|
||||||
void hydrateInbox();
|
useEffect(() => {
|
||||||
void flushQueuedNoteMutations();
|
const sub = AppState.addEventListener('change', (nextState) => {
|
||||||
void loadBroadcasts();
|
if (nextState === 'background' || nextState === 'inactive') {
|
||||||
void loadSurvey();
|
flushTelemetry();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return () => sub.remove();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasBootstrapped || !isAuthenticated) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
void (async () => {
|
||||||
|
await Promise.all([
|
||||||
|
useNotesStore.getState().hydrate(),
|
||||||
|
useWorkspaceStore.getState().hydrate(),
|
||||||
|
useInboxStore.getState().hydrate(),
|
||||||
|
]);
|
||||||
|
if (cancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void flushQueuedNoteMutations();
|
||||||
|
void loadBroadcasts();
|
||||||
|
void loadSurvey();
|
||||||
|
})();
|
||||||
|
|
||||||
const broadcastTimer = setInterval(() => {
|
const broadcastTimer = setInterval(() => {
|
||||||
void loadBroadcasts();
|
void loadBroadcasts();
|
||||||
@ -124,11 +153,12 @@ export default function RootLayout() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
clearInterval(broadcastTimer);
|
clearInterval(broadcastTimer);
|
||||||
clearInterval(surveyTimer);
|
clearInterval(surveyTimer);
|
||||||
appStateSubscription.remove();
|
appStateSubscription.remove();
|
||||||
};
|
};
|
||||||
}, [bootstrapAuth, hydrateInbox, hydrateNotes, hydrateWorkspaces]);
|
}, [hasBootstrapped, isAuthenticated]);
|
||||||
|
|
||||||
if (killSwitchState.checked && killSwitchState.disabled) {
|
if (killSwitchState.checked && killSwitchState.disabled) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user