90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
import { createContext, useContext, useCallback, useState } from "react";
|
|
import type { ReactNode } from "react";
|
|
import { pb } from "@/lib/pocketbase";
|
|
import type { AuthRecord } from "pocketbase";
|
|
import { useNavigate } from "@tanstack/react-router";
|
|
|
|
/**
|
|
* Represents the shape of the authenticated user object from PocketBase.
|
|
*/
|
|
/**
|
|
* Context value for authentication state and actions.
|
|
*/
|
|
export interface AuthContextValue {
|
|
user: AuthRecord | null;
|
|
isLoading: boolean;
|
|
login: (email: string, password: string) => Promise<void>;
|
|
signup: (
|
|
email: string,
|
|
password: string,
|
|
passwordConfirm: string,
|
|
) => Promise<void>;
|
|
logout: () => Promise<void>;
|
|
}
|
|
|
|
const AuthContext = createContext<AuthContextValue | undefined>(undefined);
|
|
|
|
/**
|
|
* Provider for authentication context.
|
|
*/
|
|
export function AuthProvider({ children }: { children: ReactNode }) {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [user, setUser] = useState<AuthRecord | null>(
|
|
pb.authStore.isValid ? pb.authStore.record : null,
|
|
);
|
|
|
|
const navigate = useNavigate();
|
|
|
|
function updateUser() {
|
|
if (pb.authStore.isValid) {
|
|
setUser(pb.authStore.record);
|
|
}
|
|
setIsLoading(false);
|
|
}
|
|
|
|
const login = useCallback(async (email: string, password: string) => {
|
|
console.log("login");
|
|
setIsLoading(true);
|
|
await pb.collection("users").authWithPassword(email, password);
|
|
updateUser();
|
|
navigate({ to: "/campaigns" });
|
|
}, []);
|
|
|
|
const signup = useCallback(
|
|
async (email: string, password: string, passwordConfirm: string) => {
|
|
console.log("signup");
|
|
setIsLoading(true);
|
|
await pb.collection("users").create({ email, password, passwordConfirm });
|
|
await pb.collection("users").authWithPassword(email, password);
|
|
updateUser();
|
|
navigate({ to: "/campaigns" });
|
|
},
|
|
[],
|
|
);
|
|
|
|
const logout = useCallback(async () => {
|
|
console.log("logout");
|
|
pb.authStore.clear();
|
|
setUser(null);
|
|
navigate({ to: "/" });
|
|
}, []);
|
|
|
|
return (
|
|
<AuthContext.Provider
|
|
value={{ user: user ?? null, isLoading, login, signup, logout }}
|
|
>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Hook to access authentication context.
|
|
* Throws if used outside of AuthProvider.
|
|
*/
|
|
export function useAuth(): AuthContextValue {
|
|
const ctx = useContext(AuthContext);
|
|
if (!ctx) throw new Error("useAuth must be used within an AuthProvider");
|
|
return ctx;
|
|
}
|