Files
frontend/apps/dm/components/ui/sdmInfoInsertForm/component.tsx
T

607 lines
17 KiB
TypeScript

import ModalSimilarPage from "@/app/(base-layout)/pages/sdmMng/sdmInfoInsert/modalSimilar/page";
import type { FormData } from "@/app/(base-layout)/pages/sdmMng/sdmInfoInsert/page";
import { useDmStore } from "@/app/store";
import {
CANDIDATE,
DatePicker,
FormField,
FormLabel,
FormUi,
SelectBox,
UiModal,
} from "@common/business_components";
import { Input } from "@common/components";
import { Button } from "@common/components/ui";
import { useSearchParams } from "next/navigation";
import { useCallback, useEffect, useState } from "react";
import { AccessibleFormField } from "./AccessibleFormField";
import type { ControllerRenderProps, UseFormReturn } from "react-hook-form";
import SearchInputText from "../common/searhDemandInput/component";
import type { DemandCompType } from "@/app/store/sdmMng";
import NewWindowPortal from "@/app/(popup-layout)/map/popup/windowPotal";
import Map from "@/app/(popup-layout)/map/popup/sdmInfoMap";
export interface SdmInfoRegFormProps {
form: UseFormReturn<FormData>;
onCheckboxChange?: (checked: boolean) => void;
facilityName?: string;
}
type FieldComponent = (
field: ControllerRenderProps<FormData, keyof FormData>
) => JSX.Element;
export function SdmInfoRegForm({
form,
onCheckboxChange,
facilityName,
}: SdmInfoRegFormProps) {
const { initializeCommonData, Sdm } = useDmStore((state) => state);
const { useTypesData } = Sdm;
const searchParams = useSearchParams();
const [sdmNmValue, setSdmNmValue] = useState<string>(
searchParams.get("dmdCoNm") || ""
);
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false);
const [isSimilarCase, setIsSimilarCase] = useState(false);
const [key, setKey] = useState(0);
// 후보지 팝업 오픈 상태
const [isCandidatePopup, setIsCandidatePopup] = useState(false);
//모달 조회에 필요한 데이터
const [sply, setSply] = useState<number>(0);
const [usageCd, setUsageCd] = useState<string>("청소");
const [money, setMoney] = useState<number>(0);
useEffect(() => {
initializeCommonData();
}, [initializeCommonData]);
useEffect(() =>{
console.log('candidateTitle ', form.getValues("candidateTitle"))
},[form.getValues("candidateTitle") ])
useEffect(() => {
if (useTypesData && useTypesData.length > 0) {
setTimeout(() => {
form.setValue("usePurpose", useTypesData[0]?.val?.toString() || "");
}, 500);
}
}, [useTypesData, form]);
useEffect(() => {
if (facilityName) {
setSdmNmValue(facilityName);
form.setValue("sdmNm", facilityName);
setKey((prev) => prev + 1);
}
}, [facilityName, form]);
useEffect(() => {
if (searchParams.get("dmdCoNm")) {
form.setValue("sdmNm", searchParams.get("dmdCoNm") || "");
setSdmNmValue(searchParams.get("dmdCoNm") || "");
setKey((prev) => prev + 1);
}
}, [searchParams, form]);
const handleCandidateClose = useCallback(
() => setIsCandidatePopup(false),
[]
);
const searchCandidate = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
//setIsCandidatePopup(true);
const popupOptions = `width=1920,height=1080,resizable='y',scrollbars='y'`;
window.open("/map/popup", "candidatePopup", popupOptions);
};
const searchSimilarCase = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
setIsSimilarCase(true);
};
const handleCheckboxChange = (checked: boolean) => {
setIsBznmTotNoDisabled(checked);
onCheckboxChange?.(checked);
};
// 시설 선택시 이벤트
const selectComp = useCallback(
(rtnData: DemandCompType[]) => {
const rtnCompData = rtnData?.[0];
form.setValue("sdmNm", rtnCompData?.dmdCoNm || "");
},
[form]
);
const formFields: Array<{
name: keyof FormData;
label: string;
component: FieldComponent | undefined;
formIndex: number;
required?: boolean;
}> = [
{
name: "sdmNm",
label: "수요처선택",
formIndex: 0,
required: true,
component: (field) => (
<div key={key}>
<SearchInputText
label="수요처명"
setValue={(val) => {
setSdmNmValue(val || "");
field.onChange(val || "");
}}
setRtnData={selectComp}
initValue={facilityName || sdmNmValue}
{...field}
/>
</div>
),
},
{
name: "demandYmd",
label: "요구시기",
formIndex: 0,
required: true,
component: (field) => (
<div className="w-full">
<DatePicker
mode="single"
selected={field.value as Date}
onSelect={(date) => {
field.onChange(date as Date);
}}
className="w-full"
defaultMonth={field.value as Date}
field={{
value: field.value as Date,
onChange: (date: Date | undefined) => {
field.onChange(date as Date);
},
}}
selectClass={undefined}
/>
</div>
),
},
{
name: "demandQnty",
label: "요구수량(㎥/d)",
formIndex: 0,
required: true,
component: (field) => (
<Input
placeholder="요구수량(㎥/d)을 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={(e) => {
field.onChange(e);
setSply(Number(e.target.value));
}}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "usePurpose",
label: "사용용도",
formIndex: 0,
required: true,
component: (field) => (
<SelectBox
selectClass={undefined}
label=""
selectArray={useTypesData}
onSelectValue={(val) => {
field.onChange(val.toString());
setUsageCd(val.toString());
}}
className=""
value={field.value as string}
/>
),
},
{
name: "money",
label: "희망단가(원/m3)",
formIndex: 0,
required: true,
component: (field) => (
<AccessibleFormField
field={field}
label="희망단가(원/㎥)"
required={true}
error={form.formState.errors.money}
inputComponent={
<FormUi
onCheckboxChange={handleCheckboxChange}
isDisabled={isBznmTotNoDisabled}
>
<Input
placeholder="희망단가(원/㎥)을 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={(e) => {
field.onChange(e);
setMoney(Number(e.target.value));
}}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
</FormUi>
}
/>
),
},
{
name: "reqWaterQlty",
label: "요구수질",
formIndex: 0,
required: true,
component: undefined,
},
{
name: "grssClfg",
label: "총대장균군수(개/100ml)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="총대장균군수를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "tn",
label: "총질소(T-N)(mg/L)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="총질소를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "combResdch",
label: "결합잔류염소(mg/L)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="결합잔류염소를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "tph",
label: "총인(T-P)(mg/L)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="총인을 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "trbt",
label: "탁도(NTU)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="탁도를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "ph",
label: "수소이온농도(pH)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="수소이온농도를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "bod",
label: "생물학적 산소요구량(BOD)(mg/L)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="생물학적 산소요구량을 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "clIonQnt",
label: "염화물(mgCL/L)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="염화물을 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "smll",
label: "냄새",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="냄새를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "cdtnv",
label: "전기전도도(㎲/cm)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="전기전도도를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "crmty",
label: "색도(도)",
formIndex: 1,
required: true,
component: (field) => (
<Input
placeholder="색도를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "rmrk",
label: "비고",
formIndex: 1,
component: (field) => (
<Input
placeholder="비고를 입력하세요"
type="text"
className="!text-xl text-gray-600"
value={field.value as string}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
ref={field.ref}
/>
),
},
{
name: "candidateTitle",
label: CANDIDATE || "공급처 후보지 선택(필수아님)",
formIndex: 2,
component: () => (
<div>
<div className="-mt-14 float-right flex gap-10">
<Button className={"bg-gray-200"} onClick={searchCandidate}>
후보지 조회
</Button>
<Button className={"bg-gray-200"} onClick={searchSimilarCase}>
유사사례
</Button>
</div>
<div className="flex justify-center gap-10 mt-5">
{(form.getValues("candidateTitle") || []).map((candidate: any, index: number) => (
<Input
key={index}
placeholder={`후보지${index + 1}`}
type="text"
className="!text-xl w-[130px] text-gray-600"
value={candidate.ruseUtztnFcltNm}
readOnly
/>
))}
</div>
</div>
),
},
];
const normalFields = formFields.filter(
(f) => f.formIndex === 0 && f.component
);
const groupFields = formFields.filter(
(f) => f.formIndex === 1 && f.component
);
const candidateFields = formFields.filter(
(f) => f.formIndex === 2 && f.component
);
return (
<>
{normalFields.map(({ name, label, component, required }) =>
component ? (
<FormField
key={name}
control={form.control}
name={name}
render={({ field }) =>
name === "money" ? (
component(field)
) : (
// <FormUi label={label}>
// {component(field)}
// </FormUi>
<AccessibleFormField
field={field}
label={label}
required={required}
error={form.formState.errors[name]}
inputComponent={component(field)}
/>
)
}
/>
) : null
)}
{groupFields.length > 0 && (
<div className="mt-10">
<FormLabel className="text-xl">요구수질</FormLabel>
<div className="flex flex-wrap justify-start gap-10 mt-3 mb-3">
{groupFields.map(({ name, label, component, required }) => (
<div key={name} className="min-w-[180px]">
<FormField
control={form.control}
name={name}
render={({ field }) => (
// <FormUi label={label}>
// {component?.(field)}
// </FormUi>
<AccessibleFormField
field={field}
label={label}
required={required}
error={form.formState.errors[name]}
inputComponent={component?.(field)}
/>
)}
/>
</div>
))}
</div>
</div>
)}
{candidateFields.map(({ name, label, component, required }, index) =>
component ? (
<FormField
key={name + index}
control={form.control}
name={name}
render={({ field }) => (
// <FormUi label={label}>
// {component(field)}
// </FormUi>
<AccessibleFormField
field={field}
label={label}
required={required}
error={form.formState.errors[name]}
inputComponent={component?.(field)}
/>
)}
/>
) : null
)}
{isSimilarCase && (
<UiModal
body={
<ModalSimilarPage sply={sply} usageCd={usageCd} money={money} />
}
bodyClass="sm:max-w-[100vw] w-[1400px] h-[900px]"
open={isSimilarCase}
onOpenChange={(open) => !open && setIsSimilarCase(false)}
noHeaderYn="Y"
noFooterYn="Y"
/>
)}
</>
);
}