| @@ -29,6 +29,9 @@ export const ApiId = { | |||||
| CONTRACTS: id++, | CONTRACTS: id++, | ||||
| LOGIN_USERS: id++, | |||||
| LOGIN_USER_CREATE: id++, | |||||
| // FOR CUSTOM | // FOR CUSTOM | ||||
| HT_CUSTOM_CUSTOMERS: id++, | HT_CUSTOM_CUSTOMERS: id++, | ||||
| HT_CUSTOM_PARKINGS: id++, | HT_CUSTOM_PARKINGS: id++, | ||||
| @@ -0,0 +1,48 @@ | |||||
| import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from "."; | |||||
| import { getUrl } from "./url"; | |||||
| export type LoginUser = { | |||||
| id: string; | |||||
| name: string; | |||||
| email: string; | |||||
| contract_id: string; | |||||
| updated_at: string; | |||||
| }; | |||||
| // ログインユーザー一覧取得 ----------------------- | |||||
| export type LoginUsersRequest = { | |||||
| id?: string; | |||||
| name?: string; | |||||
| email?: string; | |||||
| }; | |||||
| export type LoginUsersResponse = { | |||||
| data: { | |||||
| records: LoginUser[]; | |||||
| }; | |||||
| } & APICommonResponse; | |||||
| export const getLoginUsers = async (data: LoginUsersRequest) => { | |||||
| const res = await request<LoginUsersResponse>({ | |||||
| url: getUrl(ApiId.LOGIN_USERS), | |||||
| method: HttpMethod.GET, | |||||
| data: new URLSearchParams(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| // ログインユーザー新規作成 | |||||
| export type LoginUserCreateRequest = { | |||||
| name: string; | |||||
| email: string; | |||||
| password: string; | |||||
| }; | |||||
| export const createLoginUser = async (data: LoginUserCreateRequest) => { | |||||
| const res = await request({ | |||||
| url: getUrl(ApiId.LOGIN_USER_CREATE), | |||||
| method: HttpMethod.POST, | |||||
| data: makeParam(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| @@ -19,6 +19,8 @@ const urls = { | |||||
| [A.RECEIPT_ISSUING_ORDERS]: "receipt-issuing-orders", | [A.RECEIPT_ISSUING_ORDERS]: "receipt-issuing-orders", | ||||
| [A.CONTRACTS]: "contracts", | [A.CONTRACTS]: "contracts", | ||||
| [A.LOGIN_USERS]: "users", | |||||
| [A.LOGIN_USER_CREATE]: "user/create", | |||||
| // FOR CUSTOM | // FOR CUSTOM | ||||
| [A.HT_CUSTOM_CUSTOMERS]: "custom/hello-techno/customers", | [A.HT_CUSTOM_CUSTOMERS]: "custom/hello-techno/customers", | ||||
| @@ -18,6 +18,9 @@ export const PageID = { | |||||
| DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO: id++, | DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO: id++, | ||||
| DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO: id++, | DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO: id++, | ||||
| DASHBOARD_LOGIN_USER_LIST: id++, | |||||
| DASHBOARD_LOGIN_USER_CREATE: id++, | |||||
| PAGE_403: id++, | PAGE_403: id++, | ||||
| PAGE_404: id++, | PAGE_404: id++, | ||||
| } as const; | } as const; | ||||
| @@ -1,6 +1,7 @@ | |||||
| import { ExpandLess, ExpandMore } from "@mui/icons-material"; | import { ExpandLess, ExpandMore } from "@mui/icons-material"; | ||||
| import HomeIcon from "@mui/icons-material/Home"; | import HomeIcon from "@mui/icons-material/Home"; | ||||
| import PeopleIcon from "@mui/icons-material/People"; | import PeopleIcon from "@mui/icons-material/People"; | ||||
| import ArticleIcon from "@mui/icons-material/Article"; | |||||
| import SettingsIcon from "@mui/icons-material/Settings"; | import SettingsIcon from "@mui/icons-material/Settings"; | ||||
| import { Collapse } from "@mui/material"; | import { Collapse } from "@mui/material"; | ||||
| import Box from "@mui/material/Box"; | import Box from "@mui/material/Box"; | ||||
| @@ -57,7 +58,7 @@ const categories: Group[] = [ | |||||
| }, | }, | ||||
| { | { | ||||
| label: "領収証発行依頼", | label: "領収証発行依頼", | ||||
| icon: <PeopleIcon />, | |||||
| icon: <ArticleIcon />, | |||||
| children: [ | children: [ | ||||
| { | { | ||||
| id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO, | id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO, | ||||
| @@ -69,6 +70,20 @@ const categories: Group[] = [ | |||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | |||||
| label: "ユーザ管理", | |||||
| icon: <PeopleIcon />, | |||||
| children: [ | |||||
| { | |||||
| id: PageID.DASHBOARD_LOGIN_USER_LIST, | |||||
| label: "一覧", | |||||
| }, | |||||
| { | |||||
| id: PageID.DASHBOARD_LOGIN_USER_CREATE, | |||||
| label: "作成", | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| ], | ], | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -103,7 +118,7 @@ export default function Navigator(props: DrawerProps) { | |||||
| <ListItem | <ListItem | ||||
| sx={{ ...item, ...itemCategory, fontSize: 22, color: "#fff" }} | sx={{ ...item, ...itemCategory, fontSize: 22, color: "#fff" }} | ||||
| > | > | ||||
| SateReceipt | |||||
| EasyReceipt | |||||
| </ListItem> | </ListItem> | ||||
| <ListItem sx={{ ...item, ...itemCategory }}> | <ListItem sx={{ ...item, ...itemCategory }}> | ||||
| <ListItemIcon> | <ListItemIcon> | ||||
| @@ -0,0 +1,117 @@ | |||||
| import { yupResolver } from "@hookform/resolvers/yup"; | |||||
| import { Box, Button, Card, Stack, Typography } from "@mui/material"; | |||||
| import { HasChildren } from "@types"; | |||||
| import { createLoginUser } from "api/login-user"; | |||||
| import { PageID, TabID } from "codes/page"; | |||||
| import { FormProvider, RHFTextField } from "components/hook-form"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useDashboard from "hooks/useDashBoard"; | |||||
| import useNavigateCustom from "hooks/useNavigateCustom"; | |||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | |||||
| import { useSnackbar } from "notistack"; | |||||
| import { useEffect } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import { getPath } from "routes/path"; | |||||
| import * as Yup from "yup"; | |||||
| type AreaBoxProps = { | |||||
| title: string; | |||||
| } & HasChildren; | |||||
| function AreaBox({ title, children }: AreaBoxProps) { | |||||
| return ( | |||||
| <Box sx={{ maxWidth: 500 }}> | |||||
| <Typography variant="subtitle1">{title}</Typography> | |||||
| {children} | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| name: string; | |||||
| email: string; | |||||
| password: string; | |||||
| password_retype: string; | |||||
| }; | |||||
| export default function LoginUserCreate() { | |||||
| const { setHeaderTitle, setTabs } = useDashboard( | |||||
| PageID.DASHBOARD_LOGIN_USER_CREATE, | |||||
| TabID.NONE | |||||
| ); | |||||
| const { success, error } = useSnackbarCustom(); | |||||
| const { navigateWhenChanged } = useNavigateCustom(); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| name: "", | |||||
| email: "", | |||||
| password: "", | |||||
| password_retype: "", | |||||
| }, | |||||
| resolver: yupResolver( | |||||
| Yup.object().shape({ | |||||
| name: Yup.string().required("必須項目です"), | |||||
| email: Yup.string().required("必須項目です"), | |||||
| password: Yup.string().required("必須項目です"), | |||||
| password_retype: Yup.string() | |||||
| .required("必須項目です") | |||||
| .test("retype", "入力が一致しません", function (value) { | |||||
| return this.parent.password === value; | |||||
| }), | |||||
| }) | |||||
| ), | |||||
| }); | |||||
| const { callAPI } = useAPICall({ | |||||
| apiMethod: createLoginUser, | |||||
| backDrop: true, | |||||
| form, | |||||
| onSuccess: (res, sendData) => { | |||||
| success("登録しました"); | |||||
| navigateWhenChanged( | |||||
| getPath(PageID.DASHBOARD_LOGIN_USER_LIST, { | |||||
| query: { email: sendData.email }, | |||||
| }) | |||||
| ); | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const handleSubmt = (data: FormProps) => { | |||||
| callAPI({ ...data }); | |||||
| }; | |||||
| useEffect(() => { | |||||
| setHeaderTitle("ユーザ新規作成"); | |||||
| setTabs(null); | |||||
| }, []); | |||||
| return ( | |||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmt)}> | |||||
| <Box> | |||||
| <Stack spacing={2}> | |||||
| <AreaBox title="Email"> | |||||
| <RHFTextField name="email" type="email" /> | |||||
| </AreaBox> | |||||
| <AreaBox title="名前"> | |||||
| <RHFTextField name="name" /> | |||||
| </AreaBox> | |||||
| <AreaBox title="ログインパスワード"> | |||||
| <RHFTextField name="password" type="password" /> | |||||
| </AreaBox> | |||||
| <AreaBox title="ログインパスワード(再入力"> | |||||
| <RHFTextField name="password_retype" type="password" /> | |||||
| </AreaBox> | |||||
| <Stack direction="row"> | |||||
| <Button variant="contained" type="submit"> | |||||
| 登録 | |||||
| </Button> | |||||
| </Stack> | |||||
| </Stack> | |||||
| </Box> | |||||
| </FormProvider> | |||||
| ); | |||||
| } | |||||
| @@ -0,0 +1,309 @@ | |||||
| import { | |||||
| Box, | |||||
| Button, | |||||
| Dialog, | |||||
| DialogActions, | |||||
| DialogContent, | |||||
| DialogTitle, | |||||
| Drawer, | |||||
| FormControl, | |||||
| Grid, | |||||
| IconButton, | |||||
| Stack, | |||||
| Table, | |||||
| TableBody, | |||||
| TableCell, | |||||
| TableContainer, | |||||
| TablePagination, | |||||
| TableRow, | |||||
| TextField, | |||||
| Tooltip, | |||||
| Typography, | |||||
| } from "@mui/material"; | |||||
| import { Dictionary } from "@types"; | |||||
| import { | |||||
| ReceiptIssuingOrderHTCustom, | |||||
| getReceiptIssuingOrders, | |||||
| } from "api/custom/hello-techno/receipt-issuing-order"; | |||||
| import { PageID, TabID } from "codes/page"; | |||||
| import { | |||||
| FormProvider, | |||||
| RHFCheckbox, | |||||
| RHFSelect, | |||||
| RHFTextField, | |||||
| } from "components/hook-form"; | |||||
| import { TableHeadCustom } from "components/table"; | |||||
| import { SearchConditionContextProvider } from "contexts/SearchConditionContext"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useBackDrop from "hooks/useBackDrop"; | |||||
| import useDashboard from "hooks/useDashBoard"; | |||||
| import useNavigateCustom from "hooks/useNavigateCustom"; | |||||
| import useSearchConditionContext from "hooks/useSearchConditionContext"; | |||||
| import useTable, { UseTableReturn } from "hooks/useTable"; | |||||
| import { useEffect, useMemo, useState } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import { getPath } from "routes/path"; | |||||
| import AccountCircleIcon from "@mui/icons-material/AccountCircle"; | |||||
| import { RHFSelectMuiliple } from "components/hook-form/RHFSelect"; | |||||
| import useAuth from "hooks/useAuth"; | |||||
| import RHFDatePicker from "components/hook-form/RHFDatePicker"; | |||||
| import { dateParse, formatDateStr } from "utils/datetime"; | |||||
| import { Clear } from "@mui/icons-material"; | |||||
| import { LoginUser, getLoginUsers } from "api/login-user"; | |||||
| export default function LoginUserList() { | |||||
| const { setHeaderTitle, setTabs } = useDashboard( | |||||
| PageID.DASHBOARD_LOGIN_USER_LIST, | |||||
| TabID.NONE | |||||
| ); | |||||
| useEffect(() => { | |||||
| setHeaderTitle("ユーザ一覧"); | |||||
| setTabs(null); | |||||
| }, []); | |||||
| return ( | |||||
| <SearchConditionContextProvider> | |||||
| <Page /> | |||||
| </SearchConditionContextProvider> | |||||
| ); | |||||
| } | |||||
| function Page() { | |||||
| const table = useTable<LoginUser>(); | |||||
| return ( | |||||
| <Box> | |||||
| <SearchBox table={table} /> | |||||
| <TableBox table={table} /> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| name: string; | |||||
| email: string; | |||||
| }; | |||||
| type CommonProps = { | |||||
| table: UseTableReturn<LoginUser>; | |||||
| }; | |||||
| function SearchBox({ table }: CommonProps) { | |||||
| const { | |||||
| condition, | |||||
| initialized, | |||||
| get, | |||||
| addCondition: add, | |||||
| } = useSearchConditionContext(); | |||||
| const { setShowBackDrop } = useBackDrop(); | |||||
| const { name: myName } = useAuth(); | |||||
| const [openDateDialog, setOpenDateDialog] = useState(false); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| name: "", | |||||
| email: "", | |||||
| }, | |||||
| }); | |||||
| const { | |||||
| callAPI: callGetLoginUsers, | |||||
| makeSendData, | |||||
| sending, | |||||
| } = useAPICall({ | |||||
| apiMethod: getLoginUsers, | |||||
| form, | |||||
| onSuccess: (res) => { | |||||
| table.setRowData(res.data.records); | |||||
| }, | |||||
| }); | |||||
| const handleSubmit = async (data: FormProps) => { | |||||
| addCondition(data); | |||||
| }; | |||||
| const addCondition = (data: FormProps) => { | |||||
| add({ | |||||
| ...data, | |||||
| }); | |||||
| }; | |||||
| const handleBlur = () => { | |||||
| addCondition(form.getValues()); | |||||
| }; | |||||
| const fetch = async (data: Dictionary) => { | |||||
| const sendData = makeSendData({ | |||||
| ...data, | |||||
| }); | |||||
| callGetLoginUsers(sendData); | |||||
| }; | |||||
| // 初期値設定 | |||||
| useEffect(() => { | |||||
| if (initialized) { | |||||
| form.setValue("name", get("name")); | |||||
| form.setValue("email", get("email")); | |||||
| } | |||||
| }, [initialized, condition]); | |||||
| // Fetchアクション | |||||
| useEffect(() => { | |||||
| if (initialized) { | |||||
| fetch(condition); | |||||
| } | |||||
| }, [condition, initialized]); | |||||
| // バックドロップ | |||||
| useEffect(() => { | |||||
| setShowBackDrop(sending); | |||||
| }, [sending]); | |||||
| return ( | |||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | |||||
| <Box sx={{ p: 1, m: 1 }}> | |||||
| <Grid container spacing={2} mt={1}> | |||||
| <Grid item xs={3} lg={2}> | |||||
| <Stack> | |||||
| <Typography>名前</Typography> | |||||
| <RHFTextField name="name" onBlur={handleBlur} /> | |||||
| </Stack> | |||||
| </Grid> | |||||
| <Grid item xs={3} lg={2}> | |||||
| <Stack> | |||||
| <Typography>Email</Typography> | |||||
| <RHFTextField name="email" onBlur={handleBlur} /> | |||||
| </Stack> | |||||
| </Grid> | |||||
| </Grid> | |||||
| </Box> | |||||
| <Dialog | |||||
| open={openDateDialog} | |||||
| onClose={() => { | |||||
| setOpenDateDialog(false); | |||||
| }} | |||||
| > | |||||
| <DialogTitle>受付時刻検索条件</DialogTitle> | |||||
| <DialogContent> | |||||
| <Stack direction="row" spacing={2}> | |||||
| <Box> | |||||
| <Typography>From</Typography> | |||||
| <RHFDatePicker name="order_date_from" /> | |||||
| </Box> | |||||
| <Box> | |||||
| <Typography> </Typography> | |||||
| <Typography>~</Typography> | |||||
| </Box> | |||||
| <Box> | |||||
| <Typography>To</Typography> | |||||
| <RHFDatePicker name="order_date_to" /> | |||||
| </Box> | |||||
| </Stack> | |||||
| </DialogContent> | |||||
| <DialogActions> | |||||
| <Button | |||||
| onClick={() => { | |||||
| setOpenDateDialog(false); | |||||
| }} | |||||
| > | |||||
| 決定 | |||||
| </Button> | |||||
| </DialogActions> | |||||
| </Dialog> | |||||
| </FormProvider> | |||||
| ); | |||||
| } | |||||
| function TableBox({ table }: CommonProps) { | |||||
| const TABLE_HEAD = [ | |||||
| { id: "name", label: "名前", align: "left" }, | |||||
| { id: "email", label: "Email", align: "left" }, | |||||
| ]; | |||||
| const { | |||||
| order, | |||||
| page, | |||||
| sort, | |||||
| rowsPerPage, | |||||
| fetched, | |||||
| fillteredRow, | |||||
| isNotFound, | |||||
| dataLength, | |||||
| // | |||||
| onSort, | |||||
| onChangePage, | |||||
| onChangeRowsPerPage, | |||||
| // | |||||
| setRowData, | |||||
| // | |||||
| ROWS_PER_PAGES, | |||||
| } = table; | |||||
| return ( | |||||
| <> | |||||
| <TableContainer | |||||
| sx={{ | |||||
| // minWidth: 800, | |||||
| position: "relative", | |||||
| }} | |||||
| > | |||||
| <Table size="small"> | |||||
| <TableHeadCustom | |||||
| order={order} | |||||
| orderBy={sort} | |||||
| headLabel={TABLE_HEAD} | |||||
| rowCount={1} | |||||
| numSelected={0} | |||||
| onSort={onSort} | |||||
| /> | |||||
| <TableBody> | |||||
| {fillteredRow.map((row, index) => ( | |||||
| <Row data={row} key={index} /> | |||||
| ))} | |||||
| </TableBody> | |||||
| </Table> | |||||
| </TableContainer> | |||||
| <Box sx={{ position: "relative" }}> | |||||
| <TablePagination | |||||
| rowsPerPageOptions={ROWS_PER_PAGES} | |||||
| component="div" | |||||
| count={dataLength} | |||||
| rowsPerPage={rowsPerPage} | |||||
| page={page} | |||||
| onPageChange={onChangePage} | |||||
| onRowsPerPageChange={onChangeRowsPerPage} | |||||
| /> | |||||
| </Box> | |||||
| </> | |||||
| ); | |||||
| } | |||||
| type RowProps = { | |||||
| data: LoginUser; | |||||
| }; | |||||
| function Row({ data }: RowProps) { | |||||
| const { navigateWhenChanged } = useNavigateCustom(); | |||||
| const handleClick = () => { | |||||
| // navigateWhenChanged( | |||||
| // getPath( | |||||
| // PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO, | |||||
| // { | |||||
| // query: { | |||||
| // id: data.id, | |||||
| // }, | |||||
| // } | |||||
| // ) | |||||
| // ); | |||||
| }; | |||||
| return ( | |||||
| <TableRow hover sx={{ cursor: "pointer" }} onClick={handleClick}> | |||||
| <TableCell>{data.name}</TableCell> | |||||
| <TableCell>{data.email}</TableCell> | |||||
| </TableRow> | |||||
| ); | |||||
| } | |||||
| @@ -32,6 +32,8 @@ export const AUTH = { | |||||
| R.NORMAL_ADMIN, | R.NORMAL_ADMIN, | ||||
| [C.HELLO_TECHNO] | [C.HELLO_TECHNO] | ||||
| ), | ), | ||||
| [P.DASHBOARD_LOGIN_USER_LIST]: setAuth("ge", R.CONTRACT_ADMIN), | |||||
| [P.DASHBOARD_LOGIN_USER_CREATE]: setAuth("ge", R.CONTRACT_ADMIN), | |||||
| [P.PAGE_403]: setAuth("all"), | [P.PAGE_403]: setAuth("all"), | ||||
| [P.PAGE_404]: setAuth("all"), | [P.PAGE_404]: setAuth("all"), | ||||
| @@ -81,6 +81,14 @@ const DashboardRoutes = (): RouteObject => { | |||||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO, | pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO, | ||||
| element: <ReceiptIssuingOrderDetailHelloTechno />, | element: <ReceiptIssuingOrderDetailHelloTechno />, | ||||
| }, | }, | ||||
| { | |||||
| pageId: PageID.DASHBOARD_LOGIN_USER_LIST, | |||||
| element: <LoginUserList />, | |||||
| }, | |||||
| { | |||||
| pageId: PageID.DASHBOARD_LOGIN_USER_CREATE, | |||||
| element: <LoginUserCreate />, | |||||
| }, | |||||
| ]; | ]; | ||||
| const children: RouteObject[] = useMemo(() => { | const children: RouteObject[] = useMemo(() => { | ||||
| @@ -157,6 +165,14 @@ const ReceiptIssuingOrderDetailHelloTechno = Loadable( | |||||
| ) | ) | ||||
| ); | ); | ||||
| // ログインユーザー管理 | |||||
| const LoginUserList = Loadable( | |||||
| lazy(() => import("pages/dashboard/login-user/list")) | |||||
| ); | |||||
| const LoginUserCreate = Loadable( | |||||
| lazy(() => import("pages/dashboard/login-user/create")) | |||||
| ); | |||||
| // その他 --------------------------------- | // その他 --------------------------------- | ||||
| const Page403 = Loadable(lazy(() => import("pages/common/Page403"))); | const Page403 = Loadable(lazy(() => import("pages/common/Page403"))); | ||||
| const Page404 = Loadable(lazy(() => import("pages/common/Page404"))); | const Page404 = Loadable(lazy(() => import("pages/common/Page404"))); | ||||
| @@ -61,6 +61,12 @@ const PATHS = { | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO | PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO | ||||
| )]: "/dashboard/receipt-issusing-order/detail/:id", | )]: "/dashboard/receipt-issusing-order/detail/:id", | ||||
| // ログインユーザ管理 | |||||
| [makePathKey(PageID.DASHBOARD_LOGIN_USER_LIST)]: | |||||
| "/dashboard/login-user/list/:page", | |||||
| [makePathKey(PageID.DASHBOARD_LOGIN_USER_CREATE)]: | |||||
| "/dashboard/login-user/create", | |||||
| // その他 | // その他 | ||||
| [makePathKey(PageID.PAGE_403)]: "403", | [makePathKey(PageID.PAGE_403)]: "403", | ||||
| [makePathKey(PageID.PAGE_404)]: "404", | [makePathKey(PageID.PAGE_404)]: "404", | ||||