You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 line
5.9KB

  1. import { HasChildren } from "@types";
  2. import { ResultCode } from "api";
  3. import {
  4. login as APILogin,
  5. logout as APILogout,
  6. changeContract as APIChangeContract,
  7. me,
  8. } from "api/auth";
  9. import { CustomCode } from "codes/custom";
  10. import { PageID } from "codes/page";
  11. import { UserRole } from "codes/user";
  12. import useAPICall from "hooks/useAPICall";
  13. import {
  14. createContext,
  15. memo,
  16. useCallback,
  17. useEffect,
  18. useMemo,
  19. useState,
  20. } from "react";
  21. import { AUTH } from "routes/auth";
  22. type Auth = {
  23. initialized: boolean;
  24. authenticated: boolean;
  25. role: UserRole;
  26. contractId: string | null;
  27. userId: string | null;
  28. name: string;
  29. custom: CustomCode[];
  30. customerName: string;
  31. isChangedContractId: boolean;
  32. login: (email: string, password: string) => Promise<boolean>;
  33. logout: VoidFunction;
  34. changeContractId: (contractId: string | null) => Promise<boolean>;
  35. checkRole: (role?: UserRole) => boolean;
  36. canAccess: (pageId: PageID) => boolean;
  37. };
  38. export const AuthContext = createContext<Auth>({
  39. initialized: false,
  40. authenticated: false,
  41. role: UserRole.NONE,
  42. contractId: null,
  43. userId: null,
  44. name: "",
  45. custom: [],
  46. customerName: "",
  47. isChangedContractId: false,
  48. login: async (email: string, password: string) => false,
  49. logout: () => {},
  50. changeContractId: async (contractId: string | null) => false,
  51. checkRole: (role?: UserRole) => false,
  52. canAccess: (pageId: PageID) => false,
  53. });
  54. type Props = HasChildren;
  55. function AuthContextProvider({ children }: Props) {
  56. const [initialized, setInitialized] = useState(false);
  57. const [role, setRole] = useState<UserRole>(UserRole.NONE);
  58. const [contractId, setContractId] = useState<string | null>(null);
  59. const [userId, setUserId] = useState<string | null>(null);
  60. const [name, setName] = useState("");
  61. const [custom, setCustom] = useState<CustomCode[]>([]);
  62. const [customerName, setCustomerName] = useState("");
  63. const isChangedContractId = useMemo(() => {
  64. return role === UserRole.SUPER_ADMIN && contractId !== null;
  65. }, [contractId]);
  66. const authenticated = useMemo(() => {
  67. return role !== UserRole.NONE;
  68. }, [role]);
  69. const { callAPI: callMe } = useAPICall({
  70. apiMethod: me,
  71. backDrop: true,
  72. onSuccess: (res) => {
  73. setContractId(res.data.contract_id);
  74. setUserId(res.data.id);
  75. setRole(res.data.role);
  76. setName(res.data.name);
  77. setCustom(res.data.custom ?? []);
  78. setCustomerName(res.data.contract_name ?? "");
  79. setInitialized(true);
  80. },
  81. onFailed: () => {
  82. clear();
  83. setInitialized(true);
  84. },
  85. });
  86. const { callAPI: callLogin } = useAPICall({
  87. apiMethod: APILogin,
  88. backDrop: true,
  89. onSuccess: (res) => {
  90. setContractId(res.data.contract_id);
  91. setUserId(res.data.id);
  92. setRole(res.data.role);
  93. setName(res.data.name);
  94. setCustom(res.data.custom ?? []);
  95. setCustomerName(res.data.contract_name ?? "");
  96. setInitialized(true);
  97. },
  98. });
  99. const { callAPI: callLogout } = useAPICall({
  100. apiMethod: APILogout,
  101. onSuccess: () => {
  102. clear();
  103. },
  104. });
  105. const { callAPI: callChangeContract } = useAPICall({
  106. apiMethod: APIChangeContract,
  107. backDrop: true,
  108. onSuccess: (res) => {
  109. setContractId(res.data.contract_id);
  110. setCustom(res.data.custom ?? []);
  111. setCustomerName(res.data.contract_name ?? "");
  112. setInitialized(true);
  113. },
  114. });
  115. const clear = () => {
  116. setRole(UserRole.NONE);
  117. setContractId(null);
  118. setUserId(null);
  119. setName("");
  120. setCustom([]);
  121. };
  122. const login = async (email: string, password: string) => {
  123. const res = await callLogin({ email, password });
  124. if (!res) return false;
  125. return res.result === ResultCode.SUCCESS;
  126. };
  127. const logout = () => {
  128. callLogout({});
  129. console.info("ログアウト");
  130. };
  131. const changeContractId = async (contractId: string | null) => {
  132. const res = await callChangeContract({ contract_id: contractId });
  133. return res?.result === ResultCode.SUCCESS;
  134. };
  135. const checkRole = useCallback(
  136. (targetRole?: UserRole): boolean => {
  137. if (targetRole === undefined) return true;
  138. return targetRole <= role;
  139. },
  140. [role]
  141. );
  142. const canAccess = useCallback(
  143. (pageId: PageID): boolean => {
  144. const authorization = AUTH[pageId];
  145. // デバッグ用
  146. // console.log(
  147. // "RET",
  148. // pageId,
  149. // role,
  150. // custom,
  151. // !!authorization &&
  152. // authorization.role.includes(role) &&
  153. // (authorization.custom.length === 0 ||
  154. // !!custom.find((c) => {
  155. // return authorization.custom.includes(c);
  156. // })),
  157. // [
  158. // !!authorization,
  159. // authorization.role.includes(role),
  160. // authorization.custom.length === 0,
  161. // !!custom.find((c) => {
  162. // return authorization.custom.includes(c);
  163. // }),
  164. // ]
  165. // );
  166. return (
  167. !!authorization &&
  168. // 権限条件
  169. authorization.role.includes(role) &&
  170. // カスタム条件
  171. (authorization.custom.length === 0 ||
  172. !!custom.find((c) => {
  173. return authorization.custom.includes(c);
  174. })) &&
  175. // 成り代わり条件
  176. (authorization.allowChangedContract === undefined ||
  177. role !== UserRole.SUPER_ADMIN ||
  178. isChangedContractId === authorization.allowChangedContract)
  179. );
  180. },
  181. [initialized, role, custom, isChangedContractId]
  182. );
  183. useEffect(() => {
  184. callMe({});
  185. }, []);
  186. return (
  187. <AuthContext.Provider
  188. value={{
  189. // Value
  190. initialized,
  191. authenticated,
  192. role,
  193. contractId,
  194. userId,
  195. name,
  196. custom,
  197. customerName,
  198. isChangedContractId,
  199. // Func
  200. login,
  201. logout,
  202. changeContractId,
  203. checkRole,
  204. canAccess,
  205. }}
  206. >
  207. {children}
  208. </AuthContext.Provider>
  209. );
  210. }
  211. export default memo(AuthContextProvider);