You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
6.5KB

  1. import {
  2. Box,
  3. Button,
  4. Grid,
  5. Table,
  6. TableBody,
  7. TableCell,
  8. TableContainer,
  9. TablePagination,
  10. TableRow,
  11. Typography,
  12. } from "@mui/material";
  13. import {
  14. UseSummary,
  15. getUseSummaries,
  16. getUseSummaryYYYYMMs,
  17. } from "api/custom/hello-techno/use-summary";
  18. import { PageID, TabID } from "codes/page";
  19. import { FormProvider } from "components/hook-form";
  20. import RHFSelect, { SelectOptionProps } from "components/hook-form/RHFSelect";
  21. import { TableHeadCustom } from "components/table";
  22. import { SearchConditionContextProvider } from "contexts/SearchConditionContext";
  23. import useAPICall from "hooks/useAPICall";
  24. import useDashboard from "hooks/useDashBoard";
  25. import useNavigateCustom from "hooks/useNavigateCustom";
  26. import useSearchConditionContext from "hooks/useSearchConditionContext";
  27. import useTable, { UseTableReturn } from "hooks/useTable";
  28. import { useEffect, useMemo, useState } from "react";
  29. import { useForm } from "react-hook-form";
  30. import { sprintf } from "sprintf-js";
  31. export default function UseSummaryList() {
  32. const { setHeaderTitle, setTabs } = useDashboard(
  33. PageID.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO,
  34. TabID.NONE
  35. );
  36. const { navigateWhenChanged } = useNavigateCustom();
  37. useEffect(() => {
  38. setHeaderTitle("利用実績一覧");
  39. setTabs(null);
  40. }, []);
  41. return (
  42. <SearchConditionContextProvider>
  43. <Page />
  44. </SearchConditionContextProvider>
  45. );
  46. }
  47. function Page() {
  48. const table = useTable<UseSummary>();
  49. return (
  50. <Box>
  51. <SearchBox table={table} />
  52. <TableBox table={table} />
  53. </Box>
  54. );
  55. }
  56. type FormProps = {
  57. summary_yyyymm: string;
  58. };
  59. type CommonProps = {
  60. table: UseTableReturn<UseSummary>;
  61. };
  62. function SearchBox({ table }: CommonProps) {
  63. const {
  64. condition,
  65. initialized,
  66. get,
  67. addCondition: add,
  68. } = useSearchConditionContext();
  69. const form = useForm<FormProps>({
  70. defaultValues: {
  71. summary_yyyymm: "",
  72. },
  73. });
  74. const selectedYYYYMM = form.watch("summary_yyyymm");
  75. const [yyyymm, setYYYYMM] = useState<string[] | null>(null);
  76. const yyyymmOptions: SelectOptionProps[] = useMemo(() => {
  77. if (yyyymm === null) return [];
  78. return yyyymm.map((ele) => {
  79. return {
  80. value: ele,
  81. label: sprintf("%s/%s", ele.substring(0, 4), ele.substring(4, 6)),
  82. };
  83. });
  84. }, [yyyymm]);
  85. const downloadCsvUrl = useMemo(() => {
  86. if (!selectedYYYYMM) return "";
  87. const param = new URLSearchParams({
  88. summary_yyyymm: selectedYYYYMM,
  89. });
  90. return (
  91. process.env.REACT_APP_HOST_API_KEY +
  92. "/custom/hello-techno/use-summary/csv?" +
  93. param.toString()
  94. );
  95. }, [selectedYYYYMM]);
  96. const { callAPI: callGetUseSummaryYYYYMMs } = useAPICall({
  97. apiMethod: getUseSummaryYYYYMMs,
  98. backDrop: true,
  99. onSuccess: ({ data: { records } }) => {
  100. setYYYYMM(records);
  101. },
  102. });
  103. const {
  104. callAPI: callGetContracts,
  105. makeSendData,
  106. sending,
  107. } = useAPICall({
  108. apiMethod: getUseSummaries,
  109. backDrop: true,
  110. onSuccess: ({ data }) => {
  111. table.setRowData(data.records);
  112. },
  113. });
  114. const handleSubmit = async (data: FormProps) => {
  115. addCondition(data);
  116. };
  117. const addCondition = (data: FormProps) => {
  118. add({
  119. ...data,
  120. });
  121. };
  122. const fetch = async () => {
  123. const sendData = {
  124. ...condition,
  125. ...form.getValues(),
  126. };
  127. if (sendData.summary_yyyymm) {
  128. callGetContracts(sendData);
  129. }
  130. };
  131. // 初期値設定
  132. useEffect(() => {
  133. if (initialized && yyyymm !== null) {
  134. form.setValue(
  135. "summary_yyyymm",
  136. get("summary_yyyymm", yyyymm.find(() => true) ?? "")
  137. );
  138. addCondition(form.getValues());
  139. }
  140. }, [initialized, condition, yyyymm]);
  141. // Fetchアクション
  142. useEffect(() => {
  143. if (initialized) {
  144. fetch();
  145. }
  146. }, [condition, initialized, selectedYYYYMM]);
  147. useEffect(() => {
  148. callGetUseSummaryYYYYMMs({});
  149. }, []);
  150. return (
  151. <FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}>
  152. <Box sx={{ p: 1, m: 1 }}>
  153. <Grid container spacing={2}>
  154. <Grid item xs={3} lg={2}>
  155. <Typography>年月</Typography>
  156. <RHFSelect
  157. options={yyyymmOptions}
  158. name="summary_yyyymm"
  159. size="small"
  160. />
  161. </Grid>
  162. {!!selectedYYYYMM && (
  163. <Grid item xs={3} lg={2}>
  164. <Typography>CSV</Typography>
  165. <Button variant="contained" color="info" href={downloadCsvUrl}>
  166. ダウンロード
  167. </Button>
  168. </Grid>
  169. )}
  170. </Grid>
  171. </Box>
  172. </FormProvider>
  173. );
  174. }
  175. function TableBox({ table }: CommonProps) {
  176. const TABLE_HEAD = [
  177. { id: "customer_name", label: "運営会社名", align: "left" },
  178. { id: "parking_name", label: "駐車場名", align: "left" },
  179. { id: "receipt_order_count", label: "領収証発行件数", align: "left" },
  180. { id: "mail_order_count", label: "郵送依頼件数", align: "left" },
  181. { id: "sms_send_count", label: "SMS送信件数", align: "left" },
  182. ];
  183. const {
  184. order,
  185. page,
  186. sort,
  187. rowsPerPage,
  188. fetched,
  189. fillteredRow,
  190. isNotFound,
  191. dataLength,
  192. //
  193. onSort,
  194. onChangePage,
  195. onChangeRowsPerPage,
  196. //
  197. setRowData,
  198. //
  199. ROWS_PER_PAGES,
  200. } = table;
  201. return (
  202. <>
  203. <TableContainer
  204. sx={{
  205. // minWidth: 800,
  206. position: "relative",
  207. }}
  208. >
  209. <Table size="small">
  210. <TableHeadCustom
  211. order={order}
  212. orderBy={sort}
  213. headLabel={TABLE_HEAD}
  214. rowCount={1}
  215. numSelected={0}
  216. onSort={onSort}
  217. />
  218. <TableBody>
  219. {fillteredRow.map((row, index) => (
  220. <Row data={row} key={index} />
  221. ))}
  222. </TableBody>
  223. </Table>
  224. </TableContainer>
  225. <Box sx={{ position: "relative" }}>
  226. <TablePagination
  227. rowsPerPageOptions={ROWS_PER_PAGES}
  228. component="div"
  229. count={dataLength}
  230. rowsPerPage={rowsPerPage}
  231. page={page}
  232. onPageChange={onChangePage}
  233. onRowsPerPageChange={onChangeRowsPerPage}
  234. />
  235. </Box>
  236. </>
  237. );
  238. }
  239. type RowProps = {
  240. data: UseSummary;
  241. };
  242. function Row({ data }: RowProps) {
  243. return (
  244. <TableRow>
  245. <TableCell>{data.customer_name}</TableCell>
  246. <TableCell>{data.parking_name}</TableCell>
  247. <TableCell>{data.receipt_order_count}件</TableCell>
  248. <TableCell>{data.mail_order_count}件</TableCell>
  249. <TableCell>{data.sms_send_count}件</TableCell>
  250. </TableRow>
  251. );
  252. }