import { useEffect, useState } from 'react' import type { Mode, SurveyDetailInfo, SurveyDetailRequest } from '@/types/Survey' import { useAlertMsg, WARNING_MESSAGE } from '@/hooks/useAlertMsg' import { radioEtcData, supplementaryFacilities } from '@/types/Survey' import { useSurveyOptionStore } from '@/store/surveyOptionStore' const makeNumArr = (value: string) => { return value .split(',') .map((v) => v.trim()) .filter((v) => v.length > 0) } export default function RoofForm(props: { roofInfo: SurveyDetailRequest | SurveyDetailInfo setRoofInfo: (roofInfo: SurveyDetailRequest) => void mode: Mode }) { const { roofInfo, setRoofInfo, mode } = props const { showErrorAlert } = useAlertMsg() const [isFlip, setIsFlip] = useState(true) const handleNumberInput = (key: keyof SurveyDetailRequest, value: number | string) => { /** 지붕 경사도, 노지판 두께 처리 - 최대 5자리, 소수점 1자리 처리 */ if (key === 'roofSlope' || key === 'openFieldPlateThickness') { const stringValue = value.toString() if (stringValue.length > 5) { showErrorAlert(WARNING_MESSAGE.SAVE_SIZE_OVERFLOW) return } if (stringValue.includes('.')) { const decimalPlaces = stringValue.split('.')[1].length if (decimalPlaces > 1) { showErrorAlert(WARNING_MESSAGE.DECIMAL_POINT_CANNOT_EXCEED) return } } } /** 전기 계약 용량 처리 - 단위 붙여서 저장*/ if (key === 'contractCapacity') { const remainValue = roofInfo.contractCapacity?.split(' ')[1] ?? roofInfo.contractCapacity if (Number.isNaN(Number(remainValue))) { setRoofInfo({ ...roofInfo, [key]: value + ' ' + remainValue }) return } setRoofInfo({ ...roofInfo, [key]: value.toString() }) } setRoofInfo({ ...roofInfo, [key]: value.toString() }) } /** 전기 계약 용량 단위 처리 */ const handleUnitInput = (value: string) => { const numericValue = roofInfo.contractCapacity?.replace(/[^0-9.]/g, '') || '' setRoofInfo({ ...roofInfo, contractCapacity: numericValue ? `${numericValue} ${value}` : '0 ' + value, }) } return (
setIsFlip(!isFlip)}>
電気 / 屋根情報
{/* 전기 관계 */}
電気関係
{/* 전기 계약 용량 */}
電気契約容量
{mode === 'READ' && } {mode !== 'READ' && (
handleNumberInput('contractCapacity', e.target.value)} />
)}
{/* 전기 소매 회사사 */}
電気小売会社
setRoofInfo({ ...roofInfo, retailCompany: e.target.value })} />
{/* 전기 부대 설비 */}
電気付帯設備※複数選択可能
{/* 설치 희망 시스템 */}
設置希望システム
{/* 지붕 관계 */}
屋根関係
{/* 건축 연수 */}
築年数
{/* 지붕재 */}
屋根材※最大2個まで選択可能
{/* 지붕 모양 */}
屋根の形状
{/* 지붕 경사도 */}
屋根勾配
handleNumberInput('roofSlope', e.target.value)} />
{/* 주택구조조 */}
住宅構造
{/* 서까래 재질 */}
垂木材質
{/* 서까래 크기 */}
垂木サイズ
{/* 서까래 피치 */}
垂木ピッチ
{/* 서까래 방향 */}
垂木の方向
{/* 노지판 종류 */}
野地板の種類
{roofInfo.openFieldPlateKind === 'S' && (
{/* 노지판 두께 */}
路地板厚※小幅板を選択した場合, 厚さ. 小幅板間の間隔寸法を記載
handleNumberInput('openFieldPlateThickness', e.target.value)} /> mm
)}
{/* 누수 흔적 */}
雨漏りの痕跡
{/* 방수재 종류 */}
ルーフィングの種類
{/* 단열재 유무 */}
断熱材の有無
{/* 지붕 구조의 순서 */}
屋根構造の順序
{/* 지붕 제품명 설치 가능 여부 확인 */}
屋根製品名 設置可否確認
{/* 메모 */}
メモ
) } /** SelectBox 처리 */ const SelectedBox = ({ mode, column, detailInfoData, setRoofInfo, }: { mode: Mode column: string detailInfoData: SurveyDetailInfo setRoofInfo: (roofInfo: SurveyDetailRequest) => void }) => { const { selectBoxOptions, initialized, loading, loadOptions } = useSurveyOptionStore() const selectedId = detailInfoData?.[column as keyof SurveyDetailInfo] const etcValue = detailInfoData?.[`${column}Etc` as keyof SurveyDetailInfo] const [isEtcSelected, setIsEtcSelected] = useState(Boolean(etcValue)) useEffect(() => { if (!initialized && !loading) loadOptions() }, [initialized, loading]) const isSpecialCase = column === 'constructionYear' || column === 'installationAvailability' const showEtcOption = !isSpecialCase /** SelectBox 값 변경 처리 */ const handleSelectChange = (e: React.ChangeEvent) => { const value = e.target.value const isEtc = value === 'etc' const updatedData = { ...detailInfoData, [column]: isEtc ? null : value, [`${column}Etc`]: isEtc ? '' : null, } setIsEtcSelected(isEtc) setRoofInfo(updatedData) } /** 기타 입력 처리 */ const handleEtcInputChange = (e: React.ChangeEvent) => { setRoofInfo({ ...detailInfoData, [`${column}Etc`]: e.target.value }) } /** Input box 비활성화 처리 * - 읽기 모드 : 비활성화 * - 설치 가능 여부 : 기타 입력 창 항상 활성화 * - 건축 연수 : 新築 신축 (N) 체크 시 비활성화 * */ const isInputDisabled = () => { if (mode === 'READ') return true if (column === 'installationAvailability') return false if (column === 'constructionYear') { return detailInfoData.constructionYear === selectBoxOptions.constructionYear[0].code || detailInfoData.constructionYear === null } return !isEtcSelected && !etcValue } return ( <>
{column === 'constructionYear' && }
) } /** RadioBox 선택 처리 */ const RadioSelected = ({ mode, column, detailInfoData, setRoofInfo, }: { mode: Mode column: string detailInfoData: SurveyDetailInfo setRoofInfo: (roofInfo: SurveyDetailRequest) => void }) => { const etcValue = detailInfoData?.[`${column}Etc` as keyof SurveyDetailInfo] const [etcChecked, setEtcChecked] = useState(Boolean(etcValue)) const selectedId = /** 누수 흔적 boolean 타입이므로 number 타입으로 변환 - 값이 없을 경우 2(없음) 으로 초기화*/ column === 'leakTrace' ? Number(detailInfoData?.[column as keyof SurveyDetailInfo]) || radioEtcData.leakTrace[1].id : detailInfoData?.[column as keyof SurveyDetailInfo] const isSpecialColumn = column === 'rafterDirection' || column === 'leakTrace' || column === 'insulationPresence' const showEtcOption = !isSpecialColumn /** RadioBox 값 변경 처리 */ const handleRadioChange = (e: React.ChangeEvent) => { const value = e.target.value /** 누수 흔적 처리 - boolean 타입이므로 별도 처리 */ if (column === 'leakTrace') { setRoofInfo({ ...detailInfoData, leakTrace: value === String(radioEtcData.leakTrace[0].id) }) return } /** 기타 체크 처리 */ if (value === 'etc') { setEtcChecked(true) setRoofInfo({ ...detailInfoData, [column]: null, [`${column}Etc`]: '' }) return } /** 단열재 유무 - 있음(1) 선택 시 기타 체크 처리 * 서까래 방향 - 기타 입력 칸 없음 * */ const isInsulationPresence = column === 'insulationPresence' const isRafterDirection = column === 'rafterDirection' setEtcChecked(isInsulationPresence && value === String(radioEtcData.insulationPresence[1].id)) setRoofInfo({ ...detailInfoData, [column]: value, [`${column}Etc`]: isRafterDirection ? detailInfoData[`${column}Etc` as keyof SurveyDetailInfo] : null, }) } /** 기타 입력 처리 */ const handleEtcInputChange = (e: React.ChangeEvent) => { setRoofInfo({ ...detailInfoData, [`${column}Etc`]: e.target.value }) } /** Input box 비활성화 처리 * - 읽기 모드 : 비활성화 * - 단열재 유무 : 단열재 없음(1) 체크 시 비활성화 * */ const isInputDisabled = () => { if (mode === 'READ') return true if (column === 'insulationPresence') { return detailInfoData.insulationPresence === String(radioEtcData.insulationPresence[0].id) } return !etcChecked && !etcValue } return ( <> {radioEtcData[column as keyof typeof radioEtcData].map((item) => (
))} {showEtcOption && (
)} {(showEtcOption || column === 'insulationPresence') && (
)} ) } /** 다중 선택 처리 */ const MultiCheck = ({ mode, column, roofInfo, setRoofInfo, }: { mode: Mode column: string roofInfo: SurveyDetailInfo setRoofInfo: (roofInfo: SurveyDetailRequest) => void }) => { const { showErrorAlert } = useAlertMsg() const { roofMaterial, initialized, loading, loadOptions } = useSurveyOptionStore() const multiCheckData = column === 'supplementaryFacilities' ? supplementaryFacilities : roofMaterial const [etcValue, setEtcValue] = useState(roofInfo?.[`${column}Etc` as keyof SurveyDetailInfo]?.toString() ?? null) useEffect(() => { const newValue = roofInfo?.[`${column}Etc` as keyof SurveyDetailInfo]?.toString() ?? null setEtcValue(newValue) }, [roofInfo, column]) useEffect(() => { if (!initialized && !loading) loadOptions() }, [initialized, loading]) const isRoofMaterial = column === 'roofMaterial' const selectedValues = makeNumArr(String(roofInfo[column as keyof SurveyDetailInfo] ?? '')) /** 다중 선택 처리 */ const handleCheckbox = (item: { id: number; code: string | null; name: string }) => { const isOtherSelected = etcValue !== null let newValue: string[] if (selectedValues.includes(item.code ?? String(item.id))) { newValue = selectedValues.filter((v) => v !== item.code && v !== String(item.id)) } else { /** 지붕 재료 처리 - 최대 2개 선택 처리 */ if (isRoofMaterial) { const totalSelected = selectedValues.length + (isOtherSelected ? 1 : 0) if (totalSelected >= 2) { showErrorAlert(WARNING_MESSAGE.ROOF_MATERIAL_MAX_SELECT) return } } newValue = [...selectedValues, item.code ?? String(item.id)] } setRoofInfo({ ...roofInfo, [column]: newValue.join(',') }) } /** 기타 선택 처리 */ const handleOtherCheckbox = () => { setEtcValue(etcValue !== null ? null : '') const isOtherSelected = etcValue !== null if (isRoofMaterial) { /** 지붕 재료 기타 선택 포함 최대 2개 선택 처리 */ if (!isOtherSelected && selectedValues.length >= 2) { showErrorAlert(WARNING_MESSAGE.ROOF_MATERIAL_MAX_SELECT) setEtcValue(null) return } } /** 기타 선택 해제 시 값도 null로 설정 */ setRoofInfo({ ...roofInfo, [`${column}Etc`]: isOtherSelected ? null : '', }) } /** 기타 입력 처리 */ const handleOtherInputChange = (e: React.ChangeEvent) => { setRoofInfo({ ...roofInfo, [`${column}Etc`]: e.target.value }) } /** Input box 비활성화 처리 */ const isInputDisabled = () => { return mode === 'READ' || etcValue === null } return ( <>
{multiCheckData.map((item) => (
handleCheckbox(item)} />
))}
) }