diff --git a/src/app/api/survey-sales/[id]/route.ts b/src/app/api/survey-sales/[id]/route.ts index 9657f10..882079c 100644 --- a/src/app/api/survey-sales/[id]/route.ts +++ b/src/app/api/survey-sales/[id]/route.ts @@ -1,7 +1,6 @@ import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' import { convertToSnakeCase } from '@/utils/common-utils' -import { SessionData } from '@/types/Auth' interface Survey { SRL_NO: string diff --git a/src/components/survey-sale/detail/BasicForm.tsx b/src/components/survey-sale/detail/BasicForm.tsx index 0644496..10ce000 100644 --- a/src/components/survey-sale/detail/BasicForm.tsx +++ b/src/components/survey-sale/detail/BasicForm.tsx @@ -8,45 +8,34 @@ import { usePopupController } from '@/store/popupController' import { useAddressStore } from '@/store/addressStore' import { SessionData } from '@/types/Auth' -export default function BasicForm(props: { +interface BasicFormProps { basicInfo: SurveyBasicRequest setBasicInfo: (basicInfo: SurveyBasicRequest) => void mode: Mode session: SessionData -}) { - const { basicInfo, setBasicInfo, mode, session } = props +} + +export default function BasicForm({ basicInfo, setBasicInfo, mode, session }: BasicFormProps) { const { setBasicInfoSelected } = useSurveySaleTabState() const [isFlip, setIsFlip] = useState(true) - const { addressData } = useAddressStore() + const popupController = usePopupController() useEffect(() => { setBasicInfoSelected() }, []) + // 주소 데이터가 변경될 때만 업데이트 useEffect(() => { - if (session?.isLoggedIn) { - setBasicInfo({ - ...basicInfo, - representative: session.userNm ?? '', - representativeId: session.userId ?? null, - store: session.storeNm ?? null, - storeId: session.storeId ?? null, - constructionPoint: session.builderNm ?? null, - constructionPointId: session.builderNo ?? null, - }) - } - if (addressData) { - setBasicInfo({ - ...basicInfo, - postCode: addressData.post_code, - address: addressData.address, - addressDetail: addressData.address_detail, - }) - } - }, [session, addressData]) + if (!addressData) return - const popupController = usePopupController() + setBasicInfo({ + ...basicInfo, + postCode: addressData.post_code, + address: addressData.address, + addressDetail: addressData.address_detail, + }) + }, [addressData]) return ( <> diff --git a/src/components/survey-sale/detail/ButtonForm.tsx b/src/components/survey-sale/detail/ButtonForm.tsx index 62e2fee..a6236f0 100644 --- a/src/components/survey-sale/detail/ButtonForm.tsx +++ b/src/components/survey-sale/detail/ButtonForm.tsx @@ -7,79 +7,88 @@ import { useParams, useRouter, useSearchParams } from 'next/navigation' import { requiredFields, useSurvey } from '@/hooks/useSurvey' import { usePopupController } from '@/store/popupController' -export default function ButtonForm(props: { +interface ButtonFormProps { mode: Mode setMode: (mode: Mode) => void - data: { basic: SurveyBasicRequest; roof: SurveyDetailRequest } -}) { - // 라우터 - const router = useRouter() - const { mode, setMode } = props - const { session } = useSessionStore() + data: { + basic: SurveyBasicRequest + roof: SurveyDetailRequest + } +} +interface PermissionState { + isSubmiter: boolean + isWriter: boolean + isReceiver: boolean +} + +interface SaveData extends SurveyBasicRequest { + detailInfo: SurveyDetailRequest +} + +export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) { + const router = useRouter() + const { session } = useSessionStore() const searchParams = useSearchParams() const idParam = searchParams.get('id') - const params = useParams() const routeId = params.id - const popupController = usePopupController() - // ------------------------------------------------------------ - const [saveData, setSaveData] = useState({ - ...props.data.basic, - detailInfo: props.data.roof, + + const [saveData, setSaveData] = useState({ + ...data.basic, + detailInfo: data.roof, }) - // -------------------------------------------------------------- - // 권한 - // 제출권한 있는 회원 - const [isSubmiter, setIsSubmiter] = useState(false) - // 작성자 - const [isWriter, setIsWriter] = useState(false) - // 제출받은 대상자 - const [isReceiver, setIsReceiver] = useState(false) - const isSubmit = props.data.basic.submissionStatus + const [permissions, setPermissions] = useState({ + isSubmiter: false, + isWriter: false, + isReceiver: false, + }) - useEffect(() => { - if (session?.isLoggedIn) { - switch (session?.role) { - // T01 제출권한 없음 - case 'T01': - setIsSubmiter(false) - setIsReceiver(!props.data.basic.submissionTargetId && !props.data.basic.submissionTargetNm) - break - // 1차 판매점(Order) + 2차 판매점(Musubi) => 같은 판매점 제출권한 - case 'Admin': - case 'Admin_Sub': - setIsSubmiter(session.storeNm === props.data.basic.store && session.builderNo === props.data.basic.constructionPointId) - setIsReceiver(session?.storeId === props.data.basic.submissionTargetId) - break - // 시공권한 User(Musubi) + Partner => 같은 시공ID 제출권한 - case 'Builder': - case 'Partner': - setIsSubmiter(session.builderNo === props.data.basic.constructionPointId) - break - default: - setIsSubmiter(false) - break - } - setIsWriter(session.userNm === props.data.basic.representative) - } - setSaveData({ - ...props.data.basic, - detailInfo: props.data.roof, - }) - }, [session, props.data]) - - // ------------------------------------------------------------ - // 저장/임시저장/수정 + const isSubmit = data.basic.submissionStatus const id = Number(routeId) ? Number(routeId) : Number(idParam) - const { deleteSurvey, updateSurvey, isDeletingSurvey, isUpdatingSurvey } = useSurvey(Number(id)) + const { deleteSurvey, updateSurvey, isDeletingSurvey, isUpdatingSurvey } = useSurvey(id) const { validateSurveyDetail, createSurvey, isCreatingSurvey } = useSurvey() + useEffect(() => { + if (!session?.isLoggedIn) return + + const newPermissions = calculatePermissions(session, data.basic) + setPermissions(newPermissions) + + setSaveData({ + ...data.basic, + detailInfo: data.roof, + }) + }, [session, data]) + + const calculatePermissions = (session: any, basicData: SurveyBasicRequest): PermissionState => { + const isSubmiter = calculateSubmitPermission(session, basicData) + const isWriter = session.userNm === basicData.representative + const isReceiver = session?.storeId === basicData.submissionTargetId + + return { isSubmiter, isWriter, isReceiver } + } + + const calculateSubmitPermission = (session: any, basicData: SurveyBasicRequest): boolean => { + switch (session?.role) { + case 'T01': + return false + case 'Admin': + case 'Admin_Sub': + return session.storeNm === basicData.store && session.builderNo === basicData.constructionPointId + case 'Builder': + case 'Partner': + return session.builderNo === basicData.constructionPointId + default: + return false + } + } + const handleSave = (isTemporary: boolean, isSubmitProcess: boolean) => { - const emptyField = validateSurveyDetail(props.data.roof) + const emptyField = validateSurveyDetail(data.roof) const hasEmptyField = emptyField?.trim() !== '' if (isTemporary) { @@ -110,43 +119,47 @@ export default function ButtonForm(props: { const focusInput = (field: keyof SurveyDetailInfo) => { const input = document.getElementById(field) - if (input) { - input.focus() - } + input?.focus() } const saveProcess = async (emptyField: string | null, isSubmitProcess?: boolean) => { if (emptyField?.trim() === '') { - if (idParam) { - await updateSurvey({ survey: saveData, isTemporary: false, storeId: session.storeId ?? '' }) - if (!isUpdatingSurvey) { - router.push(`/survey-sale/${idParam}`) - } - } else { - const id = await createSurvey(saveData) - if (!isCreatingSurvey) { - router.push(`/survey-sale/${id}`) - } - } - if (isSubmitProcess) { - if (!isCreatingSurvey && !isUpdatingSurvey) { - await popupController.setSurveySaleSubmitPopup(true) - } - } else { - alert('保存されました。') - } + await handleSuccessfulSave(isSubmitProcess) } else { - if (emptyField?.includes('Unit')) { - alert('電気契約容量の単位を入力してください。') - focusInput(emptyField as keyof SurveyDetailInfo) - } else { - alert(requiredFields.find((field) => field.field === emptyField)?.name + ' 項目が空です。') - focusInput(emptyField as keyof SurveyDetailInfo) - } + handleFailedSave(emptyField) } } - // ------------------------------------------------------------ - // 삭제/제출 + + const handleSuccessfulSave = async (isSubmitProcess?: boolean) => { + if (idParam) { + await updateSurvey({ survey: saveData, isTemporary: false, storeId: session.storeId ?? '' }) + if (!isUpdatingSurvey) { + router.push(`/survey-sale/${idParam}`) + } + } else { + const id = await createSurvey(saveData) + if (!isCreatingSurvey) { + router.push(`/survey-sale/${id}`) + } + } + + if (isSubmitProcess) { + if (!isCreatingSurvey && !isUpdatingSurvey) { + await popupController.setSurveySaleSubmitPopup(true) + } + } else { + alert('保存されました。') + } + } + + const handleFailedSave = (emptyField: string | null) => { + if (emptyField?.includes('Unit')) { + alert('電気契約容量の単位を入力してください。') + } else { + alert(requiredFields.find((field) => field.field === emptyField)?.name + ' 項目が空です。') + } + focusInput(emptyField as keyof SurveyDetailInfo) + } const handleDelete = async () => { if (routeId) { @@ -161,10 +174,11 @@ export default function ButtonForm(props: { } const handleSubmit = async () => { - if (props.data.basic.srlNo?.startsWith('一時保存') && Number(routeId)) { + if (data.basic.srlNo?.startsWith('一時保存') && Number(routeId)) { alert('一時保存されたデータは提出できません。') return } + if (Number(routeId)) { window.neoConfirm('提出しますか?', async () => { popupController.setSurveySaleSubmitPopup(true) @@ -176,21 +190,15 @@ export default function ButtonForm(props: { } } - // ------------------------------------------------------------ + if (!session?.isLoggedIn) return null - if (!session?.isLoggedIn) { - return <> - } - - if (mode === 'READ' && isSubmit && isSubmiter) { + if (mode === 'READ' && isSubmit && permissions.isSubmiter) { return ( - <> -
-
- -
+
+
+
- +
) } @@ -200,9 +208,11 @@ export default function ButtonForm(props: {
- {(isSubmiter || (isReceiver && isSubmit)) && } - {(isWriter || (isReceiver && isSubmit)) && } - {!isSubmit && isSubmiter && } + {(permissions.isWriter || permissions.isSubmiter || (permissions.isReceiver && isSubmit)) && ( + + )} + {(permissions.isWriter || (permissions.isReceiver && isSubmit)) && } + {!isSubmit && permissions.isSubmiter && }
)} @@ -211,9 +221,9 @@ export default function ButtonForm(props: {
- handleSave(true, false)} /> + handleSave(true, false)} /> handleSave(false, false)} /> - {session?.role === 'T01' || isSubmit ? <> : } + {session?.role === 'T01' || isSubmit ? null : }
)} @@ -221,12 +231,11 @@ export default function ButtonForm(props: { ) } -// 목록 버튼 -function ListButton() { +// Button Components +const ListButton = () => { const router = useRouter() return (
- {/* 목록 */} @@ -234,12 +243,10 @@ function ListButton() { ) } -function EditButton(props: { setMode: (mode: Mode) => void; id: string; mode: Mode }) { - const { setMode, id, mode } = props +const EditButton = ({ setMode, id }: { setMode: (mode: Mode) => void; id: string }) => { const router = useRouter() return (
- {/* 수정 */} -
- - ) -} +const SubmitButton = ({ handleSubmit }: { handleSubmit: () => void }) => ( +
+ +
+) -function DeleteButton(props: { handleDelete: () => void }) { - const { handleDelete } = props - return ( -
- {/* 삭제 */} - -
- ) -} +const DeleteButton = ({ handleDelete }: { handleDelete: () => void }) => ( +
+ +
+) -function SaveButton(props: { handleSave: (isTemporary: boolean) => void }) { - const { handleSave } = props - return ( -
- {/* 저장 */} - -
- ) -} +const SaveButton = ({ handleSave }: { handleSave: () => void }) => ( +
+ +
+) -function TempButton(props: { setMode: (mode: Mode) => void; handleSave: (isTemporary: boolean) => void }) { - const { setMode, handleSave } = props - const router = useRouter() - - return ( -
- {/* 임시저장 */} - -
- ) -} +const TempButton = ({ handleSave }: { handleSave: () => void }) => ( +
+ +
+) diff --git a/src/components/survey-sale/detail/DetailForm.tsx b/src/components/survey-sale/detail/DetailForm.tsx index ef88e75..59f9864 100644 --- a/src/components/survey-sale/detail/DetailForm.tsx +++ b/src/components/survey-sale/detail/DetailForm.tsx @@ -70,7 +70,6 @@ const basicInfoForm: SurveyBasicRequest = { export default function DetailForm() { const idParam = useSearchParams().get('id') const routeId = useParams().id - const router = useRouter() const modeset = Number(routeId) ? 'READ' : idParam ? 'EDIT' : 'CREATE' @@ -80,26 +79,57 @@ export default function DetailForm() { const { session } = useSessionStore() const [mode, setMode] = useState(modeset) - const [basicInfoData, setBasicInfoData] = useState(basicInfoForm) + const [basicInfoData, setBasicInfoData] = useState(() => ({ + ...basicInfoForm, + representative: session?.userNm ?? '', + representativeId: session?.userId ?? null, + store: session?.storeNm ?? null, + storeId: session?.storeId ?? null, + constructionPoint: session?.builderNm ?? null, + constructionPointId: session?.builderNo ?? null, + })) const [roofInfoData, setRoofInfoData] = useState(roofInfoForm) + // 세션 데이터가 변경될 때 기본 정보 업데이트 useEffect(() => { - if (isLoadingSurveyDetail) return - if (surveyDetail === null) { + if (!session?.isLoggedIn) return + setBasicInfoData((prev) => ({ + ...prev, + representative: session.userNm ?? '', + representativeId: session.userId ?? null, + store: session.storeNm ?? null, + storeId: session.storeId ?? null, + constructionPoint: session.builderNm ?? null, + constructionPointId: session.builderNo ?? null, + })) + }, [session]) + + // 설문 데이터 로딩 및 업데이트 + useEffect(() => { + if (isLoadingSurveyDetail || !session?.isLoggedIn) return + + if (surveyDetail === null && mode !== 'CREATE') { alert('権限がありません。') router.replace('/survey-sale') + return } + if (surveyDetail && (mode === 'EDIT' || mode === 'READ')) { const { id, uptDt, regDt, detailInfo, ...rest } = surveyDetail - setBasicInfoData(rest) + setBasicInfoData((prev) => ({ + ...prev, + ...rest, + })) + if (detailInfo) { const { id, uptDt, regDt, basicInfoId, ...rest } = detailInfo setRoofInfoData(rest) if (validateSurveyDetail(rest).trim() !== '') { + // validation logic here if needed } } } - }, [surveyDetail, id, mode, session]) + }, [surveyDetail, mode, session?.isLoggedIn, isLoadingSurveyDetail]) const data = { basic: basicInfoData, @@ -111,9 +141,7 @@ export default function DetailForm() { return ( <>
- {/* 기본정보 */} - {/* 전기/지붕정보 */}