top-tran/toptran-app/src/contexts/AuthContext.tsx
Rayan Konecny fea50d5064 Refactors data models and sync, adds company/rides fetch APIs
Unifies naming conventions for users, companies, and rides across
backend and mobile app, standardizing field names for consistency
and easier data interchange.

Introduces endpoints to fetch all companies and rides for sync.
Enhances sync logic to support both upload and download of companies,
including first-time population from server.

Updates local database schema and access logic to match backend
structure, improving maintainability and reliability of sync.
2026-05-03 14:15:37 -03:00

156 lines
3.7 KiB
TypeScript

import { useRouter } from "expo-router";
import React, { createContext, useContext, useEffect, useState } from "react";
import {
deleteSetting,
getSetting,
initDB,
salvarUsuario,
setSetting,
} from "@/services/db";
import { getUserIdFromToken } from "@/utils/jwt";
type User = {
id: string;
email: string;
name: string;
};
type AuthContextType = {
user: User | null;
token: string | null;
isLoading: boolean;
login: (
email: string,
password: string,
token: string,
user: User,
) => Promise<void>;
signup: (
name: string,
email: string,
userId: string,
token: string,
) => Promise<void>;
logout: () => Promise<void>;
isSignedIn: boolean;
};
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [token, setToken] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
const router = useRouter();
useEffect(() => {
bootstrapAsync();
}, []);
const bootstrapAsync = async () => {
try {
await initDB();
const storedToken = await getSetting("authToken");
const storedUser = await getSetting("user");
if (storedToken && storedUser) {
let parsedUser: User = JSON.parse(storedUser);
const realId = getUserIdFromToken(storedToken);
if (realId && realId !== parsedUser.id) {
await salvarUsuario({
id: realId,
email: parsedUser.email,
name: parsedUser.name,
token: storedToken,
});
parsedUser = { ...parsedUser, id: realId };
await setSetting("user", JSON.stringify(parsedUser));
}
setToken(storedToken);
setUser(parsedUser);
router.replace("/home");
} else {
setToken(null);
setUser(null);
router.replace("/");
}
} catch (e) {
console.error("Failed to restore token", e);
} finally {
setIsLoading(false);
}
};
const authContext: AuthContextType = {
user,
token,
isLoading,
isSignedIn: token !== null,
login: async (
_email: string,
_password: string,
authToken: string,
authUser: User,
) => {
try {
setToken(authToken);
setUser(authUser);
await setSetting("authToken", authToken);
await setSetting("user", JSON.stringify(authUser));
router.replace("/home");
} catch (error) {
console.error("Login failed:", error);
throw error;
}
},
signup: async (
name: string,
email: string,
userId: string,
authToken: string,
) => {
try {
const newUser: User = {
id: userId,
email,
name,
};
setToken(authToken);
setUser(newUser);
await setSetting("authToken", authToken);
await setSetting("user", JSON.stringify(newUser));
router.replace("/home");
} catch (error) {
console.error("Signup failed:", error);
throw error;
}
},
logout: async () => {
try {
await deleteSetting("authToken");
await deleteSetting("user");
setToken(null);
setUser(null);
router.replace("/");
} catch (error) {
console.error("Logout failed:", error);
throw error;
}
},
};
return (
<AuthContext.Provider value={authContext}>{children}</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
}