| @@ -1,12 +1,15 @@ | |||||
| import { UserRole } from "codes/user"; | import { UserRole } from "codes/user"; | ||||
| import { APICommonResponse, ApiId, HttpMethod, request } from "."; | import { APICommonResponse, ApiId, HttpMethod, request } from "."; | ||||
| import { getUrl } from "./url"; | import { getUrl } from "./url"; | ||||
| import { CustomCode } from "codes/custom"; | |||||
| type MeResponse = { | type MeResponse = { | ||||
| data: { | data: { | ||||
| id: string; | id: string; | ||||
| contract_id: string; | contract_id: string; | ||||
| role: UserRole; | role: UserRole; | ||||
| name: string; | |||||
| custom: CustomCode[]; | |||||
| }; | }; | ||||
| } & APICommonResponse; | } & APICommonResponse; | ||||
| @@ -3,6 +3,7 @@ import { | |||||
| ApiId, | ApiId, | ||||
| HttpMethod, | HttpMethod, | ||||
| makeFormData, | makeFormData, | ||||
| makeParam, | |||||
| request, | request, | ||||
| } from "api"; | } from "api"; | ||||
| import { ReceiptIssuingOrder } from "api/receipt-issuing-order"; | import { ReceiptIssuingOrder } from "api/receipt-issuing-order"; | ||||
| @@ -65,6 +66,12 @@ export type ReceiptIssuingOrdersRequest = { | |||||
| customer_name?: string; | customer_name?: string; | ||||
| parking_management_code?: string; | parking_management_code?: string; | ||||
| parking_name?: string; | parking_name?: string; | ||||
| status?: string; | |||||
| order_date_from?: string; | |||||
| order_date_to?: string; | |||||
| done?: string; | |||||
| sms_phone_number?: string; | |||||
| handler_name?: string; | |||||
| }; | }; | ||||
| export type ReceiptIssuingOrdersResponse = { | export type ReceiptIssuingOrdersResponse = { | ||||
| @@ -0,0 +1,7 @@ | |||||
| export const CustomCode = { | |||||
| NONE: "", | |||||
| HELLO_TECHNO: "HELLO_TECHNO", | |||||
| } as const; | |||||
| export type CustomCode = (typeof CustomCode)[keyof typeof CustomCode]; | |||||
| @@ -13,9 +13,9 @@ export const PageID = { | |||||
| DASHBOARD_CONTRACT_LIST: id++, | DASHBOARD_CONTRACT_LIST: id++, | ||||
| DASHBOARD_CONTRACT_DETAIL: id++, | DASHBOARD_CONTRACT_DETAIL: id++, | ||||
| DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE: id++, | |||||
| DASHBOARD_RECEIPT_ISSUING_ORDER_LIST: id++, | |||||
| DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL: id++, | |||||
| DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO: id++, | |||||
| DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO: id++, | |||||
| DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO: id++, | |||||
| PAGE_403: id++, | PAGE_403: id++, | ||||
| PAGE_404: id++, | PAGE_404: id++, | ||||
| @@ -1,18 +1,47 @@ | |||||
| // form | // form | ||||
| import { useFormContext, Controller } from 'react-hook-form'; | |||||
| import { useFormContext, Controller } from "react-hook-form"; | |||||
| // @mui | // @mui | ||||
| import { Checkbox, FormControlLabel, FormGroup, FormControlLabelProps } from '@mui/material'; | |||||
| import { | |||||
| Checkbox, | |||||
| FormControlLabel, | |||||
| FormGroup, | |||||
| FormControlLabelProps, | |||||
| } from "@mui/material"; | |||||
| import { useMemo } from "react"; | |||||
| // ---------------------------------------------------------------------- | // ---------------------------------------------------------------------- | ||||
| interface RHFCheckboxProps extends Omit<FormControlLabelProps, 'control'> { | |||||
| interface RHFCheckboxProps extends Omit<FormControlLabelProps, "control"> { | |||||
| name: string; | name: string; | ||||
| readOnly?: boolean; | readOnly?: boolean; | ||||
| } | } | ||||
| export function RHFCheckbox({ name, readOnly, ...other }: RHFCheckboxProps) { | export function RHFCheckbox({ name, readOnly, ...other }: RHFCheckboxProps) { | ||||
| const { control, watch } = useFormContext(); | const { control, watch } = useFormContext(); | ||||
| const formValue: boolean = watch(name); | |||||
| const _formValue = watch(name); | |||||
| // const formValue : boolean = useMemo(()=>{ | |||||
| // if(_formValue typeof 'boolean') { | |||||
| // return _formValue; | |||||
| // } | |||||
| // return false | |||||
| // },[_formValue]) | |||||
| const formValue = useMemo(() => { | |||||
| if (typeof _formValue === "boolean") { | |||||
| console.log("boolean", _formValue); | |||||
| return _formValue; | |||||
| } | |||||
| if (typeof _formValue === "string") { | |||||
| console.log("string", _formValue); | |||||
| return _formValue === "1" || _formValue === "true"; | |||||
| } | |||||
| console.log("else"); | |||||
| return false; | |||||
| }, [_formValue]); | |||||
| if (readOnly) { | if (readOnly) { | ||||
| return ( | return ( | ||||
| @@ -24,12 +53,12 @@ export function RHFCheckbox({ name, readOnly, ...other }: RHFCheckboxProps) { | |||||
| disableFocusRipple | disableFocusRipple | ||||
| checked={formValue} | checked={formValue} | ||||
| sx={{ | sx={{ | ||||
| cursor: 'default', | |||||
| cursor: "default", | |||||
| }} | }} | ||||
| /> | /> | ||||
| } | } | ||||
| sx={{ | sx={{ | ||||
| cursor: 'default', | |||||
| cursor: "default", | |||||
| }} | }} | ||||
| {...other} | {...other} | ||||
| /> | /> | ||||
| @@ -42,7 +71,7 @@ export function RHFCheckbox({ name, readOnly, ...other }: RHFCheckboxProps) { | |||||
| <Controller | <Controller | ||||
| name={name} | name={name} | ||||
| control={control} | control={control} | ||||
| render={({ field }) => <Checkbox {...field} checked={field.value} />} | |||||
| render={({ field }) => <Checkbox {...field} checked={formValue} />} | |||||
| /> | /> | ||||
| } | } | ||||
| {...other} | {...other} | ||||
| @@ -52,7 +81,8 @@ export function RHFCheckbox({ name, readOnly, ...other }: RHFCheckboxProps) { | |||||
| // ---------------------------------------------------------------------- | // ---------------------------------------------------------------------- | ||||
| interface RHFMultiCheckboxProps extends Omit<FormControlLabelProps, 'control' | 'label'> { | |||||
| interface RHFMultiCheckboxProps | |||||
| extends Omit<FormControlLabelProps, "control" | "label"> { | |||||
| name: string; | name: string; | ||||
| options: { | options: { | ||||
| label: string; | label: string; | ||||
| @@ -60,7 +90,11 @@ interface RHFMultiCheckboxProps extends Omit<FormControlLabelProps, 'control' | | |||||
| }[]; | }[]; | ||||
| } | } | ||||
| export function RHFMultiCheckbox({ name, options, ...other }: RHFMultiCheckboxProps) { | |||||
| export function RHFMultiCheckbox({ | |||||
| name, | |||||
| options, | |||||
| ...other | |||||
| }: RHFMultiCheckboxProps) { | |||||
| const { control } = useFormContext(); | const { control } = useFormContext(); | ||||
| return ( | return ( | ||||
| @@ -1,14 +1,26 @@ | |||||
| import { useFormContext, Controller } from "react-hook-form"; | import { useFormContext, Controller } from "react-hook-form"; | ||||
| import { MenuItem, TextField, TextFieldProps } from "@mui/material"; | |||||
| import { | |||||
| Box, | |||||
| Chip, | |||||
| FormControl, | |||||
| FormHelperText, | |||||
| IconButton, | |||||
| MenuItem, | |||||
| OutlinedInput, | |||||
| Select, | |||||
| TextField, | |||||
| TextFieldProps, | |||||
| } from "@mui/material"; | |||||
| import { useCallback, useEffect, useMemo, useState } from "react"; | import { useCallback, useEffect, useMemo, useState } from "react"; | ||||
| import TextFieldEx from "../form/TextFieldEx"; | import TextFieldEx from "../form/TextFieldEx"; | ||||
| import { Dictionary } from "@types"; | import { Dictionary } from "@types"; | ||||
| import { Clear, Label } from "@mui/icons-material"; | |||||
| // ---------------------------------------------------------------------- | // ---------------------------------------------------------------------- | ||||
| export type SelectOptionProps = { | export type SelectOptionProps = { | ||||
| value: string; | value: string; | ||||
| label: string; | |||||
| label?: string; | |||||
| }; | }; | ||||
| export const makeOptions = (list: Dictionary[]): SelectOptionProps[] => { | export const makeOptions = (list: Dictionary[]): SelectOptionProps[] => { | ||||
| @@ -60,7 +72,7 @@ export default function RHFSelect({ | |||||
| return options.map((option, index) => { | return options.map((option, index) => { | ||||
| return ( | return ( | ||||
| <MenuItem value={option.value} key={index}> | <MenuItem value={option.value} key={index}> | ||||
| {option.label} | |||||
| {option.label ?? option.value} | |||||
| </MenuItem> | </MenuItem> | ||||
| ); | ); | ||||
| }); | }); | ||||
| @@ -117,3 +129,93 @@ export default function RHFSelect({ | |||||
| /> | /> | ||||
| ); | ); | ||||
| } | } | ||||
| const ITEM_HEIGHT = 48; | |||||
| const ITEM_PADDING_TOP = 8; | |||||
| const MenuProps = { | |||||
| PaperProps: { | |||||
| style: { | |||||
| maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, | |||||
| width: 250, | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| export function RHFSelectMuiliple({ | |||||
| name, | |||||
| children, | |||||
| readOnly, | |||||
| options, | |||||
| onFix, | |||||
| ...other | |||||
| }: Props) { | |||||
| const { control, watch, setValue } = useFormContext(); | |||||
| const formValue: string[] = watch(name); | |||||
| const getOptionElements = useCallback(() => { | |||||
| if (options) { | |||||
| if (options.length === 0) { | |||||
| return [ | |||||
| <MenuItem key="disabled" disabled> | |||||
| 候補がありません | |||||
| </MenuItem>, | |||||
| ]; | |||||
| } else { | |||||
| return options.map((option, index) => { | |||||
| return ( | |||||
| <MenuItem value={option.value} key={index}> | |||||
| {option.label ?? option.value} | |||||
| </MenuItem> | |||||
| ); | |||||
| }); | |||||
| } | |||||
| } | |||||
| return []; | |||||
| }, [options]); | |||||
| const clearButton = useMemo(() => { | |||||
| if (formValue.length === 0) return null; | |||||
| const handleClick = () => { | |||||
| setValue(name, []); | |||||
| }; | |||||
| return ( | |||||
| <IconButton sx={{ mr: 1 }} onClick={handleClick}> | |||||
| <Clear /> | |||||
| </IconButton> | |||||
| ); | |||||
| }, [formValue]); | |||||
| return ( | |||||
| <Controller | |||||
| name={name} | |||||
| control={control} | |||||
| render={({ field, fieldState: { error } }) => ( | |||||
| <FormControl> | |||||
| <Select | |||||
| {...field} | |||||
| size="small" | |||||
| multiple | |||||
| value={formValue} | |||||
| error={!!error} | |||||
| input={<OutlinedInput endAdornment={clearButton} />} | |||||
| renderValue={(selected) => ( | |||||
| <Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}> | |||||
| {selected.map((value) => ( | |||||
| <Chip key={value} label={value} size="small" /> | |||||
| ))} | |||||
| </Box> | |||||
| )} | |||||
| MenuProps={MenuProps} | |||||
| > | |||||
| {children} | |||||
| {getOptionElements()} | |||||
| </Select> | |||||
| {!!error?.message && <FormHelperText>{error.message}</FormHelperText>} | |||||
| </FormControl> | |||||
| )} | |||||
| /> | |||||
| ); | |||||
| } | |||||
| @@ -1,6 +1,7 @@ | |||||
| import { HasChildren } from "@types"; | import { HasChildren } from "@types"; | ||||
| import { ResultCode } from "api"; | import { ResultCode } from "api"; | ||||
| import { login as APILogin, logout as APILogout, me } from "api/auth"; | import { login as APILogin, logout as APILogout, me } from "api/auth"; | ||||
| import { CustomCode } from "codes/custom"; | |||||
| import { PageID } from "codes/page"; | import { PageID } from "codes/page"; | ||||
| import { UserRole } from "codes/user"; | import { UserRole } from "codes/user"; | ||||
| import useAPICall from "hooks/useAPICall"; | import useAPICall from "hooks/useAPICall"; | ||||
| @@ -21,6 +22,9 @@ type Auth = { | |||||
| role: UserRole; | role: UserRole; | ||||
| contractId: string | null; | contractId: string | null; | ||||
| name: string; | |||||
| custom: CustomCode[]; | |||||
| customerName: string; | |||||
| login: (email: string, password: string) => Promise<boolean>; | login: (email: string, password: string) => Promise<boolean>; | ||||
| logout: VoidFunction; | logout: VoidFunction; | ||||
| @@ -37,6 +41,9 @@ export const AuthContext = createContext<Auth>({ | |||||
| role: UserRole.NONE, | role: UserRole.NONE, | ||||
| contractId: null, | contractId: null, | ||||
| name: "", | |||||
| custom: [], | |||||
| customerName: "", | |||||
| login: async (email: string, password: string) => false, | login: async (email: string, password: string) => false, | ||||
| logout: () => {}, | logout: () => {}, | ||||
| @@ -50,6 +57,9 @@ function AuthContextProvider({ children }: Props) { | |||||
| const [initialized, setInitialized] = useState(false); | const [initialized, setInitialized] = useState(false); | ||||
| const [role, setRole] = useState<UserRole>(UserRole.NONE); | const [role, setRole] = useState<UserRole>(UserRole.NONE); | ||||
| const [contractId, setContractId] = useState<string | null>(null); | const [contractId, setContractId] = useState<string | null>(null); | ||||
| const [name, setName] = useState(""); | |||||
| const [custom, setCustom] = useState<CustomCode[]>([]); | |||||
| const [customerName, setCustomerName] = useState(""); | |||||
| const authenticated = useMemo(() => { | const authenticated = useMemo(() => { | ||||
| return role !== UserRole.NONE; | return role !== UserRole.NONE; | ||||
| @@ -60,7 +70,8 @@ function AuthContextProvider({ children }: Props) { | |||||
| onSuccess: (res) => { | onSuccess: (res) => { | ||||
| setContractId(res.data.contract_id); | setContractId(res.data.contract_id); | ||||
| setRole(res.data.role); | setRole(res.data.role); | ||||
| setName(res.data.name); | |||||
| setCustom(res.data.custom); | |||||
| setInitialized(true); | setInitialized(true); | ||||
| }, | }, | ||||
| onFailed: () => { | onFailed: () => { | ||||
| @@ -132,6 +143,10 @@ function AuthContextProvider({ children }: Props) { | |||||
| authenticated, | authenticated, | ||||
| role, | role, | ||||
| contractId, | contractId, | ||||
| name, | |||||
| custom, | |||||
| customerName, | |||||
| // Func | // Func | ||||
| login, | login, | ||||
| @@ -72,7 +72,15 @@ export function SearchConditionContextProvider({ children }: Props) { | |||||
| } | } | ||||
| }); | }); | ||||
| console.log("compare condition", { | |||||
| before, | |||||
| after, | |||||
| }); | |||||
| if (!isEqual(before, after)) { | if (!isEqual(before, after)) { | ||||
| console.log("add condition", { | |||||
| before, | |||||
| after, | |||||
| }); | |||||
| setCondition(after, "addCondition"); | setCondition(after, "addCondition"); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -90,9 +98,6 @@ export function SearchConditionContextProvider({ children }: Props) { | |||||
| const applyToURL = () => { | const applyToURL = () => { | ||||
| if (!initialized) return; | if (!initialized) return; | ||||
| const params = searchParams; | |||||
| const searchStr = params.toString(); | |||||
| const url = pathname + (searchStr ? "?" + searchStr : ""); | |||||
| navigateWhenChanged(pathname, condition, "applyToURL"); | navigateWhenChanged(pathname, condition, "applyToURL"); | ||||
| }; | }; | ||||
| @@ -60,11 +60,11 @@ const categories: Group[] = [ | |||||
| icon: <PeopleIcon />, | icon: <PeopleIcon />, | ||||
| children: [ | children: [ | ||||
| { | { | ||||
| id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST, | |||||
| id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO, | |||||
| label: "一覧", | label: "一覧", | ||||
| }, | }, | ||||
| { | { | ||||
| id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE, | |||||
| id: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO, | |||||
| label: "新規", | label: "新規", | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -14,7 +14,7 @@ import { getValue } from "components/hook-form/RHFAutoComplete"; | |||||
| export default function ReceiptIssuingOrderCreate() { | export default function ReceiptIssuingOrderCreate() { | ||||
| const { setHeaderTitle, setTabs } = useDashboard( | const { setHeaderTitle, setTabs } = useDashboard( | ||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE, | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO, | |||||
| TabID.NONE | TabID.NONE | ||||
| ); | ); | ||||
| @@ -30,7 +30,7 @@ import { ApiId } from "api"; | |||||
| export default function ReceiptIssuingOrderDetail() { | export default function ReceiptIssuingOrderDetail() { | ||||
| const { setHeaderTitle, setTabs } = useDashboard( | const { setHeaderTitle, setTabs } = useDashboard( | ||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO | |||||
| ); | ); | ||||
| const { navigate } = useNavigateCustom(); | const { navigate } = useNavigateCustom(); | ||||
| @@ -0,0 +1,425 @@ | |||||
| import { | |||||
| Box, | |||||
| Button, | |||||
| Dialog, | |||||
| DialogActions, | |||||
| DialogContent, | |||||
| DialogTitle, | |||||
| Drawer, | |||||
| FormControl, | |||||
| Grid, | |||||
| IconButton, | |||||
| Stack, | |||||
| Table, | |||||
| TableBody, | |||||
| TableCell, | |||||
| TableContainer, | |||||
| TablePagination, | |||||
| TableRow, | |||||
| TextField, | |||||
| Tooltip, | |||||
| Typography, | |||||
| } from "@mui/material"; | |||||
| import { Dictionary } from "@types"; | |||||
| import { | |||||
| ReceiptIssuingOrderHTCustom, | |||||
| getReceiptIssuingOrders, | |||||
| } from "api/custom/hello-techno/receipt-issuing-order"; | |||||
| import { PageID, TabID } from "codes/page"; | |||||
| import { | |||||
| FormProvider, | |||||
| RHFCheckbox, | |||||
| RHFSelect, | |||||
| RHFTextField, | |||||
| } from "components/hook-form"; | |||||
| import { TableHeadCustom } from "components/table"; | |||||
| import { SearchConditionContextProvider } from "contexts/SearchConditionContext"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useBackDrop from "hooks/useBackDrop"; | |||||
| import useDashboard from "hooks/useDashBoard"; | |||||
| import useNavigateCustom from "hooks/useNavigateCustom"; | |||||
| import useSearchConditionContext from "hooks/useSearchConditionContext"; | |||||
| import useTable, { UseTableReturn } from "hooks/useTable"; | |||||
| import { useEffect, useMemo, useState } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import { getPath } from "routes/path"; | |||||
| import AccountCircleIcon from "@mui/icons-material/AccountCircle"; | |||||
| import { RHFSelectMuiliple } from "components/hook-form/RHFSelect"; | |||||
| import useAuth from "hooks/useAuth"; | |||||
| import RHFDatePicker from "components/hook-form/RHFDatePicker"; | |||||
| import { dateParse, formatDateStr } from "utils/datetime"; | |||||
| import { Clear } from "@mui/icons-material"; | |||||
| export default function ReceiptIssuingOrderList() { | |||||
| const { setHeaderTitle, setTabs } = useDashboard( | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO, | |||||
| TabID.NONE | |||||
| ); | |||||
| useEffect(() => { | |||||
| setHeaderTitle("領収証発行依頼一覧"); | |||||
| setTabs(null); | |||||
| }, []); | |||||
| return ( | |||||
| <SearchConditionContextProvider> | |||||
| <Page /> | |||||
| </SearchConditionContextProvider> | |||||
| ); | |||||
| } | |||||
| function Page() { | |||||
| const table = useTable<ReceiptIssuingOrderHTCustom>(); | |||||
| return ( | |||||
| <Box> | |||||
| <SearchBox table={table} /> | |||||
| <TableBox table={table} /> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| customer_name: string; | |||||
| parking_name: string; | |||||
| include_done: boolean; | |||||
| status: string; | |||||
| sms_phone_number: string; | |||||
| handler_name: string; | |||||
| order_date_from: Date | null; | |||||
| order_date_to: Date | null; | |||||
| }; | |||||
| type CommonProps = { | |||||
| table: UseTableReturn<ReceiptIssuingOrderHTCustom>; | |||||
| }; | |||||
| function SearchBox({ table }: CommonProps) { | |||||
| const { | |||||
| condition, | |||||
| initialized, | |||||
| get, | |||||
| addCondition: add, | |||||
| } = useSearchConditionContext(); | |||||
| const { setShowBackDrop } = useBackDrop(); | |||||
| const { name: myName } = useAuth(); | |||||
| const [openDateDialog, setOpenDateDialog] = useState(false); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| customer_name: "", | |||||
| parking_name: "", | |||||
| include_done: false, | |||||
| status: "", | |||||
| sms_phone_number: "", | |||||
| handler_name: "", | |||||
| order_date_from: null, | |||||
| order_date_to: null, | |||||
| }, | |||||
| }); | |||||
| const { | |||||
| callAPI: callGetReceiptIssuingOrders, | |||||
| makeSendData, | |||||
| sending, | |||||
| } = useAPICall({ | |||||
| apiMethod: getReceiptIssuingOrders, | |||||
| form, | |||||
| onSuccess: (res) => { | |||||
| table.setRowData(res.data.records); | |||||
| }, | |||||
| }); | |||||
| const includeDone = form.watch("include_done"); | |||||
| const orderDateFrom = form.watch("order_date_from"); | |||||
| const orderDateTo = form.watch("order_date_to"); | |||||
| const isSetOrderDateConditions = useMemo(() => { | |||||
| return !!orderDateFrom || !!orderDateTo; | |||||
| }, [orderDateFrom, orderDateTo]); | |||||
| const handleSubmit = async (data: FormProps) => { | |||||
| addCondition(data); | |||||
| }; | |||||
| const addCondition = (data: FormProps) => { | |||||
| add({ | |||||
| ...data, | |||||
| include_done: data.include_done ? "1" : "0", | |||||
| order_date_from: formatDateStr(data.order_date_from), | |||||
| order_date_to: formatDateStr(data.order_date_to), | |||||
| }); | |||||
| }; | |||||
| const handleBlur = () => { | |||||
| addCondition(form.getValues()); | |||||
| }; | |||||
| const setMyName = () => { | |||||
| form.setValue("handler_name", myName); | |||||
| addCondition(form.getValues()); | |||||
| }; | |||||
| const fetch = async (data: Dictionary) => { | |||||
| const sendData = makeSendData({ | |||||
| ...data, | |||||
| // 完了を含む場合は、条件設定しない。含まない場合は未完了のみとする | |||||
| done: data.include_done === "1" ? "" : "0", | |||||
| }); | |||||
| callGetReceiptIssuingOrders(sendData); | |||||
| }; | |||||
| // 初期値設定 | |||||
| useEffect(() => { | |||||
| if (initialized) { | |||||
| form.setValue("customer_name", get("customer_name")); | |||||
| form.setValue("parking_name", get("parking_name")); | |||||
| form.setValue("include_done", get("include_done") === "1"); | |||||
| form.setValue("status", get("status")); | |||||
| form.setValue("handler_name", get("handler_name")); | |||||
| form.setValue("sms_phone_number", get("sms_phone_number")); | |||||
| form.setValue("order_date_from", dateParse(get("order_date_from"))); | |||||
| form.setValue("order_date_to", dateParse(get("order_date_to"))); | |||||
| } | |||||
| }, [initialized, condition]); | |||||
| // Fetchアクション | |||||
| useEffect(() => { | |||||
| if (initialized) { | |||||
| fetch(condition); | |||||
| } | |||||
| }, [condition, initialized]); | |||||
| // バックドロップ | |||||
| useEffect(() => { | |||||
| setShowBackDrop(sending); | |||||
| }, [sending]); | |||||
| useEffect(() => { | |||||
| addCondition(form.getValues()); | |||||
| }, [includeDone, orderDateFrom, orderDateTo]); | |||||
| return ( | |||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | |||||
| <Box sx={{ p: 1, m: 1 }}> | |||||
| <Grid container spacing={2}> | |||||
| <Grid item xs={3} lg={2}> | |||||
| <Stack> | |||||
| <Typography>担当者</Typography> | |||||
| <Stack direction="row"> | |||||
| <RHFTextField | |||||
| name="handler_name" | |||||
| fullWidth={false} | |||||
| onBlur={handleBlur} | |||||
| /> | |||||
| <Box> | |||||
| <Tooltip title="私が担当" placement="top"> | |||||
| <IconButton aria-label="私が担当" onClick={setMyName}> | |||||
| <AccountCircleIcon /> | |||||
| </IconButton> | |||||
| </Tooltip> | |||||
| </Box> | |||||
| </Stack> | |||||
| </Stack> | |||||
| </Grid> | |||||
| <Grid item xs={3} lg={2}> | |||||
| <Stack> | |||||
| <Typography>ステータス</Typography> | |||||
| <RHFTextField name="status" onBlur={handleBlur} /> | |||||
| </Stack> | |||||
| </Grid> | |||||
| <Grid item> | |||||
| <Stack> | |||||
| <Typography>完了を含む</Typography> | |||||
| <RHFCheckbox name="include_done" label="" sx={{ mx: "auto" }} /> | |||||
| </Stack> | |||||
| </Grid> | |||||
| </Grid> | |||||
| <Grid container spacing={2} mt={1}> | |||||
| <Grid item xs={3} lg={2}> | |||||
| <Stack> | |||||
| <Typography>運営会社</Typography> | |||||
| <RHFTextField name="customer_name" onBlur={handleBlur} /> | |||||
| </Stack> | |||||
| </Grid> | |||||
| <Grid item xs={3} lg={2}> | |||||
| <Stack> | |||||
| <Typography>駐車場名</Typography> | |||||
| <RHFTextField name="parking_name" onBlur={handleBlur} /> | |||||
| </Stack> | |||||
| </Grid> | |||||
| {/* <Grid item xs={3} lg={2}> | |||||
| <Stack> | |||||
| <Typography>ああ</Typography> | |||||
| <RHFSelectMuiliple | |||||
| name="aa" | |||||
| options={[ | |||||
| { value: "aaaaaaaaaaaaaaaaa" }, | |||||
| { value: "bbbbbbbbbbbbbbbbbbbb" }, | |||||
| ]} | |||||
| /> | |||||
| </Stack> | |||||
| </Grid> */} | |||||
| <Grid item xs={3} lg={2}> | |||||
| <Typography>電話番号</Typography> | |||||
| <RHFTextField name="sms_phone_number" /> | |||||
| </Grid> | |||||
| <Grid item xs={3} lg={2}> | |||||
| <Typography>受付時刻</Typography> | |||||
| <Button | |||||
| variant={isSetOrderDateConditions ? "contained" : "text"} | |||||
| color={isSetOrderDateConditions ? "secondary" : "info"} | |||||
| onClick={() => { | |||||
| setOpenDateDialog(true); | |||||
| }} | |||||
| > | |||||
| {isSetOrderDateConditions ? "設定あり" : "設定"} | |||||
| </Button> | |||||
| {isSetOrderDateConditions && ( | |||||
| <IconButton | |||||
| onClick={() => { | |||||
| form.setValue("order_date_from", null); | |||||
| form.setValue("order_date_to", null); | |||||
| }} | |||||
| > | |||||
| <Clear /> | |||||
| </IconButton> | |||||
| )} | |||||
| </Grid> | |||||
| </Grid> | |||||
| </Box> | |||||
| <Dialog | |||||
| open={openDateDialog} | |||||
| onClose={() => { | |||||
| setOpenDateDialog(false); | |||||
| }} | |||||
| > | |||||
| <DialogTitle>受付時刻検索条件</DialogTitle> | |||||
| <DialogContent> | |||||
| <Stack direction="row" spacing={2}> | |||||
| <Box> | |||||
| <Typography>From</Typography> | |||||
| <RHFDatePicker name="order_date_from" /> | |||||
| </Box> | |||||
| <Box> | |||||
| <Typography> </Typography> | |||||
| <Typography>~</Typography> | |||||
| </Box> | |||||
| <Box> | |||||
| <Typography>To</Typography> | |||||
| <RHFDatePicker name="order_date_to" /> | |||||
| </Box> | |||||
| </Stack> | |||||
| </DialogContent> | |||||
| <DialogActions> | |||||
| <Button | |||||
| onClick={() => { | |||||
| setOpenDateDialog(false); | |||||
| }} | |||||
| > | |||||
| 決定 | |||||
| </Button> | |||||
| </DialogActions> | |||||
| </Dialog> | |||||
| </FormProvider> | |||||
| ); | |||||
| } | |||||
| function TableBox({ table }: CommonProps) { | |||||
| const TABLE_HEAD = [ | |||||
| { id: "order_datetime", label: "受付時刻", align: "left" }, | |||||
| { id: "customer_name", label: "運営会社名", align: "left" }, | |||||
| { id: "parking_name", label: "駐車場名", align: "left" }, | |||||
| { id: "status_name", label: "ステータス", align: "left" }, | |||||
| { id: "handler_name", label: "担当者", align: "left" }, | |||||
| ]; | |||||
| const { | |||||
| order, | |||||
| page, | |||||
| sort, | |||||
| rowsPerPage, | |||||
| fetched, | |||||
| fillteredRow, | |||||
| isNotFound, | |||||
| dataLength, | |||||
| // | |||||
| onSort, | |||||
| onChangePage, | |||||
| onChangeRowsPerPage, | |||||
| // | |||||
| setRowData, | |||||
| // | |||||
| ROWS_PER_PAGES, | |||||
| } = table; | |||||
| 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: ReceiptIssuingOrderHTCustom; | |||||
| }; | |||||
| function Row({ data }: RowProps) { | |||||
| const { navigateWhenChanged } = useNavigateCustom(); | |||||
| const handleClick = () => { | |||||
| navigateWhenChanged( | |||||
| getPath( | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO, | |||||
| { | |||||
| query: { | |||||
| id: data.id, | |||||
| }, | |||||
| } | |||||
| ) | |||||
| ); | |||||
| }; | |||||
| return ( | |||||
| <TableRow hover sx={{ cursor: "pointer" }} onClick={handleClick}> | |||||
| <TableCell>{data.order_datetime}</TableCell> | |||||
| <TableCell>{data.customer_name}</TableCell> | |||||
| <TableCell>{data.parking_name}</TableCell> | |||||
| <TableCell>{data.status_name}</TableCell> | |||||
| <TableCell>{data.handler_name}</TableCell> | |||||
| </TableRow> | |||||
| ); | |||||
| } | |||||
| @@ -1,255 +0,0 @@ | |||||
| import { | |||||
| Box, | |||||
| Grid, | |||||
| Table, | |||||
| TableBody, | |||||
| TableCell, | |||||
| TableContainer, | |||||
| TablePagination, | |||||
| TableRow, | |||||
| } from "@mui/material"; | |||||
| import { Dictionary } from "@types"; | |||||
| import { | |||||
| ReceiptIssuingOrderHTCustom, | |||||
| getReceiptIssuingOrders, | |||||
| } from "api/custom/hello-techno/receipt-issuing-order"; | |||||
| import { PageID, TabID } from "codes/page"; | |||||
| import { FormProvider, RHFTextField } from "components/hook-form"; | |||||
| import { TableHeadCustom } from "components/table"; | |||||
| import { SearchConditionContextProvider } from "contexts/SearchConditionContext"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useBackDrop from "hooks/useBackDrop"; | |||||
| import useDashboard from "hooks/useDashBoard"; | |||||
| import useNavigateCustom from "hooks/useNavigateCustom"; | |||||
| import useSearchConditionContext from "hooks/useSearchConditionContext"; | |||||
| import useTable, { UseTableReturn } from "hooks/useTable"; | |||||
| import { useEffect } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import { getPath } from "routes/path"; | |||||
| export default function ReceiptIssuingOrderList() { | |||||
| const { setHeaderTitle, setTabs } = useDashboard( | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST, | |||||
| TabID.NONE | |||||
| ); | |||||
| useEffect(() => { | |||||
| setHeaderTitle("領収証発行依頼一覧"); | |||||
| setTabs(null); | |||||
| }, []); | |||||
| return ( | |||||
| <SearchConditionContextProvider> | |||||
| <Page /> | |||||
| </SearchConditionContextProvider> | |||||
| ); | |||||
| } | |||||
| function Page() { | |||||
| const table = useTable<ReceiptIssuingOrderHTCustom>(); | |||||
| return ( | |||||
| <Box> | |||||
| <SearchBox table={table} /> | |||||
| <TableBox table={table} /> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| type FormProps = { | |||||
| customer_name: string; | |||||
| parking_name: string; | |||||
| }; | |||||
| type CommonProps = { | |||||
| table: UseTableReturn<ReceiptIssuingOrderHTCustom>; | |||||
| }; | |||||
| function SearchBox({ table }: CommonProps) { | |||||
| const { | |||||
| condition, | |||||
| initialized, | |||||
| get, | |||||
| addCondition: add, | |||||
| } = useSearchConditionContext(); | |||||
| const { setShowBackDrop } = useBackDrop(); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| customer_name: "", | |||||
| parking_name: "", | |||||
| }, | |||||
| }); | |||||
| const { | |||||
| callAPI: calGetReceiptIssuingOrders, | |||||
| makeSendData, | |||||
| sending, | |||||
| } = 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 handleBlur = () => { | |||||
| addCondition(form.getValues()); | |||||
| }; | |||||
| const fetch = async (data: Dictionary) => { | |||||
| const sendData = makeSendData({ | |||||
| ...data, | |||||
| }); | |||||
| calGetReceiptIssuingOrders(sendData); | |||||
| }; | |||||
| // 初期値設定 | |||||
| useEffect(() => { | |||||
| if (initialized) { | |||||
| form.setValue("customer_name", get("customer_name")); | |||||
| form.setValue("parking_name", get("parking_name")); | |||||
| } | |||||
| }, [initialized, condition]); | |||||
| // Fetchアクション | |||||
| useEffect(() => { | |||||
| if (initialized) { | |||||
| fetch(condition); | |||||
| } | |||||
| }, [condition, initialized]); | |||||
| // バックドロップ | |||||
| useEffect(() => { | |||||
| setShowBackDrop(sending); | |||||
| }, [sending]); | |||||
| 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="customer_name" | |||||
| fullWidth | |||||
| size="small" | |||||
| onBlur={handleBlur} | |||||
| /> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <RHFTextField | |||||
| label="駐車場名" | |||||
| name="parking_name" | |||||
| fullWidth | |||||
| size="small" | |||||
| onBlur={handleBlur} | |||||
| /> | |||||
| </Grid> | |||||
| </Grid> | |||||
| </Box> | |||||
| </FormProvider> | |||||
| ); | |||||
| } | |||||
| function TableBox({ table }: CommonProps) { | |||||
| const TABLE_HEAD = [ | |||||
| { id: "order_datetime", label: "受付時刻", align: "left" }, | |||||
| { id: "customer_name", label: "運営会社名", align: "left" }, | |||||
| { id: "parking_name", label: "駐車場名", align: "left" }, | |||||
| { id: "status", label: "ステータス", align: "left" }, | |||||
| { id: "handler_name", label: "担当者", align: "left" }, | |||||
| ]; | |||||
| const { | |||||
| order, | |||||
| page, | |||||
| sort, | |||||
| rowsPerPage, | |||||
| fetched, | |||||
| fillteredRow, | |||||
| isNotFound, | |||||
| dataLength, | |||||
| // | |||||
| onSort, | |||||
| onChangePage, | |||||
| onChangeRowsPerPage, | |||||
| // | |||||
| setRowData, | |||||
| // | |||||
| ROWS_PER_PAGES, | |||||
| } = table; | |||||
| 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: ReceiptIssuingOrderHTCustom; | |||||
| }; | |||||
| function Row({ data }: RowProps) { | |||||
| const { navigateWhenChanged } = useNavigateCustom(); | |||||
| const handleClick = () => { | |||||
| navigateWhenChanged( | |||||
| getPath(PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL, { | |||||
| query: { | |||||
| id: data.id, | |||||
| }, | |||||
| }) | |||||
| ); | |||||
| }; | |||||
| return ( | |||||
| <TableRow hover sx={{ cursor: "pointer" }} onClick={handleClick}> | |||||
| <TableCell>{data.order_datetime}</TableCell> | |||||
| <TableCell>{data.customer_name}</TableCell> | |||||
| <TableCell>{data.parking_name}</TableCell> | |||||
| <TableCell>{data.status_name}</TableCell> | |||||
| <TableCell>{data.handler_name}</TableCell> | |||||
| </TableRow> | |||||
| ); | |||||
| } | |||||
| @@ -11,9 +11,18 @@ export const AUTH = { | |||||
| [P.DASHBOARD_CONTRACT_LIST]: setAuth("ge", R.SUPER_ADMIN), | [P.DASHBOARD_CONTRACT_LIST]: setAuth("ge", R.SUPER_ADMIN), | ||||
| [P.DASHBOARD_CONTRACT_DETAIL]: setAuth("ge", R.SUPER_ADMIN), | [P.DASHBOARD_CONTRACT_DETAIL]: setAuth("ge", R.SUPER_ADMIN), | ||||
| [P.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE]: setAuth("ge", R.NORMAL_ADMIN), | |||||
| [P.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST]: setAuth("ge", R.NORMAL_ADMIN), | |||||
| [P.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL]: setAuth("ge", R.NORMAL_ADMIN), | |||||
| [P.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO]: setAuth( | |||||
| "ge", | |||||
| R.NORMAL_ADMIN | |||||
| ), | |||||
| [P.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO]: setAuth( | |||||
| "ge", | |||||
| R.NORMAL_ADMIN | |||||
| ), | |||||
| [P.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO]: setAuth( | |||||
| "ge", | |||||
| R.NORMAL_ADMIN | |||||
| ), | |||||
| [P.PAGE_403]: setAuth("all"), | [P.PAGE_403]: setAuth("all"), | ||||
| [P.PAGE_404]: setAuth("all"), | [P.PAGE_404]: setAuth("all"), | ||||
| @@ -69,18 +69,18 @@ const DashboardRoutes = (): RouteObject => { | |||||
| target: UserRole.SUPER_ADMIN, | target: UserRole.SUPER_ADMIN, | ||||
| }, | }, | ||||
| { | { | ||||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE, | |||||
| element: <ReceiptIssuingOrderCreate />, | |||||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO, | |||||
| element: <ReceiptIssuingOrderCreateHelloTechno />, | |||||
| target: UserRole.NORMAL_ADMIN, | target: UserRole.NORMAL_ADMIN, | ||||
| }, | }, | ||||
| { | { | ||||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST, | |||||
| element: <ReceiptIssuingOrderList />, | |||||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO, | |||||
| element: <ReceiptIssuingOrderListHelloTechno />, | |||||
| target: UserRole.NORMAL_ADMIN, | target: UserRole.NORMAL_ADMIN, | ||||
| }, | }, | ||||
| { | { | ||||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL, | |||||
| element: <ReceiptIssuingOrderDetail />, | |||||
| pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO, | |||||
| element: <ReceiptIssuingOrderDetailHelloTechno />, | |||||
| target: UserRole.NORMAL_ADMIN, | target: UserRole.NORMAL_ADMIN, | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| @@ -137,14 +137,23 @@ const ContractDetail = Loadable( | |||||
| lazy(() => import("pages/dashboard/contract/detail")) | lazy(() => import("pages/dashboard/contract/detail")) | ||||
| ); | ); | ||||
| // 領収証発行依頼 | // 領収証発行依頼 | ||||
| const ReceiptIssuingOrderCreate = Loadable( | |||||
| lazy(() => import("pages/dashboard/receipt-issuing-order/create")) | |||||
| const ReceiptIssuingOrderCreateHelloTechno = Loadable( | |||||
| lazy( | |||||
| () => | |||||
| import("pages/dashboard/receipt-issuing-order/custom/hello-techno/create") | |||||
| ) | |||||
| ); | ); | ||||
| const ReceiptIssuingOrderList = Loadable( | |||||
| lazy(() => import("pages/dashboard/receipt-issuing-order/list")) | |||||
| const ReceiptIssuingOrderListHelloTechno = Loadable( | |||||
| lazy( | |||||
| () => | |||||
| import("pages/dashboard/receipt-issuing-order/custom/hello-techno/list") | |||||
| ) | |||||
| ); | ); | ||||
| const ReceiptIssuingOrderDetail = Loadable( | |||||
| lazy(() => import("pages/dashboard/receipt-issuing-order/detail")) | |||||
| const ReceiptIssuingOrderDetailHelloTechno = Loadable( | |||||
| lazy( | |||||
| () => | |||||
| import("pages/dashboard/receipt-issuing-order/custom/hello-techno/detail") | |||||
| ) | |||||
| ); | ); | ||||
| // その他 --------------------------------- | // その他 --------------------------------- | ||||
| @@ -49,12 +49,15 @@ const PATHS = { | |||||
| [makePathKey(PageID.DASHBOARD_CONTRACT_DETAIL)]: "/dashboard/contract/detail", | [makePathKey(PageID.DASHBOARD_CONTRACT_DETAIL)]: "/dashboard/contract/detail", | ||||
| // 領収証発行依頼関連 | // 領収証発行依頼関連 | ||||
| [makePathKey(PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE)]: | |||||
| "/dashboard/receipt-issusing-order/create", | |||||
| [makePathKey(PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST)]: | |||||
| "/dashboard/receipt-issusing-order/list/:page", | |||||
| [makePathKey(PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL)]: | |||||
| "/dashboard/receipt-issusing-order/detail/:id", | |||||
| [makePathKey( | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_CREATE_CUSTOM_HELLO_TECHNO | |||||
| )]: "/dashboard/receipt-issusing-order/create", | |||||
| [makePathKey( | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO | |||||
| )]: "/dashboard/receipt-issusing-order/list/:page", | |||||
| [makePathKey( | |||||
| PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO | |||||
| )]: "/dashboard/receipt-issusing-order/detail/:id", | |||||
| // その他 | // その他 | ||||
| [makePathKey(PageID.PAGE_403)]: "403", | [makePathKey(PageID.PAGE_403)]: "403", | ||||
| @@ -1,17 +1,20 @@ | |||||
| import { format, parseISO } from 'date-fns'; | |||||
| import { format, isValid, parse, parseISO } from "date-fns"; | |||||
| export const DEFAULT_DATE_FORMAT = "yyyy/MM/dd"; | |||||
| export const DEFAULT_DATET_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss"; | |||||
| type Input = Date | string | null | undefined; | type Input = Date | string | null | undefined; | ||||
| export const formatDateStr = (source: Input) => { | export const formatDateStr = (source: Input) => { | ||||
| return formatToStr(source, 'yyyy/MM/dd'); | |||||
| return formatToStr(source, DEFAULT_DATE_FORMAT); | |||||
| }; | }; | ||||
| export const formatDateTimeStr = (source: Date | string | null | undefined) => { | export const formatDateTimeStr = (source: Date | string | null | undefined) => { | ||||
| return formatToStr(source, 'yyyy/MM/dd HH:mm:ss'); | |||||
| return formatToStr(source, DEFAULT_DATET_TIME_FORMAT); | |||||
| }; | }; | ||||
| const formatToStr = (source: Input, formatStr: string) => { | const formatToStr = (source: Input, formatStr: string) => { | ||||
| if (source === null || source === undefined) return ''; | |||||
| if (source === null || source === undefined) return ""; | |||||
| if (source instanceof Date) return format(source, formatStr); | if (source instanceof Date) return format(source, formatStr); | ||||
| return format(parseISO(source), formatStr); | return format(parseISO(source), formatStr); | ||||
| }; | }; | ||||
| @@ -22,3 +25,22 @@ export const now = () => { | |||||
| export const nowStr = (): string => { | export const nowStr = (): string => { | ||||
| return formatDateTimeStr(now()); | return formatDateTimeStr(now()); | ||||
| }; | }; | ||||
| export const dateParse = (source: Input): Date | null => { | |||||
| return parseFromFormat(source, DEFAULT_DATE_FORMAT); | |||||
| }; | |||||
| export const dateTimeParse = (source: Input): Date | null => { | |||||
| return parseFromFormat(source, DEFAULT_DATET_TIME_FORMAT); | |||||
| }; | |||||
| const parseFromFormat = (source: Input, format: string): Date | null => { | |||||
| if (source === null || source === undefined) return null; | |||||
| if (source instanceof Date) return source; | |||||
| const ret = parse(source, format, new Date()); | |||||
| if (isValid(ret)) { | |||||
| return ret; | |||||
| } | |||||
| return null; | |||||
| }; | |||||