| @@ -9,6 +9,7 @@ | |||||
| "@mui/icons-material": "^5.11.16", | "@mui/icons-material": "^5.11.16", | ||||
| "@mui/lab": "^5.0.0-alpha.129", | "@mui/lab": "^5.0.0-alpha.129", | ||||
| "@mui/material": "^5.12.2", | "@mui/material": "^5.12.2", | ||||
| "@mui/x-date-pickers": "^6.4.0", | |||||
| "@testing-library/jest-dom": "^5.14.1", | "@testing-library/jest-dom": "^5.14.1", | ||||
| "@testing-library/react": "^13.0.0", | "@testing-library/react": "^13.0.0", | ||||
| "@testing-library/user-event": "^13.2.1", | "@testing-library/user-event": "^13.2.1", | ||||
| @@ -8,22 +8,31 @@ import { BrowserRouter } from "react-router-dom"; | |||||
| import { Routes } from "routes"; | import { Routes } from "routes"; | ||||
| import AppThemeProvider from "theme"; | import AppThemeProvider from "theme"; | ||||
| import { LocalizationProvider } from "@mui/x-date-pickers"; | |||||
| import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; | |||||
| import ja from "date-fns/locale/ja"; | |||||
| import BackDropContextProvider from "contexts/BackDropContext"; | |||||
| export default function App() { | export default function App() { | ||||
| return ( | return ( | ||||
| <AuthContextProvider> | |||||
| <PageContextProvider> | |||||
| <WindowSizeContextProvider> | |||||
| <BrowserRouter> | |||||
| <AppThemeProvider> | |||||
| <SnackbarProvider> | |||||
| <CsrfTokenProvider /> | |||||
| <CssBaseline /> | |||||
| <Routes /> | |||||
| </SnackbarProvider> | |||||
| </AppThemeProvider> | |||||
| </BrowserRouter> | |||||
| </WindowSizeContextProvider> | |||||
| </PageContextProvider> | |||||
| </AuthContextProvider> | |||||
| <LocalizationProvider dateAdapter={AdapterDateFns} adapterLocale={ja}> | |||||
| <AuthContextProvider> | |||||
| <PageContextProvider> | |||||
| <WindowSizeContextProvider> | |||||
| <BrowserRouter> | |||||
| <AppThemeProvider> | |||||
| <SnackbarProvider> | |||||
| <BackDropContextProvider> | |||||
| <CsrfTokenProvider /> | |||||
| <CssBaseline /> | |||||
| <Routes /> | |||||
| </BackDropContextProvider> | |||||
| </SnackbarProvider> | |||||
| </AppThemeProvider> | |||||
| </BrowserRouter> | |||||
| </WindowSizeContextProvider> | |||||
| </PageContextProvider> | |||||
| </AuthContextProvider> | |||||
| </LocalizationProvider> | |||||
| ); | ); | ||||
| } | } | ||||
| @@ -0,0 +1,69 @@ | |||||
| import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from "api"; | |||||
| import { getUrl } from "api/url"; | |||||
| export type HTCustomer = { | |||||
| customer_code: string; | |||||
| name: string; | |||||
| }; | |||||
| export type HTParking = { | |||||
| customer_code: string; | |||||
| parking_management_code: string; | |||||
| name: string; | |||||
| }; | |||||
| export type HTAdjustData = { | |||||
| customer_code: string; | |||||
| parking_management_code: string; | |||||
| adjust_seq_no: number; | |||||
| adjust_datetime: string; | |||||
| }; | |||||
| export type HTCustomersResponse = { | |||||
| data: { | |||||
| records: HTCustomer[]; | |||||
| }; | |||||
| } & APICommonResponse; | |||||
| export const getHTCustomers = async (data = {}) => { | |||||
| const res = await request<HTCustomersResponse>({ | |||||
| url: getUrl(ApiId.HT_CUSTOM_CUSTOMERS), | |||||
| method: HttpMethod.GET, | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| export type HTParkingsRequest = { | |||||
| customer_code: string; | |||||
| }; | |||||
| export type HTParkingsResponse = { | |||||
| data: { | |||||
| records: HTParking[]; | |||||
| }; | |||||
| } & APICommonResponse; | |||||
| export const getHTParkings = async (data: HTParkingsRequest) => { | |||||
| console.log({ data }); | |||||
| const res = await request<HTParkingsResponse>({ | |||||
| url: getUrl(ApiId.HT_CUSTOM_PARKINGS), | |||||
| method: HttpMethod.GET, | |||||
| data: new URLSearchParams(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| export type HTAdjustDataRequest = { | |||||
| customer_code: string; | |||||
| }; | |||||
| export type HTAdjustDataResponse = { | |||||
| data: HTAdjustData; | |||||
| } & APICommonResponse; | |||||
| export const getHTAdjustData = async (data: HTAdjustDataRequest) => { | |||||
| const res = await request<HTAdjustDataResponse>({ | |||||
| url: getUrl(ApiId.HT_CUSTOM_ADJUST_DATA), | |||||
| method: HttpMethod.GET, | |||||
| data: new URLSearchParams(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| @@ -0,0 +1,52 @@ | |||||
| import { | |||||
| APICommonResponse, | |||||
| ApiId, | |||||
| HttpMethod, | |||||
| makeFormData, | |||||
| request, | |||||
| } from "api"; | |||||
| import { getUrl } from "api/url"; | |||||
| export type HTCustomer = { | |||||
| customer_code: string; | |||||
| name: string; | |||||
| }; | |||||
| export type HTParking = { | |||||
| customer_code: string; | |||||
| parking_management_code: string; | |||||
| name: string; | |||||
| }; | |||||
| export type HTAdjustData = { | |||||
| customer_code: string; | |||||
| parking_management_code: string; | |||||
| adjust_seq_no: number; | |||||
| adjust_datetime: string; | |||||
| }; | |||||
| export type CreateReceiptIssuingOrderRequest = { | |||||
| customer_code: string; | |||||
| parking_management_code: string; | |||||
| adjust_seq_no?: string | number; | |||||
| receipt_name: string; | |||||
| receipt_use_datetime: Date | null; | |||||
| receipt_amount: string | number; | |||||
| memo?: string; | |||||
| sms_phone_number: string; | |||||
| }; | |||||
| export type HTCustomersResponse = { | |||||
| data: { | |||||
| records: HTCustomer[]; | |||||
| }; | |||||
| } & APICommonResponse; | |||||
| export const createReceiptIssuingOrder = async ( | |||||
| data: CreateReceiptIssuingOrderRequest | |||||
| ) => { | |||||
| const res = await request({ | |||||
| url: getUrl(ApiId.HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE), | |||||
| method: HttpMethod.POST, | |||||
| data: makeFormData(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| @@ -12,6 +12,16 @@ export const ApiId = { | |||||
| LOGIN: id++, | LOGIN: id++, | ||||
| LOGOUT: id++, | LOGOUT: id++, | ||||
| RECEIPT_ISSUING_ORDERS: id++, | |||||
| RECEIPT_ISSUING_ORDER: id++, | |||||
| RECEIPT_ISSUING_ORDER_CREATE: id++, | |||||
| // FOR CUSTOM | |||||
| HT_CUSTOM_CUSTOMERS: id++, | |||||
| HT_CUSTOM_PARKINGS: id++, | |||||
| HT_CUSTOM_ADJUST_DATA: id++, | |||||
| HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE: id++, | |||||
| } as const; | } as const; | ||||
| export type ApiId = (typeof ApiId)[keyof typeof ApiId]; | export type ApiId = (typeof ApiId)[keyof typeof ApiId]; | ||||
| @@ -201,34 +211,43 @@ export async function apiRequest< | |||||
| if (setSending) { | if (setSending) { | ||||
| setSending(true); | setSending(true); | ||||
| } | } | ||||
| const res = await apiMethod(sendData); | |||||
| if (setSending) { | |||||
| setSending(false); | |||||
| } | |||||
| if (res?.result === ResultCode.SUCCESS) { | |||||
| if (onSuccess) { | |||||
| onSuccess(res, sendData); | |||||
| try { | |||||
| const res = await apiMethod(sendData); | |||||
| if (setSending) { | |||||
| setSending(false); | |||||
| } | } | ||||
| } else { | |||||
| if (res?.messages.errors) { | |||||
| if (errorSetter) { | |||||
| const errorCount = setFormErrorMessages( | |||||
| sendData, | |||||
| errorSetter, | |||||
| res.messages.errors | |||||
| ); | |||||
| console.log("FormErrorCount", errorCount); | |||||
| if (res?.result === ResultCode.SUCCESS) { | |||||
| if (onSuccess) { | |||||
| onSuccess(res, sendData); | |||||
| } | |||||
| } else { | |||||
| if (res?.messages.errors) { | |||||
| if (errorSetter) { | |||||
| const errorCount = setFormErrorMessages( | |||||
| sendData, | |||||
| errorSetter, | |||||
| res.messages.errors | |||||
| ); | |||||
| console.log("FormErrorCount", errorCount); | |||||
| } | |||||
| } | |||||
| if (onFailed) { | |||||
| onFailed(res); | |||||
| } | |||||
| if (onFinaly) { | |||||
| onFinaly(res); | |||||
| } | } | ||||
| } | } | ||||
| return res; | |||||
| } catch (e) { | |||||
| console.error(e); | |||||
| if (onFailed) { | if (onFailed) { | ||||
| onFailed(res); | |||||
| onFailed(null); | |||||
| } | } | ||||
| if (onFinaly) { | |||||
| onFinaly(null); | |||||
| } | |||||
| return null; | |||||
| } | } | ||||
| if (onFinaly) { | |||||
| onFinaly(res); | |||||
| } | |||||
| return res; | |||||
| } | } | ||||
| @@ -0,0 +1,30 @@ | |||||
| import { ReceiptIssuingOrderStatus } from "codes/receipt-issuing-order"; | |||||
| import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from "."; | |||||
| import { getUrl } from "./url"; | |||||
| export type ReceiptIssuingOrder = { | |||||
| id: string; | |||||
| status: ReceiptIssuingOrderStatus; | |||||
| }; | |||||
| export type ReceiptIssuingOrdersRequest = { | |||||
| address?: string; | |||||
| status?: ReceiptIssuingOrderStatus; | |||||
| }; | |||||
| export type ReceiptIssuingOrdersResponse = { | |||||
| data: { | |||||
| records: ReceiptIssuingOrder[]; | |||||
| }; | |||||
| } & APICommonResponse; | |||||
| export const getReceiptIssuingOrders = async ( | |||||
| data: ReceiptIssuingOrdersRequest | |||||
| ) => { | |||||
| const res = await request<ReceiptIssuingOrdersResponse>({ | |||||
| url: getUrl(ApiId.RECEIPT_ISSUING_ORDERS), | |||||
| method: HttpMethod.GET, | |||||
| data: makeParam(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| @@ -1,22 +1,31 @@ | |||||
| import { ApiId } from "."; | |||||
| import { ApiId as A } from "."; | |||||
| const urls = { | const urls = { | ||||
| [ApiId.CSRF_TOKEN]: "sanctum/csrf-cookie", | |||||
| [ApiId.ME]: "me", | |||||
| [ApiId.LOGIN]: "login", | |||||
| [ApiId.LOGOUT]: "logout", | |||||
| [A.CSRF_TOKEN]: "sanctum/csrf-cookie", | |||||
| [A.ME]: "me", | |||||
| [A.LOGIN]: "login", | |||||
| [A.LOGOUT]: "logout", | |||||
| [A.RECEIPT_ISSUING_ORDERS]: "receipt-issuing-orders", | |||||
| // FOR CUSTOM | |||||
| [A.HT_CUSTOM_CUSTOMERS]: "custom/hello-techno/customers", | |||||
| [A.HT_CUSTOM_PARKINGS]: "custom/hello-techno/parkings", | |||||
| [A.HT_CUSTOM_ADJUST_DATA]: "custom/hello-techno/adjust-data", | |||||
| [A.HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE]: | |||||
| "custom/hello-techno/receipt-issuing-order/create", | |||||
| }; | }; | ||||
| const prefixs = { | const prefixs = { | ||||
| [ApiId.CSRF_TOKEN]: "", | |||||
| [A.CSRF_TOKEN]: "", | |||||
| }; | }; | ||||
| const DEFAULT_API_URL_PREFIX = "api"; | const DEFAULT_API_URL_PREFIX = "api"; | ||||
| const getPrefix = (apiId: ApiId) => { | |||||
| const getPrefix = (apiId: A) => { | |||||
| return prefixs[apiId] ?? DEFAULT_API_URL_PREFIX; | return prefixs[apiId] ?? DEFAULT_API_URL_PREFIX; | ||||
| }; | }; | ||||
| export const getUrl = (apiId: ApiId) => { | |||||
| export const getUrl = (apiId: A) => { | |||||
| let url = getPrefix(apiId); | let url = getPrefix(apiId); | ||||
| if (url.length !== 0) { | if (url.length !== 0) { | ||||
| url += "/"; | url += "/"; | ||||
| @@ -0,0 +1,22 @@ | |||||
| export const ReceiptIssuingOrderStatus = { | |||||
| NONE: 0, | |||||
| CREATED: 100, // 新規作成 | |||||
| SMS_SENDING: 200, // SMS送信中 | |||||
| SMS_RECEIVED: 300, // SMS送信完了 | |||||
| SMS_OPENED: 400, // SMS開封 | |||||
| // 郵送関連 | |||||
| MAIL_REQUEST: 500, // 郵送依頼中 | |||||
| PREPARING_FOR_MAIL: 510, // 郵送準備中 | |||||
| MAIL_DONE: 520, // 郵送完了 | |||||
| // Email送信関連 | |||||
| EMAIL_SENDING: 600, // Email送信中 | |||||
| EMAIL_DONE: 610, // Email送信完了 | |||||
| // PDFダウンロード | |||||
| DOWNLOAD_DONE: 700, // ダウンロード完了 | |||||
| } as const; | |||||
| export type ReceiptIssuingOrderStatus = | |||||
| (typeof ReceiptIssuingOrderStatus)[keyof typeof ReceiptIssuingOrderStatus]; | |||||
| @@ -1,4 +1,3 @@ | |||||
| // form | |||||
| import { | import { | ||||
| Controller, | Controller, | ||||
| ControllerFieldState, | ControllerFieldState, | ||||
| @@ -6,15 +5,8 @@ import { | |||||
| FieldValues, | FieldValues, | ||||
| useFormContext, | useFormContext, | ||||
| } from "react-hook-form"; | } from "react-hook-form"; | ||||
| // @mui | |||||
| import ClearIcon from "@mui/icons-material/Clear"; | |||||
| import { DatePicker } from "@mui/lab"; | |||||
| import { | |||||
| IconButton, | |||||
| InputAdornment, | |||||
| TextField, | |||||
| TextFieldProps, | |||||
| } from "@mui/material"; | |||||
| import { TextFieldProps } from "@mui/material"; | |||||
| import { DatePicker } from "@mui/x-date-pickers"; | |||||
| import React, { useMemo } from "react"; | import React, { useMemo } from "react"; | ||||
| import RHFTextField from "./RHFTextField"; | import RHFTextField from "./RHFTextField"; | ||||
| @@ -35,36 +27,21 @@ const RHFDatePicker = ({ | |||||
| datePickerProps, | datePickerProps, | ||||
| ...other | ...other | ||||
| }: Props) => { | }: Props) => { | ||||
| const { control, watch, setValue } = useFormContext(); | |||||
| const { | |||||
| control, | |||||
| watch, | |||||
| setValue, | |||||
| formState: { errors }, | |||||
| } = useFormContext(); | |||||
| const value: Date | null = watch(name); | const value: Date | null = watch(name); | ||||
| const handleClear = () => { | |||||
| setValue(name, null); | |||||
| }; | |||||
| const icon = useMemo(() => { | |||||
| if (value !== null) { | |||||
| return ( | |||||
| <InputAdornment position="end"> | |||||
| <IconButton onClick={handleClear} edge="end"> | |||||
| <ClearIcon /> | |||||
| </IconButton> | |||||
| </InputAdornment> | |||||
| ); | |||||
| } else { | |||||
| return null; | |||||
| } | |||||
| }, [value]); | |||||
| const iconMerge = (ele: React.ReactNode) => { | |||||
| return ( | |||||
| <> | |||||
| {icon} | |||||
| {ele} | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| const isError = useMemo(() => { | |||||
| return !!errors[name]; | |||||
| }, [errors, name]); | |||||
| const errorMessage = useMemo(() => { | |||||
| return errors[name]?.message ?? ""; | |||||
| }, [errors, name]); | |||||
| if (readOnly) { | if (readOnly) { | ||||
| return <RHFTextField name={name} readOnly {...other} variant="standard" />; | return <RHFTextField name={name} readOnly {...other} variant="standard" />; | ||||
| @@ -79,23 +56,21 @@ const RHFDatePicker = ({ | |||||
| }) => { | }) => { | ||||
| return ( | return ( | ||||
| <DatePicker | <DatePicker | ||||
| inputFormat="yyyy/MM/dd" | |||||
| mask="____/__/__" | |||||
| renderInput={(params: any) => ( | |||||
| <TextField | |||||
| {...params} | |||||
| fullWidth | |||||
| error={fieldState.invalid} | |||||
| helperText={fieldState.error?.message} | |||||
| InputProps={{ | |||||
| ...params.InputProps, | |||||
| endAdornment: iconMerge(params.InputProps?.endAdornment), | |||||
| }} | |||||
| {...other} | |||||
| /> | |||||
| )} | |||||
| {...datePickerProps} | |||||
| slotProps={{ | |||||
| actionBar: { | |||||
| actions: ["accept", "clear", "cancel"], | |||||
| }, | |||||
| inputAdornment: { | |||||
| position: "start", | |||||
| }, | |||||
| textField: { | |||||
| size: "small", | |||||
| error: isError, | |||||
| helperText: errorMessage, | |||||
| }, | |||||
| }} | |||||
| {...field} | {...field} | ||||
| {...datePickerProps} | |||||
| /> | /> | ||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -0,0 +1,35 @@ | |||||
| import { Backdrop, CircularProgress, useTheme } from "@mui/material"; | |||||
| import { createContext, useState } from "react"; | |||||
| type Props = { | |||||
| children: React.ReactNode; | |||||
| }; | |||||
| type ContextProps = { | |||||
| showBackDrop: boolean; | |||||
| setShowBackDrop: (show: boolean) => void; | |||||
| }; | |||||
| const defaultProps: ContextProps = { | |||||
| showBackDrop: false, | |||||
| setShowBackDrop: (show: boolean) => {}, | |||||
| }; | |||||
| export const BackDroptContext = createContext<ContextProps>(defaultProps); | |||||
| export default function BackDropContextProvider({ children }: Props) { | |||||
| const [showBackDrop, setShowBackDrop] = useState(false); | |||||
| return ( | |||||
| <BackDroptContext.Provider value={{ showBackDrop, setShowBackDrop }}> | |||||
| {children} | |||||
| <Backdrop | |||||
| open={showBackDrop} | |||||
| sx={{ | |||||
| // display: 'frex', | |||||
| zIndex: 9999, | |||||
| opacity: "0.3 !important", | |||||
| }} | |||||
| > | |||||
| <CircularProgress color="inherit" /> | |||||
| </Backdrop> | |||||
| </BackDroptContext.Provider> | |||||
| ); | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| import { useContext } from "react"; | |||||
| import { BackDroptContext } from "contexts/BackDropContext"; | |||||
| export default function useBackDrop() { | |||||
| return useContext(BackDroptContext); | |||||
| } | |||||
| @@ -13,5 +13,5 @@ export default function Overview() { | |||||
| setHeaderTitle("Dashboard"); | setHeaderTitle("Dashboard"); | ||||
| setTabs(null); | setTabs(null); | ||||
| }, []); | }, []); | ||||
| return <Box></Box>; | |||||
| return <Box sx={{ p: 1, m: 1 }}></Box>; | |||||
| } | } | ||||
| @@ -1,7 +1,16 @@ | |||||
| import { Box } from "@mui/material"; | |||||
| import { Box, Step, StepLabel, Stepper } from "@mui/material"; | |||||
| import { PageID, TabID } from "codes/page"; | import { PageID, TabID } from "codes/page"; | ||||
| import useDashboard from "hooks/useDashBoard"; | import useDashboard from "hooks/useDashBoard"; | ||||
| import { useEffect } from "react"; | |||||
| import { useEffect, useMemo, useState } from "react"; | |||||
| import useSelectParkingStep from "./hooks/useSelectParkingStep"; | |||||
| import useInputReceiptStep from "./hooks/useInputReceiptStep"; | |||||
| import useInputSMSSendAddress from "./hooks/useInputSMSSendAddress"; | |||||
| import useConfirm, { ConfirmDataProps } from "./hooks/useConfirm"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import { createReceiptIssuingOrder } from "api/custom/hello-techno/receipt-issuing-order"; | |||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | |||||
| import useBackDrop from "hooks/useBackDrop"; | |||||
| import { getValue } from "components/hook-form/RHFAutoComplete"; | |||||
| export default function ReceiptIssuingOrderCreate() { | export default function ReceiptIssuingOrderCreate() { | ||||
| const { setHeaderTitle, setTabs } = useDashboard( | const { setHeaderTitle, setTabs } = useDashboard( | ||||
| @@ -9,9 +18,141 @@ export default function ReceiptIssuingOrderCreate() { | |||||
| TabID.NONE | TabID.NONE | ||||
| ); | ); | ||||
| const { success, error } = useSnackbarCustom(); | |||||
| const { setShowBackDrop } = useBackDrop(); | |||||
| const [mode, setMode] = useState< | |||||
| "parking_select" | "input_receipt" | "input_address" | "confirm" | "done" | |||||
| >("parking_select"); | |||||
| const step = useMemo(() => { | |||||
| switch (mode) { | |||||
| case "parking_select": | |||||
| return 0; | |||||
| case "input_receipt": | |||||
| return 1; | |||||
| case "input_address": | |||||
| return 2; | |||||
| case "confirm": | |||||
| return 3; | |||||
| case "done": | |||||
| return 4; | |||||
| } | |||||
| }, [mode]); | |||||
| const getConfimData = (): ConfirmDataProps => { | |||||
| return { | |||||
| customerName: selectParkingStep.values("customerCode.label"), | |||||
| parkingName: selectParkingStep.values("parkingManagementCode.label"), | |||||
| adjustSeqNo: selectParkingStep.values("adjustSeqNo"), | |||||
| amount: inputReceiptStep.values("amount"), | |||||
| date: inputReceiptStep.values("date"), | |||||
| name: inputReceiptStep.values("name"), | |||||
| address: inputSMSSendAddress.values("address"), | |||||
| memo: inputReceiptStep.values("memo"), | |||||
| }; | |||||
| }; | |||||
| const getFormData = () => { | |||||
| return { | |||||
| ...selectParkingStep.values(), | |||||
| ...inputReceiptStep.values(), | |||||
| ...inputSMSSendAddress.values(), | |||||
| }; | |||||
| }; | |||||
| const selectParkingStep = useSelectParkingStep({ | |||||
| onNext: () => { | |||||
| setMode("input_receipt"); | |||||
| }, | |||||
| }); | |||||
| const inputReceiptStep = useInputReceiptStep({ | |||||
| onNext: () => { | |||||
| setMode("input_address"); | |||||
| }, | |||||
| onPrev: () => { | |||||
| setMode("parking_select"); | |||||
| }, | |||||
| }); | |||||
| const inputSMSSendAddress = useInputSMSSendAddress({ | |||||
| onNext: () => { | |||||
| confirm.setData(getConfimData()); | |||||
| setMode("confirm"); | |||||
| }, | |||||
| onPrev: () => { | |||||
| setMode("input_receipt"); | |||||
| }, | |||||
| }); | |||||
| const confirm = useConfirm({ | |||||
| onNext: () => { | |||||
| send(); | |||||
| }, | |||||
| onPrev: () => { | |||||
| setMode("input_address"); | |||||
| }, | |||||
| }); | |||||
| const createAPI = useAPICall({ | |||||
| apiMethod: createReceiptIssuingOrder, | |||||
| onSuccess: () => { | |||||
| setMode("done"); | |||||
| success("成功しました"); | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const send = () => { | |||||
| const { callAPI, makeSendData } = createAPI; | |||||
| const formData = getFormData(); | |||||
| const sendData = makeSendData({ | |||||
| customer_code: getValue(formData.customerCode), | |||||
| parking_management_code: getValue(formData.parkingManagementCode), | |||||
| adjust_seq_no: formData.adjustSeqNo, | |||||
| receipt_name: formData.name, | |||||
| receipt_use_datetime: formData.date, | |||||
| receipt_amount: formData.amount, | |||||
| sms_phone_number: formData.address, | |||||
| }); | |||||
| callAPI(sendData); | |||||
| }; | |||||
| useEffect(() => { | |||||
| setShowBackDrop(createAPI.sending); | |||||
| }, [createAPI.sending]); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| setHeaderTitle("領収証発行依頼作成"); | setHeaderTitle("領収証発行依頼作成"); | ||||
| setTabs(null); | setTabs(null); | ||||
| }, []); | }, []); | ||||
| return <Box>Create</Box>; | |||||
| return ( | |||||
| <Box sx={{ p: 1, m: 1 }}> | |||||
| <Stepper activeStep={step}> | |||||
| <Step> | |||||
| <StepLabel>駐車場選択</StepLabel> | |||||
| </Step> | |||||
| <Step> | |||||
| <StepLabel>領収証情報入力</StepLabel> | |||||
| </Step> | |||||
| <Step> | |||||
| <StepLabel>SMS送信先入力</StepLabel> | |||||
| </Step> | |||||
| <Step> | |||||
| <StepLabel>確認</StepLabel> | |||||
| </Step> | |||||
| <Step> | |||||
| <StepLabel>完了</StepLabel> | |||||
| </Step> | |||||
| </Stepper> | |||||
| {mode === "parking_select" && selectParkingStep.element} | |||||
| {mode === "input_receipt" && inputReceiptStep.element} | |||||
| {mode === "input_address" && inputSMSSendAddress.element} | |||||
| {mode === "confirm" && confirm.element} | |||||
| {mode === "done" && <Box sx={{ p: 1, py: 3, m: 1 }}>受付しました。</Box>} | |||||
| </Box> | |||||
| ); | |||||
| } | } | ||||
| @@ -0,0 +1,137 @@ | |||||
| import { yupResolver } from "@hookform/resolvers/yup"; | |||||
| import { | |||||
| Box, | |||||
| Button, | |||||
| Stack, | |||||
| Table, | |||||
| TableBody, | |||||
| TableCell, | |||||
| TableRow, | |||||
| TextField, | |||||
| Typography, | |||||
| } from "@mui/material"; | |||||
| import { HasChildren } from "@types"; | |||||
| import TextFieldEx from "components/form/TextFieldEx"; | |||||
| import { | |||||
| FormProvider, | |||||
| RHFAutoComplete, | |||||
| RHFTextField, | |||||
| } from "components/hook-form"; | |||||
| import { | |||||
| AutoCompleteOption, | |||||
| AutoCompleteOptionType, | |||||
| getValue, | |||||
| } from "components/hook-form/RHFAutoComplete"; | |||||
| import RHFDatePicker from "components/hook-form/RHFDatePicker"; | |||||
| import { useState } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import { formatDateStr, formatDateTimeStr } from "utils/datetime"; | |||||
| import * as Yup from "yup"; | |||||
| type AreaBoxProps = { | |||||
| title: string; | |||||
| } & HasChildren; | |||||
| function AreaBox({ title, children }: AreaBoxProps) { | |||||
| return ( | |||||
| <Box sx={{ maxWidth: 500 }}> | |||||
| <Typography variant="subtitle1">{title}</Typography> | |||||
| {children} | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type Props = { | |||||
| onNext?: VoidFunction; | |||||
| onPrev?: VoidFunction; | |||||
| }; | |||||
| export type ConfirmDataProps = { | |||||
| customerName: string; | |||||
| parkingName: string; | |||||
| adjustSeqNo: string; | |||||
| amount: string; | |||||
| date: Date | null; | |||||
| name: string; | |||||
| address: string; | |||||
| memo: string; | |||||
| }; | |||||
| export default function useConfirm({ onNext, onPrev }: Props) { | |||||
| const [adjustSeqNo, setAdjustSeqNo] = useState(""); | |||||
| const [data, setData] = useState<ConfirmDataProps>({ | |||||
| customerName: "", | |||||
| parkingName: "", | |||||
| adjustSeqNo: "", | |||||
| amount: "", | |||||
| date: null, | |||||
| name: "", | |||||
| address: "", | |||||
| memo: "", | |||||
| }); | |||||
| const handleNext = () => { | |||||
| if (onNext) { | |||||
| onNext(); | |||||
| } | |||||
| }; | |||||
| const handlePrev = () => { | |||||
| if (onPrev) { | |||||
| onPrev(); | |||||
| } | |||||
| }; | |||||
| const element = ( | |||||
| <Stack spacing={2} sx={{ p: 1, py: 3, m: 1 }}> | |||||
| <Typography variant="h5">領収証発行内容確認</Typography> | |||||
| <Table> | |||||
| <TableBody> | |||||
| <TableRow> | |||||
| <TableCell>運営会社名</TableCell> | |||||
| <TableCell>{data.customerName}</TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>駐車場名</TableCell> | |||||
| <TableCell>{data.parkingName}</TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>精算連番</TableCell> | |||||
| <TableCell>{data.adjustSeqNo}</TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>利用日</TableCell> | |||||
| <TableCell>{formatDateStr(data.date)}</TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>宛名</TableCell> | |||||
| <TableCell>{data.name}</TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>金額</TableCell> | |||||
| <TableCell>{data.amount}円</TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>メモ</TableCell> | |||||
| <TableCell> | |||||
| <TextFieldEx readOnly value={data.memo} multiline /> | |||||
| </TableCell> | |||||
| </TableRow> | |||||
| <TableRow> | |||||
| <TableCell>SMS送信先</TableCell> | |||||
| <TableCell>{data.address}</TableCell> | |||||
| </TableRow> | |||||
| </TableBody> | |||||
| </Table> | |||||
| <Stack direction="row" spacing={2}> | |||||
| <Button variant="text" onClick={handlePrev}> | |||||
| 戻る | |||||
| </Button> | |||||
| <Button variant="contained" onClick={handleNext}> | |||||
| 確定 | |||||
| </Button> | |||||
| </Stack> | |||||
| </Stack> | |||||
| ); | |||||
| return { element, setData }; | |||||
| } | |||||
| @@ -0,0 +1,111 @@ | |||||
| import { yupResolver } from "@hookform/resolvers/yup"; | |||||
| import { Box, Button, Stack, TextField, Typography } from "@mui/material"; | |||||
| import { HasChildren } from "@types"; | |||||
| import { | |||||
| FormProvider, | |||||
| RHFAutoComplete, | |||||
| RHFTextField, | |||||
| } from "components/hook-form"; | |||||
| import { | |||||
| AutoCompleteOption, | |||||
| AutoCompleteOptionType, | |||||
| getValue, | |||||
| } from "components/hook-form/RHFAutoComplete"; | |||||
| import RHFDatePicker from "components/hook-form/RHFDatePicker"; | |||||
| import { 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 ( | |||||
| <Box sx={{ maxWidth: 500 }}> | |||||
| <Typography variant="subtitle1">{title}</Typography> | |||||
| {children} | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| amount: string; | |||||
| date: Date | null; | |||||
| name: string; | |||||
| memo: string; | |||||
| }; | |||||
| type Props = { | |||||
| onNext?: VoidFunction; | |||||
| onPrev?: VoidFunction; | |||||
| }; | |||||
| export default function useInputReceiptStep({ onNext, onPrev }: Props) { | |||||
| const [adjustSeqNo, setAdjustSeqNo] = useState(""); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| amount: "", | |||||
| date: null, | |||||
| name: "", | |||||
| memo: "", | |||||
| }, | |||||
| resolver: yupResolver( | |||||
| Yup.object().shape({ | |||||
| date: Yup.date() | |||||
| .required("必須項目です") | |||||
| .typeError("正しく入力してください"), | |||||
| amount: Yup.number().required("必須項目です"), | |||||
| name: Yup.string().required("必須項目です"), | |||||
| memo: Yup.string().nullable(), | |||||
| }) | |||||
| ), | |||||
| }); | |||||
| const handleSubmit = (data: FormProps) => { | |||||
| console.log(data); | |||||
| if (onNext) { | |||||
| onNext(); | |||||
| } | |||||
| }; | |||||
| const handlePrev = () => { | |||||
| if (onPrev) { | |||||
| onPrev(); | |||||
| } | |||||
| }; | |||||
| const element = ( | |||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | |||||
| <Stack spacing={2} sx={{ p: 1, m: 1 }}> | |||||
| <AreaBox title="利用日"> | |||||
| <RHFDatePicker name="date" size="small" /> | |||||
| </AreaBox> | |||||
| <AreaBox title="金額"> | |||||
| <RHFTextField | |||||
| type="number" | |||||
| name="amount" | |||||
| size="small" | |||||
| InputProps={{ endAdornment: <div>円</div> }} | |||||
| sx={{ maxWidth: 150 }} | |||||
| /> | |||||
| </AreaBox> | |||||
| <AreaBox title="宛名"> | |||||
| <RHFTextField name="name" size="small" /> | |||||
| </AreaBox> | |||||
| <AreaBox title="メモ"> | |||||
| <RHFTextField name="memo" size="small" multiline rows={3} /> | |||||
| </AreaBox> | |||||
| <Stack direction="row" spacing={2}> | |||||
| <Button variant="text" onClick={handlePrev}> | |||||
| 戻る | |||||
| </Button> | |||||
| <Button variant="contained" type="submit"> | |||||
| 次へ | |||||
| </Button> | |||||
| </Stack> | |||||
| </Stack> | |||||
| </FormProvider> | |||||
| ); | |||||
| return { element, values: form.getValues, setValue: form.setValue }; | |||||
| } | |||||
| @@ -0,0 +1,83 @@ | |||||
| import { yupResolver } from "@hookform/resolvers/yup"; | |||||
| import { Box, Button, Stack, Typography } from "@mui/material"; | |||||
| import { HasChildren } from "@types"; | |||||
| import { | |||||
| FormProvider, | |||||
| RHFAutoComplete, | |||||
| RHFTextField, | |||||
| } from "components/hook-form"; | |||||
| import { | |||||
| AutoCompleteOption, | |||||
| AutoCompleteOptionType, | |||||
| getValue, | |||||
| } from "components/hook-form/RHFAutoComplete"; | |||||
| import { 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 ( | |||||
| <Box sx={{ maxWidth: 500 }}> | |||||
| <Typography variant="subtitle1">{title}</Typography> | |||||
| {children} | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| address: string; | |||||
| }; | |||||
| type Props = { | |||||
| onNext?: VoidFunction; | |||||
| onPrev?: VoidFunction; | |||||
| }; | |||||
| export default function useInputSMSSendAddress({ onNext, onPrev }: Props) { | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| address: "", | |||||
| }, | |||||
| resolver: yupResolver( | |||||
| Yup.object().shape({ | |||||
| address: Yup.string() | |||||
| .required("必須項目です") | |||||
| .matches(/^[0-9]{11}$/, "正しい電話番号を入力してください"), | |||||
| }) | |||||
| ), | |||||
| }); | |||||
| const handleSubmit = () => { | |||||
| if (onNext) { | |||||
| onNext(); | |||||
| } | |||||
| }; | |||||
| const handlePrev = () => { | |||||
| if (onPrev) { | |||||
| onPrev(); | |||||
| } | |||||
| }; | |||||
| const element = ( | |||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | |||||
| <Stack spacing={2} sx={{ p: 1, m: 1 }}> | |||||
| <AreaBox title="SMS送信先"> | |||||
| <RHFTextField name="address" size="small" /> | |||||
| </AreaBox> | |||||
| <Stack direction="row" spacing={2}> | |||||
| <Button variant="text" onClick={handlePrev}> | |||||
| 戻る | |||||
| </Button> | |||||
| <Button variant="contained" type="submit"> | |||||
| 次へ | |||||
| </Button> | |||||
| </Stack> | |||||
| </Stack> | |||||
| </FormProvider> | |||||
| ); | |||||
| return { element, values: form.getValues }; | |||||
| } | |||||
| @@ -0,0 +1,148 @@ | |||||
| import { yupResolver } from "@hookform/resolvers/yup"; | |||||
| import { Box, Button, Stack, Typography } from "@mui/material"; | |||||
| import { HasChildren } from "@types"; | |||||
| import { getHTCustomers, getHTParkings } from "api/custom/hello-techno"; | |||||
| import { | |||||
| FormProvider, | |||||
| RHFAutoComplete, | |||||
| RHFTextField, | |||||
| } from "components/hook-form"; | |||||
| import { | |||||
| AutoCompleteOption, | |||||
| AutoCompleteOptionType, | |||||
| getValue, | |||||
| } from "components/hook-form/RHFAutoComplete"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import { useEffect, 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 ( | |||||
| <Box sx={{ maxWidth: 500 }}> | |||||
| <Typography variant="subtitle1">{title}</Typography> | |||||
| {children} | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| customerCode: AutoCompleteOptionType; | |||||
| parkingManagementCode: AutoCompleteOptionType; | |||||
| adjustSeqNo: string; | |||||
| }; | |||||
| type Props = { | |||||
| onNext?: VoidFunction; | |||||
| }; | |||||
| export default function useSelectParkingStep({ onNext }: Props) { | |||||
| const [customers, setCustomers] = useState<AutoCompleteOption[]>([]); | |||||
| const [parkings, setParkings] = useState<AutoCompleteOption[]>([]); | |||||
| const customerAPI = useAPICall({ | |||||
| apiMethod: getHTCustomers, | |||||
| onSuccess: ({ data }) => { | |||||
| const options: AutoCompleteOption[] = data.records.map( | |||||
| ({ customer_code, name }) => { | |||||
| return { | |||||
| label: name, | |||||
| value: customer_code, | |||||
| }; | |||||
| } | |||||
| ); | |||||
| setCustomers(options); | |||||
| }, | |||||
| }); | |||||
| const parkingAPI = useAPICall({ | |||||
| apiMethod: getHTParkings, | |||||
| onSuccess: ({ data }) => { | |||||
| const options: AutoCompleteOption[] = data.records.map( | |||||
| ({ parking_management_code, name }) => { | |||||
| return { | |||||
| label: name, | |||||
| value: parking_management_code, | |||||
| }; | |||||
| } | |||||
| ); | |||||
| setParkings(options); | |||||
| }, | |||||
| }); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| customerCode: null, | |||||
| parkingManagementCode: null, | |||||
| adjustSeqNo: "", | |||||
| }, | |||||
| 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 handleSubmit = () => { | |||||
| if (onNext) { | |||||
| onNext(); | |||||
| } | |||||
| }; | |||||
| // 顧客一覧取得 | |||||
| useEffect(() => { | |||||
| customerAPI.callAPI({}); | |||||
| }, []); | |||||
| // 駐車場一覧取得 | |||||
| useEffect(() => { | |||||
| setParkings([]); | |||||
| form.setValue("parkingManagementCode", null); | |||||
| if (customerCode) { | |||||
| parkingAPI.callAPI({ customer_code: customerCode }); | |||||
| } | |||||
| }, [customerCode]); | |||||
| const element = ( | |||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | |||||
| <Stack spacing={2} sx={{ p: 1, m: 1 }}> | |||||
| <AreaBox title="運営会社"> | |||||
| <RHFAutoComplete | |||||
| name="customerCode" | |||||
| options={customers} | |||||
| size="small" | |||||
| /> | |||||
| </AreaBox> | |||||
| <AreaBox title="駐車場"> | |||||
| <RHFAutoComplete | |||||
| name="parkingManagementCode" | |||||
| options={parkings} | |||||
| size="small" | |||||
| /> | |||||
| </AreaBox> | |||||
| <AreaBox title="精算連番"> | |||||
| <RHFTextField name="adjustSeqNo" size="small" /> | |||||
| </AreaBox> | |||||
| <Stack direction="row" spacing={2}> | |||||
| <Button variant="contained" type="submit"> | |||||
| 次へ | |||||
| </Button> | |||||
| </Stack> | |||||
| </Stack> | |||||
| </FormProvider> | |||||
| ); | |||||
| return { element, values: form.getValues, setValue: form.setValue }; | |||||
| } | |||||
| @@ -0,0 +1,257 @@ | |||||
| import { | |||||
| Box, | |||||
| Grid, | |||||
| Table, | |||||
| TableBody, | |||||
| TableCell, | |||||
| TableContainer, | |||||
| TablePagination, | |||||
| TableRow, | |||||
| TextField, | |||||
| } from "@mui/material"; | |||||
| import { Dictionary } from "@types"; | |||||
| import { | |||||
| ReceiptIssuingOrder, | |||||
| getReceiptIssuingOrders, | |||||
| } from "api/receipt-issuing-order"; | |||||
| import { PageID, TabID } from "codes/page"; | |||||
| import { ReceiptIssuingOrderStatus } from "codes/receipt-issuing-order"; | |||||
| import { FormProvider, RHFTextField } from "components/hook-form"; | |||||
| import { TableHeadCustom } from "components/table"; | |||||
| import { SearchConditionContextProvider } from "contexts/SearchConditionContext"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useDashboard from "hooks/useDashBoard"; | |||||
| import useSearchConditionContext from "hooks/useSearchConditionContext"; | |||||
| import useTable, { UseTableReturn } from "hooks/useTable"; | |||||
| import ContractTabs from "layouts/dashbord/tab/ContractTabs"; | |||||
| import { useEffect } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import { Contract } from "types/contract"; | |||||
| export default function ReceiptIssuingOrderList() { | |||||
| const { setHeaderTitle, setTabs } = useDashboard( | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST, | |||||
| TabID.NONE | |||||
| ); | |||||
| const table = useTable<ReceiptIssuingOrder>(); | |||||
| useEffect(() => { | |||||
| setHeaderTitle("領収証発行依頼一覧"); | |||||
| setTabs(null); | |||||
| }, []); | |||||
| return ( | |||||
| <SearchConditionContextProvider> | |||||
| <Page table={table} /> | |||||
| </SearchConditionContextProvider> | |||||
| ); | |||||
| } | |||||
| type CommonProps = { | |||||
| table: UseTableReturn<ReceiptIssuingOrder>; | |||||
| }; | |||||
| function Page({ table }: CommonProps) { | |||||
| const { | |||||
| order, | |||||
| page, | |||||
| sort, | |||||
| rowsPerPage, | |||||
| fetched, | |||||
| fillteredRow, | |||||
| isNotFound, | |||||
| dataLength, | |||||
| // | |||||
| onSort, | |||||
| onChangePage, | |||||
| onChangeRowsPerPage, | |||||
| // | |||||
| setRowData, | |||||
| // | |||||
| ROWS_PER_PAGES, | |||||
| } = table; | |||||
| return ( | |||||
| <Box> | |||||
| <SearchBox table={table} /> | |||||
| <TableBox table={table} /> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| address: string; | |||||
| }; | |||||
| function SearchBox({ table }: CommonProps) { | |||||
| const { | |||||
| condition, | |||||
| initialized, | |||||
| get, | |||||
| addCondition: add, | |||||
| } = useSearchConditionContext(); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| address: "", | |||||
| }, | |||||
| }); | |||||
| const { callAPI: calGetReceiptIssuingOrders, makeSendData } = useAPICall({ | |||||
| apiMethod: getReceiptIssuingOrders, | |||||
| form, | |||||
| onSuccess: (res) => { | |||||
| table.setRowData(res.data.records); | |||||
| }, | |||||
| }); | |||||
| const handleSubmit = async (data: FormProps) => { | |||||
| addCondition(data); | |||||
| }; | |||||
| const addCondition = (data: FormProps) => { | |||||
| add({ ...data }); | |||||
| }; | |||||
| const fetch = async (data: Dictionary) => { | |||||
| const sendData = makeSendData({ | |||||
| ...data, | |||||
| }); | |||||
| calGetReceiptIssuingOrders(sendData); | |||||
| }; | |||||
| // 初期値設定 | |||||
| useEffect(() => { | |||||
| if (initialized) { | |||||
| form.setValue("address", get("address")); | |||||
| } | |||||
| }, [initialized, condition]); | |||||
| // Fetchアクション | |||||
| useEffect(() => { | |||||
| if (initialized) { | |||||
| fetch(condition); | |||||
| } | |||||
| }, [condition, initialized]); | |||||
| return ( | |||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | |||||
| <Box sx={{ p: 1, m: 1 }}> | |||||
| <Grid container spacing={1}> | |||||
| <Grid item xs={3}> | |||||
| <RHFTextField | |||||
| label="ステータス" | |||||
| name="status" | |||||
| fullWidth | |||||
| size="small" | |||||
| /> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <TextField label="a" fullWidth size="small" /> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <TextField label="a" fullWidth size="small" /> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <TextField label="a" fullWidth size="small" /> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <TextField label="a" fullWidth size="small" /> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <TextField label="a" fullWidth size="small" /> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <TextField label="a" fullWidth size="small" /> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <TextField label="a" fullWidth size="small" /> | |||||
| </Grid> | |||||
| </Grid> | |||||
| </Box> | |||||
| </FormProvider> | |||||
| ); | |||||
| } | |||||
| function TableBox({ table }: CommonProps) { | |||||
| const TABLE_HEAD = [ | |||||
| { id: "id", label: "ID", align: "left" }, | |||||
| { id: "name", label: "名前", align: "left" }, | |||||
| { id: "emply", label: "---", align: "left" }, | |||||
| ]; | |||||
| const { | |||||
| order, | |||||
| page, | |||||
| sort, | |||||
| rowsPerPage, | |||||
| fetched, | |||||
| fillteredRow, | |||||
| isNotFound, | |||||
| dataLength, | |||||
| // | |||||
| onSort, | |||||
| onChangePage, | |||||
| onChangeRowsPerPage, | |||||
| // | |||||
| setRowData, | |||||
| // | |||||
| ROWS_PER_PAGES, | |||||
| } = table; | |||||
| useEffect(() => { | |||||
| setRowData([ | |||||
| { id: "iwabuchi", status: ReceiptIssuingOrderStatus.NONE }, | |||||
| { id: "iwabuchi", status: ReceiptIssuingOrderStatus.MAIL_DONE }, | |||||
| ]); | |||||
| }, []); | |||||
| return ( | |||||
| <> | |||||
| <TableContainer | |||||
| sx={{ | |||||
| // minWidth: 800, | |||||
| position: "relative", | |||||
| }} | |||||
| > | |||||
| <Table size="small"> | |||||
| <TableHeadCustom | |||||
| order={order} | |||||
| orderBy={sort} | |||||
| headLabel={TABLE_HEAD} | |||||
| rowCount={1} | |||||
| numSelected={0} | |||||
| onSort={onSort} | |||||
| /> | |||||
| <TableBody> | |||||
| {fillteredRow.map((row, index) => ( | |||||
| <Row data={row} key={index} /> | |||||
| ))} | |||||
| </TableBody> | |||||
| </Table> | |||||
| </TableContainer> | |||||
| <Box sx={{ position: "relative" }}> | |||||
| <TablePagination | |||||
| rowsPerPageOptions={ROWS_PER_PAGES} | |||||
| component="div" | |||||
| count={dataLength} | |||||
| rowsPerPage={rowsPerPage} | |||||
| page={page} | |||||
| onPageChange={onChangePage} | |||||
| onRowsPerPageChange={onChangeRowsPerPage} | |||||
| /> | |||||
| </Box> | |||||
| </> | |||||
| ); | |||||
| } | |||||
| type RowProps = { | |||||
| data: ReceiptIssuingOrder; | |||||
| }; | |||||
| function Row({ data }: RowProps) { | |||||
| return ( | |||||
| <TableRow hover sx={{ cursor: "pointer" }}> | |||||
| <TableCell>{data.id}</TableCell> | |||||
| <TableCell>{data.status}</TableCell> | |||||
| </TableRow> | |||||
| ); | |||||
| } | |||||
| @@ -54,6 +54,11 @@ const DashboardRoutes = (): RouteObject => { | |||||
| element: <ReceiptIssuingOrderCreate />, | element: <ReceiptIssuingOrderCreate />, | ||||
| target: UserRole.NORMAL_ADMIN, | target: UserRole.NORMAL_ADMIN, | ||||
| }, | }, | ||||
| { | |||||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST, | |||||
| element: <ReceiptIssuingOrderList />, | |||||
| target: UserRole.NORMAL_ADMIN, | |||||
| }, | |||||
| ]; | ]; | ||||
| const children: RouteObject[] = useMemo(() => { | const children: RouteObject[] = useMemo(() => { | ||||
| @@ -104,6 +109,9 @@ const ContractDetail = Loadable( | |||||
| const ReceiptIssuingOrderCreate = Loadable( | const ReceiptIssuingOrderCreate = Loadable( | ||||
| lazy(() => import("pages/dashboard/receipt-issuing-order/create")) | lazy(() => import("pages/dashboard/receipt-issuing-order/create")) | ||||
| ); | ); | ||||
| const ReceiptIssuingOrderList = Loadable( | |||||
| lazy(() => import("pages/dashboard/receipt-issuing-order/list")) | |||||
| ); | |||||
| // その他 --------------------------------- | // その他 --------------------------------- | ||||
| const Page403 = Loadable(lazy(() => import("pages/common/Page403"))); | const Page403 = Loadable(lazy(() => import("pages/common/Page403"))); | ||||
| @@ -149,6 +149,15 @@ theme = { | |||||
| }, | }, | ||||
| }, | }, | ||||
| }, | }, | ||||
| MuiInput: { | |||||
| styleOverrides: { | |||||
| root: { | |||||
| "&.Mui-disabled:before": { | |||||
| "border-bottom-style": "none", | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -1825,6 +1825,18 @@ | |||||
| prop-types "^15.8.1" | prop-types "^15.8.1" | ||||
| react-is "^18.2.0" | react-is "^18.2.0" | ||||
| "@mui/x-date-pickers@^6.4.0": | |||||
| version "6.4.0" | |||||
| resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-6.4.0.tgz#97ca181edbc0d56abe08c93b036f97d8e9946572" | |||||
| integrity sha512-EdKj+TVaEvx+nIljsv1BlDOYYwcMWVYB+ZMRoOCStFojY5uuDzhttQAP6DbsAPPrpKt1lzyecIukLfmIfIGcsA== | |||||
| dependencies: | |||||
| "@babel/runtime" "^7.21.0" | |||||
| "@mui/utils" "^5.12.3" | |||||
| "@types/react-transition-group" "^4.4.5" | |||||
| clsx "^1.2.1" | |||||
| prop-types "^15.8.1" | |||||
| react-transition-group "^4.4.5" | |||||
| "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": | "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": | ||||
| version "5.1.1-v1" | version "5.1.1-v1" | ||||
| resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" | resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" | ||||