| @@ -10,6 +10,8 @@ export type Me = { | |||
| address: string; | |||
| phone_no: string; | |||
| customer_code: string; | |||
| can_pay_by_creditcard: boolean; | |||
| can_apply_to_change_payment_method_creditcard: boolean; | |||
| }; | |||
| type MeResponse = { | |||
| @@ -51,7 +51,7 @@ export const orderCustomerInfoUpdate = async ( | |||
| return res; | |||
| }; | |||
| // -------利用者情報変更申請--------------- | |||
| // -------口座振替登録用パラメータ取得--------------- | |||
| export type GetRegisterBankAccountStartParamResponse = { | |||
| data: { | |||
| url: string; | |||
| @@ -65,3 +65,12 @@ export const getRegisterBankAccountStartParam = async () => { | |||
| }); | |||
| 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++, | |||
| CUSTOMER_UPDATE_INFO_ORDER: id++, | |||
| CUSTOMER_REGISTER_BANK_ACCOUNT_START_PARAM: id++, | |||
| CUSTOMER_CHANGE_PAYMENT_METHOD_CREDITCARD_ORDER: id++, | |||
| // ロボットペイメント関連 | |||
| ROBOT_PAYMENT_CREDITCARD_TOKEN_CHECK: id++, | |||
| } as const; | |||
| 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.VERIFY_CHANGE_EMAIL]: "email/change/verify", | |||
| [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]: | |||
| "customer/bank-account-register/start", | |||
| [A.ROBOT_PAYMENT_CREDITCARD_TOKEN_CHECK]: | |||
| "robot-payment/creditcard/token/check", | |||
| }; | |||
| 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 useAuth from "hooks/useAuth"; | |||
| import useDashboard from "hooks/useDashBoard"; | |||
| import useNavigateCustom from "hooks/useNavigateCustom"; | |||
| import { PageID, TabID } from "pages"; | |||
| @@ -13,6 +14,8 @@ export default function UserDetail() { | |||
| const { navigateWhenChanged } = useNavigateCustom(); | |||
| const { user } = useAuth(); | |||
| useEffect(() => { | |||
| setHeaderTitle("利用者情報"); | |||
| setTabs(null); | |||
| @@ -56,6 +59,22 @@ export default function UserDetail() { | |||
| 口座情報変更 | |||
| </Button> | |||
| </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> | |||
| </Paper> | |||
| ); | |||
| @@ -31,6 +31,9 @@ export const PageID = { | |||
| DASHBOARD_USER_CHANGE_EMAIL_START: id++, | |||
| DASHBOARD_USER_UPDATE_USER_INFO: 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_ENTRY_CANCEL: id++, | |||
| @@ -68,6 +68,10 @@ const PATHS_DASHBOARD = { | |||
| "/dashboard/update/user/info", | |||
| [makePathKey(PageID.DASHBOARD_USER_BANK_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 = { | |||
| @@ -31,6 +31,15 @@ export default function DashboardRoutes(): RouteObject[] { | |||
| const BankRegister = Loadable( | |||
| 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 = [ | |||
| { | |||
| @@ -66,6 +75,14 @@ export default function DashboardRoutes(): RouteObject[] { | |||
| pageId: PageID.DASHBOARD_USER_BANK_REGISTER, | |||
| 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 }) => ({ | |||
| ...others, | |||