| @@ -10,6 +10,8 @@ export type Me = { | |||||
| address: string; | address: string; | ||||
| phone_no: string; | phone_no: string; | ||||
| customer_code: string; | customer_code: string; | ||||
| can_pay_by_creditcard: boolean; | |||||
| can_apply_to_change_payment_method_creditcard: boolean; | |||||
| }; | }; | ||||
| type MeResponse = { | type MeResponse = { | ||||
| @@ -51,7 +51,7 @@ export const orderCustomerInfoUpdate = async ( | |||||
| return res; | return res; | ||||
| }; | }; | ||||
| // -------利用者情報変更申請--------------- | |||||
| // -------口座振替登録用パラメータ取得--------------- | |||||
| export type GetRegisterBankAccountStartParamResponse = { | export type GetRegisterBankAccountStartParamResponse = { | ||||
| data: { | data: { | ||||
| url: string; | url: string; | ||||
| @@ -65,3 +65,12 @@ export const getRegisterBankAccountStartParam = async () => { | |||||
| }); | }); | ||||
| return res; | return res; | ||||
| }; | }; | ||||
| // -------クレジットカード利用申請--------------- | |||||
| export const orderChangePaymentMetodCreditcard = async (param: {}) => { | |||||
| const res = await request({ | |||||
| url: getUrl(ApiId.CUSTOMER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER), | |||||
| method: HttpMethod.POST, | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| @@ -53,6 +53,10 @@ export const ApiId = { | |||||
| VERIFY_CHANGE_EMAIL: id++, | VERIFY_CHANGE_EMAIL: id++, | ||||
| CUSTOMER_UPDATE_INFO_ORDER: id++, | CUSTOMER_UPDATE_INFO_ORDER: id++, | ||||
| CUSTOMER_REGISTER_BANK_ACCOUNT_START_PARAM: id++, | CUSTOMER_REGISTER_BANK_ACCOUNT_START_PARAM: id++, | ||||
| CUSTOMER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER: id++, | |||||
| // ロボットペイメント関連 | |||||
| ROBOT_PAYMENT_CREDITCARD_TOKEN_CHECK: id++, | |||||
| } as const; | } as const; | ||||
| export type ApiId = (typeof ApiId)[keyof typeof ApiId]; | export type ApiId = (typeof ApiId)[keyof typeof ApiId]; | ||||
| @@ -0,0 +1,35 @@ | |||||
| import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from "api"; | |||||
| import { getUrl } from "./url"; | |||||
| // -------領収証一覧取得--------------- | |||||
| export type CheckTokenRequest = { | |||||
| token: string; | |||||
| }; | |||||
| export type CheckTokenResponse = { | |||||
| data: { | |||||
| url: string; | |||||
| shop_code: string; | |||||
| customer_code: string; | |||||
| token: string; | |||||
| payment_type: string; | |||||
| job_type: string; | |||||
| tax: string; | |||||
| send_fee: string; | |||||
| amount: string; | |||||
| interval: string; | |||||
| payment_day: string; | |||||
| auto_amount: string; | |||||
| target_date: string; | |||||
| email: string; | |||||
| phone_number: string; | |||||
| order_no: string; | |||||
| }; | |||||
| } & APICommonResponse; | |||||
| export const checkToken = async (data: CheckTokenRequest) => { | |||||
| const res = await request<CheckTokenResponse>({ | |||||
| url: getUrl(ApiId.ROBOT_PAYMENT_CREDITCARD_TOKEN_CHECK), | |||||
| method: HttpMethod.POST, | |||||
| data: makeParam(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| @@ -50,8 +50,12 @@ const urls = { | |||||
| [A.START_CHANGE_EMAIL]: "email/change/start", | [A.START_CHANGE_EMAIL]: "email/change/start", | ||||
| [A.VERIFY_CHANGE_EMAIL]: "email/change/verify", | [A.VERIFY_CHANGE_EMAIL]: "email/change/verify", | ||||
| [A.CUSTOMER_UPDATE_INFO_ORDER]: "customer/update-info-order", | [A.CUSTOMER_UPDATE_INFO_ORDER]: "customer/update-info-order", | ||||
| [A.CUSTOMER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER]: | |||||
| "customer/change-payment-method-creditcard-order", | |||||
| [A.CUSTOMER_REGISTER_BANK_ACCOUNT_START_PARAM]: | [A.CUSTOMER_REGISTER_BANK_ACCOUNT_START_PARAM]: | ||||
| "customer/bank-account-register/start", | "customer/bank-account-register/start", | ||||
| [A.ROBOT_PAYMENT_CREDITCARD_TOKEN_CHECK]: | |||||
| "robot-payment/creditcard/token/check", | |||||
| }; | }; | ||||
| const prefixs = { | const prefixs = { | ||||
| @@ -0,0 +1,83 @@ | |||||
| import { Typography } from "@mui/material"; | |||||
| import { CheckTokenResponse, checkToken } from "api/robot-payment"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useDashboard from "hooks/useDashBoard"; | |||||
| import { PageID, TabID } from "pages"; | |||||
| import { useEffect, useRef, useState } from "react"; | |||||
| import { useParams } from "react-router-dom"; | |||||
| export default function Register() { | |||||
| const { setHeaderTitle, setTabs } = useDashboard( | |||||
| PageID.DASHBOARD_ROBOT_PAYMENT_CREDITCARD_REGISTER, | |||||
| TabID.NONE | |||||
| ); | |||||
| const { token: paramToken } = useParams(); | |||||
| const [result, setResult] = useState<boolean | null>(null); | |||||
| const [res, setRes] = useState<CheckTokenResponse | null>(null); | |||||
| const form = useRef<HTMLFormElement>(null); | |||||
| const { callAPI: callCheckToken } = useAPICall({ | |||||
| apiMethod: checkToken, | |||||
| backDrop: true, | |||||
| onSuccess: (response) => { | |||||
| setResult(true); | |||||
| setRes(response); | |||||
| }, | |||||
| onFailed: () => { | |||||
| setResult(false); | |||||
| }, | |||||
| }); | |||||
| useEffect(() => { | |||||
| if (paramToken) { | |||||
| callCheckToken({ token: paramToken }); | |||||
| } else { | |||||
| setResult(false); | |||||
| } | |||||
| }, [paramToken]); | |||||
| useEffect(() => { | |||||
| if (form.current && res) { | |||||
| form.current.submit(); | |||||
| } | |||||
| }, [form, res]); | |||||
| useEffect(() => { | |||||
| setHeaderTitle("クレジットカード登録"); | |||||
| setTabs(null); | |||||
| }, [setHeaderTitle, setTabs]); | |||||
| if (result === null) { | |||||
| return null; | |||||
| } | |||||
| if (result === false) { | |||||
| return <Typography>無効なURLです</Typography>; | |||||
| } | |||||
| if (res === null) { | |||||
| return null; | |||||
| } | |||||
| const { data } = res; | |||||
| return ( | |||||
| <form id="target-form" ref={form} action={data.url}> | |||||
| <p>遷移中...</p> | |||||
| <input type="hidden" name="aid" value={data.shop_code} /> | |||||
| <input type="hidden" name="cod" value={data.order_no} /> | |||||
| <input type="hidden" name="am" value={data.amount} /> | |||||
| <input type="hidden" name="tx" value={data.tax} /> | |||||
| <input type="hidden" name="sf" value={data.send_fee} /> | |||||
| <input type="hidden" name="jb" value={data.job_type} /> | |||||
| <input type="hidden" name="actp" value={data.interval} /> | |||||
| <input type="hidden" name="acam" value={data.auto_amount} /> | |||||
| <input type="hidden" name="ac1" value={data.payment_day} /> | |||||
| <input type="hidden" name="customer_code" value={data.customer_code} /> | |||||
| <input type="hidden" name="token" value={data.token} /> | |||||
| <input type="hidden" name="payment_type" value={data.payment_type} /> | |||||
| <input type="hidden" name="em" value={data.email} /> | |||||
| <input type="hidden" name="pn" value={data.phone_number} /> | |||||
| <input type="hidden" name="ac4" value={data.target_date} /> | |||||
| </form> | |||||
| ); | |||||
| } | |||||
| @@ -0,0 +1,128 @@ | |||||
| import { | |||||
| Box, | |||||
| Button, | |||||
| Stack, | |||||
| Table, | |||||
| TableBody, | |||||
| TableCell, | |||||
| TableRow, | |||||
| Typography, | |||||
| } from "@mui/material"; | |||||
| import { HasChildren } from "@types"; | |||||
| import { | |||||
| orderChangePaymentMetodCreditcard, | |||||
| orderCustomerInfoUpdate, | |||||
| startChangeEmail, | |||||
| } from "api/customer"; | |||||
| import RequireChip from "components/chip/RequireChip"; | |||||
| import InputAlert from "components/form/InputAlert"; | |||||
| import TextFieldEx from "components/form/TextFieldEx"; | |||||
| 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 useNavigateCustom from "hooks/useNavigateCustom"; | |||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | |||||
| import { PageID, TabID } from "pages"; | |||||
| import { useEffect, useState } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import { getPath } from "routes/path"; | |||||
| type AreaBoxProps = { | |||||
| label: string; | |||||
| require?: boolean; | |||||
| } & HasChildren; | |||||
| function AreaBox({ label, children, require }: AreaBoxProps) { | |||||
| return ( | |||||
| <Box> | |||||
| <StackRow> | |||||
| <Typography variant="subtitle1">〇{label}</Typography> | |||||
| <RequireChip require={require ?? false} /> | |||||
| </StackRow> | |||||
| {children} | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| name: string; | |||||
| name_kana: string; | |||||
| zip_code: string; | |||||
| address: string; | |||||
| phone_no: string; | |||||
| memo: string; | |||||
| }; | |||||
| export default function ChangePaymentMethodCreditcardOrder() { | |||||
| const { setHeaderTitle, setTabs } = useDashboard( | |||||
| PageID.DASHBOARD_USER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER, | |||||
| TabID.NONE | |||||
| ); | |||||
| const { navigateWhenChanged } = useNavigateCustom(); | |||||
| const { user } = useAuth(); | |||||
| const [mode, setMode] = useState<"confirm" | "done">("confirm"); | |||||
| const { error } = useSnackbarCustom(); | |||||
| const { callAPI: callOrderChangePaymentMetodCreditcard } = useAPICall({ | |||||
| apiMethod: orderChangePaymentMetodCreditcard, | |||||
| backDrop: true, | |||||
| onSuccess: () => { | |||||
| setMode("done"); | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const send = () => { | |||||
| callOrderChangePaymentMetodCreditcard({}); | |||||
| }; | |||||
| useEffect(() => { | |||||
| setHeaderTitle("利用者情報変更申請"); | |||||
| setTabs(null); | |||||
| }, []); | |||||
| useEffect(() => { | |||||
| if (user && user.can_pay_by_creditcard === false) { | |||||
| navigateWhenChanged(getPath(PageID.DASHBOARD_OVERVIEW)); | |||||
| } | |||||
| }, [user]); | |||||
| if (user?.can_pay_by_creditcard !== true) { | |||||
| return null; | |||||
| } | |||||
| if (mode === "done") { | |||||
| return ( | |||||
| <Stack spacing={2}> | |||||
| <Box>申請を行いました。受理をお待ちください。</Box> | |||||
| </Stack> | |||||
| ); | |||||
| } | |||||
| return ( | |||||
| <Box sx={{ mt: 1 }}> | |||||
| <Stack spacing={2}> | |||||
| <Box> | |||||
| <Typography>クレジットカードの登録申請を行います。</Typography> | |||||
| <Typography>申請受理後に、登録用のURLをメール送信します。</Typography> | |||||
| <Typography> | |||||
| メール送信までに数営業日を要する場合がございます。 | |||||
| </Typography> | |||||
| </Box> | |||||
| <Box></Box> | |||||
| <StackRow spacing={2}> | |||||
| <Button onClick={send} variant="contained"> | |||||
| 申請する | |||||
| </Button> | |||||
| </StackRow> | |||||
| </Stack> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| @@ -1,4 +1,5 @@ | |||||
| import { Box, Button, Paper, Stack, Typography } from "@mui/material"; | import { Box, Button, Paper, Stack, Typography } from "@mui/material"; | ||||
| import useAuth from "hooks/useAuth"; | |||||
| import useDashboard from "hooks/useDashBoard"; | import useDashboard from "hooks/useDashBoard"; | ||||
| import useNavigateCustom from "hooks/useNavigateCustom"; | import useNavigateCustom from "hooks/useNavigateCustom"; | ||||
| import { PageID, TabID } from "pages"; | import { PageID, TabID } from "pages"; | ||||
| @@ -13,6 +14,8 @@ export default function UserDetail() { | |||||
| const { navigateWhenChanged } = useNavigateCustom(); | const { navigateWhenChanged } = useNavigateCustom(); | ||||
| const { user } = useAuth(); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| setHeaderTitle("利用者情報"); | setHeaderTitle("利用者情報"); | ||||
| setTabs(null); | setTabs(null); | ||||
| @@ -56,6 +59,22 @@ export default function UserDetail() { | |||||
| 口座情報変更 | 口座情報変更 | ||||
| </Button> | </Button> | ||||
| </Box> | </Box> | ||||
| {user?.can_apply_to_change_payment_method_creditcard && ( | |||||
| <Box> | |||||
| <Button | |||||
| variant="contained" | |||||
| onClick={() => { | |||||
| navigateWhenChanged( | |||||
| getPath( | |||||
| PageID.DASHBOARD_USER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER | |||||
| ) | |||||
| ); | |||||
| }} | |||||
| > | |||||
| クレジットカード登録 | |||||
| </Button> | |||||
| </Box> | |||||
| )} | |||||
| </Stack> | </Stack> | ||||
| </Paper> | </Paper> | ||||
| ); | ); | ||||
| @@ -31,6 +31,9 @@ export const PageID = { | |||||
| DASHBOARD_USER_CHANGE_EMAIL_START: id++, | DASHBOARD_USER_CHANGE_EMAIL_START: id++, | ||||
| DASHBOARD_USER_UPDATE_USER_INFO: id++, | DASHBOARD_USER_UPDATE_USER_INFO: id++, | ||||
| DASHBOARD_USER_BANK_REGISTER: id++, | DASHBOARD_USER_BANK_REGISTER: id++, | ||||
| DASHBOARD_USER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER: id++, | |||||
| DASHBOARD_ROBOT_PAYMENT_CREDITCARD_REGISTER: id++, | |||||
| SEASON_TICKET_CONTRACT_SELECTION_ENTRY: id++, | SEASON_TICKET_CONTRACT_SELECTION_ENTRY: id++, | ||||
| SEASON_TICKET_CONTRACT_ENTRY_CANCEL: id++, | SEASON_TICKET_CONTRACT_ENTRY_CANCEL: id++, | ||||
| @@ -68,6 +68,10 @@ const PATHS_DASHBOARD = { | |||||
| "/dashboard/update/user/info", | "/dashboard/update/user/info", | ||||
| [makePathKey(PageID.DASHBOARD_USER_BANK_REGISTER)]: | [makePathKey(PageID.DASHBOARD_USER_BANK_REGISTER)]: | ||||
| "/dashboard/update/user/back-register", | "/dashboard/update/user/back-register", | ||||
| [makePathKey(PageID.DASHBOARD_USER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER)]: | |||||
| "/dashboard/order/user/payment-method/creditcard", | |||||
| [makePathKey(PageID.DASHBOARD_ROBOT_PAYMENT_CREDITCARD_REGISTER)]: | |||||
| "/dashboard/robot-payment/creditcard/register/:token", | |||||
| }; | }; | ||||
| const PATHS = { | const PATHS = { | ||||
| @@ -31,6 +31,15 @@ export default function DashboardRoutes(): RouteObject[] { | |||||
| const BankRegister = Loadable( | const BankRegister = Loadable( | ||||
| lazy(() => import("pages/dashboard/user/bank-register")) | lazy(() => import("pages/dashboard/user/bank-register")) | ||||
| ); | ); | ||||
| const ChangePaymentMethodCreditcardOrder = Loadable( | |||||
| lazy( | |||||
| () => | |||||
| import("pages/dashboard/user/change-payment-method-creditcard-order") | |||||
| ) | |||||
| ); | |||||
| const RobotPaymentCreditcardRegister = Loadable( | |||||
| lazy(() => import("pages/dashboard/robot-payment/creditcard/register")) | |||||
| ); | |||||
| const allChildren = [ | const allChildren = [ | ||||
| { | { | ||||
| @@ -66,6 +75,14 @@ export default function DashboardRoutes(): RouteObject[] { | |||||
| pageId: PageID.DASHBOARD_USER_BANK_REGISTER, | pageId: PageID.DASHBOARD_USER_BANK_REGISTER, | ||||
| element: <BankRegister />, | element: <BankRegister />, | ||||
| }, | }, | ||||
| { | |||||
| pageId: PageID.DASHBOARD_USER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER, | |||||
| element: <ChangePaymentMethodCreditcardOrder />, | |||||
| }, | |||||
| { | |||||
| pageId: PageID.DASHBOARD_ROBOT_PAYMENT_CREDITCARD_REGISTER, | |||||
| element: <RobotPaymentCreditcardRegister />, | |||||
| }, | |||||
| ]; | ]; | ||||
| return allChildren.map(({ pageId, ...others }) => ({ | return allChildren.map(({ pageId, ...others }) => ({ | ||||
| ...others, | ...others, | ||||