| @@ -9,6 +9,7 @@ | |||
| "@mui/icons-material": "^5.11.16", | |||
| "@mui/lab": "^5.0.0-alpha.129", | |||
| "@mui/material": "^5.12.2", | |||
| "@mui/x-date-pickers": "^6.4.0", | |||
| "@testing-library/jest-dom": "^5.14.1", | |||
| "@testing-library/react": "^13.0.0", | |||
| "@testing-library/user-event": "^13.2.1", | |||
| @@ -8,22 +8,31 @@ import { BrowserRouter } from "react-router-dom"; | |||
| import { Routes } from "routes"; | |||
| 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() { | |||
| 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++, | |||
| 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; | |||
| export type ApiId = (typeof ApiId)[keyof typeof ApiId]; | |||
| @@ -201,34 +211,43 @@ export async function apiRequest< | |||
| if (setSending) { | |||
| 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) { | |||
| 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 = { | |||
| [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 = { | |||
| [ApiId.CSRF_TOKEN]: "", | |||
| [A.CSRF_TOKEN]: "", | |||
| }; | |||
| const DEFAULT_API_URL_PREFIX = "api"; | |||
| const getPrefix = (apiId: ApiId) => { | |||
| const getPrefix = (apiId: A) => { | |||
| return prefixs[apiId] ?? DEFAULT_API_URL_PREFIX; | |||
| }; | |||
| export const getUrl = (apiId: ApiId) => { | |||
| export const getUrl = (apiId: A) => { | |||
| let url = getPrefix(apiId); | |||
| if (url.length !== 0) { | |||
| 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 { | |||
| Controller, | |||
| ControllerFieldState, | |||
| @@ -6,15 +5,8 @@ import { | |||
| FieldValues, | |||
| useFormContext, | |||
| } 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 RHFTextField from "./RHFTextField"; | |||
| @@ -35,36 +27,21 @@ const RHFDatePicker = ({ | |||
| datePickerProps, | |||
| ...other | |||
| }: Props) => { | |||
| const { control, watch, setValue } = useFormContext(); | |||
| const { | |||
| control, | |||
| watch, | |||
| setValue, | |||
| formState: { errors }, | |||
| } = useFormContext(); | |||
| 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) { | |||
| return <RHFTextField name={name} readOnly {...other} variant="standard" />; | |||
| @@ -79,23 +56,21 @@ const RHFDatePicker = ({ | |||
| }) => { | |||
| return ( | |||
| <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} | |||
| {...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"); | |||
| 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 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() { | |||
| const { setHeaderTitle, setTabs } = useDashboard( | |||
| @@ -9,9 +18,141 @@ export default function ReceiptIssuingOrderCreate() { | |||
| 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(() => { | |||
| setHeaderTitle("領収証発行依頼作成"); | |||
| 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 />, | |||
| target: UserRole.NORMAL_ADMIN, | |||
| }, | |||
| { | |||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST, | |||
| element: <ReceiptIssuingOrderList />, | |||
| target: UserRole.NORMAL_ADMIN, | |||
| }, | |||
| ]; | |||
| const children: RouteObject[] = useMemo(() => { | |||
| @@ -104,6 +109,9 @@ const ContractDetail = Loadable( | |||
| const ReceiptIssuingOrderCreate = Loadable( | |||
| 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"))); | |||
| @@ -149,6 +149,15 @@ theme = { | |||
| }, | |||
| }, | |||
| }, | |||
| MuiInput: { | |||
| styleOverrides: { | |||
| root: { | |||
| "&.Mui-disabled:before": { | |||
| "border-bottom-style": "none", | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }; | |||
| @@ -1825,6 +1825,18 @@ | |||
| prop-types "^15.8.1" | |||
| 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": | |||
| 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" | |||