279 lines
12 KiB
TypeScript
279 lines
12 KiB
TypeScript
import { useFoStore } from '@/app/store';
|
|
import { DatePickerRange, SelectBox } from '@common/business_components/ui';
|
|
import ListDiv from '@common/business_components/ui/list_div';
|
|
import { Table, TableCell, TableHead, TableRow } from '@common/components/ui';
|
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
|
type FacilityTermModalHeaderProps<T extends { msrDt: string }> = { // T는 반드시 msrDt: string 필드를 가져야 한다
|
|
fcltyCd: string;
|
|
fcltyName: string;
|
|
tabName: string;
|
|
searchYear: string;
|
|
searchList: T[];
|
|
ref: React.RefObject<ReturnType<T>>;
|
|
queryClick: (returnType: ReturnType<T>) => void;
|
|
}
|
|
|
|
export type ReturnType<T> = {
|
|
startDate: Date;
|
|
endDate: Date;
|
|
tabName: string;
|
|
filteredList: T[];
|
|
}
|
|
|
|
export default function FacilityTermModalHeader<T extends { msrDt: string }>({
|
|
searchList,
|
|
fcltyName,
|
|
tabName,
|
|
searchYear,
|
|
queryClick,
|
|
ref
|
|
}: FacilityTermModalHeaderProps<T & { msrDt: string }>) {
|
|
const { Common } = useFoStore((state) => state);
|
|
const { selectFlowPanel } = Common;
|
|
const [startDate, setStartDate] = useState<Date>(new Date(Number(searchYear), 0, 1));
|
|
const [endDate, setEndDate] = useState<Date>(new Date(Number(searchYear), 11, 31));
|
|
const startPickerRef = useRef<HTMLDivElement>(null);
|
|
const endPickerRef = useRef<HTMLDivElement>(null);
|
|
const [flowPanel, setFlowPanel] = useState<string>(selectFlowPanel[0]?.val ?? '0'); // 강수구분 : 초기값 "전체"
|
|
const [copySearchList, setCopySearchList] = useState<T[]>(searchList);
|
|
const [standSearchList, setStandSearchList] = useState<T[]>(searchList);
|
|
|
|
const isDateInRanges = (date: Date) => {
|
|
const standYear = parseInt(searchYear);
|
|
const isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0);
|
|
const dateRanges: { start: Date, end: Date }[] = [];
|
|
|
|
if (tabName.includes("_summer")) {
|
|
dateRanges.push({
|
|
start: new Date(standYear, 5, 1),
|
|
end: new Date(standYear, 7, 31)
|
|
});
|
|
} else if (tabName.includes("_winter")) {
|
|
dateRanges.push({
|
|
start: new Date(standYear, 0, 1),
|
|
end: new Date(standYear, 1, isLeapYear ? 29 : 28)
|
|
});
|
|
} else {
|
|
dateRanges.push({
|
|
start: new Date(standYear, 0, 1),
|
|
end: new Date(standYear, 11, 31)
|
|
});
|
|
}
|
|
|
|
return dateRanges.some(range => {
|
|
const start = new Date(range.start);
|
|
const end = new Date(range.end);
|
|
return date >= start && date <= end;
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
let startDate = new Date(Number(searchYear), 0, 1);
|
|
let endDate = new Date(Number(searchYear), 11, 31);
|
|
const standYear = Number(searchYear);
|
|
const isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0);
|
|
|
|
if (tabName.includes("_summer")) { // 하절기
|
|
startDate = new Date(Number(searchYear), 5, 1); // 6월 ~
|
|
endDate = new Date(Number(searchYear), 7, 31); // 8월
|
|
setStartDate(startDate);
|
|
setEndDate(endDate);
|
|
} else if (tabName.includes("_winter")) { // 동절기
|
|
startDate = new Date(Number(searchYear), 0, 1); // 1월 ~
|
|
endDate = new Date(Number(searchYear), 1, isLeapYear ? 29 : 28); // 2월
|
|
setStartDate(startDate);
|
|
setEndDate(endDate);
|
|
} else { // 연간
|
|
startDate = new Date(Number(searchYear), 0, 1);
|
|
endDate = new Date(Number(searchYear), 11, 31);
|
|
setStartDate(startDate);
|
|
setEndDate(endDate);
|
|
}
|
|
|
|
let filteredData: T[] = [];
|
|
|
|
if (tabName.includes("_rain")) { // 강우시
|
|
filteredData = searchList.filter((item) => {
|
|
const itemDate = new Date((item as T & { msrDt: string }).msrDt);
|
|
const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate());
|
|
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
|
const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay;
|
|
|
|
if (flowPanel === '2') { //3~10mm미만
|
|
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 3 && infoRnDay < 10;
|
|
} else if (flowPanel === '3') { //10~20mm미만
|
|
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 10 && infoRnDay < 20;
|
|
} else if (flowPanel === '4') { //20~30mm미만
|
|
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 20 && infoRnDay < 30;
|
|
} else if (flowPanel === '5') { //30~40mm미만
|
|
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 30 && infoRnDay < 40;
|
|
} else if (flowPanel === '6') { //40~50mm미만
|
|
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 40 && infoRnDay < 50;
|
|
} else if (flowPanel === '7') { //50~60mm미만
|
|
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 50 && infoRnDay < 60;
|
|
} else if (flowPanel === '8') {
|
|
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 60;
|
|
} else {
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && (rainEffectDay === 1);
|
|
}
|
|
});
|
|
} else if (tabName.includes("_chuncheon")) { // 청천시
|
|
filteredData = searchList.filter((item) => {
|
|
const itemDate = new Date((item as T & { msrDt: string }).msrDt);
|
|
const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate());
|
|
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
|
const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay;
|
|
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && rainEffectDay == 0;
|
|
});
|
|
} else {
|
|
filteredData = searchList.filter((item) => {
|
|
const itemDate = new Date((item as T & { msrDt: string }).msrDt);
|
|
const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate());
|
|
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
|
return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly;
|
|
});
|
|
}
|
|
setCopySearchList(filteredData);
|
|
setStandSearchList(filteredData);
|
|
}, [searchList, searchYear, tabName, flowPanel]);
|
|
|
|
const handleStartDateSelect = (day: Date | undefined) => {
|
|
if (day && day > endDate) {
|
|
alert('종료일은 시작일 이전일 수 없습니다.');
|
|
return;
|
|
}
|
|
|
|
const selectedDate = day ?? startDate;
|
|
setStartDate(selectedDate);
|
|
const button = startPickerRef.current?.querySelector('button');
|
|
if (button) {
|
|
setTimeout(() => button.click(), 0);
|
|
}
|
|
|
|
const filteredData = standSearchList.filter((item) => {
|
|
const itemDate = new Date((item as T & { msrDt: string }).msrDt);
|
|
const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate());
|
|
const startDateOnly = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
|
|
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
|
return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly;
|
|
});
|
|
setCopySearchList(filteredData);
|
|
};
|
|
|
|
const handleEndDateSelect = (day: Date | undefined) => {
|
|
if (day && day < startDate) {
|
|
alert('종료일은 시작일 이후일 수 없습니다.');
|
|
return;
|
|
}
|
|
|
|
const selectedDate = day ?? endDate;
|
|
setEndDate(selectedDate);
|
|
const button = endPickerRef.current?.querySelector('button');
|
|
if (button) {
|
|
setTimeout(() => button.click(), 0);
|
|
}
|
|
|
|
const filteredData = standSearchList.filter((item) => {
|
|
const itemDate = new Date((item as T & { msrDt: string }).msrDt);
|
|
const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate());
|
|
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
const endDateOnly = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
|
|
return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly;
|
|
});
|
|
setCopySearchList(filteredData);
|
|
};
|
|
|
|
const fncSetFilteredList = useCallback(() => {
|
|
queryClick({
|
|
startDate: startDate,
|
|
endDate: endDate,
|
|
tabName: tabName,
|
|
filteredList: copySearchList
|
|
});
|
|
}, [queryClick, startDate, endDate, tabName, copySearchList]);
|
|
|
|
useEffect(() => {
|
|
fncSetFilteredList();
|
|
}, [fncSetFilteredList]);
|
|
|
|
useEffect(() => {
|
|
if (ref && ref.current) {
|
|
const customRef = ref.current;
|
|
customRef.startDate = startDate;
|
|
customRef.endDate = endDate;
|
|
customRef.tabName = tabName;
|
|
customRef.filteredList = copySearchList;
|
|
}
|
|
}, [startDate, endDate, tabName, copySearchList, ref]);
|
|
|
|
return (
|
|
<ListDiv className="!h-[80px]">
|
|
<div className="!m-[0.5rem] max-h-[40rem] overflow-auto">
|
|
<Table>
|
|
<thead>
|
|
<TableRow className="!h-[20px]">
|
|
<TableHead className="w-[120px]">{'시설명'}</TableHead>
|
|
{tabName === "tab_term_rain" ? <TableCell className="w-[300px]">{fcltyName}</TableCell> :
|
|
<TableCell className="w-[380px]">{fcltyName}</TableCell>}
|
|
{tabName === "tab_term_rain" && (
|
|
<>
|
|
<TableHead className="w-[120px]">{'강수구분'}</TableHead>
|
|
<TableCell className="w-[250px]">
|
|
<div className="justify-center">
|
|
<SelectBox
|
|
selectArray={selectFlowPanel}
|
|
value={flowPanel}
|
|
onSelectValue={(val) => setFlowPanel(val.toString())}
|
|
className="mx-3 w-[150px]"
|
|
label=""
|
|
selectClass="w-full rounded border border-input bg-form p-1"
|
|
/>
|
|
</div>
|
|
</TableCell>
|
|
</>
|
|
)}
|
|
<TableHead className="w-[120px]">{'년/월'}</TableHead>
|
|
<TableCell className="">
|
|
<div className="flex">
|
|
<div ref={startPickerRef} className="flex justify-center">
|
|
<DatePickerRange
|
|
mode="single"
|
|
selected={startDate}
|
|
onSelect={(date) => handleStartDateSelect(date as Date)}
|
|
className="w-full rounded border border-input bg-form p-1 text-foreground"
|
|
disabled={(date) => !isDateInRanges(date)}
|
|
defaultMonth={startDate}
|
|
/>
|
|
</div>
|
|
<h3 className="justify-center px-5">~</h3>
|
|
<div ref={endPickerRef} className="flex justify-center">
|
|
<DatePickerRange
|
|
mode="single"
|
|
selected={endDate}
|
|
onSelect={(date) => handleEndDateSelect(date as Date)}
|
|
className="w-full rounded border border-input bg-form p-1 text-foreground"
|
|
disabled={(date) => !isDateInRanges(date)}
|
|
defaultMonth={endDate}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
</thead>
|
|
</Table>
|
|
</div>
|
|
</ListDiv>
|
|
);
|
|
}
|