From 27d4eb6a65bc7a3f4e059113d4a2877bf7b7d1d3 Mon Sep 17 00:00:00 2001 From: m Date: Thu, 10 Sep 2026 06:40:58 +0200 Subject: [PATCH] add missing features --- AGENTS.md | 2 +- mobile/context/AuthContext.tsx | 26 +++++++++++++++++++++----- mobile/context/AuthContext.types.ts | 1 + mobile/features/syncDevice.ts | 8 ++++++-- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 11e6582..39e50d9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,7 +47,7 @@ cd mobile && npm run test:db - `db/` — SQLite persistence, see `mobile/AGENTS.md` for the full contract (schema, migrations, repositories, tests) - `localStorage.ts` — thin re-export of `services/db` (legacy alias) - `features/syncDevice.ts` — device sync orchestration (two-pass SAF walk, single transaction per root, `exists = 0` reconciliation) -- `context/AuthContext.tsx` — session context +- `context/AuthContext.tsx` — session context: exposes `deviceUserId` (bootstrapped from `getDeviceUserId()`) and starts the background `syncDevice` loop - No business logic on the client — heavy processing stays server-side - API base URL configured via `EXPO_PUBLIC_API_BASE_URL` env var (client + hooks not yet built) diff --git a/mobile/context/AuthContext.tsx b/mobile/context/AuthContext.tsx index 79bc249..4e727ce 100644 --- a/mobile/context/AuthContext.tsx +++ b/mobile/context/AuthContext.tsx @@ -1,19 +1,35 @@ import { createContext, useContext, useEffect, useMemo, useState } from 'react'; import type { ReactNode } from 'react'; import { useSyncDevice } from '../features/syncDevice'; +import { getDeviceUserId } from '../services/localStorage'; import type { AuthContextValue, User } from './AuthContext.types'; const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { - useEffect(()=>{ - const {} = useSyncDevice() - },[]) - const [user, setUser] = useState(null); + const [deviceUserId, setDeviceUserId] = useState(null); - const value = useMemo(() => ({ user }), [user]); + useEffect(() => { + let active = true; + (async () => { + try { + const id = await getDeviceUserId(); + if (active) setDeviceUserId(id); + } catch (error) { + console.warn('device identity unavailable', error); + } + })(); + + useSyncDevice(); + + return () => { + active = false; + }; + }, []); + + const value = useMemo(() => ({ user, deviceUserId }), [user, deviceUserId]); return {children}; } diff --git a/mobile/context/AuthContext.types.ts b/mobile/context/AuthContext.types.ts index 8b293e8..ea71423 100644 --- a/mobile/context/AuthContext.types.ts +++ b/mobile/context/AuthContext.types.ts @@ -2,4 +2,5 @@ export type User = {}; export type AuthContextValue = { user: User | null; + deviceUserId: string | null; }; \ No newline at end of file diff --git a/mobile/features/syncDevice.ts b/mobile/features/syncDevice.ts index be147df..d1fa817 100644 --- a/mobile/features/syncDevice.ts +++ b/mobile/features/syncDevice.ts @@ -122,8 +122,12 @@ export async function useSyncDevice(intervalMs = 30_000): Promise { if (preferences.syncMode === 'none') return; while (true) { - const results = await syncDevice(); - console.info('syncDevice', JSON.stringify(results)); + try { + const results = await syncDevice(); + console.info('syncDevice', JSON.stringify(results)); + } catch (error) { + console.warn('syncDevice failed, retrying later', error); + } await new Promise((resolve) => setTimeout(resolve, intervalMs)); } } \ No newline at end of file