| @@ -27,6 +27,8 @@ export const ApiId = { | |||||
| RECEIPT_ISSUING_ORDER: id++, | RECEIPT_ISSUING_ORDER: id++, | ||||
| RECEIPT_ISSUING_ORDER_CREATE: id++, | RECEIPT_ISSUING_ORDER_CREATE: id++, | ||||
| RECEIPT_ISSUING_ORDER_MAIL_POST_COMPLETE: id++, | RECEIPT_ISSUING_ORDER_MAIL_POST_COMPLETE: id++, | ||||
| RECEIPT_ISSUING_ORDER_HANDELRS: id++, | |||||
| RECEIPT_ISSUING_ORDER_CHANGE_HANDELR: id++, | |||||
| DOWNLOAD_RECEIPT_LETTER: id++, | DOWNLOAD_RECEIPT_LETTER: id++, | ||||
| CONTRACTS: id++, | CONTRACTS: id++, | ||||
| @@ -1,5 +1,14 @@ | |||||
| import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from "."; | |||||
| import { Dictionary } from "@types"; | |||||
| import { | |||||
| APICommonResponse, | |||||
| ApiId, | |||||
| HttpMethod, | |||||
| TimestampRequest, | |||||
| makeParam, | |||||
| request, | |||||
| } from "."; | |||||
| import { getUrl } from "./url"; | import { getUrl } from "./url"; | ||||
| import { string } from "yup"; | |||||
| export type ReceiptIssuingOrder = { | export type ReceiptIssuingOrder = { | ||||
| id: string; | id: string; | ||||
| @@ -43,6 +52,11 @@ export type ReceiptIssuingOrder = { | |||||
| updated_at: string; | updated_at: string; | ||||
| }; | }; | ||||
| export type Handler = { | |||||
| id: string; | |||||
| name: string; | |||||
| }; | |||||
| // 領収証発行一覧取得 ----------------------- | // 領収証発行一覧取得 ----------------------- | ||||
| export type ReceiptIssuingOrdersRequest = { | export type ReceiptIssuingOrdersRequest = { | ||||
| address?: string; | address?: string; | ||||
| @@ -80,3 +94,35 @@ export const completeMailPost = async (data: MailPostCompleteRequest) => { | |||||
| }); | }); | ||||
| return res; | return res; | ||||
| }; | }; | ||||
| // 担当者一覧取得 ----------------------- | |||||
| export type HandlersRequest = {}; | |||||
| export type HandlersResponse = { | |||||
| data: { | |||||
| records: Handler[]; | |||||
| }; | |||||
| } & APICommonResponse; | |||||
| export const getHandlers = async (data: HandlersRequest) => { | |||||
| const res = await request<HandlersResponse>({ | |||||
| url: getUrl(ApiId.RECEIPT_ISSUING_ORDER_HANDELRS), | |||||
| method: HttpMethod.GET, | |||||
| data: makeParam(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| // 担当者変更 ----------------------- | |||||
| export type ChangeHandlerRequest = { | |||||
| id: string; | |||||
| handler_id: string; | |||||
| } & TimestampRequest; | |||||
| export const changeHandler = async (data: ChangeHandlerRequest) => { | |||||
| const res = await request({ | |||||
| url: getUrl(ApiId.RECEIPT_ISSUING_ORDER_CHANGE_HANDELR), | |||||
| method: HttpMethod.POST, | |||||
| data: makeParam(data), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| @@ -15,6 +15,9 @@ const urls = { | |||||
| [A.RECEIPT_ISSUING_ORDER_MAIL_ORDER]: "receipt-issuing-order/mail-order", | [A.RECEIPT_ISSUING_ORDER_MAIL_ORDER]: "receipt-issuing-order/mail-order", | ||||
| [A.RECEIPT_ISSUING_ORDER_MAIL_POST_COMPLETE]: | [A.RECEIPT_ISSUING_ORDER_MAIL_POST_COMPLETE]: | ||||
| "receipt-issuing-order/mail-complete", | "receipt-issuing-order/mail-complete", | ||||
| [A.RECEIPT_ISSUING_ORDER_HANDELRS]: "receipt-issuing-order/handlers", | |||||
| [A.RECEIPT_ISSUING_ORDER_CHANGE_HANDELR]: | |||||
| "receipt-issuing-order/change-handler", | |||||
| [A.DOWNLOAD_RECEIPT_LETTER]: "receipt-letter/download", | [A.DOWNLOAD_RECEIPT_LETTER]: "receipt-letter/download", | ||||
| [A.RECEIPT_ISSUING_ORDERS]: "receipt-issuing-orders", | [A.RECEIPT_ISSUING_ORDERS]: "receipt-issuing-orders", | ||||
| @@ -27,6 +27,7 @@ import { formatDateStr, formatDateTimeStr } from "utils/datetime"; | |||||
| import useMailPostCompleteDialog from "./hooks/useMailPostCompleteDialog"; | import useMailPostCompleteDialog from "./hooks/useMailPostCompleteDialog"; | ||||
| import { getFullUrl } from "api/url"; | import { getFullUrl } from "api/url"; | ||||
| import { ApiId } from "api"; | import { ApiId } from "api"; | ||||
| import useChangeHandlerDialog from "../../hooks/useChangeHandlerDialog"; | |||||
| export default function ReceiptIssuingOrderDetail() { | export default function ReceiptIssuingOrderDetail() { | ||||
| const { setHeaderTitle, setTabs } = useDashboard( | const { setHeaderTitle, setTabs } = useDashboard( | ||||
| @@ -47,6 +48,10 @@ export default function ReceiptIssuingOrderDetail() { | |||||
| fetch(); | fetch(); | ||||
| }); | }); | ||||
| const changeHandlerDialog = useChangeHandlerDialog(order, () => { | |||||
| fetch(); | |||||
| }); | |||||
| const { callAPI, sending } = useAPICall({ | const { callAPI, sending } = useAPICall({ | ||||
| apiMethod: getReceiptIssuingOrders, | apiMethod: getReceiptIssuingOrders, | ||||
| onSuccess: (res) => { | onSuccess: (res) => { | ||||
| @@ -79,7 +84,16 @@ export default function ReceiptIssuingOrderDetail() { | |||||
| { | { | ||||
| title: "担当者", | title: "担当者", | ||||
| value: order.handler_name, | value: order.handler_name, | ||||
| // end: <Button sx={{ minWidth: 80 }}>担当変更</Button>, | |||||
| end: ( | |||||
| <Button | |||||
| sx={{ minWidth: 80 }} | |||||
| onClick={() => { | |||||
| changeHandlerDialog.open(); | |||||
| }} | |||||
| > | |||||
| 担当変更 | |||||
| </Button> | |||||
| ), | |||||
| }, | }, | ||||
| { title: "SMS送信先", value: order.sms_phone_number }, | { title: "SMS送信先", value: order.sms_phone_number }, | ||||
| { title: "依頼日", value: formatDateStr(order.order_datetime) }, | { title: "依頼日", value: formatDateStr(order.order_datetime) }, | ||||
| @@ -182,94 +196,97 @@ export default function ReceiptIssuingOrderDetail() { | |||||
| }, [sending]); | }, [sending]); | ||||
| return ( | return ( | ||||
| <Box> | |||||
| <Grid container spacing={2}> | |||||
| <Grid item xs={12}> | |||||
| <Stack direction="row" spacing={2}> | |||||
| <Button onClick={() => navigate(-1)}>戻る</Button> | |||||
| </Stack> | |||||
| </Grid> | |||||
| <Grid item xs={4}> | |||||
| <Paper elevation={0} sx={{ border: "1px solid" }}> | |||||
| <Stack spacing={2}> | |||||
| <Typography | |||||
| variant="h6" | |||||
| fontWeight="bold" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 依頼内容 | |||||
| </Typography> | |||||
| <SimpleDataList data={orderInfo} /> | |||||
| <Divider sx={{ my: 2 }} /> | |||||
| <Typography | |||||
| variant="subtitle1" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 領収証情報 | |||||
| </Typography> | |||||
| <SimpleDataList data={receiptInfo} /> | |||||
| <> | |||||
| <Box> | |||||
| <Grid container spacing={2}> | |||||
| <Grid item xs={12}> | |||||
| <Stack direction="row" spacing={2}> | |||||
| <Button onClick={() => navigate(-1)}>戻る</Button> | |||||
| </Stack> | </Stack> | ||||
| </Paper> | |||||
| </Grid> | |||||
| <Grid item xs={4}> | |||||
| <Paper elevation={0} sx={{ pb: 2, border: "1px solid" }}> | |||||
| <Stack spacing={2}> | |||||
| <Typography | |||||
| variant="h6" | |||||
| fontWeight="bold" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 郵送管理 | |||||
| </Typography> | |||||
| <SimpleDataList data={mailStatus1} /> | |||||
| {hasMailOrder && ( | |||||
| <> | |||||
| <Divider sx={{ my: 2 }} /> | |||||
| <Typography | |||||
| variant="subtitle1" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 郵送先 | |||||
| </Typography> | |||||
| <SimpleDataList data={mailStatus2} /> | |||||
| <Divider /> | |||||
| <Stack direction="row" spacing={2} sx={{ px: 2 }}> | |||||
| <Button | |||||
| variant="contained" | |||||
| href={downloadUrl} | |||||
| target="_blank" | |||||
| </Grid> | |||||
| <Grid item xs={4}> | |||||
| <Paper elevation={0} sx={{ border: "1px solid" }}> | |||||
| <Stack spacing={2}> | |||||
| <Typography | |||||
| variant="h6" | |||||
| fontWeight="bold" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 依頼内容 | |||||
| </Typography> | |||||
| <SimpleDataList data={orderInfo} /> | |||||
| <Divider sx={{ my: 2 }} /> | |||||
| <Typography | |||||
| variant="subtitle1" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 領収証情報 | |||||
| </Typography> | |||||
| <SimpleDataList data={receiptInfo} /> | |||||
| </Stack> | |||||
| </Paper> | |||||
| </Grid> | |||||
| <Grid item xs={4}> | |||||
| <Paper elevation={0} sx={{ pb: 2, border: "1px solid" }}> | |||||
| <Stack spacing={2}> | |||||
| <Typography | |||||
| variant="h6" | |||||
| fontWeight="bold" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 郵送管理 | |||||
| </Typography> | |||||
| <SimpleDataList data={mailStatus1} /> | |||||
| {hasMailOrder && ( | |||||
| <> | |||||
| <Divider sx={{ my: 2 }} /> | |||||
| <Typography | |||||
| variant="subtitle1" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | > | ||||
| 印字 | |||||
| </Button> | |||||
| 郵送先 | |||||
| </Typography> | |||||
| <SimpleDataList data={mailStatus2} /> | |||||
| <Divider /> | |||||
| <Stack direction="row" spacing={2} sx={{ px: 2 }}> | |||||
| <Button | |||||
| variant="contained" | |||||
| href={downloadUrl} | |||||
| target="_blank" | |||||
| > | |||||
| 印字 | |||||
| </Button> | |||||
| <Button | |||||
| variant="contained" | |||||
| onClick={postCompleteDialog.open} | |||||
| > | |||||
| 投函完了 | |||||
| </Button> | |||||
| </Stack> | |||||
| {postCompleteDialog.element} | |||||
| </> | |||||
| )} | |||||
| </Stack> | |||||
| </Paper> | |||||
| </Grid> | |||||
| <Grid item xs={4}> | |||||
| <Paper elevation={0} sx={{ border: "1px solid" }}> | |||||
| <Stack spacing={2}> | |||||
| <Typography | |||||
| variant="h6" | |||||
| fontWeight="bold" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 各種アクション日時 | |||||
| </Typography> | |||||
| <SimpleDataList data={actionDatetimes} /> | |||||
| </Stack> | |||||
| </Paper> | |||||
| <Button | |||||
| variant="contained" | |||||
| onClick={postCompleteDialog.open} | |||||
| > | |||||
| 投函完了 | |||||
| </Button> | |||||
| </Stack> | |||||
| {postCompleteDialog.element} | |||||
| </> | |||||
| )} | |||||
| </Stack> | |||||
| </Paper> | |||||
| </Grid> | |||||
| <Grid item xs={4}> | |||||
| <Paper elevation={0} sx={{ border: "1px solid" }}> | |||||
| <Stack spacing={2}> | |||||
| <Typography | |||||
| variant="h6" | |||||
| fontWeight="bold" | |||||
| sx={{ my: 2, textAlign: "center" }} | |||||
| > | |||||
| 各種アクション日時 | |||||
| </Typography> | |||||
| <SimpleDataList data={actionDatetimes} /> | |||||
| </Stack> | |||||
| </Paper> | |||||
| </Grid> | |||||
| </Grid> | </Grid> | ||||
| </Grid> | |||||
| </Box> | |||||
| </Box> | |||||
| {changeHandlerDialog.element} | |||||
| </> | |||||
| ); | ); | ||||
| } | } | ||||
| @@ -0,0 +1,144 @@ | |||||
| import { yupResolver } from "@hookform/resolvers/yup"; | |||||
| import { | |||||
| Button, | |||||
| Dialog, | |||||
| DialogActions, | |||||
| DialogContent, | |||||
| DialogTitle, | |||||
| } from "@mui/material"; | |||||
| import { Dictionary } from "@types"; | |||||
| import { | |||||
| Handler, | |||||
| ReceiptIssuingOrder, | |||||
| changeHandler, | |||||
| getHandlers, | |||||
| } from "api/receipt-issuing-order"; | |||||
| import { FormProvider } from "components/hook-form"; | |||||
| import RHFSelect, { | |||||
| SelectOptionProps, | |||||
| makeOptions, | |||||
| } from "components/hook-form/RHFSelect"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | |||||
| import { useEffect, useMemo, useState } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import * as Yup from "yup"; | |||||
| type FormProps = { | |||||
| handler_id: string; | |||||
| }; | |||||
| export default function useChangeHandlerDialog( | |||||
| order: ReceiptIssuingOrder | null, | |||||
| onComplete?: VoidFunction | |||||
| ) { | |||||
| const [show, setShow] = useState(false); | |||||
| const { success, error } = useSnackbarCustom(); | |||||
| const [handlers, setHandlers] = useState<Handler[] | null>(null); | |||||
| const options: SelectOptionProps[] = useMemo(() => { | |||||
| if (handlers === null) return []; | |||||
| return handlers.map((ele) => ({ | |||||
| value: ele.id, | |||||
| label: ele.name, | |||||
| })); | |||||
| }, [handlers]); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| handler_id: "", | |||||
| }, | |||||
| resolver: yupResolver( | |||||
| Yup.object().shape({ | |||||
| handler_id: Yup.string().required("必須項目です"), | |||||
| }) | |||||
| ), | |||||
| }); | |||||
| const { callAPI: callGetHandlers } = useAPICall({ | |||||
| apiMethod: getHandlers, | |||||
| backDrop: true, | |||||
| onSuccess: ({ data }) => { | |||||
| setHandlers(data.records); | |||||
| }, | |||||
| }); | |||||
| const { callAPI: callChangeHandler } = useAPICall({ | |||||
| apiMethod: changeHandler, | |||||
| backDrop: true, | |||||
| onSuccess: () => { | |||||
| success("変更しました"); | |||||
| setShow(false); | |||||
| if (onComplete) { | |||||
| onComplete(); | |||||
| } | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const open = () => { | |||||
| setShow(true); | |||||
| }; | |||||
| const close = () => { | |||||
| setShow(false); | |||||
| }; | |||||
| const handleSubmit = (data: FormProps) => { | |||||
| if (!order) return; | |||||
| callChangeHandler({ | |||||
| id: order.id, | |||||
| handler_id: data.handler_id, | |||||
| timestamp: order.updated_at, | |||||
| }); | |||||
| }; | |||||
| const element = ( | |||||
| <Dialog | |||||
| open={show} | |||||
| onClose={close} | |||||
| PaperProps={{ | |||||
| sx: { | |||||
| width: "50%", | |||||
| }, | |||||
| }} | |||||
| > | |||||
| <DialogTitle>担当者変更</DialogTitle> | |||||
| <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}> | |||||
| <DialogContent> | |||||
| <RHFSelect name="handler_id" label="担当者" options={options} /> | |||||
| </DialogContent> | |||||
| <DialogActions> | |||||
| <Button onClick={close}>CANCEL</Button> | |||||
| <Button type="submit">OK</Button> | |||||
| </DialogActions> | |||||
| </FormProvider> | |||||
| </Dialog> | |||||
| ); | |||||
| useEffect(() => { | |||||
| setHandlers(null); | |||||
| form.setValue("handler_id", ""); | |||||
| if (show) { | |||||
| callGetHandlers({}); | |||||
| } | |||||
| }, [show]); | |||||
| return { | |||||
| // param | |||||
| show, | |||||
| // Element | |||||
| element, | |||||
| // function | |||||
| open, | |||||
| close, | |||||
| setShow, | |||||
| }; | |||||
| } | |||||