chore: merge admin repo history into monorepo at admin/

git-subtree-dir: admin
git-subtree-mainline: 35f5084005
git-subtree-split: 9f1eccd2f7
This commit is contained in:
2026-09-27 10:30:47 +03:30
49 changed files with 11446 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
"use client";
import {
createContext,
useCallback,
useContext,
useEffect,
useState,
ReactNode,
} from "react";
import { tokenStore } from "./token-store";
import { UserProfile, verifyOtp as apiVerifyOtp, getProfileMe, ApiError } from "./api";
type AuthStatus = "loading" | "guest" | "not-admin" | "authenticated";
interface AuthContextValue {
status: AuthStatus;
user: UserProfile | null;
login: (phone: string, otp: string) => Promise<UserProfile>;
logout: () => void;
}
const AuthContext = createContext<AuthContextValue | null>(null);
export function AuthProvider({ children }: { children: ReactNode }) {
const [status, setStatus] = useState<AuthStatus>("loading");
const [user, setUser] = useState<UserProfile | null>(null);
const bootstrap = useCallback(async () => {
const access = tokenStore.getAccess();
if (!access) {
setStatus("guest");
return;
}
try {
const profile = await getProfileMe();
if (!profile.user.is_admin) {
setUser(profile.user);
setStatus("not-admin");
return;
}
setUser(profile.user);
setStatus("authenticated");
} catch {
tokenStore.clear();
setStatus("guest");
}
}, []);
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
bootstrap();
}, [bootstrap]);
const login = useCallback(async (phone: string, otp: string) => {
const data = await apiVerifyOtp(phone, otp);
tokenStore.set(data.tokens.access_token, data.tokens.refresh_token);
if (!data.user.is_admin) {
setUser(data.user);
setStatus("not-admin");
// توکن رو نگه می‌داریم نه، پاک می‌کنیم چون این پنل فقط برای ادمین‌هاست
tokenStore.clear();
throw new ApiError("این حساب دسترسی ادمین نداره", 403);
}
setUser(data.user);
setStatus("authenticated");
return data.user;
}, []);
const logout = useCallback(() => {
tokenStore.clear();
setUser(null);
setStatus("guest");
}, []);
return (
<AuthContext.Provider value={{ status, user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error("useAuth باید داخل AuthProvider استفاده بشه");
return ctx;
}