From 02b1cf005cf3e1df64183d20ba42930eb2767a9f Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 21 Aug 2025 06:57:36 +0000 Subject: (대표님, 최겸) 설계메뉴추가, 작업사항 업데이트 설계메뉴 - 문서관리 설계메뉴 - 벤더 데이터 gtc 메뉴 업데이트 정보시스템 - 메뉴리스트 및 정보 업데이트 파일 라우트 업데이트 엑셀임포트 개선 기본계약 개선 벤더 가입과정 변경 및 개선 벤더 기본정보 - pq 돌체 오류 수정 및 개선 벤더 로그인 과정 이메일 오류 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/menu-list/servcie.ts | 61 +++++++++++++++++++-------------- lib/menu-list/table/menu-list-table.tsx | 54 ++++++++++++++++++++++------- 2 files changed, 77 insertions(+), 38 deletions(-) (limited to 'lib/menu-list') diff --git a/lib/menu-list/servcie.ts b/lib/menu-list/servcie.ts index 8686bf43..cd414ab4 100644 --- a/lib/menu-list/servcie.ts +++ b/lib/menu-list/servcie.ts @@ -3,7 +3,7 @@ "use server"; import db from "@/db/db"; -import { menuAssignments, users } from "@/db/schema"; +import { menuAssignments, users, pageInformation, notice } from "@/db/schema"; import { eq, and } from "drizzle-orm"; import { revalidatePath, revalidateTag } from "next/cache"; import { mainNav, mainNavVendor, additionalNav, additionalNavVendor } from "@/config/menuConfig"; @@ -27,10 +27,10 @@ function extractMenusFromConfig(): MenuData[] { section.items.forEach(item => { menus.push({ menuPath: item.href, - menuTitle: item.title, - menuDescription: item.description, - menuGroup: item.group, - sectionTitle: section.title, + menuTitle: item.titleKey, + menuDescription: item.descriptionKey, + menuGroup: item.groupKey, + sectionTitle: section.titleKey, domain: "evcp" }); }); @@ -40,8 +40,8 @@ function extractMenusFromConfig(): MenuData[] { additionalNav.forEach(item => { menus.push({ menuPath: item.href, - menuTitle: item.title, - menuDescription: item.description, + menuTitle: item.titleKey, + menuDescription: item.descriptionKey, menuGroup: undefined, sectionTitle: "추가 메뉴", domain: "evcp" @@ -53,10 +53,10 @@ function extractMenusFromConfig(): MenuData[] { section.items.forEach(item => { menus.push({ menuPath: item.href, - menuTitle: item.title, - menuDescription: item.description, - menuGroup: item.group, - sectionTitle: section.title, + menuTitle: item.titleKey, + menuDescription: item.descriptionKey, + menuGroup: item.groupKey, + sectionTitle: section.titleKey, domain: "partners" }); }); @@ -66,8 +66,8 @@ function extractMenusFromConfig(): MenuData[] { additionalNavVendor.forEach(item => { menus.push({ menuPath: item.href, - menuTitle: item.title, - menuDescription: item.description, + menuTitle: item.titleKey, + menuDescription: item.descriptionKey, menuGroup: undefined, sectionTitle: "추가 메뉴", domain: "partners" @@ -84,23 +84,34 @@ export async function initializeMenuAssignments() { const existingMenus = await db.select().from(menuAssignments); const existingPaths = new Set(existingMenus.map(m => m.menuPath)); - // 새로운 메뉴만 추가 + // 새로운 메뉴만 추가 (특정 경로 예외처리) const newMenus = configMenus.filter(menu => !existingPaths.has(menu.menuPath)); console.log(newMenus, newMenus) if (newMenus.length > 0) { - await db.insert(menuAssignments).values( - newMenus.map(menu => ({ - menuPath: menu.menuPath, - menuTitle: menu.menuTitle, - menuDescription: menu.menuDescription || null, - menuGroup: menu.menuGroup || null, - sectionTitle: menu.sectionTitle, - domain: menu.domain, - isActive: true, - })) - ); + // 개별적으로 insert하여 중복 오류 처리 + for (const menu of newMenus) { + try { + await db.insert(menuAssignments).values({ + menuPath: menu.menuPath, + menuTitle: menu.menuTitle, + menuDescription: menu.menuDescription || null, + menuGroup: menu.menuGroup || null, + sectionTitle: menu.sectionTitle, + domain: menu.domain, + isActive: true, + }); + } catch (insertError: any) { + // /partners/vendor-data 경로의 중복 오류는 무시 + if (insertError?.code === '23505' && menu.menuPath === '/partners/vendor-data') { + console.warn(`중복 메뉴 경로 건너뛰기: ${menu.menuPath}`); + continue; + } + // 다른 오류는 다시 throw + throw insertError; + } + } } // 기존 메뉴 정보 업데이트 (title, description 등이 변경될 수 있음) diff --git a/lib/menu-list/table/menu-list-table.tsx b/lib/menu-list/table/menu-list-table.tsx index 097be082..dedbc9bf 100644 --- a/lib/menu-list/table/menu-list-table.tsx +++ b/lib/menu-list/table/menu-list-table.tsx @@ -3,6 +3,8 @@ "use client"; import { useState, useMemo } from "react"; +import { useParams } from "next/navigation"; +import { useTranslation } from "@/i18n/client"; import { Table, TableBody, @@ -25,6 +27,7 @@ import { Button } from "@/components/ui/button"; import { Search, Filter, ExternalLink } from "lucide-react"; import { toast } from "sonner"; import { ManagerSelect } from "./manager-select"; +import { InitializeButton } from "./initialize-button"; import { toggleMenuActive } from "../servcie"; interface MenuAssignment { @@ -59,6 +62,26 @@ interface MenuListTableProps { } export function MenuListTable({ initialMenus, initialUsers }: MenuListTableProps) { + // URL에서 언어 파라미터 가져오기 + const params = useParams(); + const lng = (params?.lng as string) || 'ko'; + const { t } = useTranslation(lng, 'menu'); + + // 안전한 번역 함수 (키가 없을 때 원본 키 반환) + const safeTranslate = (key: string): string => { + try { + const translated = t(key); + // 번역 키가 그대로 반환되는 경우 원본 키 사용 + if (translated === key) { + return key; + } + return translated || key; + } catch (error) { + console.warn(`Translation failed for key: ${key}`, error); + return key; + } + }; + const [searchQuery, setSearchQuery] = useState(""); const [domainFilter, setDomainFilter] = useState("all"); const [sectionFilter, setSectionFilter] = useState("all"); @@ -67,27 +90,31 @@ export function MenuListTable({ initialMenus, initialUsers }: MenuListTableProps // 필터링된 메뉴 데이터 const filteredMenus = useMemo(() => { return initialMenus.filter((menu) => { + const translatedTitle = safeTranslate(menu.menuTitle); + const translatedSection = safeTranslate(menu.sectionTitle); + const translatedDescription = menu.menuDescription ? safeTranslate(menu.menuDescription) : ''; + const matchesSearch = - menu.menuTitle.toLowerCase().includes(searchQuery.toLowerCase()) || + translatedTitle.toLowerCase().includes(searchQuery.toLowerCase()) || menu.menuPath.toLowerCase().includes(searchQuery.toLowerCase()) || - menu.sectionTitle.toLowerCase().includes(searchQuery.toLowerCase()) || - (menu.menuDescription?.toLowerCase().includes(searchQuery.toLowerCase()) ?? false); + translatedSection.toLowerCase().includes(searchQuery.toLowerCase()) || + translatedDescription.toLowerCase().includes(searchQuery.toLowerCase()); const matchesDomain = domainFilter === "all" || menu.domain === domainFilter; - const matchesSection = sectionFilter === "all" || menu.sectionTitle === sectionFilter; + const matchesSection = sectionFilter === "all" || translatedSection === sectionFilter; const matchesStatus = statusFilter === "all" || (statusFilter === "active" && menu.isActive) || (statusFilter === "inactive" && !menu.isActive); return matchesSearch && matchesDomain && matchesSection && matchesStatus; }); - }, [initialMenus, searchQuery, domainFilter, sectionFilter, statusFilter]); + }, [initialMenus, searchQuery, domainFilter, sectionFilter, statusFilter, safeTranslate]); - // 섹션 리스트 추출 + // 섹션 리스트 추출 (번역된 이름으로) const sections = useMemo(() => { - const sectionSet = new Set(initialMenus.map(menu => menu.sectionTitle)); + const sectionSet = new Set(initialMenus.map(menu => safeTranslate(menu.sectionTitle))); return Array.from(sectionSet).sort(); - }, [initialMenus]); + }, [initialMenus, safeTranslate]); // 도메인별 사용자 필터링 const getFilteredUsers = (domain: string) => { @@ -163,12 +190,13 @@ export function MenuListTable({ initialMenus, initialUsers }: MenuListTableProps - {/* 결과 요약 */} + {/* 결과 요약 및 초기화 버튼 */}
총 {filteredMenus.length}개의 메뉴 {searchQuery && ` (${initialMenus.length}개 중 검색 결과)`} +
{/* 테이블 */} @@ -207,13 +235,13 @@ export function MenuListTable({ initialMenus, initialUsers }: MenuListTableProps
- {menu.menuTitle} + {(menu as any).translatedMenuTitle || safeTranslate(menu.menuTitle)} - {menu.sectionTitle} + {(menu as any).translatedSectionTitle || safeTranslate(menu.sectionTitle)} {menu.menuGroup && ( - {menu.menuGroup} + {(menu as any).translatedMenuGroup || safeTranslate(menu.menuGroup)} )}
@@ -222,7 +250,7 @@ export function MenuListTable({ initialMenus, initialUsers }: MenuListTableProps
{menu.menuDescription && (
- {menu.menuDescription} + {(menu as any).translatedMenuDescription || safeTranslate(menu.menuDescription)}
)} -- cgit v1.2.3