diff --git a/.gitignore b/.gitignore index f167b61e8..878447ead 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ apps/fo/.next/**/* .qodo pnpm-lock.yaml -settings.json \ No newline at end of file +settings.json +.npmrc diff --git a/apps/cm/middleware.ts b/apps/cm/middleware.ts index 9ec06daa2..123cd3c5c 100644 --- a/apps/cm/middleware.ts +++ b/apps/cm/middleware.ts @@ -14,8 +14,8 @@ const serverApiUrl = const serverApiUrl2 = process.env.NEXT_PUBLIC_SERVER_API_URL2 ?? serverApiUrl; - // const serverApiUrl3 = - // process.env.NEXT_PUBLIC_SERVER_API_URL3 ?? serverApiUrl; + const serverApiUrl3 = + process.env.NEXT_PUBLIC_SERVER_API_URL3 ?? serverApiUrl; // const serverApiUrl4 = // process.env.NEXT_PUBLIC_SERVER_API_URL4 ?? serverApiUrl; @@ -110,11 +110,12 @@ export function middleware(req: NextRequest) { }); } - if (pathname.startsWith("/ic-service")) { + if (pathname.startsWith("/server/ic-service")) { const requestHeaders = new Headers(req.headers); const token = req.cookies.get(CLAIM_NAME)?.value; const userId = req.cookies.get(AUTH_USER_ID)?.value; - const newUrl = `${serverApiUrl5}${pathname}`; + + const newUrl = `${serverApiUrl3}${pathname.replace("/server/", "")}${searchParams ? `?${searchParams}` : ""}`; if (token) requestHeaders.set(CLAIM_NAME, token); if (userId) requestHeaders.set(AUTH_USER_ID, userId); @@ -128,11 +129,12 @@ export function middleware(req: NextRequest) { }); } - if (pathname.startsWith("/dc-service")) { + if (pathname.startsWith("/server/dc-service")) { const requestHeaders = new Headers(req.headers); const token = req.cookies.get(CLAIM_NAME)?.value; const userId = req.cookies.get(AUTH_USER_ID)?.value; - const newUrl = `${serverApiUrl5}${pathname}`; + + const newUrl = `${serverApiUrl3}${pathname.replace("/server/", "")}${searchParams ? `?${searchParams}` : ""}`; if (token) requestHeaders.set(CLAIM_NAME, token); if (userId) requestHeaders.set(AUTH_USER_ID, userId); diff --git a/apps/cm/src/pages/dashboard/api/banner.ts b/apps/cm/src/pages/dashboard/api/banner.ts index 81bf86566..ee9a32dd7 100644 --- a/apps/cm/src/pages/dashboard/api/banner.ts +++ b/apps/cm/src/pages/dashboard/api/banner.ts @@ -15,41 +15,13 @@ export interface Banner { } export const getBannerList = async (siteId: string) => { - const url = `/api/proxy${ENDPOINT.CMS_SERVICE.BANNERS}/${siteId}`; - console.log("[getBannerList] API 호출 시작 (프록시, 인증 없음):", url); - try { - const response = await fetch(url, { - method: "GET", - headers: { - "Content-Type": "application/json", - accept: "application/json", - }, - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = await response.json(); - console.log("[getBannerList] API 응답 성공:", data); - return data; - } catch (error: any) { - console.error("[getBannerList] API 호출 실패:", { - url, - error, - status: error?.status, - message: error?.message, - }); - throw error; - } + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.BANNERS}/${siteId}`, + ); + return response.data; }; export const getImageUrlByAtflCd = async (atflCd: string): Promise => { - if (!atflCd) { - console.warn("[getImageUrlByAtflCd] atflCd가 없습니다"); - return ""; - } - console.log("[getImageUrlByAtflCd] 이미지 URL 조회 시작:", `${ENDPOINT.ATTACH_SERVICE.IMAGES}/atflCd/${atflCd}`); try { const response = await client.get( `${ENDPOINT.ATTACH_SERVICE.IMAGES}/atflCd/${atflCd}`, @@ -61,8 +33,16 @@ export const getImageUrlByAtflCd = async (atflCd: string): Promise => { const url = URL.createObjectURL(blob); console.log("[getImageUrlByAtflCd] 이미지 URL 생성 성공:", url); return url; - } catch (error) { - console.error("[getImageUrlByAtflCd] 이미지 URL 조회 실패:", error); + } catch (error: unknown) { + const err = error as + | { status?: number; message?: string; response?: { status?: number } } + | undefined; + console.error("[getImageUrlByAtflCd] 이미지 URL 조회 실패:", { + atflCd, + error: err, + status: err?.status ?? err?.response?.status, + message: err instanceof Error ? err.message : String(err), + }); throw error; } -}; \ No newline at end of file +}; diff --git a/apps/cm/src/pages/dashboard/api/support.ts b/apps/cm/src/pages/dashboard/api/support.ts index c4a8b138c..b0513d28f 100644 --- a/apps/cm/src/pages/dashboard/api/support.ts +++ b/apps/cm/src/pages/dashboard/api/support.ts @@ -1,4 +1,3 @@ -import { client } from "@/shared/api"; import { ENDPOINT } from "@/shared/config"; export interface Support { @@ -30,12 +29,15 @@ export const getSupportList = async () => { const data = await response.json(); console.log("[getSupportList] API 응답 성공:", data); return data; - } catch (error: any) { - console.error("[getSupportList] API 호출 실패:", { + } catch (error: unknown) { + const err = error as + | { status?: number; message?: string; response?: { status?: number } } + | undefined; + console.error("[getBannerList] API 호출 실패:", { url, - error, - status: error?.status, - message: error?.message, + error: err, + status: err?.status ?? err?.response?.status, + message: err instanceof Error ? err.message : String(err), }); throw error; } diff --git a/apps/cm/src/pages/dashboard/ui/banner-list.tsx b/apps/cm/src/pages/dashboard/ui/banner-list.tsx index 04d0cdd92..a755facd4 100644 --- a/apps/cm/src/pages/dashboard/ui/banner-list.tsx +++ b/apps/cm/src/pages/dashboard/ui/banner-list.tsx @@ -7,155 +7,180 @@ import { getImageUrlByAtflCd, getBannerList, type Banner } from "../api/banner"; import { getCookie } from "@/shared/lib"; import { - Carousel, - CarouselContent, - CarouselItem, - CarouselNext, - CarouselPrevious, - Autoplay, - } from "@common/components"; + Carousel, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, + Autoplay, +} from "@common/components"; - - type BannerImageProps = { - atflCd: string; - bnrSn: number; - lnkgUrlAddr: string; - }; - -const BannerList: React.FC = () => { - const siteId = getCookie("site-id-key") ?? ""; - - const BannerImage = ({ atflCd, bnrSn, lnkgUrlAddr }: BannerImageProps) => { - const { data: imageUrl, isLoading } = useQuery({ - queryKey: [ENDPOINT.ATTACH_SERVICE.IMAGES, atflCd], - queryFn: () => getImageUrlByAtflCd(atflCd), - enabled: !!atflCd, - }); - - const handleClick = () => { - if (lnkgUrlAddr) { - window.open(lnkgUrlAddr, '_blank'); - } - }; - - if (isLoading) { - return ( -
-
로딩 중...
-
- ); - } - - if (!imageUrl) { - return ( -
-
이미지 없음
-
- ); - } - - return ( -
- 배너 이미지 -
- ); - }; - const { data: bannerList, error: bannerError, isLoading: isLoadingBanners } = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.BANNERS, siteId], - queryFn: () => getBannerList(siteId), - enabled: !!siteId, - retry: false, - }); - - const plugin = useRef(Autoplay({ delay: 2000, stopOnInteraction: true })); - - // MAIN 타입 배너만 필터링 - const mainBanners = bannerList?.filter((banner) => banner.bnrTypeCd === "BNRMAIN") ?? []; - - // 401 에러 처리 - if (bannerError) { - const is401Error = bannerError instanceof Error && - (bannerError.message.includes("401") || - (bannerError as any)?.response?.status === 401 || - (bannerError as any)?.status === 401); - - if (is401Error) { - console.error("[BannerList] 401 인증 오류:", bannerError); - return ( -
-
-
인증이 필요합니다. 로그인해주세요.
-
-
- ); - } - - console.error("[BannerList] 배너 조회 오류:", bannerError); - return ( -
-
-
배너를 불러올 수 없습니다
-
-
- ); - } - - // 로딩 중 - if (isLoadingBanners) { - return ( -
-
-
배너 로딩 중...
-
-
- ); - } - - // siteId가 없을 때 - if (!siteId) { - return ( -
-
-
사이트 ID가 없습니다
-
-
- ); - } - - return ( -
- - - {mainBanners.length > 0 ? ( - mainBanners.map((banner) => ( - - - - )) - ) : ( - -
-
배너가 없습니다
-
-
- )} -
- - -
-
- ); +type BannerImageProps = { + atflCd: string; + lnkgUrlAddr: string; }; -export default BannerList; \ No newline at end of file +const BannerList: React.FC = () => { + const siteId = getCookie("site-id-key") ?? ""; + + const BannerImage = ({ atflCd, lnkgUrlAddr }: BannerImageProps) => { + const { data: imageUrl, isLoading } = useQuery({ + queryKey: [ENDPOINT.ATTACH_SERVICE.IMAGES, atflCd], + queryFn: () => getImageUrlByAtflCd(atflCd), + enabled: !!atflCd, + }); + + const handleClick = () => { + if (lnkgUrlAddr) { + window.open(lnkgUrlAddr, "_blank"); + } + }; + + if (isLoading) { + return ( +
+
로딩 중...
+
+ ); + } + + if (!imageUrl) { + return ( +
+
이미지 없음
+
+ ); + } + + return ( +
+
+
+ ); + }; + + const { + data: bannerList, + error: bannerError, + isLoading: isLoadingBanners, + } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.BANNERS, siteId], + queryFn: () => getBannerList(siteId), + enabled: !!siteId, + retry: false, + }); + + const plugin = useRef(Autoplay({ delay: 2000, stopOnInteraction: true })); + + // MAIN 타입 배너만 필터링 + const mainBanners = + bannerList?.filter((banner) => banner.bnrTypeCd === "BNRMAIN") ?? []; + + // 에러 상태 판별 헬퍼 함수 + const getErrorStatus = (e: unknown): number | undefined => { + if (!e || typeof e !== "object") return undefined; + const maybe = e as { status?: number; response?: { status?: number } }; + return maybe.status ?? maybe.response?.status; + }; + + // 401 에러 처리 + if (bannerError) { + const is401Error = + (bannerError instanceof Error && bannerError.message.includes("401")) || + getErrorStatus(bannerError) === 401; + + if (is401Error) { + console.error("[BannerList] 401 인증 오류:", bannerError); + return ( +
+
+
+ 인증이 필요합니다. 로그인해주세요. +
+
+
+ ); + } + + console.error("[BannerList] 배너 조회 오류:", bannerError); + return ( +
+
+
+ 배너를 불러올 수 없습니다 +
+
+
+ ); + } + + // 로딩 중 + if (isLoadingBanners) { + return ( +
+
+
배너 로딩 중...
+
+
+ ); + } + + // siteId가 없을 때 + if (!siteId) { + return ( +
+
+
+ 사이트 ID가 없습니다 +
+
+
+ ); + } + + return ( +
+ + + {mainBanners.length > 0 ? ( + mainBanners.map((banner) => ( + + + + )) + ) : ( + +
+
+ 배너가 없습니다 +
+
+
+ )} +
+ + +
+
+ ); +}; + +export default BannerList; diff --git a/apps/cm/src/pages/dashboard/ui/notice-list.tsx b/apps/cm/src/pages/dashboard/ui/notice-list.tsx index f6c21a4db..feb0f4f80 100644 --- a/apps/cm/src/pages/dashboard/ui/notice-list.tsx +++ b/apps/cm/src/pages/dashboard/ui/notice-list.tsx @@ -9,10 +9,14 @@ import { useDataTable } from "@/shared/lib"; import { noticePostTableColumns, } from "../model/table-columns"; +import { Button } from "@common/components"; const NoticeList: React.FC = () => { const router = useRouter(); + // #region agent log + fetch('http://127.0.0.1:7242/ingest/fdf9af6c-c6f9-41cb-8b7f-640be19ecbac',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'notice-list.tsx:16',message:'Router initialized',data:{routerExists:!!router},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'E'})}).catch(()=>{}); + // #endregion const noticePostQuery = useQuery({ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS], queryFn: () => @@ -28,6 +32,25 @@ const NoticeList: React.FC = () => { router.push(`/bbs/bbsnotice/${row.bbsId}/${row.pstNo}`); }; + const handleMoreClick = () => { + // #region agent log + fetch('http://127.0.0.1:7242/ingest/fdf9af6c-c6f9-41cb-8b7f-640be19ecbac',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'notice-list.tsx:32',message:'Button click handler called',data:{targetPath:'/cms/bbsnotice/7'},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{}); + // #endregion + try { + // #region agent log + fetch('http://127.0.0.1:7242/ingest/fdf9af6c-c6f9-41cb-8b7f-640be19ecbac',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'notice-list.tsx:35',message:'Before router.push',data:{routerExists:!!router,path:'/cms/bbsnotice/7'},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{}); + // #endregion + router.push('/cms/bbsnotice/7'); + // #region agent log + fetch('http://127.0.0.1:7242/ingest/fdf9af6c-c6f9-41cb-8b7f-640be19ecbac',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'notice-list.tsx:43',message:'After router.push',data:{navigationCalled:true},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{}); + // #endregion + } catch (error) { + // #region agent log + fetch('http://127.0.0.1:7242/ingest/fdf9af6c-c6f9-41cb-8b7f-640be19ecbac',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'notice-list.tsx:41',message:'Router.push error',data:{error:error instanceof Error?error.message:String(error)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{}); + // #endregion + } + }; + const { tableComponent: noticePostTableComponent } = useDataTable({ query: noticePostQuery, tableOptions: { @@ -44,6 +67,7 @@ const NoticeList: React.FC = () => {

공지사항

+
{noticePostTableComponent}
diff --git a/apps/cm/src/pages/dashboard/ui/support-list.tsx b/apps/cm/src/pages/dashboard/ui/support-list.tsx index 59eb15067..7567d5862 100644 --- a/apps/cm/src/pages/dashboard/ui/support-list.tsx +++ b/apps/cm/src/pages/dashboard/ui/support-list.tsx @@ -1,34 +1,28 @@ "use client"; -import { useRouter } from "next/navigation"; import { useQuery } from "@tanstack/react-query"; import { getCoreRowModel } from "@tanstack/react-table"; import { ENDPOINT } from "@/shared/config"; import { useDataTable } from "@/shared/lib"; -import { - supportTableColumns, -} from "../model/support-columns"; +import { supportTableColumns } from "../model/support-columns"; import { getSupportList } from "../api/support"; - const SupportList: React.FC = () => { - const router = useRouter(); - const supportQuery = useQuery({ - queryKey: [ENDPOINT.BOARD_SERVICE.POSTS], - queryFn: () => - getSupportList(), - }); + const supportQuery = useQuery({ + queryKey: [ENDPOINT.BOARD_SERVICE.POSTS], + queryFn: () => getSupportList(), + }); - const { tableComponent: supportTableComponent } = useDataTable({ - query: supportQuery, - tableOptions: { - columns: supportTableColumns, - getCoreRowModel: getCoreRowModel(), - }, - dataTableOptions: { - variant: "line", - }, - }); + const { tableComponent: supportTableComponent } = useDataTable({ + query: supportQuery, + tableOptions: { + columns: supportTableColumns, + getCoreRowModel: getCoreRowModel(), + }, + dataTableOptions: { + variant: "line", + }, + }); return (
@@ -40,4 +34,4 @@ const SupportList: React.FC = () => { ); }; -export default SupportList; \ No newline at end of file +export default SupportList; diff --git a/apps/cm/src/shared/ui/page-layout.tsx b/apps/cm/src/shared/ui/page-layout.tsx index d792d0ff7..5355531aa 100644 --- a/apps/cm/src/shared/ui/page-layout.tsx +++ b/apps/cm/src/shared/ui/page-layout.tsx @@ -1,4 +1,3 @@ -import { PageTitle } from "@common/components"; import { useMenuStore } from "../lib/use-menu-store"; function PageLayout({ children }: { children: React.ReactNode }) { @@ -8,11 +7,7 @@ function PageLayout({ children }: { children: React.ReactNode }) { ?.split(">") .map((path) => path.trim()); - return ( -
- {children} -
- ); + return
{children}
; } export { PageLayout }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3545c8ca1..3d4e6ffd9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -170,10 +170,10 @@ importers: version: 5.28.5 eslint: specifier: ^9.0.0 - version: 9.39.1(jiti@1.21.7) + version: 9.39.1(jiti@2.6.1) eslint-config-next: specifier: 15.4.0 - version: 15.4.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + version: 15.4.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) postcss: specifier: ^8.4.49 version: 8.5.6 @@ -300,10 +300,10 @@ importers: version: 5.28.5 eslint: specifier: ^9 - version: 9.39.1(jiti@2.6.1) + version: 9.39.1(jiti@1.21.7) eslint-config-next: specifier: 15.1.7 - version: 15.1.7(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + version: 15.1.7(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) postcss: specifier: ^8 version: 8.5.6 @@ -10080,6 +10080,26 @@ snapshots: optionalDependencies: source-map: 0.7.6 + eslint-config-next@15.1.7(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3): + dependencies: + '@next/eslint-plugin-next': 15.1.7 + '@rushstack/eslint-patch': 1.15.0 + '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.1(jiti@1.21.7) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@1.21.7)) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + eslint-config-next@15.1.7(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 15.1.7 @@ -10100,26 +10120,6 @@ snapshots: - eslint-plugin-import-x - supports-color - eslint-config-next@15.4.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3): - dependencies: - '@next/eslint-plugin-next': 15.4.0 - '@rushstack/eslint-patch': 1.15.0 - '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.49.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.1(jiti@1.21.7) - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@1.21.7)) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - eslint-import-resolver-webpack - - eslint-plugin-import-x - - supports-color - eslint-config-next@15.4.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 15.4.0