import React, { createContext, useContext, useEffect, useState } from "react"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { authApi, LoginPayload, RegisterPayload, subscriptionsApi, UserUpdateDTO, } from "@/services/api"; type User = { id: string; email: string; token: string; subscribedSubjectIds: string[]; }; type AuthContextValue = { user: User | null; loading: boolean; login: (p: LoginPayload) => Promise; register: (p: RegisterPayload) => Promise; logout: () => Promise; subscribe: (subjectId: string) => Promise; unsubscribe: (subjectId: string) => Promise; isSubscribed: (subjectId: string) => boolean; updateUser: (newEmail?: string, newPassword?: string) => Promise; }; const AuthContext = createContext(null); export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { AsyncStorage.getItem("auth_user") .then((raw) => { if (raw) setUser(JSON.parse(raw)); }) .finally(() => setLoading(false)); }, []); const persist = async (u: User | null) => { if (u) await AsyncStorage.setItem("auth_user", JSON.stringify(u)); else await AsyncStorage.removeItem("auth_user"); setUser(u); }; const login = async (payload: LoginPayload) => { const res = await authApi.login(payload); // Gracefully fetch subscriptions — don't block login if this fails let subscribedSubjectIds: string[] = []; if (res.userId) { try { const dto = await authApi.getUser(res.userId, res.token); subscribedSubjectIds = dto.subjectSet?.map((s) => s.id) ?? []; } catch { // aaaa } } await persist({ id: res.userId ?? "", email: res.email, token: res.token, subscribedSubjectIds, }); }; const register = async (payload: RegisterPayload) => { await authApi.register(payload); await login({ email: payload.email, password: payload.password }); }; const updateUser = async (newEmail?: string, newPassword?: string) => { if (!user) return; const body: UserUpdateDTO = { email: user.email, newEmail: newEmail || undefined, password: newPassword || undefined, subjectSet: user.subscribedSubjectIds.map((id) => ({ id })), }; const dto = await authApi.updateUser(body, user.token); const updated: User = { ...user, email: newEmail ?? user.email, subscribedSubjectIds: dto.subjectSet?.map((s: any) => s.id) ?? user.subscribedSubjectIds, }; await persist(updated); }; const logout = () => persist(null); const subscribe = async (subjectId: string) => { if (!user) return; const dto = await subscriptionsApi.subscribe(user.id, subjectId, user.token); const updated = { ...user, subscribedSubjectIds: dto.subjectSet?.map((s) => s.id) ?? [...user.subscribedSubjectIds, subjectId], }; await persist(updated); }; const unsubscribe = async (subjectId: string) => { if (!user) return; const dto = await subscriptionsApi.unsubscribe(user.id, subjectId, user.token); const updated = { ...user, subscribedSubjectIds: dto.subjectSet?.map((s) => s.id) ?? user.subscribedSubjectIds.filter((id) => id !== subjectId), }; await persist(updated); }; const isSubscribed = (subjectId: string) => user?.subscribedSubjectIds.includes(subjectId) ?? false; return ( {children} ); } export function useAuth() { const ctx = useContext(AuthContext); if (!ctx) throw new Error("useAuth must be used inside AuthProvider"); return ctx; }