summaryrefslogtreecommitdiff
path: root/lib/menu-list
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-08-21 06:57:36 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-08-21 06:57:36 +0000
commit02b1cf005cf3e1df64183d20ba42930eb2767a9f (patch)
treee932c54d5260b0e6fda2b46be2a6ba1c3ee30434 /lib/menu-list
parentd78378ecd7ceede1429359f8058c7a99ac34b1b7 (diff)
(대표님, 최겸) 설계메뉴추가, 작업사항 업데이트
설계메뉴 - 문서관리 설계메뉴 - 벤더 데이터 gtc 메뉴 업데이트 정보시스템 - 메뉴리스트 및 정보 업데이트 파일 라우트 업데이트 엑셀임포트 개선 기본계약 개선 벤더 가입과정 변경 및 개선 벤더 기본정보 - pq 돌체 오류 수정 및 개선 벤더 로그인 과정 이메일 오류 수정
Diffstat (limited to 'lib/menu-list')
-rw-r--r--lib/menu-list/servcie.ts61
-rw-r--r--lib/menu-list/table/menu-list-table.tsx54
2 files changed, 77 insertions, 38 deletions
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<string>("all");
const [sectionFilter, setSectionFilter] = useState<string>("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
</div>
</div>
- {/* 결과 요약 */}
+ {/* 결과 요약 및 초기화 버튼 */}
<div className="flex items-center justify-between text-sm text-muted-foreground">
<span>
총 {filteredMenus.length}개의 메뉴
{searchQuery && ` (${initialMenus.length}개 중 검색 결과)`}
</span>
+ <InitializeButton />
</div>
{/* 테이블 */}
@@ -207,13 +235,13 @@ export function MenuListTable({ initialMenus, initialUsers }: MenuListTableProps
<TableCell>
<div className="space-y-1">
<div className="flex items-center gap-2">
- <span className="font-medium">{menu.menuTitle}</span>
+ <span className="font-medium">{(menu as any).translatedMenuTitle || safeTranslate(menu.menuTitle)}</span>
<Badge variant="outline" className="text-xs">
- {menu.sectionTitle}
+ {(menu as any).translatedSectionTitle || safeTranslate(menu.sectionTitle)}
</Badge>
{menu.menuGroup && (
<Badge variant="secondary" className="text-xs">
- {menu.menuGroup}
+ {(menu as any).translatedMenuGroup || safeTranslate(menu.menuGroup)}
</Badge>
)}
</div>
@@ -222,7 +250,7 @@ export function MenuListTable({ initialMenus, initialUsers }: MenuListTableProps
</div>
{menu.menuDescription && (
<div className="text-xs text-muted-foreground">
- {menu.menuDescription}
+ {(menu as any).translatedMenuDescription || safeTranslate(menu.menuDescription)}
</div>
)}
</div>