Просмотр исходного кода

パスワード変更機能追加

develop
sosuke.iwabuchi 2 лет назад
Родитель
Сommit
5a96abdaf0
12 измененных файлов: 269 добавлений и 73 удалений
  1. +5
    -0
      src/api/index.ts
  2. +23
    -1
      src/api/login-user.ts
  3. +1
    -0
      src/api/url.ts
  4. +1
    -0
      src/codes/page.ts
  5. +7
    -0
      src/contexts/AuthContext.tsx
  6. +82
    -61
      src/layouts/dashbord/navigator.tsx
  7. +132
    -0
      src/pages/dashboard/login-user/change-password.tsx
  8. +1
    -1
      src/pages/dashboard/login-user/create.tsx
  9. +7
    -10
      src/pages/dashboard/login-user/list.tsx
  10. +1
    -0
      src/routes/auth.ts
  11. +7
    -0
      src/routes/index.tsx
  12. +2
    -0
      src/routes/path.ts

+ 5
- 0
src/api/index.ts Просмотреть файл

@@ -31,6 +31,7 @@ export const ApiId = {

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

// FOR CUSTOM
HT_CUSTOM_CUSTOMERS: id++,
@@ -55,6 +56,10 @@ export const ResultCode = {
};
export type ResultCode = (typeof ResultCode)[keyof typeof ResultCode];

export interface TimestampRequest {
timestamp: string;
}

export interface APICommonResponse {
result: ResultCode;
messages: {


+ 23
- 1
src/api/login-user.ts Просмотреть файл

@@ -1,4 +1,11 @@
import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from ".";
import {
APICommonResponse,
ApiId,
HttpMethod,
TimestampRequest,
makeParam,
request,
} from ".";
import { getUrl } from "./url";

export type LoginUser = {
@@ -46,3 +53,18 @@ export const createLoginUser = async (data: LoginUserCreateRequest) => {
});
return res;
};

// パスワード変更
export type ChangePasswordRequest = {
password: string;
id?: string; // UserID
} & TimestampRequest;

export const changeLoginPassword = async (data: ChangePasswordRequest) => {
const res = await request({
url: getUrl(ApiId.LOGIN_USER_CHANGE_PASSWORD),
method: HttpMethod.POST,
data: makeParam(data),
});
return res;
};

+ 1
- 0
src/api/url.ts Просмотреть файл

@@ -21,6 +21,7 @@ const urls = {
[A.CONTRACTS]: "contracts",
[A.LOGIN_USERS]: "users",
[A.LOGIN_USER_CREATE]: "user/create",
[A.LOGIN_USER_CHANGE_PASSWORD]: "user/change-password",

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


+ 1
- 0
src/codes/page.ts Просмотреть файл

@@ -20,6 +20,7 @@ export const PageID = {

DASHBOARD_LOGIN_USER_LIST: id++,
DASHBOARD_LOGIN_USER_CREATE: id++,
DASHBOARD_LOGIN_USER_CHANGE_PASSWORD: id++,

PAGE_403: id++,
PAGE_404: id++,


+ 7
- 0
src/contexts/AuthContext.tsx Просмотреть файл

@@ -22,6 +22,7 @@ type Auth = {

role: UserRole;
contractId: string | null;
userId: string | null;
name: string;
custom: CustomCode[];
customerName: string;
@@ -41,6 +42,7 @@ export const AuthContext = createContext<Auth>({

role: UserRole.NONE,
contractId: null,
userId: null,
name: "",
custom: [],
customerName: "",
@@ -57,6 +59,7 @@ function AuthContextProvider({ children }: Props) {
const [initialized, setInitialized] = useState(false);
const [role, setRole] = useState<UserRole>(UserRole.NONE);
const [contractId, setContractId] = useState<string | null>(null);
const [userId, setUserId] = useState<string | null>(null);
const [name, setName] = useState("");
const [custom, setCustom] = useState<CustomCode[]>([]);
const [customerName, setCustomerName] = useState("");
@@ -69,6 +72,7 @@ function AuthContextProvider({ children }: Props) {
apiMethod: me,
onSuccess: (res) => {
setContractId(res.data.contract_id);
setUserId(res.data.id);
setRole(res.data.role);
setName(res.data.name);
setCustom(res.data.custom ?? []);
@@ -84,6 +88,7 @@ function AuthContextProvider({ children }: Props) {
apiMethod: APILogin,
onSuccess: (res) => {
setContractId(res.data.contract_id);
setUserId(res.data.id);
setRole(res.data.role);
setName(res.data.name);
setCustom(res.data.custom ?? []);
@@ -101,6 +106,7 @@ function AuthContextProvider({ children }: Props) {
const clear = () => {
setRole(UserRole.NONE);
setContractId(null);
setUserId(null);
setName("");
setCustom([]);
};
@@ -178,6 +184,7 @@ function AuthContextProvider({ children }: Props) {
authenticated,
role,
contractId,
userId,
name,
custom,



+ 82
- 61
src/layouts/dashbord/navigator.tsx Просмотреть файл

@@ -3,6 +3,7 @@ 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 AccountBoxIcon from "@mui/icons-material/AccountBox";
import { Collapse } from "@mui/material";
import Box from "@mui/material/Box";
import Divider from "@mui/material/Divider";
@@ -17,7 +18,7 @@ import useAuth from "hooks/useAuth";
import useNavigateCustom from "hooks/useNavigateCustom";
import usePage from "hooks/usePage";
import * as React from "react";
import { getPath } from "routes/path";
import { PathOption, getPath } from "routes/path";

type Group = {
label: string;
@@ -31,69 +32,15 @@ type SubGroup = {

// 子要素を持たない場合は設定
id?: PageID;
option?: PathOption;
};

type Child = {
label: string;
id: PageID;
option?: PathOption;
};

const categories: Group[] = [
{
label: "管理",
children: [
{
label: "契約",
icon: <PeopleIcon />,
children: [
{
id: PageID.DASHBOARD_CONTRACT_LIST,
label: "一覧",
},
{
id: PageID.DASHBOARD_CONTRACT_CREATE,
label: "作成",
},
],
},
{
label: "領収証発行依頼",
icon: <ArticleIcon />,
children: [
{
id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO,
label: "一覧",
},
{
id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO,
label: "新規",
},
],
},
{
label: "ユーザ管理",
icon: <PeopleIcon />,
children: [
{
id: PageID.DASHBOARD_LOGIN_USER_LIST,
label: "一覧",
},
{
id: PageID.DASHBOARD_LOGIN_USER_CREATE,
label: "作成",
},
],
},
],
},
{
label: "アカウント",
children: [
{ label: "ログアウト", icon: <SettingsIcon />, id: PageID.LOGOUT },
],
},
];

const item = {
py: "2px",
px: 3,
@@ -112,6 +59,79 @@ const itemCategory = {
export default function Navigator(props: DrawerProps) {
const { ...other } = props;

const { userId } = useAuth();

const categories: Group[] = [
{
label: "管理",
children: [
{
label: "契約",
icon: <PeopleIcon />,
children: [
{
id: PageID.DASHBOARD_CONTRACT_LIST,
label: "一覧",
},
{
id: PageID.DASHBOARD_CONTRACT_CREATE,
label: "作成",
},
],
},
{
label: "領収証発行依頼",
icon: <ArticleIcon />,
children: [
{
id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO,
label: "一覧",
},
{
id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO,
label: "新規",
},
],
},
{
label: "ユーザ管理",
icon: <PeopleIcon />,
children: [
{
id: PageID.DASHBOARD_LOGIN_USER_LIST,
label: "一覧",
},
{
id: PageID.DASHBOARD_LOGIN_USER_CREATE,
label: "作成",
},
],
},
],
},
{
label: "アカウント",
children: [
{
label: "アカウント編集",
icon: <AccountBoxIcon />,
children: [
{
id: PageID.DASHBOARD_LOGIN_USER_CHANGE_PASSWORD,
label: "パスワード変更",
option: {
query: {
id: userId ?? "empty",
},
},
},
],
},
{ label: "ログアウト", icon: <SettingsIcon />, id: PageID.LOGOUT },
],
},
];

return (
<Drawer variant="permanent" {...other}>
<List disablePadding>
@@ -155,7 +175,7 @@ function Group(group: Group) {
);
}

function SubGroup({ icon, label, id, children }: SubGroup) {
function SubGroup({ icon, label, id, children, option }: SubGroup) {
const { pageId } = usePage();
const { navigateWhenChanged } = useNavigateCustom();

@@ -191,7 +211,7 @@ function SubGroup({ icon, label, id, children }: SubGroup) {
if (id !== undefined) {
const handleClick = () => {
if (id) {
const path = getPath(id);
const path = getPath(id, option);
navigateWhenChanged(path);
}
};
@@ -217,14 +237,15 @@ function useContents(children: Child[]) {
setShouldOpen(false);
return children
.filter(({ id }) => canAccess(id))
.map(({ label, id }, index) => {
.map(({ label, id, option }, index) => {
const selected = id === pageId;
if (selected) {
setShouldOpen(true);
}

const handleClick = () => {
const path = getPath(id);
const path = getPath(id, option);
console.log(path, id, option);
navigateWhenChanged(path);
};



+ 132
- 0
src/pages/dashboard/login-user/change-password.tsx Просмотреть файл

@@ -0,0 +1,132 @@
import { yupResolver } from "@hookform/resolvers/yup";
import { Box, Button, Card, Stack, Typography } from "@mui/material";
import { HasChildren } from "@types";
import {
changeLoginPassword,
createLoginUser,
getLoginUsers,
} 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, useState } from "react";
import { useForm } from "react-hook-form";
import { useParams } from "react-router-dom";
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 = {
password: string;
password_retype: string;
};

export default function ChangePassword() {
const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_LOGIN_USER_CHANGE_PASSWORD,
TabID.NONE
);

const { success, error } = useSnackbarCustom();

const { id: paramUserId } = useParams();

const [timestamp, setTimestamp] = useState("");

const [mode, setMode] = useState<"input" | "done">("input");

const form = useForm<FormProps>({
defaultValues: {
password: "",
password_retype: "",
},
resolver: yupResolver(
Yup.object().shape({
password: Yup.string().required("必須項目です"),
password_retype: Yup.string()
.required("必須項目です")
.test("retype", "入力が一致しません", function (value) {
return this.parent.password === value;
}),
})
),
});

const { callAPI: callGetLoginUsers } = useAPICall({
apiMethod: getLoginUsers,
onSuccess: ({ data: { records } }) => {
if (records.length === 1) {
setTimestamp(records[0].updated_at);
}
},
});

const { callAPI: callChangeLoginPassword } = useAPICall({
apiMethod: changeLoginPassword,
backDrop: true,
form,
onSuccess: () => {
success("登録しました");
setMode("done");
},
onFailed: () => {
error("失敗しました");
},
});

const fetch = () => {
callGetLoginUsers({
id: paramUserId,
});
};

const handleSubmt = (data: FormProps) => {
callChangeLoginPassword({ ...data, timestamp });
};

useEffect(() => {
setHeaderTitle("パスワード変更");
setTabs(null);
fetch();
}, []);

return (
<>
{mode === "input" && (
<FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmt)}>
<Box>
<Stack spacing={2}>
<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>
)}
{mode === "done" && <Box>変更完了しました</Box>}
</>
);
}

+ 1
- 1
src/pages/dashboard/login-user/create.tsx Просмотреть файл

@@ -102,7 +102,7 @@ export default function LoginUserCreate() {
<AreaBox title="ログインパスワード">
<RHFTextField name="password" type="password" />
</AreaBox>
<AreaBox title="ログインパスワード(再入力">
<AreaBox title="ログインパスワード(再入力">
<RHFTextField name="password_retype" type="password" />
</AreaBox>
<Stack direction="row">


+ 7
- 10
src/pages/dashboard/login-user/list.tsx Просмотреть файл

@@ -288,16 +288,13 @@ function Row({ data }: RowProps) {
const { navigateWhenChanged } = useNavigateCustom();

const handleClick = () => {
// navigateWhenChanged(
// getPath(
// PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO,
// {
// query: {
// id: data.id,
// },
// }
// )
// );
navigateWhenChanged(
getPath(PageID.DASHBOARD_LOGIN_USER_CHANGE_PASSWORD, {
query: {
id: data.id,
},
})
);
};

return (


+ 1
- 0
src/routes/auth.ts Просмотреть файл

@@ -34,6 +34,7 @@ export const AUTH = {
),
[P.DASHBOARD_LOGIN_USER_LIST]: setAuth("ge", R.CONTRACT_ADMIN),
[P.DASHBOARD_LOGIN_USER_CREATE]: setAuth("ge", R.CONTRACT_ADMIN),
[P.DASHBOARD_LOGIN_USER_CHANGE_PASSWORD]: setAuth("ge", R.NORMAL_ADMIN),

[P.PAGE_403]: setAuth("all"),
[P.PAGE_404]: setAuth("all"),


+ 7
- 0
src/routes/index.tsx Просмотреть файл

@@ -89,6 +89,10 @@ const DashboardRoutes = (): RouteObject => {
pageId: PageID.DASHBOARD_LOGIN_USER_CREATE,
element: <LoginUserCreate />,
},
{
pageId: PageID.DASHBOARD_LOGIN_USER_CHANGE_PASSWORD,
element: <ChangePassword />,
},
];

const children: RouteObject[] = useMemo(() => {
@@ -172,6 +176,9 @@ const LoginUserList = Loadable(
const LoginUserCreate = Loadable(
lazy(() => import("pages/dashboard/login-user/create"))
);
const ChangePassword = Loadable(
lazy(() => import("pages/dashboard/login-user/change-password"))
);

// その他 ---------------------------------
const Page403 = Loadable(lazy(() => import("pages/common/Page403")));


+ 2
- 0
src/routes/path.ts Просмотреть файл

@@ -66,6 +66,8 @@ const PATHS = {
"/dashboard/login-user/list/:page",
[makePathKey(PageID.DASHBOARD_LOGIN_USER_CREATE)]:
"/dashboard/login-user/create",
[makePathKey(PageID.DASHBOARD_LOGIN_USER_CHANGE_PASSWORD)]:
"/dashboard/login-user/change-password/:id",

// その他
[makePathKey(PageID.PAGE_403)]: "403",


Загрузка…
Отмена
Сохранить