Pārlūkot izejas kodu

ログインユーザー機能 拡充

develop
sosuke.iwabuchi pirms 2 gadiem
vecāks
revīzija
df55f04e43
10 mainītis faili ar 523 papildinājumiem un 2 dzēšanām
  1. +3
    -0
      src/api/index.ts
  2. +48
    -0
      src/api/login-user.ts
  3. +2
    -0
      src/api/url.ts
  4. +3
    -0
      src/codes/page.ts
  5. +17
    -2
      src/layouts/dashbord/navigator.tsx
  6. +117
    -0
      src/pages/dashboard/login-user/create.tsx
  7. +309
    -0
      src/pages/dashboard/login-user/list.tsx
  8. +2
    -0
      src/routes/auth.ts
  9. +16
    -0
      src/routes/index.tsx
  10. +6
    -0
      src/routes/path.ts

+ 3
- 0
src/api/index.ts Parādīt failu

@@ -29,6 +29,9 @@ export const ApiId = {

CONTRACTS: id++,

LOGIN_USERS: id++,
LOGIN_USER_CREATE: id++,

// FOR CUSTOM
HT_CUSTOM_CUSTOMERS: id++,
HT_CUSTOM_PARKINGS: id++,


+ 48
- 0
src/api/login-user.ts Parādīt failu

@@ -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;
};

+ 2
- 0
src/api/url.ts Parādīt failu

@@ -19,6 +19,8 @@ const urls = {
[A.RECEIPT_ISSUING_ORDERS]: "receipt-issuing-orders",

[A.CONTRACTS]: "contracts",
[A.LOGIN_USERS]: "users",
[A.LOGIN_USER_CREATE]: "user/create",

// FOR CUSTOM
[A.HT_CUSTOM_CUSTOMERS]: "custom/hello-techno/customers",


+ 3
- 0
src/codes/page.ts Parādīt failu

@@ -18,6 +18,9 @@ export const PageID = {
DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_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_404: id++,
} as const;


+ 17
- 2
src/layouts/dashbord/navigator.tsx Parādīt failu

@@ -1,6 +1,7 @@
import { ExpandLess, ExpandMore } from "@mui/icons-material";
import HomeIcon from "@mui/icons-material/Home";
import PeopleIcon from "@mui/icons-material/People";
import ArticleIcon from "@mui/icons-material/Article";
import SettingsIcon from "@mui/icons-material/Settings";
import { Collapse } from "@mui/material";
import Box from "@mui/material/Box";
@@ -57,7 +58,7 @@ const categories: Group[] = [
},
{
label: "領収証発行依頼",
icon: <PeopleIcon />,
icon: <ArticleIcon />,
children: [
{
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
sx={{ ...item, ...itemCategory, fontSize: 22, color: "#fff" }}
>
SateReceipt
EasyReceipt
</ListItem>
<ListItem sx={{ ...item, ...itemCategory }}>
<ListItemIcon>


+ 117
- 0
src/pages/dashboard/login-user/create.tsx Parādīt failu

@@ -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>
);
}

+ 309
- 0
src/pages/dashboard/login-user/list.tsx Parādīt failu

@@ -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>&nbsp;</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>
);
}

+ 2
- 0
src/routes/auth.ts Parādīt failu

@@ -32,6 +32,8 @@ export const AUTH = {
R.NORMAL_ADMIN,
[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_404]: setAuth("all"),


+ 16
- 0
src/routes/index.tsx Parādīt failu

@@ -81,6 +81,14 @@ const DashboardRoutes = (): RouteObject => {
pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO,
element: <ReceiptIssuingOrderDetailHelloTechno />,
},
{
pageId: PageID.DASHBOARD_LOGIN_USER_LIST,
element: <LoginUserList />,
},
{
pageId: PageID.DASHBOARD_LOGIN_USER_CREATE,
element: <LoginUserCreate />,
},
];

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 Page404 = Loadable(lazy(() => import("pages/common/Page404")));

+ 6
- 0
src/routes/path.ts Parādīt failu

@@ -61,6 +61,12 @@ const PATHS = {
PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO
)]: "/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_404)]: "404",


Notiek ielāde…
Atcelt
Saglabāt