import { HasChildren } from "@types"; import { ResultCode } from "api"; import { login as APILogin, logout as APILogout, changeContract as APIChangeContract, me, } from "api/auth"; import { CustomCode } from "codes/custom"; import { PageID } from "codes/page"; import { UserRole } from "codes/user"; import useAPICall from "hooks/useAPICall"; import { createContext, memo, useCallback, useEffect, useMemo, useState, } from "react"; import { AUTH } from "routes/auth"; type Auth = { initialized: boolean; authenticated: boolean; role: UserRole; contractId: string | null; userId: string | null; name: string; custom: CustomCode[]; customerName: string; isChangedContractId: boolean; login: (email: string, password: string) => Promise; logout: VoidFunction; changeContractId: (contractId: string | null) => Promise; checkRole: (role?: UserRole) => boolean; canAccess: (pageId: PageID) => boolean; }; export const AuthContext = createContext({ initialized: false, authenticated: false, role: UserRole.NONE, contractId: null, userId: null, name: "", custom: [], customerName: "", isChangedContractId: false, login: async (email: string, password: string) => false, logout: () => {}, changeContractId: async (contractId: string | null) => false, checkRole: (role?: UserRole) => false, canAccess: (pageId: PageID) => false, }); type Props = HasChildren; function AuthContextProvider({ children }: Props) { const [initialized, setInitialized] = useState(false); const [role, setRole] = useState(UserRole.NONE); const [contractId, setContractId] = useState(null); const [userId, setUserId] = useState(null); const [name, setName] = useState(""); const [custom, setCustom] = useState([]); const [customerName, setCustomerName] = useState(""); const isChangedContractId = useMemo(() => { return role === UserRole.SUPER_ADMIN && contractId !== null; }, [contractId]); const authenticated = useMemo(() => { return role !== UserRole.NONE; }, [role]); const { callAPI: callMe } = useAPICall({ apiMethod: me, backDrop: true, onSuccess: (res) => { setContractId(res.data.contract_id); setUserId(res.data.id); setRole(res.data.role); setName(res.data.name); setCustom(res.data.custom ?? []); setCustomerName(res.data.contract_name ?? ""); setInitialized(true); }, onFailed: () => { clear(); setInitialized(true); }, }); const { callAPI: callLogin } = useAPICall({ apiMethod: APILogin, backDrop: true, onSuccess: (res) => { setContractId(res.data.contract_id); setUserId(res.data.id); setRole(res.data.role); setName(res.data.name); setCustom(res.data.custom ?? []); setCustomerName(res.data.contract_name ?? ""); setInitialized(true); }, }); const { callAPI: callLogout } = useAPICall({ apiMethod: APILogout, onSuccess: () => { clear(); }, }); const { callAPI: callChangeContract } = useAPICall({ apiMethod: APIChangeContract, backDrop: true, onSuccess: (res) => { setContractId(res.data.contract_id); setCustom(res.data.custom ?? []); setCustomerName(res.data.contract_name ?? ""); setInitialized(true); }, }); const clear = () => { setRole(UserRole.NONE); setContractId(null); setUserId(null); setName(""); setCustom([]); }; const login = async (email: string, password: string) => { const res = await callLogin({ email, password }); if (!res) return false; return res.result === ResultCode.SUCCESS; }; const logout = () => { callLogout({}); console.info("ログアウト"); }; const changeContractId = async (contractId: string | null) => { const res = await callChangeContract({ contract_id: contractId }); return res?.result === ResultCode.SUCCESS; }; const checkRole = useCallback( (targetRole?: UserRole): boolean => { if (targetRole === undefined) return true; return targetRole <= role; }, [role] ); const canAccess = useCallback( (pageId: PageID): boolean => { const authorization = AUTH[pageId]; // デバッグ用 // console.log( // "RET", // pageId, // role, // custom, // !!authorization && // authorization.role.includes(role) && // (authorization.custom.length === 0 || // !!custom.find((c) => { // return authorization.custom.includes(c); // })), // [ // !!authorization, // authorization.role.includes(role), // authorization.custom.length === 0, // !!custom.find((c) => { // return authorization.custom.includes(c); // }), // ] // ); return ( !!authorization && // 権限条件 authorization.role.includes(role) && // カスタム条件 (authorization.custom.length === 0 || !!custom.find((c) => { return authorization.custom.includes(c); })) && // 成り代わり条件 (authorization.allowChangedContract === undefined || role !== UserRole.SUPER_ADMIN || isChangedContractId === authorization.allowChangedContract) ); }, [initialized, role, custom, isChangedContractId] ); useEffect(() => { callMe({}); }, []); return ( {children} ); } export default memo(AuthContextProvider);