| @@ -4,6 +4,9 @@ import { getUrl } from "./url"; | |||||
| export type Me = { | export type Me = { | ||||
| customer_name: string; | customer_name: string; | ||||
| email: string; | email: string; | ||||
| zip_code: string; | |||||
| address: string; | |||||
| phone_no: string; | |||||
| }; | }; | ||||
| type MeResponse = { | type MeResponse = { | ||||
| @@ -14,6 +14,7 @@ export type SeasonTicketContract = { | |||||
| room_no: string | null; | room_no: string | null; | ||||
| season_ticket_seq_no: string | null; | season_ticket_seq_no: string | null; | ||||
| vehicle_no: string | null; | vehicle_no: string | null; | ||||
| register_no: string | null; | |||||
| vehicle_type: string | null; | vehicle_type: string | null; | ||||
| contract_start_date: string | null; | contract_start_date: string | null; | ||||
| contract_end_date: string | null; | contract_end_date: string | null; | ||||
| @@ -78,10 +79,13 @@ export const reOrderSticker = async (data: StickerReOrderRequest) => { | |||||
| // -------定期券再発行依頼------------------ | // -------定期券再発行依頼------------------ | ||||
| type SeasonTicketReOrderRequest = { | type SeasonTicketReOrderRequest = { | ||||
| season_ticket_contract_record_no: string; | season_ticket_contract_record_no: string; | ||||
| parking_name: string; | |||||
| reason: string; | |||||
| memo?: string; | |||||
| }; | }; | ||||
| export const reOrderSeasonTicket = async (data: SeasonTicketReOrderRequest) => { | export const reOrderSeasonTicket = async (data: SeasonTicketReOrderRequest) => { | ||||
| const res = await request({ | 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, | method: HttpMethod.POST, | ||||
| data: makeParam(data), | data: makeParam(data), | ||||
| }); | }); | ||||
| @@ -107,9 +111,10 @@ export const orderParkingCertificate = async ( | |||||
| // -------解約依頼------------------ | // -------解約依頼------------------ | ||||
| type TerminateOrderRequest = { | type TerminateOrderRequest = { | ||||
| season_ticket_contract_record_no: string; | season_ticket_contract_record_no: string; | ||||
| date: string; | |||||
| parking_name: string; | |||||
| terminate_date: string; | |||||
| reason: string; | reason: string; | ||||
| other_reason: string; | |||||
| reason_detail: string; | |||||
| opinion: string; | opinion: string; | ||||
| memo: string; | memo: string; | ||||
| }; | }; | ||||
| @@ -146,6 +151,11 @@ export const getSeasonTicketContractTerminateOptions = async ( | |||||
| // -------車両情報変更依頼------------------ | // -------車両情報変更依頼------------------ | ||||
| type UpdateVehicleInfoOrderRequest = { | type UpdateVehicleInfoOrderRequest = { | ||||
| season_ticket_contract_record_no: string; | season_ticket_contract_record_no: string; | ||||
| parking_name: string; | |||||
| change_date: string; | |||||
| vehicle_no?: string; | |||||
| register_no?: string; | |||||
| memo?: string; | |||||
| }; | }; | ||||
| export const orderUpdateVehicleInfo = async ( | export const orderUpdateVehicleInfo = async ( | ||||
| data: UpdateVehicleInfoOrderRequest | data: UpdateVehicleInfoOrderRequest | ||||
| @@ -1,13 +1,15 @@ | |||||
| import { Alert, SxProps } from "@mui/material"; | import { Alert, SxProps } from "@mui/material"; | ||||
| import { APIErrorType } from "hooks/useAPICall"; | import { APIErrorType } from "hooks/useAPICall"; | ||||
| import React, { useEffect, useMemo, useRef } from "react"; | import React, { useEffect, useMemo, useRef } from "react"; | ||||
| import { FieldErrors, FieldValues, FormState } from "react-hook-form"; | |||||
| type Props = { | |||||
| error: APIErrorType; | |||||
| type Props<T extends FieldValues> = { | |||||
| error?: APIErrorType; | |||||
| sx?: SxProps; | sx?: SxProps; | ||||
| getMessage?: (errpr: APIErrorType) => string | null; | getMessage?: (errpr: APIErrorType) => string | null; | ||||
| message?: string; | message?: string; | ||||
| errorScroll?: boolean; | errorScroll?: boolean; | ||||
| formState?: FormState<T>; | |||||
| }; | }; | ||||
| const InputAlert = ({ | const InputAlert = ({ | ||||
| error, | error, | ||||
| @@ -15,26 +17,29 @@ const InputAlert = ({ | |||||
| getMessage, | getMessage, | ||||
| message: errorMessage, | message: errorMessage, | ||||
| errorScroll, | errorScroll, | ||||
| }: Props) => { | |||||
| formState, | |||||
| }: Props<FieldValues>) => { | |||||
| const ref = useRef<HTMLDivElement>(null); | const ref = useRef<HTMLDivElement>(null); | ||||
| const message = useMemo(() => { | const message = useMemo(() => { | ||||
| if (errorMessage) { | if (errorMessage) { | ||||
| return errorMessage; | return errorMessage; | ||||
| } | } | ||||
| if (getMessage) { | |||||
| if (getMessage && error) { | |||||
| const m = getMessage(error); | const m = getMessage(error); | ||||
| if (m !== null) { | if (m !== null) { | ||||
| return m; | return m; | ||||
| } | } | ||||
| } | } | ||||
| if (!!formState && formState.isSubmitted && !formState.isValid) | |||||
| return "入力項目を確認してください。"; | |||||
| if (error === APIErrorType.INPUT) return "入力項目を確認してください。"; | if (error === APIErrorType.INPUT) return "入力項目を確認してください。"; | ||||
| if (error === APIErrorType.SERVER) | if (error === APIErrorType.SERVER) | ||||
| return "エラーが発生しております。しばらくお待ちください。"; | return "エラーが発生しております。しばらくお待ちください。"; | ||||
| if (error === APIErrorType.EXCLUSIVE) | if (error === APIErrorType.EXCLUSIVE) | ||||
| return "ページの期限が切れています。再度読込を行ってください"; | return "ページの期限が切れています。再度読込を行ってください"; | ||||
| return ""; | return ""; | ||||
| }, [error, errorMessage, getMessage]); | |||||
| }, [error, errorMessage, getMessage, formState]); | |||||
| // エラー時に自動的にスクロール制御 | // エラー時に自動的にスクロール制御 | ||||
| useEffect(() => { | useEffect(() => { | ||||
| @@ -7,6 +7,8 @@ import { | |||||
| FormGroup, | FormGroup, | ||||
| FormControlLabelProps, | FormControlLabelProps, | ||||
| Typography, | Typography, | ||||
| Stack, | |||||
| Alert, | |||||
| } from "@mui/material"; | } from "@mui/material"; | ||||
| import { useMemo } from "react"; | import { useMemo } from "react"; | ||||
| @@ -100,28 +102,34 @@ export function RHFMultiCheckbox({ | |||||
| <Controller | <Controller | ||||
| name={name} | name={name} | ||||
| control={control} | control={control} | ||||
| render={({ field }) => { | |||||
| render={({ field, fieldState: { error } }) => { | |||||
| const onSelected = (option: string) => | const onSelected = (option: string) => | ||||
| field.value.includes(option) | field.value.includes(option) | ||||
| ? field.value.filter((value: string) => value !== option) | ? field.value.filter((value: string) => value !== option) | ||||
| : [...field.value, option]; | : [...field.value, option]; | ||||
| return ( | return ( | ||||
| <FormGroup> | |||||
| {options.map((option) => ( | |||||
| <FormControlLabel | |||||
| key={option.value} | |||||
| control={ | |||||
| <Checkbox | |||||
| checked={field.value.includes(option.value)} | |||||
| onChange={() => field.onChange(onSelected(option.value))} | |||||
| /> | |||||
| } | |||||
| label={<Typography variant="body2">{option.label}</Typography>} | |||||
| {...other} | |||||
| /> | |||||
| ))} | |||||
| </FormGroup> | |||||
| <Stack> | |||||
| {!!error && <Alert severity="warning">{error.message}</Alert>} | |||||
| <FormGroup> | |||||
| {options.map((option) => ( | |||||
| <FormControlLabel | |||||
| key={option.value} | |||||
| control={ | |||||
| <Checkbox | |||||
| checked={field.value.includes(option.value)} | |||||
| onChange={() => field.onChange(onSelected(option.value))} | |||||
| color="error" | |||||
| /> | |||||
| } | |||||
| label={ | |||||
| <Typography variant="body2">{option.label}</Typography> | |||||
| } | |||||
| {...other} | |||||
| /> | |||||
| ))} | |||||
| </FormGroup> | |||||
| </Stack> | |||||
| ); | ); | ||||
| }} | }} | ||||
| /> | /> | ||||
| @@ -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 { HasChildren } from "@types"; | ||||
| import { | import { | ||||
| reOrderSeasonTicket, | reOrderSeasonTicket, | ||||
| reOrderSticker, | reOrderSticker, | ||||
| } from "api/season-ticket-contract"; | } from "api/season-ticket-contract"; | ||||
| import TextFieldEx from "components/form/TextFieldEx"; | |||||
| import { FormProvider, RHFTextField } from "components/hook-form"; | import { FormProvider, RHFTextField } from "components/hook-form"; | ||||
| import StackRow from "components/stack/StackRow"; | |||||
| import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext"; | import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext"; | ||||
| import useAPICall from "hooks/useAPICall"; | import useAPICall from "hooks/useAPICall"; | ||||
| import useDashboard from "hooks/useDashBoard"; | import useDashboard from "hooks/useDashBoard"; | ||||
| @@ -14,6 +26,7 @@ import { PageID, TabID } from "pages"; | |||||
| import { useEffect, useState } from "react"; | import { useEffect, useState } from "react"; | ||||
| import { useForm } from "react-hook-form"; | import { useForm } from "react-hook-form"; | ||||
| import { getPath } from "routes/path"; | import { getPath } from "routes/path"; | ||||
| import { object, string } from "yup"; | |||||
| type AreaBoxProps = { | type AreaBoxProps = { | ||||
| label: string; | label: string; | ||||
| @@ -28,7 +41,8 @@ function AreaBox({ label, children }: AreaBoxProps) { | |||||
| } | } | ||||
| type FormProps = { | type FormProps = { | ||||
| upload1: File[]; | |||||
| reason: string; | |||||
| memo: string; | |||||
| }; | }; | ||||
| export default function SeasonTicketReOrder() { | export default function SeasonTicketReOrder() { | ||||
| @@ -39,35 +53,48 @@ export default function SeasonTicketReOrder() { | |||||
| const form = useForm<FormProps>({ | const form = useForm<FormProps>({ | ||||
| defaultValues: { | defaultValues: { | ||||
| upload1: [], | |||||
| reason: "", | |||||
| memo: "", | |||||
| }, | }, | ||||
| resolver: yupResolver( | |||||
| object().shape({ | |||||
| reason: string().required("入力してください"), | |||||
| }) | |||||
| ), | |||||
| }); | }); | ||||
| const { navigateWhenChanged, navigate } = useNavigateCustom(); | |||||
| const { navigateWhenChanged } = useNavigateCustom(); | |||||
| const { error } = useSnackbarCustom(); | const { error } = useSnackbarCustom(); | ||||
| const { selectedseasonTicketContract, backToDetailHome, initialized } = | const { selectedseasonTicketContract, backToDetailHome, initialized } = | ||||
| useSeasonTicketContractContext(); | useSeasonTicketContractContext(); | ||||
| const [done, setDone] = useState(false); | |||||
| const [mode, setMode] = useState<"input" | "confirm" | "done">("input"); | |||||
| const { callAPI: callReOrderSeasonTicket } = useAPICall({ | const { callAPI: callReOrderSeasonTicket } = useAPICall({ | ||||
| apiMethod: reOrderSeasonTicket, | apiMethod: reOrderSeasonTicket, | ||||
| backDrop: true, | backDrop: true, | ||||
| onSuccess: () => { | onSuccess: () => { | ||||
| setDone(true); | |||||
| setMode("done"); | |||||
| }, | }, | ||||
| onFailed: () => { | onFailed: () => { | ||||
| error("依頼失敗しました"); | error("依頼失敗しました"); | ||||
| setMode("input"); | |||||
| }, | }, | ||||
| }); | }); | ||||
| const handleSubmit = (data: FormProps) => { | |||||
| const handleSubmit = () => { | |||||
| setMode("confirm"); | |||||
| }; | |||||
| const send = () => { | |||||
| if (selectedseasonTicketContract === null) return; | |||||
| callReOrderSeasonTicket({ | callReOrderSeasonTicket({ | ||||
| season_ticket_contract_record_no: | season_ticket_contract_record_no: | ||||
| selectedseasonTicketContract?.season_ticekt_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) { | if (selectedseasonTicketContract === null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| if (done) { | |||||
| if (mode === "done") { | |||||
| return ( | return ( | ||||
| <Box sx={{ mt: 1 }}> | <Box sx={{ mt: 1 }}> | ||||
| <Stack spacing={2}> | <Stack spacing={2}> | ||||
| @@ -100,6 +127,58 @@ export default function SeasonTicketReOrder() { | |||||
| ); | ); | ||||
| } | } | ||||
| if (mode === "confirm") { | |||||
| return ( | |||||
| <Box sx={{ mt: 1 }}> | |||||
| <Stack spacing={2}> | |||||
| <Box> | |||||
| <Typography>下記内容で申請を行います。</Typography> | |||||
| </Box> | |||||
| <Box> | |||||
| <Table size="small"> | |||||
| <TableBody> | |||||
| <TableRow> | |||||
| <TableCell>理由</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| multiline | |||||
| value={form.getValues("reason")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>備考</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| multiline | |||||
| value={form.getValues("memo")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| </TableBody> | |||||
| </Table> | |||||
| </Box> | |||||
| <StackRow spacing={2}> | |||||
| <Button | |||||
| onClick={() => { | |||||
| setMode("input"); | |||||
| }} | |||||
| > | |||||
| 戻る | |||||
| </Button> | |||||
| <Button onClick={send} variant="contained"> | |||||
| 送信 | |||||
| </Button> | |||||
| </StackRow> | |||||
| </Stack> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| return ( | return ( | ||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | ||||
| <Box sx={{ mt: 1 }}> | <Box sx={{ mt: 1 }}> | ||||
| @@ -117,6 +196,15 @@ export default function SeasonTicketReOrder() { | |||||
| maxRows={10} | maxRows={10} | ||||
| /> | /> | ||||
| </AreaBox> | </AreaBox> | ||||
| <AreaBox label="備考"> | |||||
| <RHFTextField | |||||
| name="memo" | |||||
| size="small" | |||||
| multiline | |||||
| minRows={3} | |||||
| maxRows={10} | |||||
| /> | |||||
| </AreaBox> | |||||
| <Box> | <Box> | ||||
| <Button variant="contained" type="submit"> | <Button variant="contained" type="submit"> | ||||
| @@ -1,4 +1,14 @@ | |||||
| 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 { HasChildren } from "@types"; | ||||
| import { | import { | ||||
| getSeasonTicketContractTerminateOptions, | getSeasonTicketContractTerminateOptions, | ||||
| @@ -6,6 +16,8 @@ import { | |||||
| reOrderSticker, | reOrderSticker, | ||||
| } from "api/season-ticket-contract"; | } from "api/season-ticket-contract"; | ||||
| import RequireChip from "components/chip/RequireChip"; | import RequireChip from "components/chip/RequireChip"; | ||||
| import InputAlert from "components/form/InputAlert"; | |||||
| import TextFieldEx from "components/form/TextFieldEx"; | |||||
| import { | import { | ||||
| FormProvider, | FormProvider, | ||||
| RHFCheckbox, | RHFCheckbox, | ||||
| @@ -25,6 +37,8 @@ import { PageID, TabID } from "pages"; | |||||
| import { useEffect, useMemo, useState } from "react"; | import { useEffect, useMemo, useState } from "react"; | ||||
| import { useForm } from "react-hook-form"; | import { useForm } from "react-hook-form"; | ||||
| import { getPath } from "routes/path"; | import { getPath } from "routes/path"; | ||||
| import { scrollToTop } from "utils/page"; | |||||
| import { array, object, string } from "yup"; | |||||
| type AreaBoxProps = { | type AreaBoxProps = { | ||||
| label: string; | label: string; | ||||
| @@ -43,9 +57,9 @@ function AreaBox({ label, children, require }: AreaBoxProps) { | |||||
| } | } | ||||
| type FormProps = { | type FormProps = { | ||||
| date: string; | |||||
| terminate_date: string; | |||||
| reason: string[]; | reason: string[]; | ||||
| other_reason: string; | |||||
| reason_detail: string; | |||||
| opinion: string; | opinion: string; | ||||
| memo: string; | memo: string; | ||||
| }; | }; | ||||
| @@ -58,12 +72,18 @@ export default function TerminateOrder() { | |||||
| const form = useForm<FormProps>({ | const form = useForm<FormProps>({ | ||||
| defaultValues: { | defaultValues: { | ||||
| date: "", | |||||
| terminate_date: "", | |||||
| reason: [], | reason: [], | ||||
| other_reason: "", | |||||
| reason_detail: "", | |||||
| opinion: "", | opinion: "", | ||||
| memo: "", | memo: "", | ||||
| }, | }, | ||||
| resolver: yupResolver( | |||||
| object().shape({ | |||||
| terminate_date: string().required("入力してください"), | |||||
| reason: array().min(1, "選択してください"), | |||||
| }) | |||||
| ), | |||||
| }); | }); | ||||
| const { navigateWhenChanged, navigate } = useNavigateCustom(); | const { navigateWhenChanged, navigate } = useNavigateCustom(); | ||||
| @@ -73,6 +93,8 @@ export default function TerminateOrder() { | |||||
| const { selectedseasonTicketContract, backToDetailHome } = | const { selectedseasonTicketContract, backToDetailHome } = | ||||
| useSeasonTicketContractContext(); | useSeasonTicketContractContext(); | ||||
| const [mode, setMode] = useState<"input" | "confirm" | "done">("input"); | |||||
| const [monthes, setMonthes] = useState<string[]>([]); | const [monthes, setMonthes] = useState<string[]>([]); | ||||
| const monthOptions: SelectOptionProps[] = useMemo(() => { | const monthOptions: SelectOptionProps[] = useMemo(() => { | ||||
| @@ -82,35 +104,54 @@ export default function TerminateOrder() { | |||||
| })); | })); | ||||
| }, [monthes]); | }, [monthes]); | ||||
| const [done, setDone] = useState(false); | |||||
| const { callAPI: callOrderSeasonTicketContractTerminate } = useAPICall({ | const { callAPI: callOrderSeasonTicketContractTerminate } = useAPICall({ | ||||
| apiMethod: orderSeasonTicketContractTerminate, | apiMethod: orderSeasonTicketContractTerminate, | ||||
| backDrop: true, | backDrop: true, | ||||
| onSuccess: () => { | onSuccess: () => { | ||||
| setDone(true); | |||||
| setMode("done"); | |||||
| }, | }, | ||||
| onFailed: () => { | onFailed: () => { | ||||
| error("依頼失敗しました"); | error("依頼失敗しました"); | ||||
| setMode("input"); | |||||
| }, | }, | ||||
| }); | }); | ||||
| const { callAPI: callGetSeasonTicketContractTerminateOptions } = useAPICall({ | |||||
| apiMethod: getSeasonTicketContractTerminateOptions, | |||||
| backDrop: true, | |||||
| onSuccess: ({ data }) => { | |||||
| setMonthes(data.monthes); | |||||
| }, | |||||
| }); | |||||
| const { callAPI: callGetSeasonTicketContractTerminateOptions, errorMode } = | |||||
| useAPICall({ | |||||
| apiMethod: getSeasonTicketContractTerminateOptions, | |||||
| backDrop: true, | |||||
| onSuccess: ({ data }) => { | |||||
| setMonthes(data.monthes); | |||||
| }, | |||||
| }); | |||||
| const handleSubmit = () => { | |||||
| // form.clearErrors(); | |||||
| const handleSubmit = (data: FormProps) => { | |||||
| // if (form.getValues("reason").length === 0) { | |||||
| // form.setError("reason", { | |||||
| // message: "選択してください", | |||||
| // type: "required", | |||||
| // }); | |||||
| // } | |||||
| // if (!form.formState.isValid) { | |||||
| // scrollToTop(); | |||||
| // return; | |||||
| // } | |||||
| setMode("confirm"); | |||||
| }; | |||||
| const send = () => { | |||||
| if (selectedseasonTicketContract === null) return; | if (selectedseasonTicketContract === null) return; | ||||
| callOrderSeasonTicketContractTerminate({ | callOrderSeasonTicketContractTerminate({ | ||||
| ...data, | |||||
| ...form.getValues(), | |||||
| season_ticket_contract_record_no: | season_ticket_contract_record_no: | ||||
| selectedseasonTicketContract.season_ticekt_contract_record_no ?? "", | selectedseasonTicketContract.season_ticekt_contract_record_no ?? "", | ||||
| reason: data.reason.join(","), | |||||
| parking_name: selectedseasonTicketContract.parking_name ?? "", | |||||
| reason: form.getValues("reason").join(","), | |||||
| }); | }); | ||||
| }; | }; | ||||
| @@ -151,7 +192,8 @@ export default function TerminateOrder() { | |||||
| if (selectedseasonTicketContract === null) { | if (selectedseasonTicketContract === null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| if (done) { | |||||
| if (mode === "done") { | |||||
| return ( | return ( | ||||
| <Box sx={{ mt: 1 }}> | <Box sx={{ mt: 1 }}> | ||||
| <Stack spacing={2}> | <Stack spacing={2}> | ||||
| @@ -164,22 +206,117 @@ export default function TerminateOrder() { | |||||
| ); | ); | ||||
| } | } | ||||
| if (mode === "confirm") { | |||||
| return ( | |||||
| <Box sx={{ mt: 1 }}> | |||||
| <Stack spacing={2}> | |||||
| <Box> | |||||
| <Typography>下記内容で申請を行います。</Typography> | |||||
| </Box> | |||||
| <Box> | |||||
| <Table size="small"> | |||||
| <TableBody> | |||||
| <TableRow> | |||||
| <TableCell>解約希望日</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| multiline | |||||
| value={form.getValues("terminate_date")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>解約理由</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| multiline | |||||
| value={form.getValues("reason").join("\n")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>解約理由詳細</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| multiline | |||||
| value={form.getValues("reason_detail")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>ご意見</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| multiline | |||||
| value={form.getValues("opinion")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>備考</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| multiline | |||||
| value={form.getValues("memo")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| </TableBody> | |||||
| </Table> | |||||
| </Box> | |||||
| <StackRow spacing={2}> | |||||
| <Button | |||||
| onClick={() => { | |||||
| setMode("input"); | |||||
| }} | |||||
| > | |||||
| 戻る | |||||
| </Button> | |||||
| <Button onClick={send} variant="contained"> | |||||
| 送信 | |||||
| </Button> | |||||
| </StackRow> | |||||
| </Stack> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| return ( | return ( | ||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | |||||
| <FormProvider | |||||
| methods={form} | |||||
| onSubmit={form.handleSubmit(handleSubmit, (aaa) => { | |||||
| scrollToTop(); | |||||
| })} | |||||
| > | |||||
| <Box sx={{ mt: 1 }}> | <Box sx={{ mt: 1 }}> | ||||
| <Stack spacing={2}> | <Stack spacing={2}> | ||||
| <Box> | <Box> | ||||
| <Button onClick={backToDetailHome}>戻る</Button> | <Button onClick={backToDetailHome}>戻る</Button> | ||||
| </Box> | </Box> | ||||
| <InputAlert formState={form.formState} error={errorMode} /> | |||||
| <AreaBox label="解約希望日" require> | <AreaBox label="解約希望日" require> | ||||
| <RHFSelect name="date" size="small" options={monthOptions} /> | |||||
| <RHFSelect | |||||
| name="terminate_date" | |||||
| size="small" | |||||
| options={monthOptions} | |||||
| /> | |||||
| </AreaBox> | </AreaBox> | ||||
| <AreaBox label="解約理由(複数選択可)" require> | <AreaBox label="解約理由(複数選択可)" require> | ||||
| <Typography variant="body2"> | <Typography variant="body2"> | ||||
| 解約の理由についてお聞かせ下さい(複数選択可) | 解約の理由についてお聞かせ下さい(複数選択可) | ||||
| </Typography> | </Typography> | ||||
| <RHFMultiCheckbox name="reason" options={reasons} /> | <RHFMultiCheckbox name="reason" options={reasons} /> | ||||
| </AreaBox> | </AreaBox> | ||||
| <AreaBox label="解約理由詳細"> | <AreaBox label="解約理由詳細"> | ||||
| @@ -187,7 +324,7 @@ export default function TerminateOrder() { | |||||
| 前質問 7・8を選択された方 詳細を詳しくお聞かせください。 | 前質問 7・8を選択された方 詳細を詳しくお聞かせください。 | ||||
| </Typography> | </Typography> | ||||
| <RHFTextField | <RHFTextField | ||||
| name="reason_other" | |||||
| name="reason_detail" | |||||
| size="small" | size="small" | ||||
| multiline | multiline | ||||
| minRows={3} | minRows={3} | ||||
| @@ -1,10 +1,23 @@ | |||||
| 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 { HasChildren } from "@types"; | ||||
| import { | import { | ||||
| orderUpdateVehicleInfo, | orderUpdateVehicleInfo, | ||||
| reOrderSticker, | reOrderSticker, | ||||
| } from "api/season-ticket-contract"; | } from "api/season-ticket-contract"; | ||||
| import TextFieldEx from "components/form/TextFieldEx"; | |||||
| import { FormProvider, RHFTextField } from "components/hook-form"; | import { FormProvider, RHFTextField } from "components/hook-form"; | ||||
| import RHFDatePicker from "components/hook-form/RHFDatePicker"; | |||||
| import StackRow from "components/stack/StackRow"; | |||||
| import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext"; | import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext"; | ||||
| import useAPICall from "hooks/useAPICall"; | import useAPICall from "hooks/useAPICall"; | ||||
| import useDashboard from "hooks/useDashBoard"; | import useDashboard from "hooks/useDashBoard"; | ||||
| @@ -14,6 +27,8 @@ import { PageID, TabID } from "pages"; | |||||
| import { useEffect, useState } from "react"; | import { useEffect, useState } from "react"; | ||||
| import { useForm } from "react-hook-form"; | import { useForm } from "react-hook-form"; | ||||
| import { getPath } from "routes/path"; | import { getPath } from "routes/path"; | ||||
| import { formatDateStr } from "utils/datetime"; | |||||
| import { date, object } from "yup"; | |||||
| type AreaBoxProps = { | type AreaBoxProps = { | ||||
| label: string; | label: string; | ||||
| @@ -28,7 +43,10 @@ function AreaBox({ label, children }: AreaBoxProps) { | |||||
| } | } | ||||
| type FormProps = { | type FormProps = { | ||||
| upload1: File[]; | |||||
| change_date: Date | null; | |||||
| vehicle_no: string; | |||||
| register_no: string; | |||||
| memo: string; | |||||
| }; | }; | ||||
| export default function UpdateVehicleInfoOrder() { | export default function UpdateVehicleInfoOrder() { | ||||
| @@ -39,8 +57,16 @@ export default function UpdateVehicleInfoOrder() { | |||||
| const form = useForm<FormProps>({ | const form = useForm<FormProps>({ | ||||
| defaultValues: { | defaultValues: { | ||||
| upload1: [], | |||||
| change_date: null, | |||||
| vehicle_no: "", | |||||
| register_no: "", | |||||
| memo: "", | |||||
| }, | }, | ||||
| resolver: yupResolver( | |||||
| object().shape({ | |||||
| change_date: date().required("入力してください"), | |||||
| }) | |||||
| ), | |||||
| }); | }); | ||||
| const { navigateWhenChanged, navigate } = useNavigateCustom(); | const { navigateWhenChanged, navigate } = useNavigateCustom(); | ||||
| @@ -50,25 +76,33 @@ export default function UpdateVehicleInfoOrder() { | |||||
| const { selectedseasonTicketContract, backToDetailHome } = | const { selectedseasonTicketContract, backToDetailHome } = | ||||
| useSeasonTicketContractContext(); | useSeasonTicketContractContext(); | ||||
| const [done, setDone] = useState(false); | |||||
| const [mode, setMode] = useState<"input" | "confirm" | "done">("input"); | |||||
| const { callAPI: callOrderUpdateVehicleInfo } = useAPICall({ | const { callAPI: callOrderUpdateVehicleInfo } = useAPICall({ | ||||
| apiMethod: orderUpdateVehicleInfo, | apiMethod: orderUpdateVehicleInfo, | ||||
| backDrop: true, | backDrop: true, | ||||
| form, | form, | ||||
| onSuccess: () => { | onSuccess: () => { | ||||
| setDone(true); | |||||
| setMode("done"); | |||||
| }, | }, | ||||
| onFailed: () => { | onFailed: () => { | ||||
| error("依頼失敗しました"); | error("依頼失敗しました"); | ||||
| setMode("input"); | |||||
| }, | }, | ||||
| }); | }); | ||||
| const handleSubmit = (data: FormProps) => { | |||||
| const handleSubmit = () => { | |||||
| setMode("confirm"); | |||||
| }; | |||||
| const send = () => { | |||||
| if (selectedseasonTicketContract === null) return; | |||||
| callOrderUpdateVehicleInfo({ | callOrderUpdateVehicleInfo({ | ||||
| season_ticket_contract_record_no: | season_ticket_contract_record_no: | ||||
| selectedseasonTicketContract?.season_ticekt_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( | navigateWhenChanged( | ||||
| getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST) | getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST) | ||||
| ); | ); | ||||
| } else { | |||||
| form.setValue( | |||||
| "vehicle_no", | |||||
| selectedseasonTicketContract.vehicle_no ?? "" | |||||
| ); | |||||
| form.setValue( | |||||
| "register_no", | |||||
| selectedseasonTicketContract.register_no ?? "" | |||||
| ); | |||||
| } | } | ||||
| }, [selectedseasonTicketContract]); | }, [selectedseasonTicketContract]); | ||||
| if (selectedseasonTicketContract === null) { | if (selectedseasonTicketContract === null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| if (done) { | |||||
| if (mode === "done") { | |||||
| return ( | return ( | ||||
| <Box sx={{ mt: 1 }}> | <Box sx={{ mt: 1 }}> | ||||
| <Stack spacing={2}> | <Stack spacing={2}> | ||||
| @@ -101,6 +144,77 @@ export default function UpdateVehicleInfoOrder() { | |||||
| ); | ); | ||||
| } | } | ||||
| if (mode === "confirm") { | |||||
| return ( | |||||
| <Box sx={{ mt: 1 }}> | |||||
| <Stack spacing={2}> | |||||
| <Box> | |||||
| <Typography>下記内容で申請を行います。</Typography> | |||||
| </Box> | |||||
| <Box> | |||||
| <Table size="small"> | |||||
| <TableBody> | |||||
| <TableRow> | |||||
| <TableCell>変更日</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| value={formatDateStr(form.getValues("change_date"))} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>車両番号</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| value={form.getValues("vehicle_no")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>防犯登録番号</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| value={form.getValues("register_no")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>備考</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx | |||||
| multiline | |||||
| value={form.getValues("memo")} | |||||
| readOnly | |||||
| fullWidth | |||||
| /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| </TableBody> | |||||
| </Table> | |||||
| </Box> | |||||
| <StackRow spacing={2}> | |||||
| <Button | |||||
| onClick={() => { | |||||
| setMode("input"); | |||||
| }} | |||||
| > | |||||
| 戻る | |||||
| </Button> | |||||
| <Button onClick={send} variant="contained"> | |||||
| 送信 | |||||
| </Button> | |||||
| </StackRow> | |||||
| </Stack> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| return ( | return ( | ||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | ||||
| <Box sx={{ mt: 1 }}> | <Box sx={{ mt: 1 }}> | ||||
| @@ -109,11 +223,23 @@ export default function UpdateVehicleInfoOrder() { | |||||
| <Button onClick={backToDetailHome}>戻る</Button> | <Button onClick={backToDetailHome}>戻る</Button> | ||||
| </Box> | </Box> | ||||
| <AreaBox label="変更日"> | |||||
| <RHFDatePicker name="change_date" /> | |||||
| </AreaBox> | |||||
| <AreaBox label="車両番号"> | <AreaBox label="車両番号"> | ||||
| <RHFTextField name="vehicle_no" /> | <RHFTextField name="vehicle_no" /> | ||||
| </AreaBox> | </AreaBox> | ||||
| <AreaBox label="車体番号"> | |||||
| <RHFTextField name="chassis_no" /> | |||||
| <AreaBox label="防犯登録番号"> | |||||
| <RHFTextField name="register_no" /> | |||||
| </AreaBox> | |||||
| <AreaBox label="備考"> | |||||
| <RHFTextField | |||||
| name="memo" | |||||
| size="small" | |||||
| multiline | |||||
| minRows={3} | |||||
| maxRows={10} | |||||
| /> | |||||
| </AreaBox> | </AreaBox> | ||||
| <Box> | <Box> | ||||