Files
ksan 7d7e641f5b
CI/CD / Backend Unit Tests (push) Successful in 2m17s
CI/CD / Deploy (push) Successful in 2m26s
fixed push notifications and auth modified
2026-06-11 13:30:36 +02:00

155 lines
5.3 KiB
TypeScript

import React, { createContext, useContext, useEffect, useState } from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";
import Toast from "react-native-toast-message";
import {
authApi,
LoginPayload, RegisterPayload, setUnauthorizedHandler, subscriptionsApi, userApi, UserUpdateDTO,
} from "@/services/api";
type User = {
id: string;
email: string;
token: string;
subscribedSubjectIds: string[];
notificationType: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION';
};
type AuthContextValue = {
user: User | null;
loading: boolean;
login: (p: LoginPayload) => Promise<void>;
register: (p: RegisterPayload) => Promise<void>;
logout: () => Promise<void>;
subscribe: (subjectId: string) => Promise<void>;
unsubscribe: (subjectId: string) => Promise<void>;
isSubscribed: (subjectId: string) => boolean;
updateUser: (newEmail?: string, newPassword?: string) => Promise<void>;
updateNotificationType: (type: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION') => Promise<void>;
};
const AuthContext = createContext<AuthContextValue | null>(null);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(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);
};
useEffect(() => {
setUnauthorizedHandler(() => {
persist(null);
Toast.show({
type: 'info',
text1: 'Session expired',
text2: 'Please sign in again.',
position: 'top',
visibilityTime: 4000,
});
});
return () => setUnauthorizedHandler(null);
}, []);
const updateNotificationType = async (type: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION') => {
if (!user) return;
await userApi.updateNotificationType(type, user.token);
await persist({ ...user, notificationType: type });
};
const login = async (payload: LoginPayload) => {
const res = await authApi.login(payload);
let subscribedSubjectIds: string[] = [];
let notificationType: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION' = 'PUSH_NOTIFICATION';
if (res.userId) {
try {
const dto = await authApi.getUser(res.token);
subscribedSubjectIds = dto.subjectSet?.map((s) => s.id) ?? [];
notificationType = dto.notificationType ?? 'PUSH_NOTIFICATION';
} catch (e) {
console.error('Failed to load subscriptions on login:', e);
}
}
await persist({
id: res.userId ?? "",
email: res.email,
token: res.token,
subscribedSubjectIds,
notificationType,
});
};
const register = async (payload: RegisterPayload) => {
await authApi.register(payload);
await login({
email: payload.email.trim(),
password: payload.password.trim(),
});
};
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( 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( 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 (
<AuthContext.Provider value={{ user, loading, login, register, logout, subscribe, unsubscribe, isSubscribed, updateUser, updateNotificationType }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
return ctx;
}