import { useState } from 'react' import type { Mode, SurveyDetailInfo, SurveyDetailRequest } from '@/types/Survey' import { useAlertMsg, WARNING_MESSAGE } from '@/hooks/useAlertMsg' import { radioEtcData, selectBoxOptions, supplementaryFacilities, roofMaterial } from '@/types/Survey' 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 === '4' && (
{/* 노지판 두께 */}
路地板厚※小幅板を選択した場合, 厚さ. 小幅板間の間隔寸法を記載
handleNumberInput('openFieldPlateThickness', e.target.value)} /> mm
)}
{/* 누수 흔적 */}
水漏れの痕跡
{/* 방수재 종류 */}
防水材の種類
{/* 단열재 유무 */}
断熱材の有無
{/* 지붕 구조의 순서 */}
屋根構造の順序
{/* 지붕 제품명 설치 가능 여부 확인 */}
屋根製品名 設置可否確認
{/* 메모 */}
メモ
) } /** SelectBox 처리 */ const SelectedBox = ({ mode, column, detailInfoData, setRoofInfo, }: { mode: Mode column: string detailInfoData: SurveyDetailInfo setRoofInfo: (roofInfo: SurveyDetailRequest) => void }) => { const selectedId = detailInfoData?.[column as keyof SurveyDetailInfo] const etcValue = detailInfoData?.[`${column}Etc` as keyof SurveyDetailInfo] const [isEtcSelected, setIsEtcSelected] = useState(Boolean(etcValue)) 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 isSpecialEtc = isSpecialCase && value === '2' const updatedData = { ...detailInfoData, [column]: isEtc ? null : value, [`${column}Etc`]: isEtc ? '' : null, } if (isSpecialEtc) { updatedData[column] = value } setIsEtcSelected(isEtc || isSpecialEtc) setRoofInfo(updatedData) } /** 기타 입력 처리 */ const handleEtcInputChange = (e: React.ChangeEvent) => { setRoofInfo({ ...detailInfoData, [`${column}Etc`]: e.target.value }) } /** Input box 비활성화 처리 * - 읽기 모드 : 비활성화 * - 설치 가능 여부 : 기타 입력 창 항상 활성화 * - 건축 연수 : 신축(1) 체크 시 비활성화 * */ const isInputDisabled = () => { if (mode === 'READ') return true if (column === 'installationAvailability') return false if (column === 'constructionYear') { return detailInfoData.constructionYear === '1' || 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 = column === 'leakTrace' ? Number(detailInfoData?.[column as keyof SurveyDetailInfo]) || 2 : 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 === '1' }) 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 === '2') 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 !== '2' } 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 multiCheckData = column === 'supplementaryFacilities' ? supplementaryFacilities : roofMaterial const etcValue = roofInfo?.[`${column}Etc` as keyof SurveyDetailInfo] const [isOtherCheck, setIsOtherCheck] = useState(Boolean(etcValue)) const isRoofMaterial = column === 'roofMaterial' const selectedValues = makeNumArr(String(roofInfo[column as keyof SurveyDetailInfo] ?? '')) /** 다중 선택 처리 */ const handleCheckbox = (id: number) => { const isOtherSelected = Boolean(etcValue) let newValue: string[] if (selectedValues.includes(String(id))) { newValue = selectedValues.filter((v) => v !== String(id)) } else { /** 지붕 재료 처리 - 최대 2개 선택 처리 */ if (isRoofMaterial) { const totalSelected = selectedValues.length + (isOtherSelected || isOtherCheck ? 1 : 0) if (totalSelected >= 2) { showErrorAlert(WARNING_MESSAGE.ROOF_MATERIAL_MAX_SELECT) return } } newValue = [...selectedValues, String(id)] } setRoofInfo({ ...roofInfo, [column]: newValue.join(',') }) } /** 기타 선택 처리 */ const handleOtherCheckbox = () => { if (isRoofMaterial) { const currentSelected = selectedValues.length if (!isOtherCheck && currentSelected >= 2) { showErrorAlert(WARNING_MESSAGE.ROOF_MATERIAL_MAX_SELECT) return } } const newIsOtherCheck = !isOtherCheck setIsOtherCheck(newIsOtherCheck) /** 기타 선택 해제 시 값도 null로 설정 */ setRoofInfo({ ...roofInfo, [`${column}Etc`]: newIsOtherCheck ? '' : null, }) } /** 기타 입력 처리 */ const handleOtherInputChange = (e: React.ChangeEvent) => { setRoofInfo({ ...roofInfo, [`${column}Etc`]: e.target.value }) } /** Input box 비활성화 처리 */ const isInputDisabled = () => { return mode === 'READ' || (!isOtherCheck && !etcValue) } return ( <>
{multiCheckData.map((item) => (
handleCheckbox(item.id)} />
))}
) }