From c1a834e67676962b38a5a111adfb4872b2621ca7 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Thu, 27 Jul 2023 18:15:00 +0900 Subject: [PATCH] =?UTF-8?q?=E9=A0=98=E5=8F=8E=E8=A8=BC=E7=99=BA=E8=A1=8C?= =?UTF-8?q?=E4=BE=9D=E9=A0=BC=E3=81=AE=E9=A7=90=E8=BB=8A=E5=A0=B4=E9=81=B8?= =?UTF-8?q?=E6=8A=9E=E6=96=B9=E5=BC=8F=E3=82=92=E8=A6=8B=E7=9B=B4=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SATE_RECEIPT-19 領収証作成箇所 --- src/api/custom/hello-techno/index.ts | 8 +- .../hello-techno/contexts/CreateContext.tsx | 41 ++++ .../custom/hello-techno/create.tsx | 66 +++-- .../custom/hello-techno/hooks/useCreate.ts | 8 + .../hooks/useInputReceiptStep.tsx | 131 ++++++++-- .../hooks/useInputSMSSendAddress.tsx | 30 +-- .../hello-techno/hooks/useParkingList.tsx | 227 ++++++++++++++++++ .../hooks/useSelectParkingStep.tsx | 221 ----------------- 8 files changed, 429 insertions(+), 303 deletions(-) create mode 100644 src/pages/dashboard/receipt-issuing-order/custom/hello-techno/contexts/CreateContext.tsx create mode 100644 src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useCreate.ts create mode 100644 src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useParkingList.tsx delete mode 100644 src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useSelectParkingStep.tsx diff --git a/src/api/custom/hello-techno/index.ts b/src/api/custom/hello-techno/index.ts index c87d713..4d57206 100644 --- a/src/api/custom/hello-techno/index.ts +++ b/src/api/custom/hello-techno/index.ts @@ -7,8 +7,10 @@ export type HTCustomer = { }; export type HTParking = { customer_code: string; + customer_name: string; parking_management_code: string; - name: string; + parking_name: string; + name: string; // 旧API仕様 }; export type HTAdjustData = { customer_code: string; @@ -39,7 +41,9 @@ export const getHTCustomers = async (data = {}) => { // 駐車場一覧取得 --------------------- export type HTParkingsRequest = { - customer_code: string; + customer_code?: string; + parking_management_code?: string; + parking_name?: string; }; export type HTParkingsResponse = { diff --git a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/contexts/CreateContext.tsx b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/contexts/CreateContext.tsx new file mode 100644 index 0000000..f985c1b --- /dev/null +++ b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/contexts/CreateContext.tsx @@ -0,0 +1,41 @@ +import { HasChildren } from "@types"; +import { HTAdjustData, HTParking } from "api/custom/hello-techno"; +import { createContext, useState } from "react"; + +type ContextProps = { + parking: HTParking | null; + setParking: (parking: HTParking | null) => void; + + adjustData: HTAdjustData | null; + setAdjustData: (adjustData: HTAdjustData | null) => void; +}; + +export const CreateContext = createContext({ + parking: null, + setParking: (parking: HTParking | null) => { + console.error("setParking未定義"); + }, + adjustData: null, + setAdjustData: (adjustData: HTAdjustData | null) => { + console.error("setAdjustData未定義"); + }, +}); + +type ProviderProps = {} & HasChildren; +export function CreateContextProvider({ children }: ProviderProps) { + const [parking, setParking] = useState(null); + const [adjustData, setAdjustData] = useState(null); + + return ( + + {children} + + ); +} diff --git a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/create.tsx b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/create.tsx index e8146c1..d6d09a9 100644 --- a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/create.tsx +++ b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/create.tsx @@ -1,16 +1,17 @@ import { Box, Step, StepLabel, Stepper } from "@mui/material"; -import { getHTAdjustData } from "api/custom/hello-techno"; +import { HTParking } from "api/custom/hello-techno"; import { createReceiptIssuingOrder } from "api/custom/hello-techno/receipt-issuing-order"; import { PageID, TabID } from "codes/page"; -import { getValue } from "components/hook-form/RHFAutoComplete"; import useAPICall from "hooks/useAPICall"; import useDashboard from "hooks/useDashBoard"; import useSnackbarCustom from "hooks/useSnackbarCustom"; import { useEffect, useMemo, useState } from "react"; +import { CreateContextProvider } from "./contexts/CreateContext"; import useConfirm, { ConfirmDataProps } from "./hooks/useConfirm"; +import useCreate from "./hooks/useCreate"; import useInputReceiptStep from "./hooks/useInputReceiptStep"; import useInputSMSSendAddress from "./hooks/useInputSMSSendAddress"; -import useSelectParkingStep from "./hooks/useSelectParkingStep"; +import useParkingList from "./hooks/useParkingList"; export default function ReceiptIssuingOrderCreate() { const { setHeaderTitle, setTabs } = useDashboard( @@ -18,6 +19,19 @@ export default function ReceiptIssuingOrderCreate() { TabID.NONE ); + useEffect(() => { + setHeaderTitle("領収証発行依頼作成"); + setTabs(null); + }, []); + return ( + + + + ); +} +function Create() { + const { parking, adjustData } = useCreate(); + const { success, error } = useSnackbarCustom(); const [mode, setMode] = useState< @@ -41,9 +55,9 @@ export default function ReceiptIssuingOrderCreate() { const getConfimData = (): ConfirmDataProps => { return { - customerName: selectParkingStep.values("customerCode.label"), - parkingName: selectParkingStep.values("parkingManagementCode.label"), - adjustSeqNo: selectParkingStep.values("adjustSeqNo"), + customerName: parking?.customer_name ?? "XXXXXXXXXXXX", + parkingName: parking?.parking_name ?? "XXXXXXXXXXXXXXX", + adjustSeqNo: adjustData ? String(adjustData.adjust_seq_no) : "", amount: inputReceiptStep.values("amount"), date: inputReceiptStep.values("date"), address: inputSMSSendAddress.values("address"), @@ -52,39 +66,17 @@ export default function ReceiptIssuingOrderCreate() { }; const getFormData = () => { return { - ...selectParkingStep.values(), + ...parking, ...inputReceiptStep.values(), ...inputSMSSendAddress.values(), }; }; - const adjustDataAPI = useAPICall({ - apiMethod: getHTAdjustData, - backDrop: true, - onSuccess: ({ data }) => { - inputReceiptStep.setAdjustData(data); + const selectParkingStep = useParkingList({ + onNext: (parking: HTParking) => { + inputReceiptStep.init(); setMode("input_receipt"); }, - onFailed: () => { - error("精算履歴が存在しません"); - }, - }); - - const selectParkingStep = useSelectParkingStep({ - onNext: () => { - const { customerCode, parkingManagementCode, adjustSeqNo } = - getFormData(); - if (adjustSeqNo) { - adjustDataAPI.callAPI({ - customer_code: getValue(customerCode), - parking_management_code: getValue(parkingManagementCode), - adjust_seq_no: adjustSeqNo, - }); - } else { - inputReceiptStep.setAdjustData(null); - setMode("input_receipt"); - } - }, }); const inputReceiptStep = useInputReceiptStep({ @@ -131,9 +123,9 @@ export default function ReceiptIssuingOrderCreate() { const formData = getFormData(); const sendData = makeSendData({ - customer_code: getValue(formData.customerCode), - parking_management_code: getValue(formData.parkingManagementCode), - adjust_seq_no: formData.adjustSeqNo, + customer_code: formData.customer_code ?? "", + parking_management_code: formData.parking_management_code ?? "", + adjust_seq_no: adjustData?.adjust_seq_no, receipt_use_date: formData.date, receipt_amount: formData.amount, tax_amount: formData.tax_amount, @@ -144,10 +136,6 @@ export default function ReceiptIssuingOrderCreate() { callAPI(sendData); }; - useEffect(() => { - setHeaderTitle("領収証発行依頼作成"); - setTabs(null); - }, []); return ( diff --git a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useCreate.ts b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useCreate.ts new file mode 100644 index 0000000..1f160e4 --- /dev/null +++ b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useCreate.ts @@ -0,0 +1,8 @@ +import { useContext } from "react"; +import { CreateContext } from "../contexts/CreateContext"; + +export default function useCreate() { + const context = useContext(CreateContext); + + return context; +} diff --git a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useInputReceiptStep.tsx b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useInputReceiptStep.tsx index 9b10608..780fb29 100644 --- a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useInputReceiptStep.tsx +++ b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useInputReceiptStep.tsx @@ -1,16 +1,19 @@ import { yupResolver } from "@hookform/resolvers/yup"; -import { Box, Button, Stack, Typography } from "@mui/material"; +import { Box, Button, Divider, Stack, Typography } from "@mui/material"; import { HasChildren } from "@types"; -import { HTAdjustData } from "api/custom/hello-techno"; +import { getHTAdjustData } from "api/custom/hello-techno"; import RequireChip from "components/chip/RequireChip"; import { FormProvider, RHFTextField } from "components/hook-form"; import RHFDatePicker from "components/hook-form/RHFDatePicker"; import StackRow from "components/stack/StackRow"; -import { useEffect, useMemo, useState } from "react"; +import useAPICall from "hooks/useAPICall"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import { useEffect, useMemo } from "react"; import { useForm } from "react-hook-form"; import { dateTimeParse } from "utils/datetime"; import { calcInnerTax } from "utils/tax"; import * as Yup from "yup"; +import useCreate from "./useCreate"; type AreaBoxProps = { title: string; @@ -18,17 +21,18 @@ type AreaBoxProps = { } & HasChildren; function AreaBox({ title, children, require }: AreaBoxProps) { return ( - + {title} - + {children} - + ); } type FormProps = { + adjust_seq_no: string; amount: string; tax_amount: string; date: Date | null; @@ -40,10 +44,13 @@ type Props = { onPrev?: VoidFunction; }; export default function useInputReceiptStep({ onNext, onPrev }: Props) { - const [adjustData, _setAdjustData] = useState(null); + const { parking, adjustData, setAdjustData } = useCreate(); + + const { error } = useSnackbarCustom(); const form = useForm({ defaultValues: { + adjust_seq_no: "", amount: "", tax_amount: "", date: null, @@ -82,10 +89,6 @@ export default function useInputReceiptStep({ onNext, onPrev }: Props) { } }; - const setAdjustData = (data: HTAdjustData | null) => { - _setAdjustData(data); - }; - const canCalcTax = useMemo(() => { return !adjustData; }, [adjustData]); @@ -97,29 +100,108 @@ export default function useInputReceiptStep({ onNext, onPrev }: Props) { form.setValue("tax_amount", String(calcInnerTax(amount))); }; + const adjustDataAPI = useAPICall({ + apiMethod: getHTAdjustData, + backDrop: true, + onSuccess: ({ data }) => { + setAdjustData(data); + }, + onFailed: () => { + error("精算履歴が存在しません"); + }, + }); + + const handleSearchAdjsutData = () => { + const adjustSeqNo = form.getValues("adjust_seq_no"); + + if (!adjustSeqNo) { + error("精算連番を入力してください"); + return; + } + const adjustSeqNoNumber = Number(adjustSeqNo); + if (!(1 <= adjustSeqNoNumber && adjustSeqNoNumber <= 99999)) { + error("1-999999の範囲で入力してください"); + return; + } + if (!parking) { + error("駐車場未選択"); + return; + } + + adjustDataAPI.callAPI({ + adjust_seq_no: adjustSeqNo, + customer_code: parking.customer_code, + parking_management_code: parking.parking_management_code, + }); + }; + + const handleClearAdjustData = () => { + init(); + }; + const readOnly = useMemo(() => { return adjustData !== null; }, [adjustData]); + const init = () => { + form.clearErrors(); + setAdjustData(null); + form.setValue("adjust_seq_no", ""); + form.setValue("amount", ""); + form.setValue("tax_amount", ""); + form.setValue("date", null); + form.setValue("memo", ""); + }; + const element = ( - + 〇精算連番が特定できる場合は入力してください + + + + + + + + + + + + + - - 円, - }} - sx={{ maxWidth: 150 }} - readOnly={readOnly} - /> + + + 円 + ), + }} + sx={{ maxWidth: 150 }} + readOnly={readOnly} + /> + - + - {title} + + + {title} + + {children} - + ); } @@ -64,7 +60,7 @@ export default function useInputSMSSendAddress({ onNext, onPrev }: Props) { const element = ( - + diff --git a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useParkingList.tsx b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useParkingList.tsx new file mode 100644 index 0000000..4850b13 --- /dev/null +++ b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useParkingList.tsx @@ -0,0 +1,227 @@ +import { + Box, + Grid, + Stack, + Table, + TableBody, + TableCell, + TableContainer, + TablePagination, + TableRow, + Typography, +} from "@mui/material"; +import { + HTParking, + HTParkingsRequest, + getHTParkings, +} from "api/custom/hello-techno"; +import { FormProvider, RHFTextField } from "components/hook-form"; +import { TableHeadCustom } from "components/table"; +import { HeadLabelProps } from "components/table/TableHeadCustom"; +import useAPICall from "hooks/useAPICall"; +import useTable, { UseTableReturn } from "hooks/useTable"; +import { isEqual } from "lodash"; +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import useCreate from "./useCreate"; + +export const SearchParam = { + PARKING_MANAGEMENT_CODE: "parking_management_code", + PARKING_NAME: "parking_name", +} as const; +export type SearchParam = (typeof SearchParam)[keyof typeof SearchParam]; + +type Props = { onNext: (parking: HTParking) => void }; +export default function useParkingList({ onNext }: Props) { + const table = useTable(); + const { setParking } = useCreate(); + + const handleNext = (parking: HTParking) => { + setParking(parking); + onNext(parking); + }; + + const element = ( + + + + + ); + + return { element }; +} + +type FormProps = { + [SearchParam.PARKING_MANAGEMENT_CODE]: string; + [SearchParam.PARKING_NAME]: string; +}; +type CommonProps = { + table: UseTableReturn; +}; +function SearchBox({ table }: CommonProps) { + const form = useForm({ + defaultValues: { + [SearchParam.PARKING_MANAGEMENT_CODE]: "", + [SearchParam.PARKING_NAME]: "", + }, + }); + + const { callAPI: callGetHTParkings, makeSendData } = useAPICall({ + apiMethod: getHTParkings, + backDrop: true, + form, + onSuccess: (res) => { + table.setRowData(res.data.records); + }, + }); + + const [currentSendData, setCurrentSendData] = + useState(null); + + const handleSubmit = () => { + fetch(); + }; + + const handleBlur = () => { + fetch(); + }; + + const fetch = async () => { + const data = form.getValues(); + + if (!data.parking_name && !data.parking_management_code) return; + + const sendData = makeSendData({ + ...data, + }); + + if (!isEqual(sendData, currentSendData)) { + callGetHTParkings(sendData); + setCurrentSendData(sendData); + } + }; + + return ( + + + + + + 駐車場管理コード5桁 + + + + + + 駐車場名 + + + + + + + ); +} + +type TableProps = { + onNext: (parking: HTParking) => void; +} & CommonProps; +function TableBox({ table, onNext }: TableProps) { + const TABLE_HEAD: HeadLabelProps[] = [ + { + id: "customer_name", + label: "運営会社名", + align: "left", + needSort: false, + }, + { id: "parking_name", label: "駐車場名", align: "left", needSort: false }, + { + id: "parking_management_code", + label: "駐車場管理コード", + align: "left", + needSort: false, + }, + ]; + const { + order, + page, + sort, + rowsPerPage, + fetched, + fillteredRow, + isNotFound, + dataLength, + // + onSort, + onChangePage, + onChangeRowsPerPage, + // + setRowData, + // + ROWS_PER_PAGES, + } = table; + + return ( + <> + + + + + + {fillteredRow.map((row, index) => ( + + ))} + +
+
+ + + + + + ); +} + +type RowProps = { + data: HTParking; + onNext: (parking: HTParking) => void; +}; +function Row({ data, onNext }: RowProps) { + const handleClick = () => { + onNext(data); + }; + + return ( + + {data.customer_name} + {data.parking_name ?? data.name} + {data.parking_management_code} + + ); +} diff --git a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useSelectParkingStep.tsx b/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useSelectParkingStep.tsx deleted file mode 100644 index 37c31f2..0000000 --- a/src/pages/dashboard/receipt-issuing-order/custom/hello-techno/hooks/useSelectParkingStep.tsx +++ /dev/null @@ -1,221 +0,0 @@ -import { yupResolver } from "@hookform/resolvers/yup"; -import { Box, Button, Grid, Stack, Typography } from "@mui/material"; -import { HasChildren } from "@types"; -import { - getHTCustomers, - getHTParking, - getHTParkings, -} from "api/custom/hello-techno"; -import { - FormProvider, - RHFAutoComplete, - RHFTextField, -} from "components/hook-form"; -import { - AutoCompleteOption, - AutoCompleteOptionType, -} from "components/hook-form/RHFAutoComplete"; -import useAPICall from "hooks/useAPICall"; -import useSnackbarCustom from "hooks/useSnackbarCustom"; -import { useEffect, useMemo, useState } from "react"; -import { useForm } from "react-hook-form"; -import * as Yup from "yup"; - -type AreaBoxProps = { - title: string; -} & HasChildren; -function AreaBox({ title, children }: AreaBoxProps) { - return ( - - {title} - {children} - - ); -} - -type FormProps = { - customerCode: AutoCompleteOptionType; - parkingManagementCode: AutoCompleteOptionType; - adjustSeqNo: string; - serachParkingManagementCode: string; -}; - -type Props = { - onNext?: VoidFunction; -}; -export default function useSelectParkingStep({ onNext }: Props) { - const [customers, setCustomers] = useState([]); - const [parkings, setParkings] = useState([]); - - const { error } = useSnackbarCustom(); - - const customerAPI = useAPICall({ - apiMethod: getHTCustomers, - backDrop: true, - onSuccess: ({ data }) => { - const options: AutoCompleteOption[] = data.records.map( - ({ customer_code, name }) => { - return { - label: name, - value: customer_code, - }; - } - ); - setCustomers(options); - }, - }); - - const parkingAPI = useAPICall({ - apiMethod: getHTParkings, - backDrop: true, - onSuccess: ({ data }) => { - const options: AutoCompleteOption[] = data.records.map( - ({ parking_management_code, name }) => { - return { - label: name, - value: parking_management_code, - }; - } - ); - setParkings(options); - }, - }); - - const parkingByCodeAPI = useAPICall({ - apiMethod: getHTParking, - backDrop: true, - onSuccess: ({ data }) => { - const options: AutoCompleteOption[] = []; - options.push({ - label: data.name, - value: data.parking_management_code, - }); - setParkings(options); - - form.setValue("customerCode", data.customer_code); - }, - onFailed: (res) => { - error("駐車場の特定に失敗しました"); - console.log(res); - }, - }); - - const form = useForm({ - defaultValues: { - customerCode: null, - parkingManagementCode: null, - adjustSeqNo: "", - serachParkingManagementCode: "", - }, - resolver: yupResolver( - Yup.object().shape({ - customerCode: Yup.object().required("必須項目です"), - parkingManagementCode: Yup.object().required("必須項目です"), - adjustSeqNo: Yup.number() - .nullable() - .transform((value, originalValue) => - String(originalValue).trim() === "" ? null : value - ) - .typeError("数値を入力してください"), - }) - ), - }); - - const customerCode = form.watch("customerCode.value"); - const searchParkingManagementCode = form.watch("serachParkingManagementCode"); - - const handleSubmit = () => { - if (onNext) { - onNext(); - } - }; - - const handleClickSearchParking = () => { - parkingByCodeAPI.callAPI({ - parking_management_code: searchParkingManagementCode, - }); - }; - - const canSearchParking = useMemo(() => { - const reg = /^[0-9]{5}$/; - return reg.test(searchParkingManagementCode); - }, [searchParkingManagementCode]); - - // 顧客一覧取得 - useEffect(() => { - customerAPI.callAPI({}); - }, []); - - // 駐車場一覧取得 - useEffect(() => { - if (!canSearchParking) { - setParkings([]); - form.setValue("parkingManagementCode", null); - - if (customerCode) { - parkingAPI.callAPI({ customer_code: customerCode }); - } - } - }, [customerCode]); - - useEffect(() => { - if (parkings.length === 1) { - const parking = parkings[0]; - form.setValue("parkingManagementCode", parking); - } - }, [parkings]); - - const element = ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); - - return { element, values: form.getValues, setValue: form.setValue }; -}