diff --git a/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx b/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx index 8e1e9af50..af9806488 100644 --- a/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx +++ b/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx @@ -69,22 +69,9 @@ const num = (v: string) => parseFloat(v.replace(/,/g, "") || "0"); const fmt = (v: number) => (isNaN(v) ? "" : v.toLocaleString()); /* ------------------------------------------------------------------ */ -/* 공통 셀 컴포넌트 (컴포넌트 외부에 선언해야 re-mount 방지) */ +/* 공통 셀 컴포넌트 분리: widgets/cnfm/ui/cells.tsx에서 import */ /* ------------------------------------------------------------------ */ -const NumCell = ({ value, onChange }: { value: string; onChange: (v: string) => void }) => ( - - onChange(e.target.value)} - /> - -); - -const ReadCell = ({ value }: { value: string | number }) => ( - {value} -); +import { NumCell, ReadCell, PrivacyConsent, EtcAttachments } from '@/widgets/cnfm'; /* ------------------------------------------------------------------ */ /* 메인 컴포넌트 */ @@ -112,7 +99,6 @@ function CnfmRegistPage() { sessionStorage.removeItem(INSTL_SNCN_REGISTER_SELECTION_KEY); } }, []); - /* ── 기본 정보 ── */ const [bzNm, setBzNm] = useState(""); const [bzBgngYr, setBzBgngYr] = useState(""); @@ -129,23 +115,6 @@ function CnfmRegistPage() { /* ── 개인정보 동의 ── */ const [privacyAgree, setPrivacyAgree] = useState<"Y" | "N">("N"); - /* ── 기타 첨부파일 ── */ - type EtcFile = { - id: string; - name: string; - ext: string; - size: string; - uploader: string; - atflCd: string; - atflId: string; - }; - const [etcFiles, setEtcFiles] = useState([]); - const [etcNoticeOpen, setEtcNoticeOpen] = useState(true); - const [etcFileGroupId, setEtcFileGroupId] = useState(""); - const [etcUploading, setEtcUploading] = useState(false); - const etcFileGroupIdRef = useRef(""); - - /* ── 필수 첨부파일 ── */ const { data: requiredAttachmentDefs = [] } = useQuery({ queryKey: ["esntlAtchFileTree", docSeComCd], queryFn: () => esntlAtchFileMngService.findTree({ docSeComCd }), @@ -237,8 +206,24 @@ function CnfmRegistPage() { upload.start(); }; - /** 기타첨부파일 삭제 핸들러: 백엔드에 DELETE 요청을 보내 소프트삭제 처리 후 상태 갱신 */ - const handleDeleteEtcFile = async (fileId: string, atflId: string) => { + /* ── 기타 첨부파일 ── */ + type EtcFile = { + id: string; + name: string; + ext: string; + size: string; + uploader: string; + atflCd: string; + atflId: string; + }; + const [etcFiles, setEtcFiles] = useState([]); + const [etcNoticeOpen, setEtcNoticeOpen] = useState(true); + const [etcFileGroupId, setEtcFileGroupId] = useState(""); + const [etcUploading, setEtcUploading] = useState(false); + const etcFileGroupIdRef = useRef(""); + + /** 기타첨부파일 삭제 핸들러: 백엔드에 DELETE 요청을 보내 소프트삭제 처리 후 상태 갱신 */ + const handleDeleteEtcFile = async (fileId: string, atflId: string) => { try { if (atflId) { await deleteAttachment(atflId); @@ -932,61 +917,35 @@ function CnfmRegistPage() { - {/* ── 개인정보 동의 ── */} -
-

개인정보 동의

-
-

[ 개인정보 수집항목 ]

-
- * 필수항목 : 소속기관, 소속부서, 담당자, 직급, 사무실 번호, FAX 번호
- ․ 선택항목 : 휴대폰 번호, 이메일 주소
- ․ 기타항목 : IP Address, 쿠키, 시스템 접속 및 이용 기록
- ※ 시스템 이용과정에서 기타 항목의 정보들이 자동으로 생성되어 수집될 수 있습니다. -
- -

[ 개인정보 이용목적 ]

-
- ․ 국가하수도정보시스템 웹서비스 이용에 따른 본인 확인 절차에 이용
- ․ 국가하수도정보시스템 사용에 필요한 권한 부여
- ․ 사용자별 맞춤 컨텐츠 (처리시설의 운영 데이터 조회, 수질현황 데이터 조회, 예산 편성 / 예산편성 등) 제공에 이용 -
- -
● 개인정보의 보유 및 이용기간
-
- ․ 수집된 고객의 개인정보는 2년 동안 보유하며 그 이후에는 문서를 파쇄합니다.
- ․ 정보제공자가 개인정보 파쇄를 요청할 경우 즉시 파쇄합니다. -
- -
-
● 개인정보 제공 거부에 따른 제한사항
-
- ․ 귀하는 개인정보 제공 동의를 거부할 권리가 있으나, 동의 거부 시 국가하수도정보시스템 이용 서비스에 제한이 있을 수 있습니다. -
+ {/* ── 개인정보 동의 (위젯으로 분리) ── */} + +

[ 개인정보 수집항목 ]

+
+ * 필수항목 : 소속기관, 소속부서, 담당자, 직급, 사무실 번호, FAX 번호
+ ․ 선택항목 : 휴대폰 번호, 이메일 주소
+ ․ 기타항목 : IP Address, 쿠키, 시스템 접속 및 이용 기록
+ ※ 시스템 이용과정에서 기타 항목의 정보들이 자동으로 생성되어 수집될 수 있습니다.
-
- - +

[ 개인정보 이용목적 ]

+
+ ․ 국가하수도정보시스템 웹서비스 이용에 따른 본인 확인 절차에 이용
+ ․ 국가하수도정보시스템 사용에 필요한 권한 부여
+ ․ 사용자별 맞춤 컨텐츠 (처리시설의 운영 데이터 조회, 수질현황 데이터 조회, 예산 편성 / 예산편성 등) 제공에 이용
-
+ +
● 개인정보의 보유 및 이용기간
+
+ ․ 수집된 고객의 개인정보는 2년 동안 보유하며 그 이후에는 문서를 파쇄합니다.
+ ․ 정보제공자가 개인정보 파쇄를 요청할 경우 즉시 파쇄합니다. +
+ +
+
● 개인정보 제공 거부에 따른 제한사항
+
+ ․ 귀하는 개인정보 제공 동의를 거부할 권리가 있으나, 동의 거부 시 국가하수도정보시스템 이용 서비스에 제한이 있을 수 있습니다. +
+
{/* ── 사업규모 ── */}
@@ -1345,74 +1304,12 @@ function CnfmRegistPage() {
- {/* 파일 업로드 영역 */} -
- 0 - ? `${etcFiles.length}개 파일 등록됨` - : "" - } - readOnly - /> - -
- - {/* 첨부된 파일 목록 테이블 */} -
- - - - - - - - - - - - {etcFiles.length === 0 ? ( - - - - ) : ( - etcFiles.map((f) => ( - - - - - - - - )) - )} - -
파일명확장자크기등록자삭제
- 첨부된 파일이 없습니다. -
{f.name}{f.ext}{f.size}{f.uploader} - -
-
+ void handleDeleteEtcFile(fileId, atflId)} + />
{/* ── 액션 버튼 ── */} diff --git a/apps/as/src/widgets/cnfm/index.ts b/apps/as/src/widgets/cnfm/index.ts new file mode 100644 index 000000000..5ecdd1f34 --- /dev/null +++ b/apps/as/src/widgets/cnfm/index.ts @@ -0,0 +1 @@ +export * from './ui'; diff --git a/apps/as/src/widgets/cnfm/ui/attachments.tsx b/apps/as/src/widgets/cnfm/ui/attachments.tsx new file mode 100644 index 000000000..b481e04c9 --- /dev/null +++ b/apps/as/src/widgets/cnfm/ui/attachments.tsx @@ -0,0 +1,71 @@ +import React from "react"; + +type EtcFile = { + id: string; + name: string; + ext: string; + size: string; + uploader: string; + atflCd: string; + atflId: string; +}; + +type Props = { + etcFiles: EtcFile[]; + etcUploading: boolean; + onFilesChange: (e: React.ChangeEvent) => void; + onDelete: (fileId: string, atflId: string) => void; +}; + +export function EtcAttachments({ etcFiles, etcUploading, onFilesChange, onDelete }: Props) { + return ( +
+
+ 0 ? `${etcFiles.length}개 파일 등록됨` : "" + } + readOnly + /> + +
+ +
+ + + + + + + + + + + + {etcFiles.map((f) => ( + + + + + + + + ))} + +
파일명확장자크기등록자액션
{f.name}{f.ext}{f.size}{f.uploader} + +
+
+
+ ); +} + +export default EtcAttachments; diff --git a/apps/as/src/widgets/cnfm/ui/cells.tsx b/apps/as/src/widgets/cnfm/ui/cells.tsx new file mode 100644 index 000000000..7aac164e5 --- /dev/null +++ b/apps/as/src/widgets/cnfm/ui/cells.tsx @@ -0,0 +1,18 @@ +import React from "react"; + +export const NumCell = ({ value, onChange }: { value: string; onChange: (v: string) => void }) => ( + + onChange(e.target.value)} + /> + +); + +export const ReadCell = ({ value }: { value: string | number }) => ( + {value} +); + +export default { NumCell, ReadCell }; diff --git a/apps/as/src/widgets/cnfm/ui/index.ts b/apps/as/src/widgets/cnfm/ui/index.ts new file mode 100644 index 000000000..ff7d2ac04 --- /dev/null +++ b/apps/as/src/widgets/cnfm/ui/index.ts @@ -0,0 +1,3 @@ +export { NumCell, ReadCell } from './cells'; +export { PrivacyConsent } from './privacy-consent'; +export { EtcAttachments } from './attachments'; diff --git a/apps/as/src/widgets/cnfm/ui/privacy-consent.tsx b/apps/as/src/widgets/cnfm/ui/privacy-consent.tsx new file mode 100644 index 000000000..347a811b2 --- /dev/null +++ b/apps/as/src/widgets/cnfm/ui/privacy-consent.tsx @@ -0,0 +1,31 @@ +import React from "react"; + +type Props = { + value: "Y" | "N"; + onChange: (v: "Y" | "N") => void; + children?: React.ReactNode; +}; + +export function PrivacyConsent({ value, onChange, children }: Props) { + return ( +
+

개인정보 동의

+
+ {children} +
+ +
+ + +
+
+ ); +} + +export default PrivacyConsent;