From b6cc1b564fe36f5fe520635aa0b3a66464be4835 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Wed, 20 Sep 2023 13:41:20 +0900 Subject: [PATCH] =?UTF-8?q?Email=E5=A4=89=E6=9B=B4=E5=87=A6=E7=90=86?= =?UTF-8?q?=E3=80=80=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/customer.ts | 30 ++++- src/api/index.ts | 3 + src/api/url.ts | 2 + src/pages/auth/change-email-verify.tsx | 60 +++++++++ src/pages/common/Page404.tsx | 2 + .../dashboard/user/change-email-start.tsx | 121 ++++++++++++++++++ src/pages/dashboard/user/detail.tsx | 9 ++ src/pages/index.ts | 2 + src/routes/index.tsx | 7 + src/routes/path.ts | 3 + src/routes/sub/dashboard.tsx | 7 + 11 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 src/pages/auth/change-email-verify.tsx create mode 100644 src/pages/dashboard/user/change-email-start.tsx diff --git a/src/api/customer.ts b/src/api/customer.ts index 787c2b2..a6b87d5 100644 --- a/src/api/customer.ts +++ b/src/api/customer.ts @@ -1,4 +1,4 @@ -import { ApiId, HttpMethod, makeFormData, request } from "api"; +import { ApiId, HttpMethod, makeFormData, makeParam, request } from "api"; import { getUrl } from "./url"; // -------学生証アップロード--------------- @@ -34,3 +34,31 @@ export const uploadOtherLicenseImages = async ( }); return res; }; + +// -------Email変更手続き開始--------------- +export type StartChangeEmailRequest = { + new_email: string; +}; +export const startChangeEmail = async (param: StartChangeEmailRequest) => { + const sendData = makeParam(param); + const res = await request({ + url: getUrl(ApiId.START_CHANGE_EMAIL), + method: HttpMethod.POST, + data: sendData, + }); + return res; +}; + +// -------Email変更手続き認証--------------- +export type VerifyChangeEmailRequest = { + token: string; +}; +export const verifyChangeEmail = async (param: VerifyChangeEmailRequest) => { + const sendData = makeParam(param); + const res = await request({ + url: getUrl(ApiId.VERIFY_CHANGE_EMAIL), + method: HttpMethod.POST, + data: sendData, + }); + return res; +}; diff --git a/src/api/index.ts b/src/api/index.ts index a014be6..4c989ca 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -28,6 +28,9 @@ export const ApiId = { UPLOAD_STUDENT_LICENSE_IMAGES: id++, UPLOAD_OTHER_LICENSE_IMAGES: id++, + + START_CHANGE_EMAIL: id++, + VERIFY_CHANGE_EMAIL: id++, } as const; export type ApiId = (typeof ApiId)[keyof typeof ApiId]; diff --git a/src/api/url.ts b/src/api/url.ts index 7d5fc89..3b5e3f7 100644 --- a/src/api/url.ts +++ b/src/api/url.ts @@ -20,6 +20,8 @@ const urls = { [A.ASK]: "ask", [A.UPLOAD_STUDENT_LICENSE_IMAGES]: "upload/student-license-images", [A.UPLOAD_OTHER_LICENSE_IMAGES]: "upload/other-license-images", + [A.START_CHANGE_EMAIL]: "email/change/start", + [A.VERIFY_CHANGE_EMAIL]: "email/change/verify", }; const prefixs = { diff --git a/src/pages/auth/change-email-verify.tsx b/src/pages/auth/change-email-verify.tsx new file mode 100644 index 0000000..3c57de4 --- /dev/null +++ b/src/pages/auth/change-email-verify.tsx @@ -0,0 +1,60 @@ +import { Box, Button, Stack } from "@mui/material"; +import { verifyChangeEmail } from "api/customer"; +import useAPICall from "hooks/useAPICall"; +import useAuth from "hooks/useAuth"; +import useNavigateCustom from "hooks/useNavigateCustom"; +import { PageID } from "pages"; +import { useEffect, useState } from "react"; +import { useParams } from "react-router-dom"; +import { getPath } from "routes/path"; + +export default function ChangeEmailStart() { + const { logout, initialized } = useAuth(); + const { navigateWhenChanged } = useNavigateCustom(); + const { token: paramToken } = useParams(); + + const [done, setDone] = useState(null); + + const { callAPI: callVerifyChangeEmail } = useAPICall({ + apiMethod: verifyChangeEmail, + backDrop: true, + onSuccess: () => { + setDone(true); + logout(); + }, + onFailed: () => { + setDone(false); + }, + }); + + const toLogin = () => { + navigateWhenChanged(getPath(PageID.LOGIN)); + }; + + useEffect(() => { + if (!paramToken) { + setDone(false); + return; + } + if (initialized) { + callVerifyChangeEmail({ token: paramToken }); + } + }, [paramToken, initialized]); + + if (done === true) { + return ( + + + 新規メールアドレスに変更手続きのご案内を送信しました。ご確認ください。 + + + + + + ); + } else if (done === false) { + return 認証に失敗しました。再度お試しください。; + } + + return null; +} diff --git a/src/pages/common/Page404.tsx b/src/pages/common/Page404.tsx index ba85ee4..bda62cd 100644 --- a/src/pages/common/Page404.tsx +++ b/src/pages/common/Page404.tsx @@ -12,9 +12,11 @@ export default function Page404() { useEffect(() => { if (!initialized) return; if (authenticated) { + console.log("404 to dashboard"); navigateWhenChanged(getPath(PageID.DASHBOARD_OVERVIEW)); return; } else { + console.log("404 to login"); navigateWhenChanged(getPath(PageID.LOGIN)); return; } diff --git a/src/pages/dashboard/user/change-email-start.tsx b/src/pages/dashboard/user/change-email-start.tsx new file mode 100644 index 0000000..eaa4466 --- /dev/null +++ b/src/pages/dashboard/user/change-email-start.tsx @@ -0,0 +1,121 @@ +import { yupResolver } from "@hookform/resolvers/yup"; +import { Box, Button, Stack, Typography } from "@mui/material"; +import { HasChildren } from "@types"; +import { startChangeEmail } from "api/customer"; +import RequireChip from "components/chip/RequireChip"; +import InputAlert from "components/form/InputAlert"; +import { FormProvider, RHFTextField } from "components/hook-form"; +import StackRow from "components/stack/StackRow"; +import useAPICall from "hooks/useAPICall"; +import useAuth from "hooks/useAuth"; +import useDashboard from "hooks/useDashBoard"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import { PageID, TabID } from "pages"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import * as Yup from "yup"; + +type AreaBoxProps = { + label: string; + require?: boolean; +} & HasChildren; +function AreaBox({ label, children, require }: AreaBoxProps) { + return ( + + + 〇{label} + + + {children} + + ); +} + +type FormProps = { + new_email: string; + email_retype: string; +}; + +export default function ChangeEmailStart() { + const { setHeaderTitle, setTabs } = useDashboard( + PageID.DASHBOARD_USER_CHANGE_EMAIL_START, + TabID.NONE + ); + + const { user } = useAuth(); + + const [done, setDone] = useState(false); + const { error } = useSnackbarCustom(); + + const form = useForm({ + defaultValues: { + new_email: "", + email_retype: "", + }, + resolver: yupResolver( + Yup.object().shape({ + new_email: Yup.string().required("必須項目です"), + email_retype: Yup.string() + .required("必須項目です") + .test("retype", "一致しません", function (value) { + return value === this.parent.new_email; + }), + }) + ), + }); + + const { + callAPI: callStartChangeEmail, + errorMode, + generalErrorMessage, + } = useAPICall({ + apiMethod: startChangeEmail, + backDrop: true, + form, + onSuccess: () => { + setDone(true); + }, + onFailed: () => { + error("失敗しました"); + }, + }); + + const handleSubmit = (data: FormProps) => { + callStartChangeEmail({ new_email: data.new_email }); + }; + + useEffect(() => { + setHeaderTitle("メールアドレス変更"); + setTabs(null); + }, []); + + if (done) { + return ( + + 新規メールアドレスに変更手続きのご案内を送信しました。ご確認ください。 + + ); + } + + return ( + + + + + + + + <> + 確認のため再度入力してください + + + + + + + + + ); +} diff --git a/src/pages/dashboard/user/detail.tsx b/src/pages/dashboard/user/detail.tsx index 753e394..cfbf417 100644 --- a/src/pages/dashboard/user/detail.tsx +++ b/src/pages/dashboard/user/detail.tsx @@ -21,6 +21,15 @@ export default function UserDetail() { return ( +