diff --git a/src/app/api/qna/list/route.ts b/src/app/api/qna/list/route.ts index f793b98..9708e4f 100644 --- a/src/app/api/qna/list/route.ts +++ b/src/app/api/qna/list/route.ts @@ -1,8 +1,19 @@ import axios from 'axios' import { NextResponse } from 'next/server' import { queryStringFormatter } from '@/utils/common-utils' +import { getIronSession } from 'iron-session' +import { cookies } from 'next/headers' +import { sessionOptions } from '@/libs/session' +import { SessionData } from '@/types/Auth' export async function GET(request: Request) { + const cookieStore = await cookies() + const session = await getIronSession(cookieStore, sessionOptions) + + if (!session.isLoggedIn) { + return NextResponse.json({ error: 'ログインしていません。' }, { status: 401 }) + } + const { searchParams } = new URL(request.url) const params: Record = {} diff --git a/src/app/api/survey-sales/[id]/route.ts b/src/app/api/survey-sales/[id]/route.ts index 8d7806c..5c23cd4 100644 --- a/src/app/api/survey-sales/[id]/route.ts +++ b/src/app/api/survey-sales/[id]/route.ts @@ -1,99 +1,86 @@ import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' import { convertToSnakeCase } from '@/utils/common-utils' +import { getIronSession } from 'iron-session' +import { sessionOptions } from '@/libs/session' +import { cookies } from 'next/headers' +import type { SessionData } from '@/types/Auth' -interface Survey { - SRL_NO: string - SUBMISSION_STATUS: boolean - SUBMISSION_TARGET_ID: string | null - STORE_ID: string | null - CONSTRUCTION_POINT_ID: string | null -} +const ERROR_MESSAGES = { + NOT_FOUND: 'データが見つかりません。', + UNAUTHORIZED: 'Unauthorized', + NO_PERMISSION: '該当物件の照会権限がありません。', + FETCH_ERROR: 'データの取得に失敗しました。', +} as const -interface SessionParams { - role: string | null - storeId: string | null - builderId: string | null - isLoggedIn: string | null - isPdf: boolean | null -} +// Role check functions +const checkT01Role = (survey: any): boolean => survey.SRL_NO !== '一時保存' -const checkT01Role = (survey: Survey): boolean => survey.SRL_NO !== '一時保存' - -const checkAdminRole = (survey: Survey, storeId: string | null): boolean => { +const checkAdminRole = (survey: any, storeId: string | null): boolean => { if (!storeId) return false - - if (survey.SUBMISSION_STATUS) { - return survey.SUBMISSION_TARGET_ID === storeId || survey.STORE_ID === storeId - } - return survey.STORE_ID === storeId + return survey.SUBMISSION_STATUS ? survey.SUBMISSION_TARGET_ID === storeId || survey.STORE_ID === storeId : survey.STORE_ID === storeId } -const checkAdminSubRole = (survey: Survey, storeId: string | null): boolean => { +const checkAdminSubRole = (survey: any, storeId: string | null): boolean => { if (!storeId) return false - - if (survey.SUBMISSION_STATUS) { - return survey.SUBMISSION_TARGET_ID === storeId || (survey.STORE_ID === storeId && survey.CONSTRUCTION_POINT_ID === null) - } - return survey.STORE_ID === storeId && survey.CONSTRUCTION_POINT_ID === null + return survey.SUBMISSION_STATUS + ? survey.SUBMISSION_TARGET_ID === storeId || (survey.STORE_ID === storeId && !survey.CONSTRUCTION_POINT_ID) + : survey.STORE_ID === storeId && !survey.CONSTRUCTION_POINT_ID } -const checkPartnerOrBuilderRole = (survey: Survey, builderId: string | null): boolean => { +const checkPartnerOrBuilderRole = (survey: any, builderId: string | null): boolean => { if (!builderId) return false return survey.CONSTRUCTION_POINT_ID === builderId } -const checkRole = (survey: Survey, sessionParams: SessionParams): boolean => { - if (!survey || !sessionParams.role) return false +const checkRole = (survey: any, session: any): boolean => { + if (!survey || !session.isLoggedIn) return false - switch (sessionParams.role) { - case 'T01': - return checkT01Role(survey) - // T01 이외 1차점 - case 'Admin': - return checkAdminRole(survey, sessionParams.storeId) - // 2차점 - case 'Admin_Sub': - return checkAdminSubRole(survey, sessionParams.storeId) - // partner - case 'Partner': - // 2차점 시공권한 user - case 'Builder': - return checkPartnerOrBuilderRole(survey, sessionParams.builderId) - default: - return false + const roleChecks = { + T01: () => checkT01Role(survey), + Admin: () => checkAdminRole(survey, session.storeId), + Admin_Sub: () => checkAdminSubRole(survey, session.storeId), + Partner: () => checkPartnerOrBuilderRole(survey, session.builderId), + Builder: () => checkPartnerOrBuilderRole(survey, session.builderId), } + + return roleChecks[session.role as keyof typeof roleChecks]?.() ?? false } +const fetchSurvey = async (id: number) => { + // @ts-ignore + return await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({ + where: { ID: id }, + include: { DETAIL_INFO: true }, + }) +} + +// API Route Handlers export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { try { + const cookieStore = await cookies() + const session = await getIronSession(cookieStore, sessionOptions) const { id } = await params const { searchParams } = new URL(request.url) + const isPdf = searchParams.get('isPdf') === 'true' - const sessionParams: SessionParams = { - role: searchParams.get('role'), - storeId: searchParams.get('storeId'), - builderId: searchParams.get('builderId'), - isLoggedIn: searchParams.get('isLoggedIn'), - isPdf: searchParams.get('isPdf') === 'true' ? true : false, + const survey = await fetchSurvey(Number(id)) + if (!survey) { + return NextResponse.json({ error: ERROR_MESSAGES.NOT_FOUND }, { status: 404 }) } - // @ts-ignore - const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({ - where: { - ID: Number(id), - }, - include: { - DETAIL_INFO: true, - }, - }) - if (sessionParams.isPdf || checkRole(survey, sessionParams)) { + + if (isPdf || checkRole(survey, session)) { return NextResponse.json(survey) - } else { - return NextResponse.json({ error: '該当物件の照会権限がありません。' }, { status: 403 }) } - } catch (error: any) { + + if (!session?.isLoggedIn || session?.role === null) { + return NextResponse.json({ error: ERROR_MESSAGES.UNAUTHORIZED }, { status: 401 }) + } + + return NextResponse.json({ error: ERROR_MESSAGES.NO_PERMISSION }, { status: 403 }) + } catch (error) { console.error('Error fetching survey:', error) - return NextResponse.json({ error: 'データの取得に失敗しました。' }, { status: 500 }) + return NextResponse.json({ error: ERROR_MESSAGES.FETCH_ERROR }, { status: 500 }) } } @@ -106,7 +93,7 @@ const getNewSrlNo = async (srlNo: string, storeId: string, role: string) => { const lastSurvey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({ where: { SRL_NO: { - startsWith: srlRole + storeId, + startsWith: srlRole, }, }, orderBy: { @@ -152,7 +139,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{ return NextResponse.json(survey) } catch (error) { console.error('Error updating survey:', error) - return NextResponse.json({ error: 'Failed to update survey' }, { status: 500 }) + return NextResponse.json({ error: 'データ保存に失敗しました。' }, { status: 500 }) } } @@ -182,10 +169,10 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise }) }) - return NextResponse.json({ message: 'Survey deleted successfully' }) + return NextResponse.json({ message: 'success' }) } catch (error) { console.error('Error deleting survey:', error) - return NextResponse.json({ error: 'Failed to delete survey' }, { status: 500 }) + return NextResponse.json({ error: 'データ削除に失敗しました。' }, { status: 500 }) } } @@ -207,6 +194,6 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise< return NextResponse.json({ message: 'Survey confirmed successfully', data: survey }) } catch (error) { console.error('Error updating survey:', error) - return NextResponse.json({ error: 'Failed to update survey' }, { status: 500 }) + return NextResponse.json({ error: 'データ保存に失敗しました。' }, { status: 500 }) } } diff --git a/src/app/api/survey-sales/route.ts b/src/app/api/survey-sales/route.ts index 39c8f02..dfb486c 100644 --- a/src/app/api/survey-sales/route.ts +++ b/src/app/api/survey-sales/route.ts @@ -135,6 +135,21 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { return where } +const checkSession = (params: SearchParams) => { + if (params.role === null) { + return NextResponse.json({ data: [], count: 0 }) + } + if (params.role === 'Builder' || params.role === 'Partner') { + if (params.builderId === null) { + return NextResponse.json({ data: [], count: 0 }) + } + } else { + if (params.storeId === null) { + return NextResponse.json({ data: [], count: 0 }) + } + } + return null +} /** * GET 핸들러 - 설문 목록 조회 @@ -154,6 +169,12 @@ export async function GET(request: Request) { builderId: searchParams.get('builderId'), } + // 세션 체크 결과 처리 + const sessionCheckResult = checkSession(params) + if (sessionCheckResult) { + return sessionCheckResult + } + // 검색 조건 구성 const where: WhereCondition = { AND: [] } @@ -186,7 +207,7 @@ export async function GET(request: Request) { return NextResponse.json({ data: { data: surveys, count: count } }) } catch (error) { console.error(error) - return NextResponse.json({ error: 'Fail Read Survey' }, { status: 500 }) + return NextResponse.json({ error: 'データ照会に失敗しました。' }, { status: 500 }) } } @@ -273,6 +294,6 @@ export async function POST(request: Request) { return NextResponse.json(result) } catch (error) { console.error(error) - return NextResponse.json({ error: 'Fail Create Survey' }, { status: 500 }) + return NextResponse.json({ error: 'データ保存に失敗しました。' }, { status: 500 }) } } diff --git a/src/app/survey-sale/@navTab/default.tsx b/src/app/survey-sale/@navTab/default.tsx deleted file mode 100644 index 6fefef5..0000000 --- a/src/app/survey-sale/@navTab/default.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import NavTab from '@/components/survey-sale/common/NavTab' - -export default function page() { - return -} diff --git a/src/app/survey-sale/[id]/page.tsx b/src/app/survey-sale/[id]/page.tsx index acbb03e..392ea19 100644 --- a/src/app/survey-sale/[id]/page.tsx +++ b/src/app/survey-sale/[id]/page.tsx @@ -1,9 +1,9 @@ -import DataTable from '@/components/survey-sale/detail/DataTable' +import DetailForm from '@/components/survey-sale/detail/DetailForm' export default function page() { return ( <> - + ) } diff --git a/src/app/survey-sale/layout.tsx b/src/app/survey-sale/layout.tsx index 83f37c0..6e7278a 100644 --- a/src/app/survey-sale/layout.tsx +++ b/src/app/survey-sale/layout.tsx @@ -2,10 +2,9 @@ import type { ReactNode } from 'react' interface SurveySaleLayoutProps { children: ReactNode - navTab: ReactNode } -export default function layout({ children, navTab }: SurveySaleLayoutProps) { +export default function layout({ children }: SurveySaleLayoutProps) { return ( <>
diff --git a/src/components/popup/SurveySaleSubmitPopup.tsx b/src/components/popup/SurveySaleSubmitPopup.tsx index ce6be9e..bb4cdfe 100644 --- a/src/components/popup/SurveySaleSubmitPopup.tsx +++ b/src/components/popup/SurveySaleSubmitPopup.tsx @@ -123,7 +123,7 @@ export default function SurveySaleSubmitPopup() { .then(() => { if (!isSubmittingSurvey) { alert('提出が完了しました。') - // submitSurvey({ targetId: submitData.targetId, targetNm: submitData.targetNm }) + submitSurvey({ targetId: submitData.targetId, targetNm: submitData.targetNm }) popupController.setSurveySaleSubmitPopup(false) } }) @@ -132,7 +132,6 @@ export default function SurveySaleSubmitPopup() { alert('メール送信に失敗しました。 再度送信してください。') }) .finally(() => { - submitSurvey({ targetId: submitData.targetId, targetNm: submitData.targetNm }) setIsShow(false) popupController.setSurveySaleSubmitPopup(false) }) diff --git a/src/components/survey-sale/common/NavTab.tsx b/src/components/survey-sale/common/NavTab.tsx deleted file mode 100644 index ffa6ea7..0000000 --- a/src/components/survey-sale/common/NavTab.tsx +++ /dev/null @@ -1,90 +0,0 @@ -'use client' - -import { useSurveySaleTabState } from '@/store/surveySaleTabState' -import { usePathname, useRouter, useSearchParams, useParams } from 'next/navigation' -import { useEffect } from 'react' - -export default function NavTab() { - const router = useRouter() - const pathname = usePathname() - - const searchParams = useSearchParams() - const id = searchParams.get('id') - const isTemp = searchParams.get('isTemp') - - const params = useParams() - const detailId = params.id - - const { basicInfoSelected, roofInfoSelected, reset, setBasicInfoSelected, setRoofInfoSelected } = useSurveySaleTabState() - - useEffect(() => { - return () => { - reset() - } - }, [reset]) - - if (pathname === '/survey-sale') { - return null - } - - const scrollSection = (section: string) => { - const sectionElement = document.getElementById(section) - if (sectionElement) { - sectionElement.scrollIntoView({ behavior: 'smooth' }) - } - } - - const handleBasicInfoClick = () => { - // if (id) { - // router.push(`/survey-sale/basic-info?id=${id}`) - // return - // } - if (detailId) { - router.push(`/survey-sale/${detailId}`) - return - } - scrollSection('basic-form-section') - - setBasicInfoSelected() - } - - const handleRoofInfoClick = () => { - // if (id) { - // if (isTemp === 'true') { - // alert('基本情報が一時保存された状態です。') - // return - // } - // router.push(`/survey-sale/roof-info?id=${id}`) - // return - // } - if (detailId) { - router.push(`/survey-sale/${detailId}?tab=roof-info`) - return - } - if (pathname === '/survey-sale/basic-info') { - alert('基本情報を先に保存してください。') - return null - } - // if (pathname === '/survey-sale/regist') { - scrollSection('roof-form-section') - // } - setRoofInfoSelected() - } - - return ( - <> -
-
-
- - -
-
-
- - ) -} diff --git a/src/components/survey-sale/detail/BasicForm.tsx b/src/components/survey-sale/detail/BasicForm.tsx index 10ce000..520393d 100644 --- a/src/components/survey-sale/detail/BasicForm.tsx +++ b/src/components/survey-sale/detail/BasicForm.tsx @@ -18,7 +18,7 @@ interface BasicFormProps { export default function BasicForm({ basicInfo, setBasicInfo, mode, session }: BasicFormProps) { const { setBasicInfoSelected } = useSurveySaleTabState() const [isFlip, setIsFlip] = useState(true) - const { addressData } = useAddressStore() + const { addressData, resetAddressData } = useAddressStore() const popupController = usePopupController() useEffect(() => { @@ -28,13 +28,13 @@ export default function BasicForm({ basicInfo, setBasicInfo, mode, session }: Ba // 주소 데이터가 변경될 때만 업데이트 useEffect(() => { if (!addressData) return - setBasicInfo({ ...basicInfo, - postCode: addressData.post_code, + postCode: addressData.post_code.slice(0, 3) + '-' + addressData.post_code.slice(3), address: addressData.address, addressDetail: addressData.address_detail, }) + resetAddressData() }, [addressData]) return ( diff --git a/src/components/survey-sale/detail/ButtonForm.tsx b/src/components/survey-sale/detail/ButtonForm.tsx index 2088629..d452aec 100644 --- a/src/components/survey-sale/detail/ButtonForm.tsx +++ b/src/components/survey-sale/detail/ButtonForm.tsx @@ -29,10 +29,9 @@ interface SaveData extends SurveyBasicRequest { 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 id = Number(params.id) const popupController = usePopupController() const [saveData, setSaveData] = useState({ @@ -47,7 +46,6 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) { }) const isSubmit = data.basic.submissionStatus - const id = Number(routeId) ? Number(routeId) : Number(idParam) const { deleteSurvey, updateSurvey, isDeletingSurvey, isUpdatingSurvey } = useSurvey(id) const { validateSurveyDetail, createSurvey, isCreatingSurvey } = useSurvey() @@ -66,7 +64,7 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) { const calculatePermissions = (session: any, basicData: SurveyBasicRequest): PermissionState => { const isSubmiter = calculateSubmitPermission(session, basicData) - const isWriter = session.userNm === basicData.representative + const isWriter = session.userId === basicData.representativeId const isReceiver = session?.storeId === basicData.submissionTargetId return { isSubmiter, isWriter, isReceiver } @@ -99,19 +97,19 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) { } const tempSaveProcess = async () => { - if (idParam) { + if (!Number.isNaN(id)) { await updateSurvey({ survey: saveData, isTemporary: true }) if (!isUpdatingSurvey) { - router.push(`/survey-sale/${idParam}`) + setMode('READ') } } else { const updatedData = { ...saveData, srlNo: '一時保存', } - const id = await createSurvey(updatedData) + const savedId = await createSurvey(updatedData) if (!isCreatingSurvey) { - router.push(`/survey-sale/${id}`) + router.push(`/survey-sale/${savedId}`) } } alert('一時保存されました。') @@ -131,25 +129,24 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) { } const handleSuccessfulSave = async (isSubmitProcess?: boolean) => { - if (idParam) { - await updateSurvey({ survey: saveData, isTemporary: false, storeId: session.storeId ?? '' }) + if (!Number.isNaN(id)) { + await updateSurvey({ + survey: saveData, + isTemporary: false, + storeId: session?.role === 'Partner' ? session?.builderId ?? null : session?.storeId ?? null, + }) if (!isUpdatingSurvey) { - router.push(`/survey-sale/${idParam}`) + setMode('READ') } } else { - const id = await createSurvey(saveData) - if (!isCreatingSurvey) { - router.push(`/survey-sale/${id}`) + const savedId = await createSurvey(saveData) + if (isSubmitProcess) { + await router.push(`/survey-sale/${savedId}?show=true`) + } else { + await router.push(`/survey-sale/${savedId}`) + alert('保存されました。') } } - - if (isSubmitProcess) { - if (!isCreatingSurvey && !isUpdatingSurvey) { - await popupController.setSurveySaleSubmitPopup(true) - } - } else { - alert('保存されました。') - } } const handleFailedSave = (emptyField: string | null) => { @@ -162,7 +159,7 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) { } const handleDelete = async () => { - if (routeId) { + if (!Number.isNaN(id)) { window.neoConfirm('削除しますか?', async () => { await deleteSurvey() if (!isDeletingSurvey) { @@ -174,12 +171,12 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) { } const handleSubmit = async () => { - if (data.basic.srlNo?.startsWith('一時保存') && Number(routeId)) { + if (data.basic.srlNo?.startsWith('一時保存') && Number.isNaN(id)) { alert('一時保存されたデータは提出できません。') return } - if (Number(routeId)) { + if (mode === 'READ') { window.neoConfirm('提出しますか?', async () => { popupController.setSurveySaleSubmitPopup(true) }) @@ -208,9 +205,7 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
- {(permissions.isWriter || permissions.isSubmiter || (permissions.isReceiver && isSubmit)) && ( - - )} + {(permissions.isWriter || permissions.isSubmiter || (permissions.isReceiver && isSubmit)) && } {(permissions.isWriter || (permissions.isReceiver && isSubmit)) && } {!isSubmit && permissions.isSubmiter && }
@@ -243,14 +238,12 @@ const ListButton = () => { ) } -const EditButton = ({ setMode, id }: { setMode: (mode: Mode) => void; id: string }) => { - const router = useRouter() +const EditButton = ({ setMode }: { setMode: (mode: Mode) => void }) => { return (
@@ -92,7 +75,6 @@ export default function DataTable() {
- ) } diff --git a/src/components/survey-sale/detail/DetailForm.tsx b/src/components/survey-sale/detail/DetailForm.tsx index 503f7b6..b4a995a 100644 --- a/src/components/survey-sale/detail/DetailForm.tsx +++ b/src/components/survey-sale/detail/DetailForm.tsx @@ -5,9 +5,11 @@ import { useEffect, useState } from 'react' import ButtonForm from './ButtonForm' import BasicForm from './BasicForm' import RoofForm from './RoofForm' -import { useParams, useSearchParams } from 'next/navigation' +import { useParams, useRouter, useSearchParams, usePathname } from 'next/navigation' import { useSurvey } from '@/hooks/useSurvey' import { useSessionStore } from '@/store/session' +import DataTable from './DataTable' +import { usePopupController } from '@/store/popupController' const roofInfoForm: SurveyDetailRequest = { contractCapacity: null, @@ -68,16 +70,19 @@ const basicInfoForm: SurveyBasicRequest = { } export default function DetailForm() { - const idParam = useSearchParams().get('id') - const routeId = useParams().id + const id = useParams().id - const modeset = Number(routeId) ? 'READ' : idParam ? 'EDIT' : 'CREATE' - const id = Number(routeId) ? Number(routeId) : Number(idParam) + const modeset = !Number.isNaN(Number(id)) ? 'READ' : 'CREATE' const { surveyDetail, isLoadingSurveyDetail } = useSurvey(Number(id)) const { session } = useSessionStore() + const searchParams = useSearchParams() + const popupController = usePopupController() + const router = useRouter() + const pathname = usePathname() const [mode, setMode] = useState(modeset) + const [basicInfoData, setBasicInfoData] = useState(() => ({ ...basicInfoForm, representative: session?.userNm ?? '', @@ -89,6 +94,14 @@ export default function DetailForm() { })) const [roofInfoData, setRoofInfoData] = useState(roofInfoForm) + useEffect(() => { + const show = searchParams.get('show') + if (show === 'true') { + popupController.setSurveySaleSubmitPopup(true) + router.replace(pathname) + } + }, [searchParams, pathname]) + // 세션 데이터가 변경될 때 기본 정보 업데이트 useEffect(() => { if (!session?.isLoggedIn) return @@ -104,8 +117,7 @@ export default function DetailForm() { }, [session?.isLoggedIn]) useEffect(() => { - if (isLoadingSurveyDetail) return - if (surveyDetail && (mode === 'EDIT' || mode === 'READ')) { + if (!isLoadingSurveyDetail && surveyDetail && (mode === 'EDIT' || mode === 'READ')) { const { id, uptDt, regDt, detailInfo, ...rest } = surveyDetail setBasicInfoData((prev) => ({ ...prev, @@ -128,6 +140,7 @@ export default function DetailForm() { return ( <> + {mode === 'READ' && surveyDetail && }
diff --git a/src/hooks/useInquiry.ts b/src/hooks/useInquiry.ts index 23b433e..7bec432 100644 --- a/src/hooks/useInquiry.ts +++ b/src/hooks/useInquiry.ts @@ -4,6 +4,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useInquiryFilterStore } from '@/store/inquiryFilterStore' import { useMemo } from 'react' import { useSessionStore } from '@/store/session' +import { useRouter } from 'next/navigation' export function useInquiry( qnoNo?: number, @@ -22,6 +23,32 @@ export function useInquiry( const { inquiryListRequest, offset } = useInquiryFilterStore() const { session } = useSessionStore() const { axiosInstance } = useAxios() + const router = useRouter() + + const errorRouter = (error: any) => { + const status = error.response?.status + alert(error.response?.data.error) + switch (status) { + // session 없는 경우 + case 401: + router.replace('/login') + break + // 조회 권한 없는 경우 + case 403: + router.replace('/inquiry/list') + break + // 데이터 DB상 존재하지 않는 경우 + case 404: + router.replace('/inquiry/list') + break + // 서버 오류 + case 500: + router.back() + break + default: + break + } + } const { data: inquiryList, isLoading: isLoadingInquiryList } = useQuery({ queryKey: ['inquiryList', inquiryListRequest, offset], @@ -32,7 +59,7 @@ export function useInquiry( }) return resp.data.data } catch (error: any) { - console.error(error.response.data) + errorRouter(error) return [] } }, @@ -57,7 +84,7 @@ export function useInquiry( }) return resp.data.data } catch (error: any) { - console.error(error.response) + errorRouter(error) return null } }, @@ -72,6 +99,9 @@ export function useInquiry( onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['inquiryList'] }) }, + onError: (error: any) => { + errorRouter(error) + }, }) const downloadFile = async (encodeFileNo: number, srcFileNm: string) => { @@ -90,7 +120,6 @@ export function useInquiry( return blob } catch (error) { - console.error('File download error:', error) alert('ファイルのダウンロードに失敗しました') return null } diff --git a/src/hooks/useSurvey.ts b/src/hooks/useSurvey.ts index 7fcc6d5..bafe8ab 100644 --- a/src/hooks/useSurvey.ts +++ b/src/hooks/useSurvey.ts @@ -6,6 +6,7 @@ import { useSessionStore } from '@/store/session' import { useAxios } from './useAxios' import { queryStringFormatter } from '@/utils/common-utils' import { useRouter } from 'next/navigation' +import { usePopupController } from '@/store/popupController' export const requiredFields = [ { @@ -68,12 +69,13 @@ export function useSurvey( isDeletingSurvey: boolean isSubmittingSurvey: boolean createSurvey: (survey: SurveyRegistRequest) => Promise - updateSurvey: ({ survey, isTemporary, storeId }: { survey: SurveyRegistRequest; isTemporary: boolean; storeId?: string }) => void + updateSurvey: ({ survey, isTemporary, storeId }: { survey: SurveyRegistRequest; isTemporary: boolean; storeId?: string | null }) => void deleteSurvey: () => Promise submitSurvey: (params: { targetId?: string | null; targetNm?: string | null }) => void validateSurveyDetail: (surveyDetail: SurveyDetailRequest) => string getZipCode: (zipCode: string) => Promise refetchSurveyList: () => void + refetchSurveyDetail: () => void getSubmitTarget: (params: { storeId: string; role: string }) => Promise } { const queryClient = useQueryClient() @@ -82,34 +84,29 @@ export function useSurvey( const { axiosInstance } = useAxios() const router = useRouter() - const checkSession = () => { - if (session?.isLoggedIn) { - switch (session?.role) { - case 'T01': - case 'Admin': - case 'Admin_Sub': - if (session?.storeId === null) { - alert('販売店IDがありません。') - return false - } - return true - case 'Builder': - case 'Partner': - if (session?.builderId === null) { - alert('施工店IDがありません。') - return false - } - return true - default: - alert('権限が間違っています。') - return false - } + const errorRouter = (error: any) => { + const status = error.response?.status + alert(error.response?.data.error) + switch (status) { + // session 없는 경우 + case 401: + router.replace('/login') + break + // 조회 권한 없는 경우 + case 403: + router.replace('/survey-sale') + break + // 데이터 DB상 존재하지 않는 경우 + case 404: + router.replace('/survey-sale') + break + // 서버 오류 + case 500: + router.back() + break + default: + break } - if (isPdf) { - return true - } - alert('ログインしていません。') - return false } const { @@ -119,23 +116,24 @@ export function useSurvey( } = useQuery({ queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort, offset, session?.storeNm, session?.builderId, session?.role], queryFn: async () => { - if (!checkSession()) { - router.replace('/login') + try { + const resp = await axiosInstance(null).get<{ data: SurveyBasicInfo[]; count: number }>('/api/survey-sales', { + params: { + keyword, + searchOption, + isMySurvey, + sort, + offset, + storeId: session?.storeId, + builderId: session?.builderId, + role: session?.role, + }, + }) + return resp.data + } catch (error: any) { + errorRouter(error) return { data: [], count: 0 } } - const resp = await axiosInstance(null).get<{ data: SurveyBasicInfo[]; count: number }>('/api/survey-sales', { - params: { - keyword, - searchOption, - isMySurvey, - sort, - offset, - storeId: session?.storeId, - builderId: session?.builderId, - role: session?.role, - }, - }) - return resp.data }, }) const surveyData = useMemo(() => { @@ -145,39 +143,34 @@ export function useSurvey( } }, [surveyListData]) - const { data: surveyDetail, isLoading: isLoadingSurveyDetail } = useQuery({ + const { + data: surveyDetail, + isLoading: isLoadingSurveyDetail, + refetch: refetchSurveyDetail, + } = useQuery({ queryKey: ['survey', id], queryFn: async () => { - if (!checkSession()) { - router.replace('/login') - return null - } - if (id === 0 || id === undefined) return null + if (Number.isNaN(id) || id === undefined || id === 0) return null try { const resp = await axiosInstance(null).get(`/api/survey-sales/${id}`, { params: { - role: session?.role, - storeId: session?.storeId, - builderId: session?.builderId, - isLoggedIn: session?.isLoggedIn, isPdf: isPdf, }, }) return resp.data } catch (error: any) { - alert(error.response?.data.error) - router.replace('/survey-sale') + errorRouter(error) return null } }, - enabled: id !== 0 && id !== undefined, + enabled: id !== 0 && id !== undefined && id !== null, }) const { mutateAsync: createSurvey, isPending: isCreatingSurvey } = useMutation({ mutationFn: async (survey: SurveyRegistRequest) => { - const resp = await axiosInstance(null).post('/api/survey-sales', { + const resp = await axiosInstance(null).post<{ id: number }>('/api/survey-sales', { survey: survey, - storeId: session?.storeId ?? null, + storeId: session?.role === 'Partner' ? session?.builderId ?? null : session?.storeId ?? null, role: session?.role ?? null, }) return resp.data.id ?? 0 @@ -189,7 +182,7 @@ export function useSurvey( }) const { mutate: updateSurvey, isPending: isUpdatingSurvey } = useMutation({ - mutationFn: async ({ survey, isTemporary, storeId }: { survey: SurveyRegistRequest; isTemporary: boolean; storeId?: string }) => { + mutationFn: async ({ survey, isTemporary, storeId }: { survey: SurveyRegistRequest; isTemporary: boolean; storeId?: string | null }) => { if (id === undefined) throw new Error('id is required') const resp = await axiosInstance(null).put(`/api/survey-sales/${id}`, { survey: survey, @@ -213,7 +206,9 @@ export function useSurvey( }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['survey', 'list'] }) - queryClient.invalidateQueries({ queryKey: ['survey', id] }) + }, + onError: (error: any) => { + alert(error.response?.data.error) }, }) @@ -230,15 +225,16 @@ export function useSurvey( queryClient.invalidateQueries({ queryKey: ['survey', 'list'] }) queryClient.invalidateQueries({ queryKey: ['survey', id] }) }, + onError: (error: any) => { + alert(error.response?.data.error) + }, }) const validateSurveyDetail = (surveyDetail: SurveyDetailRequest) => { - // 상수 정의 const ETC_FIELDS = ['installationSystem', 'rafterSize', 'rafterPitch', 'waterproofMaterial', 'structureOrder'] as const const SPECIAL_CONDITIONS = ['constructionYear', 'insulationPresence'] as const - // 유틸리티 함수들 const isEmptyValue = (value: any): boolean => { return value === null || value?.toString().trim() === '' } @@ -306,8 +302,7 @@ export function useSurvey( const { data } = await axiosInstance(null).get(endpoint) return data } catch (error: any) { - console.error('Failed to fetch submit target:', error) - alert(error.response?.data.error || 'データの取得に失敗しました。') + alert(error.response?.data.error) return null } } @@ -329,5 +324,6 @@ export function useSurvey( getZipCode, getSubmitTarget, refetchSurveyList, + refetchSurveyDetail, } } diff --git a/src/types/Survey.ts b/src/types/Survey.ts index 7128926..312c96b 100644 --- a/src/types/Survey.ts +++ b/src/types/Survey.ts @@ -145,7 +145,7 @@ export type SurveyRegistRequest = { srlNo: string | null //판매점IDyyMMdd000 } -export type Mode = 'CREATE' | 'EDIT' | 'READ' | 'TEMP' // 등록 | 수정 | 상세 | 임시저장 +export type Mode = 'CREATE' | 'EDIT' | 'READ' | 'SUBMIT' // 등록 | 수정 | 상세 | 제출 export type SubmitTargetResponse = { targetStoreId: string