메뉴 관리 기능 추가

This commit is contained in:
2026-05-02 16:45:52 +09:00
parent 27cf05aba6
commit 04b8a7006a
18 changed files with 497 additions and 37 deletions

View File

@@ -5,6 +5,7 @@ import {
getSamplePosts,
getSampleTags
} from '../utils/sample-content'
import { getDefaultNavigationItems, groupNavigationItems } from '../utils/navigation-items'
import { getDefaultSiteSettings } from '../utils/site-settings'
import { getPostgresClient } from './postgres-client'
@@ -70,6 +71,22 @@ const mapSiteSettingsRow = (row) => ({
updatedAt: row.updated_at.toISOString()
})
/**
* 네비게이션 행을 API 응답 구조로 변환
* @param {Object} row - 네비게이션 행
* @returns {Object} 네비게이션 응답
*/
const mapNavigationItemRow = (row) => ({
id: row.id,
label: row.label,
url: row.url,
location: row.location,
sortOrder: row.sort_order,
isVisible: row.is_visible,
createdAt: row.created_at.toISOString(),
updatedAt: row.updated_at.toISOString()
})
/**
* 태그 슬러그 목록 정규화
* @param {Array<string>} tags - 태그 슬러그 목록
@@ -569,6 +586,82 @@ export const updateSiteSettings = async (input) => {
return mapSiteSettingsRow(rows[0])
}
/**
* 네비게이션 항목 목록 조회
* @param {Object} options - 조회 옵션
* @param {boolean} options.visibleOnly - 표시 항목만 조회할지 여부
* @returns {Promise<Array>} 네비게이션 항목 목록
*/
export const listNavigationItems = async ({ visibleOnly = false } = {}) => {
const sql = getPostgresClient()
if (!sql) {
return getDefaultNavigationItems()
.filter((item) => !visibleOnly || item.isVisible)
}
const rows = visibleOnly
? await sql`
SELECT *
FROM navigation_items
WHERE is_visible = true
ORDER BY location ASC, sort_order ASC, label ASC
`
: await sql`
SELECT *
FROM navigation_items
ORDER BY location ASC, sort_order ASC, label ASC
`
return rows.map(mapNavigationItemRow)
}
/**
* 공개 네비게이션 조회
* @returns {Promise<{primary: Array<Object>, footer: Array<Object>}>} 위치별 공개 네비게이션
*/
export const getPublicNavigation = async () => groupNavigationItems(await listNavigationItems({ visibleOnly: true }))
/**
* 관리자 네비게이션 항목 일괄 저장
* @param {Array<Object>} items - 저장할 네비게이션 항목 목록
* @returns {Promise<Array>} 저장된 네비게이션 항목 목록
*/
export const updateNavigationItems = async (items) => {
const sql = getPostgresClient()
if (!sql) {
throw new Error('DATABASE_REQUIRED')
}
await sql.begin(async (transaction) => {
await transaction`
DELETE FROM navigation_items
`
for (const item of items) {
await transaction`
INSERT INTO navigation_items (
label,
url,
location,
sort_order,
is_visible
)
VALUES (
${item.label},
${item.url},
${item.location},
${item.sortOrder},
${item.isVisible}
)
`
}
})
return listNavigationItems()
}
/**
* 관리자 태그 상세 조회
* @param {string} id - 태그 ID