From e18a62f56f1f335afeea08ce6d77004e06b03d0b Mon Sep 17 00:00:00 2001 From: kmh Date: Mon, 27 Apr 2026 14:45:00 +0900 Subject: [PATCH] refactor(pop): trim main page widgets, drop layout auto-clone - Remove KpiCarousel/RecentActivity from pop main pages (7 companies) - Empty banner default; rename settings key home -> main - Strip API fetch/cache from usePopSettings, return hardcoded defaults - Drop screen_layouts_pop auto-clone/fallback for regular users - Add SUPER_ADMIN direct-entry branch in AppLayout pop handler Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/services/screenManagementService.ts | 60 +------ .../pop/_components/common/PopShell.tsx | 10 +- .../app/(main)/COMPANY_10/pop/main/page.tsx | 3 - .../pop/_components/common/PopShell.tsx | 10 +- .../app/(main)/COMPANY_16/pop/main/page.tsx | 3 - .../pop/_components/common/PopShell.tsx | 10 +- .../app/(main)/COMPANY_29/pop/main/page.tsx | 3 - .../pop/_components/common/PopShell.tsx | 10 +- .../app/(main)/COMPANY_30/pop/main/page.tsx | 3 - .../pop/_components/common/PopShell.tsx | 10 +- .../app/(main)/COMPANY_7/pop/main/page.tsx | 3 - .../pop/_components/common/PopShell.tsx | 10 +- .../app/(main)/COMPANY_8/pop/main/page.tsx | 3 - .../pop/_components/common/PopShell.tsx | 10 +- .../app/(main)/COMPANY_9/pop/main/page.tsx | 3 - frontend/app/(main)/layout.tsx | 2 +- frontend/app/(pop)/layout.tsx | 2 + frontend/components/layout/AppLayout.tsx | 19 +- frontend/components/pop/hardcoded/index.ts | 2 + frontend/hooks/pop/usePopSettings.ts | 170 ++---------------- 20 files changed, 77 insertions(+), 269 deletions(-) diff --git a/backend-node/src/services/screenManagementService.ts b/backend-node/src/services/screenManagementService.ts index 471935db..917486d3 100644 --- a/backend-node/src/services/screenManagementService.ts +++ b/backend-node/src/services/screenManagementService.ts @@ -5936,65 +5936,12 @@ export class ScreenManagementService { ); } } else { - // 일반 사용자: 회사별 우선, 없으면 템플릿에서 자동 복제 + // 일반 사용자: 회사별 레이아웃만 조회 (fallback/자동 복제 없음) layout = await queryOne<{ layout_data: any }>( `SELECT layout_data FROM screen_layouts_pop WHERE screen_id = $1 AND company_code = $2`, [screenId, companyCode], ); - - // 회사별 레이아웃이 없으면 템플릿에서 자동 복제 - if (!layout && companyCode !== "*") { - // 1. 공통(*) 템플릿 조회 - let templateLayout = await queryOne<{ layout_data: any }>( - `SELECT layout_data FROM screen_layouts_pop - WHERE screen_id = $1 AND company_code = '*'`, - [screenId], - ); - - // 2. 공통 없으면 COMPANY_7(탑씰) 폴백 - if (!templateLayout) { - templateLayout = await queryOne<{ layout_data: any }>( - `SELECT layout_data FROM screen_layouts_pop - WHERE screen_id = $1 AND company_code = 'COMPANY_7'`, - [screenId], - ); - } - - // 3. 템플릿이 있으면 해당 회사용으로 복제 - if (templateLayout) { - console.log(`POP 레이아웃 자동 복제: screen_id=${screenId}, 대상 회사=${companyCode}`); - - // 회사명 조회 (레이아웃 내 회사명 치환용) - const companyInfo = await queryOne<{ company_name: string }>( - `SELECT company_name FROM company_mng WHERE company_code = $1`, - [companyCode], - ); - const companyName = companyInfo?.company_name || companyCode; - - let clonedData = JSON.parse(JSON.stringify(templateLayout.layout_data)); - - // layout_data 내 회사명 텍스트 치환 (탑씰 관련 문자열 → 대상 회사명) - const layoutStr = JSON.stringify(clonedData); - const replacedStr = layoutStr - .replace(/\(주\)탑씰/g, companyName) - .replace(/탑씰/g, companyName) - .replace(/TOPSEAL/gi, companyName); - clonedData = JSON.parse(replacedStr); - - // 해당 회사 코드로 INSERT (UPSERT) - await query( - `INSERT INTO screen_layouts_pop (screen_id, company_code, layout_data, created_at, updated_at, created_by, updated_by) - VALUES ($1, $2, $3, NOW(), NOW(), 'SYSTEM', 'SYSTEM') - ON CONFLICT (screen_id, company_code) - DO UPDATE SET layout_data = $3, updated_at = NOW(), updated_by = 'SYSTEM'`, - [screenId, companyCode, JSON.stringify(clonedData)], - ); - - console.log(`POP 레이아웃 자동 복제 완료: screen_id=${screenId}, company=${companyCode}`); - layout = { layout_data: clonedData }; - } - } } if (!layout) { @@ -6133,11 +6080,10 @@ export class ScreenManagementService { [], ); } else { - // 일반 회사: 해당 회사 레이아웃 + 공통(*)/COMPANY_7 템플릿도 포함 - // (getLayoutPop에서 자동 복제하므로 템플릿이 있으면 해당 회사도 사용 가능) + // 일반 회사: 해당 회사 레이아웃만 조회 (자동 복제/fallback 없음) result = await query<{ screen_id: number }>( `SELECT DISTINCT screen_id FROM screen_layouts_pop - WHERE company_code IN ($1, '*', 'COMPANY_7')`, + WHERE company_code = $1`, [companyCode], ); } diff --git a/frontend/app/(main)/COMPANY_10/pop/_components/common/PopShell.tsx b/frontend/app/(main)/COMPANY_10/pop/_components/common/PopShell.tsx index 456dc0e0..ab5fd807 100644 --- a/frontend/app/(main)/COMPANY_10/pop/_components/common/PopShell.tsx +++ b/frontend/app/(main)/COMPANY_10/pop/_components/common/PopShell.tsx @@ -143,10 +143,10 @@ export function PopShell({ children, showBanner = true, title, showBack = false, // POP 설정에서 배너 텍스트 로드 (POP화면설정에서 관리) const { settings: popSettings } = usePopSettings(); - const homeConfig = (popSettings as any)?.screens?.home; - const bannerEnabled = homeConfig?.bannerEnabled ?? true; - const bannerText = homeConfig?.bannerText; - const marqueeText = bannerText || "[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. | [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 | [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!"; + const mainConfig = (popSettings as any)?.screens?.main; + const bannerEnabled = mainConfig?.bannerEnabled ?? true; + const bannerText = mainConfig?.bannerText; + const marqueeText = bannerText || ""; return (
@@ -402,7 +402,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false, )} {/* ===== NOTICE BANNER (Marquee) ===== */} - {showBanner && bannerEnabled &&
+ {showBanner && bannerEnabled && bannerText &&
📢 공지 diff --git a/frontend/app/(main)/COMPANY_10/pop/main/page.tsx b/frontend/app/(main)/COMPANY_10/pop/main/page.tsx index ae6e9404..182e6659 100644 --- a/frontend/app/(main)/COMPANY_10/pop/main/page.tsx +++ b/frontend/app/(main)/COMPANY_10/pop/main/page.tsx @@ -2,7 +2,6 @@ import { useRouter } from "next/navigation"; import type React from "react"; -import { KpiCarousel, RecentActivity } from "@/components/pop/hardcoded"; import { usePopCompanyPath } from "@/hooks/usePopCompanyPath"; interface MenuIconItem { @@ -142,9 +141,7 @@ function LocalMenuIcons() { export default function PopMainPage() { return ( <> - - ); } diff --git a/frontend/app/(main)/COMPANY_16/pop/_components/common/PopShell.tsx b/frontend/app/(main)/COMPANY_16/pop/_components/common/PopShell.tsx index 045607c8..5c03ac62 100644 --- a/frontend/app/(main)/COMPANY_16/pop/_components/common/PopShell.tsx +++ b/frontend/app/(main)/COMPANY_16/pop/_components/common/PopShell.tsx @@ -143,10 +143,10 @@ export function PopShell({ children, showBanner = true, title, showBack = false, // POP 설정에서 배너 텍스트 로드 (POP화면설정에서 관리) const { settings: popSettings } = usePopSettings(); - const homeConfig = (popSettings as any)?.screens?.home; - const bannerEnabled = homeConfig?.bannerEnabled ?? true; - const bannerText = homeConfig?.bannerText; - const marqueeText = bannerText || "[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. | [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 | [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!"; + const mainConfig = (popSettings as any)?.screens?.main; + const bannerEnabled = mainConfig?.bannerEnabled ?? true; + const bannerText = mainConfig?.bannerText; + const marqueeText = bannerText || ""; return (
@@ -402,7 +402,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false, )} {/* ===== NOTICE BANNER (Marquee) ===== */} - {showBanner && bannerEnabled &&
+ {showBanner && bannerEnabled && bannerText &&
📢 공지 diff --git a/frontend/app/(main)/COMPANY_16/pop/main/page.tsx b/frontend/app/(main)/COMPANY_16/pop/main/page.tsx index ae6e9404..182e6659 100644 --- a/frontend/app/(main)/COMPANY_16/pop/main/page.tsx +++ b/frontend/app/(main)/COMPANY_16/pop/main/page.tsx @@ -2,7 +2,6 @@ import { useRouter } from "next/navigation"; import type React from "react"; -import { KpiCarousel, RecentActivity } from "@/components/pop/hardcoded"; import { usePopCompanyPath } from "@/hooks/usePopCompanyPath"; interface MenuIconItem { @@ -142,9 +141,7 @@ function LocalMenuIcons() { export default function PopMainPage() { return ( <> - - ); } diff --git a/frontend/app/(main)/COMPANY_29/pop/_components/common/PopShell.tsx b/frontend/app/(main)/COMPANY_29/pop/_components/common/PopShell.tsx index ad2eb100..a641cba7 100644 --- a/frontend/app/(main)/COMPANY_29/pop/_components/common/PopShell.tsx +++ b/frontend/app/(main)/COMPANY_29/pop/_components/common/PopShell.tsx @@ -143,10 +143,10 @@ export function PopShell({ children, showBanner = true, title, showBack = false, // POP 설정에서 배너 텍스트 로드 (POP화면설정에서 관리) const { settings: popSettings } = usePopSettings(); - const homeConfig = (popSettings as any)?.screens?.home; - const bannerEnabled = homeConfig?.bannerEnabled ?? true; - const bannerText = homeConfig?.bannerText; - const marqueeText = bannerText || "[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. | [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 | [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!"; + const mainConfig = (popSettings as any)?.screens?.main; + const bannerEnabled = mainConfig?.bannerEnabled ?? true; + const bannerText = mainConfig?.bannerText; + const marqueeText = bannerText || ""; return (
@@ -402,7 +402,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false, )} {/* ===== NOTICE BANNER (Marquee) ===== */} - {showBanner && bannerEnabled &&
+ {showBanner && bannerEnabled && bannerText &&
📢 공지 diff --git a/frontend/app/(main)/COMPANY_29/pop/main/page.tsx b/frontend/app/(main)/COMPANY_29/pop/main/page.tsx index ae6e9404..182e6659 100644 --- a/frontend/app/(main)/COMPANY_29/pop/main/page.tsx +++ b/frontend/app/(main)/COMPANY_29/pop/main/page.tsx @@ -2,7 +2,6 @@ import { useRouter } from "next/navigation"; import type React from "react"; -import { KpiCarousel, RecentActivity } from "@/components/pop/hardcoded"; import { usePopCompanyPath } from "@/hooks/usePopCompanyPath"; interface MenuIconItem { @@ -142,9 +141,7 @@ function LocalMenuIcons() { export default function PopMainPage() { return ( <> - - ); } diff --git a/frontend/app/(main)/COMPANY_30/pop/_components/common/PopShell.tsx b/frontend/app/(main)/COMPANY_30/pop/_components/common/PopShell.tsx index 21b6ff08..a4d4c861 100644 --- a/frontend/app/(main)/COMPANY_30/pop/_components/common/PopShell.tsx +++ b/frontend/app/(main)/COMPANY_30/pop/_components/common/PopShell.tsx @@ -143,10 +143,10 @@ export function PopShell({ children, showBanner = true, title, showBack = false, // POP 설정에서 배너 텍스트 로드 (POP화면설정에서 관리) const { settings: popSettings } = usePopSettings(); - const homeConfig = (popSettings as any)?.screens?.home; - const bannerEnabled = homeConfig?.bannerEnabled ?? true; - const bannerText = homeConfig?.bannerText; - const marqueeText = bannerText || "[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. | [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 | [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!"; + const mainConfig = (popSettings as any)?.screens?.main; + const bannerEnabled = mainConfig?.bannerEnabled ?? true; + const bannerText = mainConfig?.bannerText; + const marqueeText = bannerText || ""; return (
@@ -402,7 +402,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false, )} {/* ===== NOTICE BANNER (Marquee) ===== */} - {showBanner && bannerEnabled &&
+ {showBanner && bannerEnabled && bannerText &&
📢 공지 diff --git a/frontend/app/(main)/COMPANY_30/pop/main/page.tsx b/frontend/app/(main)/COMPANY_30/pop/main/page.tsx index ae6e9404..182e6659 100644 --- a/frontend/app/(main)/COMPANY_30/pop/main/page.tsx +++ b/frontend/app/(main)/COMPANY_30/pop/main/page.tsx @@ -2,7 +2,6 @@ import { useRouter } from "next/navigation"; import type React from "react"; -import { KpiCarousel, RecentActivity } from "@/components/pop/hardcoded"; import { usePopCompanyPath } from "@/hooks/usePopCompanyPath"; interface MenuIconItem { @@ -142,9 +141,7 @@ function LocalMenuIcons() { export default function PopMainPage() { return ( <> - - ); } diff --git a/frontend/app/(main)/COMPANY_7/pop/_components/common/PopShell.tsx b/frontend/app/(main)/COMPANY_7/pop/_components/common/PopShell.tsx index 67b87e4d..a8ca51fe 100644 --- a/frontend/app/(main)/COMPANY_7/pop/_components/common/PopShell.tsx +++ b/frontend/app/(main)/COMPANY_7/pop/_components/common/PopShell.tsx @@ -143,10 +143,10 @@ export function PopShell({ children, showBanner = true, title, showBack = false, // POP 설정에서 배너 텍스트 로드 (POP화면설정에서 관리) const { settings: popSettings } = usePopSettings(); - const homeConfig = (popSettings as any)?.screens?.home; - const bannerEnabled = homeConfig?.bannerEnabled ?? true; - const bannerText = homeConfig?.bannerText; - const marqueeText = bannerText || "[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. | [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 | [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!"; + const mainConfig = (popSettings as any)?.screens?.main; + const bannerEnabled = mainConfig?.bannerEnabled ?? true; + const bannerText = mainConfig?.bannerText; + const marqueeText = bannerText || ""; return (
@@ -402,7 +402,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false, )} {/* ===== NOTICE BANNER (Marquee) ===== */} - {showBanner && bannerEnabled &&
+ {showBanner && bannerEnabled && bannerText &&
📢 공지 diff --git a/frontend/app/(main)/COMPANY_7/pop/main/page.tsx b/frontend/app/(main)/COMPANY_7/pop/main/page.tsx index ae6e9404..182e6659 100644 --- a/frontend/app/(main)/COMPANY_7/pop/main/page.tsx +++ b/frontend/app/(main)/COMPANY_7/pop/main/page.tsx @@ -2,7 +2,6 @@ import { useRouter } from "next/navigation"; import type React from "react"; -import { KpiCarousel, RecentActivity } from "@/components/pop/hardcoded"; import { usePopCompanyPath } from "@/hooks/usePopCompanyPath"; interface MenuIconItem { @@ -142,9 +141,7 @@ function LocalMenuIcons() { export default function PopMainPage() { return ( <> - - ); } diff --git a/frontend/app/(main)/COMPANY_8/pop/_components/common/PopShell.tsx b/frontend/app/(main)/COMPANY_8/pop/_components/common/PopShell.tsx index 76c6a09b..ed8cf828 100644 --- a/frontend/app/(main)/COMPANY_8/pop/_components/common/PopShell.tsx +++ b/frontend/app/(main)/COMPANY_8/pop/_components/common/PopShell.tsx @@ -143,10 +143,10 @@ export function PopShell({ children, showBanner = true, title, showBack = false, // POP 설정에서 배너 텍스트 로드 (POP화면설정에서 관리) const { settings: popSettings } = usePopSettings(); - const homeConfig = (popSettings as any)?.screens?.home; - const bannerEnabled = homeConfig?.bannerEnabled ?? true; - const bannerText = homeConfig?.bannerText; - const marqueeText = bannerText || "[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. | [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 | [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!"; + const mainConfig = (popSettings as any)?.screens?.main; + const bannerEnabled = mainConfig?.bannerEnabled ?? true; + const bannerText = mainConfig?.bannerText; + const marqueeText = bannerText || ""; return (
@@ -402,7 +402,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false, )} {/* ===== NOTICE BANNER (Marquee) ===== */} - {showBanner && bannerEnabled &&
+ {showBanner && bannerEnabled && bannerText &&
📢 공지 diff --git a/frontend/app/(main)/COMPANY_8/pop/main/page.tsx b/frontend/app/(main)/COMPANY_8/pop/main/page.tsx index ae6e9404..182e6659 100644 --- a/frontend/app/(main)/COMPANY_8/pop/main/page.tsx +++ b/frontend/app/(main)/COMPANY_8/pop/main/page.tsx @@ -2,7 +2,6 @@ import { useRouter } from "next/navigation"; import type React from "react"; -import { KpiCarousel, RecentActivity } from "@/components/pop/hardcoded"; import { usePopCompanyPath } from "@/hooks/usePopCompanyPath"; interface MenuIconItem { @@ -142,9 +141,7 @@ function LocalMenuIcons() { export default function PopMainPage() { return ( <> - - ); } diff --git a/frontend/app/(main)/COMPANY_9/pop/_components/common/PopShell.tsx b/frontend/app/(main)/COMPANY_9/pop/_components/common/PopShell.tsx index 6357431f..64fcde74 100644 --- a/frontend/app/(main)/COMPANY_9/pop/_components/common/PopShell.tsx +++ b/frontend/app/(main)/COMPANY_9/pop/_components/common/PopShell.tsx @@ -143,10 +143,10 @@ export function PopShell({ children, showBanner = true, title, showBack = false, // POP 설정에서 배너 텍스트 로드 (POP화면설정에서 관리) const { settings: popSettings } = usePopSettings(); - const homeConfig = (popSettings as any)?.screens?.home; - const bannerEnabled = homeConfig?.bannerEnabled ?? true; - const bannerText = homeConfig?.bannerText; - const marqueeText = bannerText || "[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. | [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 | [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!"; + const mainConfig = (popSettings as any)?.screens?.main; + const bannerEnabled = mainConfig?.bannerEnabled ?? true; + const bannerText = mainConfig?.bannerText; + const marqueeText = bannerText || ""; return (
@@ -402,7 +402,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false, )} {/* ===== NOTICE BANNER (Marquee) ===== */} - {showBanner && bannerEnabled &&
+ {showBanner && bannerEnabled && bannerText &&
📢 공지 diff --git a/frontend/app/(main)/COMPANY_9/pop/main/page.tsx b/frontend/app/(main)/COMPANY_9/pop/main/page.tsx index ae6e9404..182e6659 100644 --- a/frontend/app/(main)/COMPANY_9/pop/main/page.tsx +++ b/frontend/app/(main)/COMPANY_9/pop/main/page.tsx @@ -2,7 +2,6 @@ import { useRouter } from "next/navigation"; import type React from "react"; -import { KpiCarousel, RecentActivity } from "@/components/pop/hardcoded"; import { usePopCompanyPath } from "@/hooks/usePopCompanyPath"; interface MenuIconItem { @@ -142,9 +141,7 @@ function LocalMenuIcons() { export default function PopMainPage() { return ( <> - - ); } diff --git a/frontend/app/(main)/layout.tsx b/frontend/app/(main)/layout.tsx index ddc15372..b34a3904 100644 --- a/frontend/app/(main)/layout.tsx +++ b/frontend/app/(main)/layout.tsx @@ -12,7 +12,7 @@ import { MessengerModal } from "@/components/messenger/MessengerModal"; export default function MainLayout({ children }: { children: React.ReactNode }) { const pathname = usePathname(); - const isPop = pathname.includes("/pop/") || pathname.endsWith("/pop"); + const isPop = pathname.includes("/pop/"); if (isPop) { return <>{children}; diff --git a/frontend/app/(pop)/layout.tsx b/frontend/app/(pop)/layout.tsx index 1c41d1c0..64d322f5 100644 --- a/frontend/app/(pop)/layout.tsx +++ b/frontend/app/(pop)/layout.tsx @@ -1,3 +1,5 @@ +// DEPRECATED: 구 POP 라우트 그룹. 신 POP 는 frontend/app/(main)/COMPANY_X/pop/ 사용 + import "@/app/globals.css"; export const metadata = { diff --git a/frontend/components/layout/AppLayout.tsx b/frontend/components/layout/AppLayout.tsx index ede0e1b8..58ae4db9 100644 --- a/frontend/components/layout/AppLayout.tsx +++ b/frontend/components/layout/AppLayout.tsx @@ -525,11 +525,27 @@ function AppLayoutInner({ children }: AppLayoutProps) { // POP 모드 진입 핸들러 const handlePopModeClick = async () => { - if (isSuperAdmin) { + const userCompanyCode = (user as ExtendedUserInfo)?.companyCode; + + // SUPER_ADMIN: 회사 미선택(*) 상태 → 회사 선택 모달 + if (isSuperAdmin && userCompanyCode === "*") { setPopCompanySelectOpen(true); return; } + // SUPER_ADMIN: 특정 회사 선택 상태 → 해당 회사 POP 으로 직행 + if (isSuperAdmin && userCompanyCode && userCompanyCode !== "*") { + try { + if (!document.fullscreenElement) { + await document.documentElement.requestFullscreen(); + } + } catch { + // 전체화면 미지원 또는 거부 시 무시 + } + router.push(`/${userCompanyCode}/pop/main`); + return; + } + try { // PC → POP 전환 시 전체화면 적용 try { @@ -551,7 +567,6 @@ function AppLayoutInner({ children }: AppLayoutProps) { } else if (childMenus.length === 1) { router.push(childMenus[0].menu_url); } else { - const userCompanyCode = (user as ExtendedUserInfo)?.companyCode; if (userCompanyCode && userCompanyCode !== "*") { router.push(`/${userCompanyCode}/pop/main`); } else { diff --git a/frontend/components/pop/hardcoded/index.ts b/frontend/components/pop/hardcoded/index.ts index 4101be3d..45dbd3c7 100644 --- a/frontend/components/pop/hardcoded/index.ts +++ b/frontend/components/pop/hardcoded/index.ts @@ -1,3 +1,5 @@ +// DEPRECATED: 구 POP 컴포넌트 묶음. 신 POP 는 frontend/app/(main)/COMPANY_X/pop/_components/ 사용 + export { InboundCart, InboundTypeSelect, diff --git a/frontend/hooks/pop/usePopSettings.ts b/frontend/hooks/pop/usePopSettings.ts index c2722496..79fcac2c 100644 --- a/frontend/hooks/pop/usePopSettings.ts +++ b/frontend/hooks/pop/usePopSettings.ts @@ -1,8 +1,6 @@ "use client"; -import { useState, useEffect, useCallback } from "react"; -import { usePathname } from "next/navigation"; -import { apiClient } from "@/lib/api/client"; +import { useState } from "react"; export interface PopSettings { version: string; @@ -34,7 +32,7 @@ export interface PopSettings { photoUpload: boolean; barcodeEnabled: boolean; }; - home: { + main: { kpiCarousel: boolean; recentActivity: boolean; bannerEnabled: boolean; @@ -66,13 +64,13 @@ const DEFAULT_SETTINGS: PopSettings = { version: "hardcoded-1.0", screens: { processExecution: { - materialInput: true, - photoUpload: true, + materialInput: false, + photoUpload: false, plcEnabled: false, - bomFlexible: true, - packagingOptions: ["낱개", "박스", "파렛트"], - defectTypes: ["스크래치", "치수불량", "변색", "크랙", "기포"], - reworkTargetSelection: true, + bomFlexible: false, + packagingOptions: [], + defectTypes: [], + reworkTargetSelection: false, groupPhotoEnabled: false, dateFilter: false, lastProcessInventory: "manual", @@ -84,20 +82,20 @@ const DEFAULT_SETTINGS: PopSettings = { inbound: { inspectionRequired: false, photoUpload: false, - barcodeEnabled: true, + barcodeEnabled: false, packagingRecord: false, defectSeparation: false, }, outbound: { photoUpload: false, - barcodeEnabled: true, + barcodeEnabled: false, }, - home: { - kpiCarousel: true, - recentActivity: true, + main: { + kpiCarousel: false, + recentActivity: false, bannerEnabled: false, bannerText: "", - iconThemeColor: "#2563eb", + iconThemeColor: "", iconCustomImages: false, dashboardLayout: "default", }, @@ -110,142 +108,8 @@ const DEFAULT_SETTINGS: PopSettings = { }, }; -// URL -> screen_id mapping -const POP_SCREEN_MAP: Record = { - "/pop/home": 6526, - "/pop/inbound": 6529, - "/pop/inbound/purchase": 6528, - "/pop/inbound/cart": 6527, - "/pop/outbound": 6, - "/pop/outbound/sales": 5, - "/pop/production": 8, - "/pop/production/process": 7, - "/COMPANY_7/pop/production/process": 7, -}; - -// URL -> settingsKey mapping -const PATH_TO_SETTINGS_KEY: Record = { - "/pop/home": "home", - "/pop/inbound": "inbound", - "/pop/inbound/purchase": "inbound", - "/pop/inbound/cart": "inbound", - "/pop/outbound": "outbound", - "/pop/outbound/sales": "outbound", - "/pop/production": "processExecution", - "/pop/production/process": "processExecution", - "/COMPANY_7/pop/production/process": "processExecution", -}; - -// 신 URL `/COMPANY_X/pop/` 에서 화면 키 추출 (main → home 정규화) -function extractScreenKey(pathname: string): string | null { - const match = pathname.match(/^\/COMPANY_\d+\/pop\/(.+)$/); - if (!match) return null; - const tail = match[1]; - return tail === "main" ? "home" : tail; -} - -function getScreenIdFromPath(pathname: string): number | null { - // 신 URL 우선 처리 (회사 prefix 제거 후 화면 키 매핑) - const screenKey = extractScreenKey(pathname); - if (screenKey) { - const lookupPath = `/pop/${screenKey}`; - if (POP_SCREEN_MAP[lookupPath]) return POP_SCREEN_MAP[lookupPath]; - const sortedNew = Object.keys(POP_SCREEN_MAP).sort((a, b) => b.length - a.length); - for (const path of sortedNew) { - if (lookupPath.startsWith(path)) return POP_SCREEN_MAP[path]; - } - return null; - } - - // 구 (pop)/ 라우트 호환 fallback - if (POP_SCREEN_MAP[pathname]) return POP_SCREEN_MAP[pathname]; - const sorted = Object.keys(POP_SCREEN_MAP).sort((a, b) => b.length - a.length); - for (const path of sorted) { - if (pathname.startsWith(path)) return POP_SCREEN_MAP[path]; - } - return null; -} - -function getSettingsKeyFromPath(pathname: string): keyof PopSettings["screens"] | null { - // 신 URL 우선 처리 (회사 prefix 제거 후 화면 키 매핑) - const screenKey = extractScreenKey(pathname); - if (screenKey) { - const lookupPath = `/pop/${screenKey}`; - if (PATH_TO_SETTINGS_KEY[lookupPath]) return PATH_TO_SETTINGS_KEY[lookupPath]; - const sortedNew = Object.keys(PATH_TO_SETTINGS_KEY).sort((a, b) => b.length - a.length); - for (const path of sortedNew) { - if (lookupPath.startsWith(path)) return PATH_TO_SETTINGS_KEY[path]; - } - return null; - } - - // 구 (pop)/ 라우트 호환 fallback - if (PATH_TO_SETTINGS_KEY[pathname]) return PATH_TO_SETTINGS_KEY[pathname]; - const sorted = Object.keys(PATH_TO_SETTINGS_KEY).sort((a, b) => b.length - a.length); - for (const path of sorted) { - if (pathname.startsWith(path)) return PATH_TO_SETTINGS_KEY[path]; - } - return null; -} - -// Per-screenId cache to avoid redundant fetches -const screenCache: Record> = {}; - -export function usePopSettings(screenPath?: string) { - const autoPathname = usePathname(); - const pathname = screenPath || autoPathname || ""; - - const [settings, setSettings] = useState(DEFAULT_SETTINGS); - const [loading, setLoading] = useState(true); - - const fetchSettings = useCallback(async () => { - const screenId = getScreenIdFromPath(pathname); - const settingsKey = getSettingsKeyFromPath(pathname); - - if (!screenId || !settingsKey) { - setLoading(false); - return; - } - - // Use cache if available - if (screenCache[screenId]) { - const popConfig = screenCache[screenId]; - const merged = { ...DEFAULT_SETTINGS }; - merged.screens = { - ...merged.screens, - [settingsKey]: { ...merged.screens[settingsKey], ...popConfig }, - }; - setSettings(merged); - setLoading(false); - return; - } - - try { - const res = await apiClient - .get(`/screen-management/screens/${screenId}/layout-pop`) - .catch(() => null); - - if (res?.data?.data?.settings?.popConfig) { - const popConfig = res.data.data.settings.popConfig; - screenCache[screenId] = popConfig; - - const merged = { ...DEFAULT_SETTINGS }; - merged.screens = { - ...merged.screens, - [settingsKey]: { ...merged.screens[settingsKey], ...popConfig }, - }; - setSettings(merged); - } - } catch { - // Use default settings on failure - } - - setLoading(false); - }, [pathname]); - - useEffect(() => { - fetchSettings(); - }, [fetchSettings]); - +export function usePopSettings(_screenPath?: string) { + const [settings] = useState(DEFAULT_SETTINGS); + const [loading] = useState(false); return { settings, loading }; }