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.

305 lines
7.9KB

  1. import { ExpandLess, ExpandMore } from "@mui/icons-material";
  2. import HomeIcon from "@mui/icons-material/Home";
  3. import PeopleIcon from "@mui/icons-material/People";
  4. import ArticleIcon from "@mui/icons-material/Article";
  5. import SettingsIcon from "@mui/icons-material/Settings";
  6. import AccountBoxIcon from "@mui/icons-material/AccountBox";
  7. import AccountCircleIcon from "@mui/icons-material/AccountCircle";
  8. import AccountBalanceIcon from "@mui/icons-material/AccountBalance";
  9. import { Collapse, Typography } from "@mui/material";
  10. import Box from "@mui/material/Box";
  11. import Divider from "@mui/material/Divider";
  12. import Drawer, { DrawerProps } from "@mui/material/Drawer";
  13. import List from "@mui/material/List";
  14. import ListItem from "@mui/material/ListItem";
  15. import ListItemButton from "@mui/material/ListItemButton";
  16. import ListItemIcon from "@mui/material/ListItemIcon";
  17. import ListItemText from "@mui/material/ListItemText";
  18. import { PageID } from "codes/page";
  19. import useAuth from "hooks/useAuth";
  20. import useNavigateCustom from "hooks/useNavigateCustom";
  21. import usePage from "hooks/usePage";
  22. import * as React from "react";
  23. import { PathOption, getPath } from "routes/path";
  24. type Group = {
  25. label: string;
  26. children: SubGroup[];
  27. };
  28. type SubGroup = {
  29. label: string;
  30. icon: React.ReactNode;
  31. children?: Child[];
  32. // 子要素を持たない場合は設定
  33. id?: PageID;
  34. option?: PathOption;
  35. };
  36. type Child = {
  37. label: string;
  38. id: PageID;
  39. option?: PathOption;
  40. };
  41. const item = {
  42. py: "2px",
  43. px: 3,
  44. color: "rgba(255, 255, 255, 0.7)",
  45. "&:hover, &:focus": {
  46. bgcolor: "rgba(255, 255, 255, 0.08)",
  47. },
  48. };
  49. const viewItem = {
  50. py: "2px",
  51. px: 3,
  52. color: "rgba(255, 255, 255, 0.7)",
  53. };
  54. const itemCategory = {
  55. boxShadow: "0 -1px 0 rgb(255,255,255,0.1) inset",
  56. py: 1.5,
  57. px: 3,
  58. };
  59. export default function Navigator(props: DrawerProps) {
  60. const { ...other } = props;
  61. const { userId, customerName, name, isChangedContractId } = useAuth();
  62. const categories: Group[] = [
  63. {
  64. label: "管理",
  65. children: [
  66. {
  67. label: "契約",
  68. icon: <PeopleIcon />,
  69. children: [
  70. {
  71. id: PageID.DASHBOARD_CONTRACT_LIST,
  72. label: "一覧",
  73. },
  74. {
  75. id: PageID.DASHBOARD_CONTRACT_CREATE,
  76. label: "作成",
  77. },
  78. ],
  79. },
  80. {
  81. label: "領収証発行依頼",
  82. icon: <ArticleIcon />,
  83. children: [
  84. {
  85. id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO,
  86. label: "一覧",
  87. },
  88. {
  89. id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO,
  90. label: "新規",
  91. },
  92. ],
  93. },
  94. {
  95. label: "利用実績",
  96. icon: <AccountBalanceIcon />,
  97. children: [
  98. {
  99. id: PageID.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO,
  100. label: "一覧",
  101. },
  102. {
  103. id: PageID.DASHBOARD_USE_SUMMARY_LIST_BY_CONTRACT,
  104. label: "一覧",
  105. },
  106. ],
  107. },
  108. {
  109. label: "ユーザ管理",
  110. icon: <PeopleIcon />,
  111. children: [
  112. {
  113. id: PageID.DASHBOARD_LOGIN_USER_LIST,
  114. label: "一覧",
  115. },
  116. {
  117. id: PageID.DASHBOARD_LOGIN_USER_CREATE,
  118. label: "作成",
  119. },
  120. ],
  121. },
  122. ],
  123. },
  124. {
  125. label: "アカウント",
  126. children: [
  127. {
  128. label: "アカウント編集",
  129. icon: <AccountBoxIcon />,
  130. children: [
  131. {
  132. id: PageID.DASHBOARD_LOGIN_USER_CHANGE_PASSWORD,
  133. label: "パスワード変更",
  134. option: {
  135. query: {
  136. id: userId ?? "empty",
  137. },
  138. },
  139. },
  140. ],
  141. },
  142. {
  143. label: "成り代わり解除",
  144. icon: <SettingsIcon />,
  145. id: PageID.CLEAR_CHANGE_CONTRACT,
  146. },
  147. { label: "ログアウト", icon: <SettingsIcon />, id: PageID.LOGOUT },
  148. ],
  149. },
  150. ];
  151. return (
  152. <Drawer variant="permanent" {...other}>
  153. <List disablePadding>
  154. <ListItem
  155. sx={{ ...item, ...itemCategory, fontSize: 22, color: "#fff" }}
  156. >
  157. EasyReceipt
  158. </ListItem>
  159. <ListItem sx={{ ...viewItem, ...itemCategory }}>
  160. <ListItemIcon>
  161. <AccountCircleIcon />
  162. </ListItemIcon>
  163. <ListItemText>{}</ListItemText>
  164. <ListItemText>
  165. <Typography>{customerName}</Typography>
  166. <Typography>{name}</Typography>
  167. {isChangedContractId && (
  168. <Typography color="error">!!成り代わり中!!</Typography>
  169. )}
  170. </ListItemText>
  171. </ListItem>
  172. {categories.map((group, index) => {
  173. return <Group {...group} key={index} />;
  174. })}
  175. </List>
  176. </Drawer>
  177. );
  178. }
  179. function Group(group: Group) {
  180. const { label, children } = group;
  181. const elements = children.map((ele, index) => (
  182. <SubGroup {...ele} key={index} />
  183. ));
  184. if (elements.length === 0) return null;
  185. return (
  186. <Box sx={{ bgcolor: "#101F33" }}>
  187. <ListItem sx={{ py: 2, px: 3 }}>
  188. <ListItemText sx={{ color: "#fff" }}>{label}</ListItemText>
  189. </ListItem>
  190. {elements}
  191. <Divider sx={{ mt: 2 }} />
  192. </Box>
  193. );
  194. }
  195. function SubGroup({ icon, label, id, children, option }: SubGroup) {
  196. const { pageId } = usePage();
  197. const { canAccess } = useAuth();
  198. const { navigateWhenChanged } = useNavigateCustom();
  199. const { elements, shouldOpen } = useContents(children ?? []);
  200. const [open, setOpen] = React.useState(false);
  201. React.useEffect(() => {
  202. setOpen(shouldOpen);
  203. }, [shouldOpen]);
  204. // 子要素ありの場合
  205. if (elements && elements.length !== 0) {
  206. const handleClick = () => {
  207. setOpen(!open);
  208. };
  209. return (
  210. <>
  211. <ListItemButton onClick={handleClick} sx={item} selected={false}>
  212. <ListItemIcon>{icon}</ListItemIcon>
  213. <ListItemText>{label}</ListItemText>
  214. {open ? <ExpandLess /> : <ExpandMore />}
  215. </ListItemButton>
  216. <Collapse in={open} timeout="auto" unmountOnExit>
  217. <List component="div" disablePadding>
  218. {elements}
  219. </List>
  220. </Collapse>
  221. </>
  222. );
  223. }
  224. // 子要素なしの場合
  225. if (id !== undefined && canAccess(id)) {
  226. const handleClick = () => {
  227. if (id) {
  228. const path = getPath(id, option);
  229. navigateWhenChanged(path);
  230. }
  231. };
  232. const selected = id === pageId;
  233. return (
  234. <ListItemButton onClick={handleClick} selected={selected} sx={item}>
  235. <ListItemIcon>{icon}</ListItemIcon>
  236. <ListItemText>{label}</ListItemText>
  237. </ListItemButton>
  238. );
  239. }
  240. return null;
  241. }
  242. function useContents(children: Child[]) {
  243. const { pageId } = usePage();
  244. const { navigateWhenChanged } = useNavigateCustom();
  245. const { canAccess, initialized } = useAuth();
  246. const [shouldOpen, setShouldOpen] = React.useState(false);
  247. const elements = React.useMemo(() => {
  248. setShouldOpen(false);
  249. return children
  250. .filter(({ id }) => canAccess(id))
  251. .map(({ label, id, option }, index) => {
  252. const selected = id === pageId;
  253. if (selected) {
  254. setShouldOpen(true);
  255. }
  256. const handleClick = () => {
  257. const path = getPath(id, option);
  258. console.log(path, id, option);
  259. navigateWhenChanged(path);
  260. };
  261. return (
  262. <ListItemButton
  263. selected={selected}
  264. sx={{ ...item, pl: 4 }}
  265. key={index}
  266. onClick={handleClick}
  267. >
  268. <ListItemText primary={label} />
  269. </ListItemButton>
  270. );
  271. });
  272. }, [pageId, initialized, canAccess]);
  273. return {
  274. elements,
  275. shouldOpen,
  276. };
  277. }