diff --git a/apps/as/src/entities/fnrs-cnsltn/api/fnrs-cnsltn-rvw-opnn-service.ts b/apps/as/src/entities/fnrs-cnsltn/api/fnrs-cnsltn-rvw-opnn-service.ts new file mode 100644 index 000000000..3b29d0814 --- /dev/null +++ b/apps/as/src/entities/fnrs-cnsltn/api/fnrs-cnsltn-rvw-opnn-service.ts @@ -0,0 +1,22 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { RvwOpnnUpdateRequestDto } from "@/shared/model"; + +const BASE = ENDPOINT.AS_SERVICE.FNRS_CNSLTN_RVW_OPNN; + +async function update( + fnrsCnsltnDocNo: string, + rvwOpnnSn: number, + body: RvwOpnnUpdateRequestDto, +): Promise { + await client.put(`${BASE}/${fnrsCnsltnDocNo}/${rvwOpnnSn}`, body); +} + +async function deleteFn(fnrsCnsltnDocNo: string, rvwOpnnSn: number): Promise { + await client.delete(`${BASE}/${fnrsCnsltnDocNo}/${rvwOpnnSn}`); +} + +export const fnrsCnsltnRvwOpnnService = { + update, + delete: deleteFn, +}; diff --git a/apps/as/src/entities/fnrs-cnsltn/index.ts b/apps/as/src/entities/fnrs-cnsltn/index.ts index 19941fb04..aea9c149e 100644 --- a/apps/as/src/entities/fnrs-cnsltn/index.ts +++ b/apps/as/src/entities/fnrs-cnsltn/index.ts @@ -1,65 +1,66 @@ -export { fnrsCnsltnMngService } from "./api/fnrs-cnsltn-service"; -export { fnrsCnsltnKeys } from "./api/queries"; -export { - useChangePrgrsSttsComCd, - useDeleteFnrsCnsltnMng, - useFnrsCnsltnFileVrfcResults, - useFnrsCnsltnMng, - useFnrsCnsltnMngPage, - useRequestActnReviewFnrsCnsltnMng, - useRequestExamineFnrsCnsltnMng, - useSaveApplyFnrsCnsltnMng, - useSaveFnrsCnsltnMng, - useSubmitReqSupplementFnrsCnsltnMng, - useSubmitSupplementFnrsCnsltnMng, - useTechReviewFnrsCnsltnMng, - useUpdateFnrsCnsltnMng, -} from "./api/queries"; -export type { - BizCstItem, - BzScaleItem, - CklstResultItem, - EsntlAtchFileItem, - FnrsCnsltnApplySaveRequestDto, - FnrsCnsltnMngSaveRequestDto, - FnrsCnsltnRvwOpnnSaveRequestDto, - FnrsCnsltnSplmntDmndItem, - FnrsSharItem, -} from "./model/fnrs-cnsltn-apply-payload-schema"; -export { - fnrsCnsltnApplySaveSchema, - fnrsCnsltnBizCstItemSchema, - fnrsCnsltnBzScaleItemSchema, - fnrsCnsltnCklstResultItemSchema, - fnrsCnsltnEsntlAtchFileItemSchema, - fnrsCnsltnMngSaveSchema, - fnrsCnsltnRvwOpnnSaveSchema, - fnrsCnsltnSplmntDmndItemSchema, - fnrsSharItemSchema, -} from "./model/fnrs-cnsltn-apply-payload-schema"; -export type { - AtflMngClientResponseDto, - BizCstTreeDto, - BizSclTreeDto, - CklstRvwRsltTreeDto, - DocPrgrsUpdateRequestDto, - ElaprDocPrgrsClientResponseDto, - EsntlAtchFileMngTreeResponseDto, - FnrsCnsltnFileVrfcRsltResponseDto, - FnrsCnsltnMngDetResponseDto, - FnrsCnsltnMngResponseDto, - FnrsCnsltnMngSearchDto, - FnrsCnsltnMngService, - FnrsCnsltnMngUpdateRequestDto, - FnrsCnsltnRvwOpnnResponseDto, - FnrsCnsltnSplmntDmndResponseDto, - RagIndexingInfoDto, -} from "./model/fnrs-cnsltn-interface"; -export type { - EnvoActnReviewReqDto, - FnrsExamineRequestDto, -} from "./model/fnrs-cnsltn-payload-schema"; -export { - envoActnReviewReqSchema, - fnrsExamineRequestSchema, -} from "./model/fnrs-cnsltn-payload-schema"; +export { fnrsCnsltnRvwOpnnService } from "./api/fnrs-cnsltn-rvw-opnn-service"; +export { fnrsCnsltnMngService } from "./api/fnrs-cnsltn-service"; +export { fnrsCnsltnKeys } from "./api/queries"; +export { + useChangePrgrsSttsComCd, + useDeleteFnrsCnsltnMng, + useFnrsCnsltnFileVrfcResults, + useFnrsCnsltnMng, + useFnrsCnsltnMngPage, + useRequestActnReviewFnrsCnsltnMng, + useRequestExamineFnrsCnsltnMng, + useSaveApplyFnrsCnsltnMng, + useSaveFnrsCnsltnMng, + useSubmitReqSupplementFnrsCnsltnMng, + useSubmitSupplementFnrsCnsltnMng, + useTechReviewFnrsCnsltnMng, + useUpdateFnrsCnsltnMng, +} from "./api/queries"; +export type { + BizCstItem, + BzScaleItem, + CklstResultItem, + EsntlAtchFileItem, + FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnMngSaveRequestDto, + FnrsCnsltnRvwOpnnSaveRequestDto, + FnrsCnsltnSplmntDmndItem, + FnrsSharItem, +} from "./model/fnrs-cnsltn-apply-payload-schema"; +export { + fnrsCnsltnApplySaveSchema, + fnrsCnsltnBizCstItemSchema, + fnrsCnsltnBzScaleItemSchema, + fnrsCnsltnCklstResultItemSchema, + fnrsCnsltnEsntlAtchFileItemSchema, + fnrsCnsltnMngSaveSchema, + fnrsCnsltnRvwOpnnSaveSchema, + fnrsCnsltnSplmntDmndItemSchema, + fnrsSharItemSchema, +} from "./model/fnrs-cnsltn-apply-payload-schema"; +export type { + AtflMngClientResponseDto, + BizCstTreeDto, + BizSclTreeDto, + CklstRvwRsltTreeDto, + DocPrgrsUpdateRequestDto, + ElaprDocPrgrsClientResponseDto, + EsntlAtchFileMngTreeResponseDto, + FnrsCnsltnFileVrfcRsltResponseDto, + FnrsCnsltnMngDetResponseDto, + FnrsCnsltnMngResponseDto, + FnrsCnsltnMngSearchDto, + FnrsCnsltnMngService, + FnrsCnsltnMngUpdateRequestDto, + FnrsCnsltnRvwOpnnResponseDto, + FnrsCnsltnSplmntDmndResponseDto, + RagIndexingInfoDto, +} from "./model/fnrs-cnsltn-interface"; +export type { + EnvoActnReviewReqDto, + FnrsExamineRequestDto, +} from "./model/fnrs-cnsltn-payload-schema"; +export { + envoActnReviewReqSchema, + fnrsExamineRequestSchema, +} from "./model/fnrs-cnsltn-payload-schema"; diff --git a/apps/as/src/entities/instl-sncn/api/instl-sncn-rvw-opnn-service.ts b/apps/as/src/entities/instl-sncn/api/instl-sncn-rvw-opnn-service.ts new file mode 100644 index 000000000..ad6f09210 --- /dev/null +++ b/apps/as/src/entities/instl-sncn/api/instl-sncn-rvw-opnn-service.ts @@ -0,0 +1,22 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { RvwOpnnUpdateRequestDto } from "@/shared/model"; + +const BASE = ENDPOINT.AS_SERVICE.INSTL_SNCN_RVW_OPNN; + +async function update( + instlSncnDocNo: string, + rvwOpnnSn: number, + body: RvwOpnnUpdateRequestDto, +): Promise { + await client.put(`${BASE}/${instlSncnDocNo}/${rvwOpnnSn}`, body); +} + +async function deleteFn(instlSncnDocNo: string, rvwOpnnSn: number): Promise { + await client.delete(`${BASE}/${instlSncnDocNo}/${rvwOpnnSn}`); +} + +export const instlSncnRvwOpnnService = { + update, + delete: deleteFn, +}; diff --git a/apps/as/src/entities/instl-sncn/index.ts b/apps/as/src/entities/instl-sncn/index.ts index 5579b4c06..01a78a146 100644 --- a/apps/as/src/entities/instl-sncn/index.ts +++ b/apps/as/src/entities/instl-sncn/index.ts @@ -1,3 +1,4 @@ +export { instlSncnRvwOpnnService } from "./api/instl-sncn-rvw-opnn-service"; export { instlSncnRegionService, instlSncnService } from "./api/instl-sncn-service"; export { instlSncnKeys, diff --git a/apps/as/src/entities/sewer-bsc-plan/api/sewer-bsc-plan-rvw-opnn-service.ts b/apps/as/src/entities/sewer-bsc-plan/api/sewer-bsc-plan-rvw-opnn-service.ts new file mode 100644 index 000000000..7eea1e549 --- /dev/null +++ b/apps/as/src/entities/sewer-bsc-plan/api/sewer-bsc-plan-rvw-opnn-service.ts @@ -0,0 +1,23 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { RvwOpnnUpdateRequestDto } from "@/shared/model"; + +const BASE = ENDPOINT.AS_SERVICE.SEWER_BSC_PLAN_RVW_OPNNS; + +async function update( + sewerBscPlanDocNo: string, + chgCycl: number, + rvwOpnnSn: number, + body: RvwOpnnUpdateRequestDto, +): Promise { + await client.put(`${BASE}/${sewerBscPlanDocNo}/${chgCycl}/${rvwOpnnSn}`, body); +} + +async function deleteFn(sewerBscPlanDocNo: string, chgCycl: number, rvwOpnnSn: number): Promise { + await client.delete(`${BASE}/${sewerBscPlanDocNo}/${chgCycl}/${rvwOpnnSn}`); +} + +export const sewerBscPlanRvwOpnnService = { + update, + delete: deleteFn, +}; diff --git a/apps/as/src/entities/sewer-bsc-plan/index.ts b/apps/as/src/entities/sewer-bsc-plan/index.ts index fd98c82ff..a07dd9603 100644 --- a/apps/as/src/entities/sewer-bsc-plan/index.ts +++ b/apps/as/src/entities/sewer-bsc-plan/index.ts @@ -1,64 +1,65 @@ -export { sewerBscPlanKeys } from "./api/queries"; -export { - useDeleteSewerBscPlan, - useSaveApplySewerBscPlan, - useSaveSewerBscPlan, - useSewerBscPlan, - useSewerBscPlanDetails, - useSewerBscPlanPage, - useSubmitReqSupplementSewerBscPlan, - useSubmitSupplementSewerBscPlan, - useTechReviewSewerBscPlan, - useUpdateSewerBscPlan, -} from "./api/queries"; -export { sewerBscPlanService } from "./api/sewer-bsc-plan-service"; -export type { - CklstResultItem, - EsntlAtchFileItem, - SewerBscPlanApplySaveRequestDto, - SewerBscPlanBizCstItem, - SewerBscPlanDtlSaveRequestDto, - SewerBscPlanFnrsCstItem, - SewerBscPlanOtlnItem, - SewerBscPlanRvwOpnnItem, - SewerBscPlanSaveRequestDto, - SewerBscPlanSplmntDmndItem, - SewerBscPlanTmplntDtlItem, - SewerBscPlanTmplntItem, - SewerBscPlanTmplntTmprStrgItem, -} from "./model/sewer-bsc-plan-apply-payload-schema"; -export { - sewerBscPlanApplySaveSchema, - sewerBscPlanBizCstItemSchema, - sewerBscPlanCklstResultItemSchema, - sewerBscPlanDtlSaveSchema, - sewerBscPlanEsntlAtchFileItemSchema, - sewerBscPlanFnrsCstItemSchema, - sewerBscPlanOtlnItemSchema, - sewerBscPlanRvwOpnnItemSchema, - sewerBscPlanSaveSchema, - sewerBscPlanSplmntDmndItemSchema, - sewerBscPlanTmplntDtlItemSchema, - sewerBscPlanTmplntItemSchema, - sewerBscPlanTmplntTmprStrgItemSchema, -} from "./model/sewer-bsc-plan-apply-payload-schema"; -export type { - AtflMngClientResponseDto, - CklstRvwRsltTreeDto, - EsntlAtchFileMngTreeResponseDto, - SewerBscPlanApplySaveResponseDto, - SewerBscPlanBizCstResponseDto, - SewerBscPlanDetResponseDto, - SewerBscPlanDtlResponseDto, - SewerBscPlanFnrsCstResponseDto, - SewerBscPlanOtlnResponseDto, - SewerBscPlanResponseDto, - SewerBscPlanRvwOpnnResponseDto, - SewerBscPlanSearchRequestDto, - SewerBscPlanService, - SewerBscPlanSplmntDmndResponseDto, - SewerBscPlanTmplntDtlResponseDto, - SewerBscPlanTmplntResponseDto, - SewerBscPlanTmplntTmprStrgResponseDto, - SewerBscPlanUpdateRequestDto, -} from "./model/sewer-bsc-plan-interface"; +export { sewerBscPlanKeys } from "./api/queries"; +export { + useDeleteSewerBscPlan, + useSaveApplySewerBscPlan, + useSaveSewerBscPlan, + useSewerBscPlan, + useSewerBscPlanDetails, + useSewerBscPlanPage, + useSubmitReqSupplementSewerBscPlan, + useSubmitSupplementSewerBscPlan, + useTechReviewSewerBscPlan, + useUpdateSewerBscPlan, +} from "./api/queries"; +export { sewerBscPlanRvwOpnnService } from "./api/sewer-bsc-plan-rvw-opnn-service"; +export { sewerBscPlanService } from "./api/sewer-bsc-plan-service"; +export type { + CklstResultItem, + EsntlAtchFileItem, + SewerBscPlanApplySaveRequestDto, + SewerBscPlanBizCstItem, + SewerBscPlanDtlSaveRequestDto, + SewerBscPlanFnrsCstItem, + SewerBscPlanOtlnItem, + SewerBscPlanRvwOpnnItem, + SewerBscPlanSaveRequestDto, + SewerBscPlanSplmntDmndItem, + SewerBscPlanTmplntDtlItem, + SewerBscPlanTmplntItem, + SewerBscPlanTmplntTmprStrgItem, +} from "./model/sewer-bsc-plan-apply-payload-schema"; +export { + sewerBscPlanApplySaveSchema, + sewerBscPlanBizCstItemSchema, + sewerBscPlanCklstResultItemSchema, + sewerBscPlanDtlSaveSchema, + sewerBscPlanEsntlAtchFileItemSchema, + sewerBscPlanFnrsCstItemSchema, + sewerBscPlanOtlnItemSchema, + sewerBscPlanRvwOpnnItemSchema, + sewerBscPlanSaveSchema, + sewerBscPlanSplmntDmndItemSchema, + sewerBscPlanTmplntDtlItemSchema, + sewerBscPlanTmplntItemSchema, + sewerBscPlanTmplntTmprStrgItemSchema, +} from "./model/sewer-bsc-plan-apply-payload-schema"; +export type { + AtflMngClientResponseDto, + CklstRvwRsltTreeDto, + EsntlAtchFileMngTreeResponseDto, + SewerBscPlanApplySaveResponseDto, + SewerBscPlanBizCstResponseDto, + SewerBscPlanDetResponseDto, + SewerBscPlanDtlResponseDto, + SewerBscPlanFnrsCstResponseDto, + SewerBscPlanOtlnResponseDto, + SewerBscPlanResponseDto, + SewerBscPlanRvwOpnnResponseDto, + SewerBscPlanSearchRequestDto, + SewerBscPlanService, + SewerBscPlanSplmntDmndResponseDto, + SewerBscPlanTmplntDtlResponseDto, + SewerBscPlanTmplntResponseDto, + SewerBscPlanTmplntTmprStrgResponseDto, + SewerBscPlanUpdateRequestDto, +} from "./model/sewer-bsc-plan-interface"; diff --git a/apps/as/src/pages/design-cnstn/ui/sections/tech-review-opinion-section.tsx b/apps/as/src/pages/design-cnstn/ui/sections/tech-review-opinion-section.tsx index fb8991deb..f63db2fbe 100644 --- a/apps/as/src/pages/design-cnstn/ui/sections/tech-review-opinion-section.tsx +++ b/apps/as/src/pages/design-cnstn/ui/sections/tech-review-opinion-section.tsx @@ -1,338 +1,336 @@ -"use client"; - -import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; - -import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib"; -import { TextShimmer } from "@/shared/ui"; -import { SectionCollapsible } from "@/shared/ui"; -import { Field, FieldLabel, FieldSet } from "@/shared/ui/field"; -import { AttachmentDownloadLink, attachService } from "@/entities/attach"; -import type { DesignCnstnRvwOpnnResponseDto } from "@/entities/design-cnstn"; -import { - Button, - RadioGroup, - RadioGroupItem, - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, - Textarea, -} from "@common/components"; - -import type { - ReviewOpinionFormData, - ReviewOpinionGetFormDataResult, -} from "../../lib/review-opinion-utils"; -import type { ReviewStepCode } from "../../model/view-types"; -import { REVIEW_STEP_LABELS } from "../../model/view-types"; - -const RVW_OPNN_FILE_KEY_PREFIX = "rvw-opnn::"; - -interface TechReviewOpinionSectionProps { - rvwList: DesignCnstnRvwOpnnResponseDto[]; - editableReviewStep?: ReviewStepCode; - atrzSeComCdList?: string[]; - isAtrzLoading?: boolean; -} - -export interface TechReviewOpinionSectionHandle { - getFormData: () => ReviewOpinionGetFormDataResult | null; - resetForm: () => void; -} - -interface TechReviewOpinionTableProps { - items: DesignCnstnRvwOpnnResponseDto[]; -} - -interface UploadedOpinionFile { - fileName: string; - fileKey: string; - atflId?: string; - atflCd?: string; -} - -const EMPTY_FORM_DATA: ReviewOpinionFormData = { - rvwRsltCn: "", - rvwRsltAnmlyYn: "", - atchFileGroupId: "", - opnrSeComCd: "", -}; - -function createRvwOpnnUploadKey(file: File) { - return `${RVW_OPNN_FILE_KEY_PREFIX}${getDefaultFileKey(file)}`; -} - -function hasFormContent(formData: ReviewOpinionFormData) { - return Boolean(formData.rvwRsltCn.trim() || formData.rvwRsltAnmlyYn || formData.atchFileGroupId); -} - -const TechReviewOpinionSection = forwardRef< - TechReviewOpinionSectionHandle, - TechReviewOpinionSectionProps ->(function TechReviewOpinionSection( - { rvwList, editableReviewStep, atrzSeComCdList = [], isAtrzLoading = false }, - ref, -) { - const canWriteOpinion = !isAtrzLoading && atrzSeComCdList.includes("ATRZ02"); - const [formData, setFormData] = useState({ - ...EMPTY_FORM_DATA, - opnrSeComCd: editableReviewStep ?? "", - }); - const [uploadedFile, setUploadedFile] = useState(null); - - useEffect(() => { - setFormData((prev) => ({ - ...prev, - opnrSeComCd: editableReviewStep ?? "", - })); - }, [editableReviewStep]); - - const { uploadFileAsync, isUploading, uploads } = useTus({ - onSuccess: (atflCd, atflId, _file, fileKey) => { - if (!atflCd || !atflId) return; - - setFormData((prev) => ({ ...prev, atchFileGroupId: atflCd })); - setUploadedFile((prev) => (prev?.fileKey === fileKey ? { ...prev, atflCd, atflId } : prev)); - }, - onError: (_error, _file, fileKey) => { - setUploadedFile((prev) => (prev?.fileKey === fileKey ? null : prev)); - }, - }); - - useImperativeHandle( - ref, - () => ({ - getFormData: () => { - if (!canWriteOpinion || !editableReviewStep || !hasFormContent(formData)) { - return null; - } - - return { - formData: { - ...formData, - opnrSeComCd: editableReviewStep, - }, - rvwList, - }; - }, - resetForm: () => { - setFormData({ - ...EMPTY_FORM_DATA, - opnrSeComCd: editableReviewStep ?? "", - }); - setUploadedFile(null); - }, - }), - [canWriteOpinion, editableReviewStep, formData, rvwList], - ); - - const kecoRvwList = rvwList.filter((item) => item.opnrSeComCd === "KECO"); - const hasKecoSection = - kecoRvwList.length > 0 || (editableReviewStep === "KECO" && canWriteOpinion); - - if (!hasKecoSection) { - return null; - } - - async function handleFileUpload(files: FileList | null) { - if (!files || files.length === 0) return; - - const file = files[0]; - const fileKey = createRvwOpnnUploadKey(file); - const existingAtflCd = formData.atchFileGroupId; - - setUploadedFile({ fileName: file.name, fileKey }); - - try { - await uploadFileAsync(file, { - fileKey, - metadata: existingAtflCd ? { atflCd: existingAtflCd } : undefined, - }); - } catch { - // onError callback handles cleanup - } - } - - async function handleFileRemove() { - if (!uploadedFile) return; - - uploads[uploadedFile.fileKey]?.abort(); - - if (uploadedFile.atflId) { - try { - await attachService.deleteAttachmentByAtflId(uploadedFile.atflId); - } catch (error) { - console.error("검토의견 첨부파일 삭제 실패:", error); - } - } - - setUploadedFile(null); - setFormData((prev) => ({ ...prev, atchFileGroupId: "" })); - } - - function renderOpinionForm(reviewStep: ReviewStepCode) { - if (editableReviewStep !== reviewStep || !canWriteOpinion) return null; - - const uploading = uploadedFile ? (isUploading[uploadedFile.fileKey] ?? false) : false; - - return ( -
-

검토의견 작성

- - - - 의견내용 - -