Files
frontend/apps/st/src/components/statistics/input/StatsInputStatusInp.tsx
T

185 lines
7.2 KiB
TypeScript

import { useEffect, useRef, useState } from "react";
import { RealGridReact } from "realgrid-react";
import useSWR, { useSWRConfig } from "swr";
import { useAlertStore } from "@/shared/lib";
import { StatisticsInputStatusApi } from "@/entities/statistics/api/input/statistics-input-status-service";
import type { StatsInputStatusListRequestParams } from "@/entities/statistics/model/input/statistics-input-status-interface";
import type { StatsInputStatusListApiResponse } from "@/entities/statistics/model/input/statistics-input-status-interface";
import { LoadingWithAnimation } from "@common/components";
import ApproveButton from "@/components/button/ApproveButton";
import RejectButton from "@/components/button/RejectButton";
import DataGrid from "@/components/module/DataGrid";
import SearchForm from "@/components/module/SearchForm";
import type { SearchFormValues } from "@/components/type/SearchForm.type";
import { doList } from "@/components/util/column/input/DoList";
import { StatsInputStatusInpColumn } from "@/components/util/column/input/StatsInputStatusInpColumn";
import { toGridRows } from "@/components/util/grid/gridFunction";
import { useTabStore } from "@/store/tab-store";
const getStatsInputStatusFetcher = async (
key: [string, StatsInputStatusListRequestParams],
): Promise<StatsInputStatusListApiResponse> => {
return StatisticsInputStatusApi.getStatisticsInputStatusList(key[1]);
};
// 하수도 통계 관리 > 00. 통계 입력 현황
const StatsInputStatusInp = () => {
const { setMessage: alert } = useAlertStore((state) => state);
const activeTabId = useTabStore((state) => state.activeTabId);
const [rowData, setRowData] = useState<Record<string, string | number>[]>(
[],
);
const [searchParams, setSearchParams] =
useState<StatsInputStatusListRequestParams | null>(null);
const [lastSearchedValues, setLastSearchedValues] =
useState<SearchFormValues | null>(null);
const [hasCompletedSearch, setHasCompletedSearch] = useState(false);
const gridRef = useRef<RealGridReact | null>(null);
const swrKey = searchParams
? (["stats-input-status", searchParams] as const)
: null;
const { mutate } = useSWRConfig();
const { isLoading } = useSWR<StatsInputStatusListApiResponse>(
swrKey,
getStatsInputStatusFetcher,
{
revalidateOnFocus: true,
onSuccess: (data) => {
if (data.status === "success" && data.data) {
setRowData(toGridRows(data.data));
setHasCompletedSearch(true);
} else {
setHasCompletedSearch(false);
setRowData([]);
alert(data.message ?? "조회에 실패했습니다.");
}
},
onError: () => {
alert("데이터 조회 중 오류가 발생했습니다.");
setHasCompletedSearch(false);
setRowData([]);
},
},
);
useEffect(() => {
if (activeTabId === "StatsInputStatusInp" && swrKey) {
mutate(swrKey);
}
}, [activeTabId]);
const handleSearch = (values: SearchFormValues) => {
if (values.sido === "" || values.sido === "ALL") {
alert("시도를 선택해주세요.");
return;
}
const params: StatsInputStatusListRequestParams = {
ctpvNm: values.sido,
sewerBzmnCd: values.bsnmCd,
sggNm: values.gugun === "ALL" ? "" : values.gugun,
statsYr: values.year ?? "",
};
setHasCompletedSearch(false);
setLastSearchedValues(values);
setSearchParams(params);
mutate(["stats-input-status", params]);
};
const handleReset = () => {
setSearchParams(null);
setRowData([]);
setLastSearchedValues(null);
setHasCompletedSearch(false);
};
const rejectFunc = () => {
// 보완 요청 로직
};
const approveFunc = () => {
const checkedRows =
gridRef.current?.gridView?.getCheckedRows?.(true, false, true) ?? [];
if (rowData.length === 0 || checkedRows.length !== rowData.length) {
alert('모든 통계 항목을 체크해주세요.');
return;
}
const hasInvalidStatus = rowData.some((row) =>
["0", "1", "4"].includes(String(row.laeSbmsnSttsCd ?? "")),
);
if (hasInvalidStatus) {
alert("미작성이나 미제출, 혹은 보완요청(반려) 상태인 항목이 있습니다.");
return;
}
// 승인 요청 로직
};
const gugunOkOrNotDoList = doList.includes(lastSearchedValues?.bsnmCd || "")
? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== "ALL")
: true;
const showActionToolbarCard =
hasCompletedSearch && rowData.length > 0 && gugunOkOrNotDoList;
return (
<>
<div className="relative">
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
{showActionToolbarCard && (
<div className="card !py-0">
<div className="m-[0.6rem] flex items-center justify-end gap-[0.6rem]">
<RejectButton rejectFunc={rejectFunc} />
<ApproveButton approveFunc={approveFunc} />
</div>
</div>
)}
{isLoading && (
<div className="[data-theme='black']:bg-transparent absolute inset-0 z-50 flex items-center justify-center rounded-lg p-10">
<div className="relative size-[5rem]">
<LoadingWithAnimation color="primary" />
</div>
</div>
)}
<DataGrid
columnInfo={StatsInputStatusInpColumn}
rowStartNum={2}
fixedColumns={3}
rowData={rowData}
setRowData={setRowData}
isExcelImport={false}
showHeaderCheckbox={true}
getGridRef={gridRef}
cellStyleCallback={({ row, fieldName }) => {
if (fieldName !== "laeSbmsnSttsNm") {
return undefined;
}
const statusCd = String(row.laeSbmsnSttsCd ?? "");
if (statusCd === "0" || statusCd === "1") {
return "rg-cell-stats-status-pending";
}
if (statusCd === "2") {
return "rg-cell-stats-status-submitted";
}
if (statusCd === "3") {
return "rg-cell-stats-status-approved";
}
if (statusCd === "4") {
return "rg-cell-stats-status-rejected";
}
return undefined;
}}
/>
</div>
</>
);
};
export default StatsInputStatusInp;