From 2b334711541ce32a793fa597e36bd9e1e56287e7 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Thu, 28 Sep 2023 15:58:09 +0900 Subject: [PATCH] =?UTF-8?q?=E7=94=B3=E8=AB=8B=E3=80=80=E6=95=B4=E5=82=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.ts | 3 + src/api/season-ticket-contract.ts | 16 +- src/components/form/InputAlert.tsx | 15 +- src/components/hook-form/RHFCheckbox.tsx | 40 ++-- .../contract/season-ticket-re-order.tsx | 106 +++++++++- .../dashboard/contract/terminate-order.tsx | 183 +++++++++++++++--- .../contract/update-vehicle-info-order.tsx | 146 +++++++++++++- 7 files changed, 443 insertions(+), 66 deletions(-) diff --git a/src/api/auth.ts b/src/api/auth.ts index 51ea8b2..07d609f 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -4,6 +4,9 @@ import { getUrl } from "./url"; export type Me = { customer_name: string; email: string; + zip_code: string; + address: string; + phone_no: string; }; type MeResponse = { diff --git a/src/api/season-ticket-contract.ts b/src/api/season-ticket-contract.ts index 32d6ad5..e2cd9e2 100644 --- a/src/api/season-ticket-contract.ts +++ b/src/api/season-ticket-contract.ts @@ -14,6 +14,7 @@ export type SeasonTicketContract = { room_no: string | null; season_ticket_seq_no: string | null; vehicle_no: string | null; + register_no: string | null; vehicle_type: string | null; contract_start_date: string | null; contract_end_date: string | null; @@ -78,10 +79,13 @@ export const reOrderSticker = async (data: StickerReOrderRequest) => { // -------定期券再発行依頼------------------ type SeasonTicketReOrderRequest = { season_ticket_contract_record_no: string; + parking_name: string; + reason: string; + memo?: string; }; export const reOrderSeasonTicket = async (data: SeasonTicketReOrderRequest) => { const res = await request({ - url: getUrl(ApiId.SEASON_TICKET_CONTRACT_STICKER_RE_ORDER), + url: getUrl(ApiId.SEASON_TICKET_CONTRACT_SEASON_TICKET_RE_ORDER), method: HttpMethod.POST, data: makeParam(data), }); @@ -107,9 +111,10 @@ export const orderParkingCertificate = async ( // -------解約依頼------------------ type TerminateOrderRequest = { season_ticket_contract_record_no: string; - date: string; + parking_name: string; + terminate_date: string; reason: string; - other_reason: string; + reason_detail: string; opinion: string; memo: string; }; @@ -146,6 +151,11 @@ export const getSeasonTicketContractTerminateOptions = async ( // -------車両情報変更依頼------------------ type UpdateVehicleInfoOrderRequest = { season_ticket_contract_record_no: string; + parking_name: string; + change_date: string; + vehicle_no?: string; + register_no?: string; + memo?: string; }; export const orderUpdateVehicleInfo = async ( data: UpdateVehicleInfoOrderRequest diff --git a/src/components/form/InputAlert.tsx b/src/components/form/InputAlert.tsx index 144af10..76ffcc0 100644 --- a/src/components/form/InputAlert.tsx +++ b/src/components/form/InputAlert.tsx @@ -1,13 +1,15 @@ import { Alert, SxProps } from "@mui/material"; import { APIErrorType } from "hooks/useAPICall"; import React, { useEffect, useMemo, useRef } from "react"; +import { FieldErrors, FieldValues, FormState } from "react-hook-form"; -type Props = { - error: APIErrorType; +type Props = { + error?: APIErrorType; sx?: SxProps; getMessage?: (errpr: APIErrorType) => string | null; message?: string; errorScroll?: boolean; + formState?: FormState; }; const InputAlert = ({ error, @@ -15,26 +17,29 @@ const InputAlert = ({ getMessage, message: errorMessage, errorScroll, -}: Props) => { + formState, +}: Props) => { const ref = useRef(null); const message = useMemo(() => { if (errorMessage) { return errorMessage; } - if (getMessage) { + if (getMessage && error) { const m = getMessage(error); if (m !== null) { return m; } } + if (!!formState && formState.isSubmitted && !formState.isValid) + return "入力項目を確認してください。"; if (error === APIErrorType.INPUT) return "入力項目を確認してください。"; if (error === APIErrorType.SERVER) return "エラーが発生しております。しばらくお待ちください。"; if (error === APIErrorType.EXCLUSIVE) return "ページの期限が切れています。再度読込を行ってください"; return ""; - }, [error, errorMessage, getMessage]); + }, [error, errorMessage, getMessage, formState]); // エラー時に自動的にスクロール制御 useEffect(() => { diff --git a/src/components/hook-form/RHFCheckbox.tsx b/src/components/hook-form/RHFCheckbox.tsx index 8e921a4..2a936b7 100644 --- a/src/components/hook-form/RHFCheckbox.tsx +++ b/src/components/hook-form/RHFCheckbox.tsx @@ -7,6 +7,8 @@ import { FormGroup, FormControlLabelProps, Typography, + Stack, + Alert, } from "@mui/material"; import { useMemo } from "react"; @@ -100,28 +102,34 @@ export function RHFMultiCheckbox({ { + render={({ field, fieldState: { error } }) => { const onSelected = (option: string) => field.value.includes(option) ? field.value.filter((value: string) => value !== option) : [...field.value, option]; return ( - - {options.map((option) => ( - field.onChange(onSelected(option.value))} - /> - } - label={{option.label}} - {...other} - /> - ))} - + + {!!error && {error.message}} + + {options.map((option) => ( + field.onChange(onSelected(option.value))} + color="error" + /> + } + label={ + {option.label} + } + {...other} + /> + ))} + + ); }} /> diff --git a/src/pages/dashboard/contract/season-ticket-re-order.tsx b/src/pages/dashboard/contract/season-ticket-re-order.tsx index a16cd8d..7ce1e03 100644 --- a/src/pages/dashboard/contract/season-ticket-re-order.tsx +++ b/src/pages/dashboard/contract/season-ticket-re-order.tsx @@ -1,10 +1,22 @@ -import { Box, Button, Stack, Typography } from "@mui/material"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { + Box, + Button, + Stack, + Table, + TableBody, + TableCell, + TableRow, + Typography, +} from "@mui/material"; import { HasChildren } from "@types"; import { reOrderSeasonTicket, reOrderSticker, } from "api/season-ticket-contract"; +import TextFieldEx from "components/form/TextFieldEx"; import { FormProvider, RHFTextField } from "components/hook-form"; +import StackRow from "components/stack/StackRow"; import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext"; import useAPICall from "hooks/useAPICall"; import useDashboard from "hooks/useDashBoard"; @@ -14,6 +26,7 @@ import { PageID, TabID } from "pages"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { getPath } from "routes/path"; +import { object, string } from "yup"; type AreaBoxProps = { label: string; @@ -28,7 +41,8 @@ function AreaBox({ label, children }: AreaBoxProps) { } type FormProps = { - upload1: File[]; + reason: string; + memo: string; }; export default function SeasonTicketReOrder() { @@ -39,35 +53,48 @@ export default function SeasonTicketReOrder() { const form = useForm({ defaultValues: { - upload1: [], + reason: "", + memo: "", }, + resolver: yupResolver( + object().shape({ + reason: string().required("入力してください"), + }) + ), }); - const { navigateWhenChanged, navigate } = useNavigateCustom(); + const { navigateWhenChanged } = useNavigateCustom(); const { error } = useSnackbarCustom(); const { selectedseasonTicketContract, backToDetailHome, initialized } = useSeasonTicketContractContext(); - const [done, setDone] = useState(false); + const [mode, setMode] = useState<"input" | "confirm" | "done">("input"); const { callAPI: callReOrderSeasonTicket } = useAPICall({ apiMethod: reOrderSeasonTicket, backDrop: true, onSuccess: () => { - setDone(true); + setMode("done"); }, onFailed: () => { error("依頼失敗しました"); + setMode("input"); }, }); - const handleSubmit = (data: FormProps) => { + const handleSubmit = () => { + setMode("confirm"); + }; + + const send = () => { + if (selectedseasonTicketContract === null) return; callReOrderSeasonTicket({ season_ticket_contract_record_no: selectedseasonTicketContract?.season_ticekt_contract_record_no ?? "", - ...data, + parking_name: selectedseasonTicketContract.parking_name ?? "", + ...form.getValues(), }); }; @@ -87,7 +114,7 @@ export default function SeasonTicketReOrder() { if (selectedseasonTicketContract === null) { return null; } - if (done) { + if (mode === "done") { return ( @@ -100,6 +127,58 @@ export default function SeasonTicketReOrder() { ); } + if (mode === "confirm") { + return ( + + + + 下記内容で申請を行います。 + + + + + + 理由 + + + + + + 備考 + + + + + +
+
+ + + + +
+
+ ); + } + return ( @@ -117,6 +196,15 @@ export default function SeasonTicketReOrder() { maxRows={10} /> + + + + + +
+
+ ); + } + return ( - + { + scrollToTop(); + })} + > + + - + 解約の理由についてお聞かせ下さい(複数選択可) - @@ -187,7 +324,7 @@ export default function TerminateOrder() { 前質問 7・8を選択された方 詳細を詳しくお聞かせください。 ({ defaultValues: { - upload1: [], + change_date: null, + vehicle_no: "", + register_no: "", + memo: "", }, + resolver: yupResolver( + object().shape({ + change_date: date().required("入力してください"), + }) + ), }); const { navigateWhenChanged, navigate } = useNavigateCustom(); @@ -50,25 +76,33 @@ export default function UpdateVehicleInfoOrder() { const { selectedseasonTicketContract, backToDetailHome } = useSeasonTicketContractContext(); - const [done, setDone] = useState(false); + const [mode, setMode] = useState<"input" | "confirm" | "done">("input"); const { callAPI: callOrderUpdateVehicleInfo } = useAPICall({ apiMethod: orderUpdateVehicleInfo, backDrop: true, form, onSuccess: () => { - setDone(true); + setMode("done"); }, onFailed: () => { error("依頼失敗しました"); + setMode("input"); }, }); - const handleSubmit = (data: FormProps) => { + const handleSubmit = () => { + setMode("confirm"); + }; + + const send = () => { + if (selectedseasonTicketContract === null) return; callOrderUpdateVehicleInfo({ season_ticket_contract_record_no: selectedseasonTicketContract?.season_ticekt_contract_record_no ?? "", - ...data, + parking_name: selectedseasonTicketContract.parking_name ?? "", + ...form.getValues(), + change_date: formatDateStr(form.getValues("change_date")), }); }; @@ -82,13 +116,22 @@ export default function UpdateVehicleInfoOrder() { navigateWhenChanged( getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST) ); + } else { + form.setValue( + "vehicle_no", + selectedseasonTicketContract.vehicle_no ?? "" + ); + form.setValue( + "register_no", + selectedseasonTicketContract.register_no ?? "" + ); } }, [selectedseasonTicketContract]); if (selectedseasonTicketContract === null) { return null; } - if (done) { + if (mode === "done") { return ( @@ -101,6 +144,77 @@ export default function UpdateVehicleInfoOrder() { ); } + if (mode === "confirm") { + return ( + + + + 下記内容で申請を行います。 + + + + + + 変更日 + + + + + + 車両番号 + + + + + + 防犯登録番号 + + + + + + 備考 + + + + + +
+
+ + + + +
+
+ ); + } + return ( @@ -109,11 +223,23 @@ export default function UpdateVehicleInfoOrder() { + + + - - + + + + +