diff options
Diffstat (limited to 'lib/notice/service.ts')
| -rw-r--r-- | lib/notice/service.ts | 215 |
1 files changed, 41 insertions, 174 deletions
diff --git a/lib/notice/service.ts b/lib/notice/service.ts index c261cd2e..9c05b98f 100644 --- a/lib/notice/service.ts +++ b/lib/notice/service.ts @@ -1,203 +1,81 @@ "use server"
-import { revalidateTag, unstable_noStore } from "next/cache"
import { getErrorMessage } from "@/lib/handle-error"
-import { unstable_cache } from "@/lib/unstable-cache"
-import { filterColumns } from "@/lib/filter-columns"
-import { asc, desc, ilike, and, or, eq } from "drizzle-orm"
+import { desc, eq } from "drizzle-orm"
import db from "@/db/db"
-import { notice, pageInformation, menuAssignments } from "@/db/schema"
+import { notice, pageInformation, menuAssignments, users } from "@/db/schema"
import type {
CreateNoticeSchema,
- UpdateNoticeSchema,
- GetNoticeSchema
+ UpdateNoticeSchema
} from "./validations"
import {
- selectNotice,
- countNotice,
getNoticesByPagePath,
insertNotice,
updateNotice,
deleteNoticeById,
deleteNoticeByIds,
- getNoticeById,
- selectNoticeLists,
- countNoticeLists
+ getNoticeById
} from "./repository"
import type { Notice } from "@/db/schema/notice"
-export async function getNoticeLists(input: GetNoticeSchema) {
- return unstable_cache(
- async () => {
- try {
- // 고급 검색 로직
- const { page, perPage, search, filters, joinOperator, pagePath, title, content, authorId, isActive } = input
-
- // 기본 검색 조건들
- const conditions = []
-
- // 검색어가 있으면 여러 필드에서 검색
- if (search && search.trim()) {
- const searchConditions = [
- ilike(notice.pagePath, `%${search}%`),
- ilike(notice.title, `%${search}%`),
- ilike(notice.content, `%${search}%`)
- ]
- conditions.push(or(...searchConditions))
- }
-
- // 개별 필드 조건들
- if (pagePath && pagePath.trim()) {
- conditions.push(ilike(notice.pagePath, `%${pagePath}%`))
- }
-
- if (title && title.trim()) {
- conditions.push(ilike(notice.title, `%${title}%`))
- }
-
- if (content && content.trim()) {
- conditions.push(ilike(notice.content, `%${content}%`))
- }
-
- if (authorId !== null && authorId !== undefined) {
- conditions.push(eq(notice.authorId, authorId))
- }
-
- if (isActive !== null && isActive !== undefined) {
- conditions.push(eq(notice.isActive, isActive))
- }
- // 고급 필터 처리
- if (filters && filters.length > 0) {
- const advancedConditions = filters.map(() =>
- filterColumns({
- table: notice,
- filters: filters,
- joinOperator: joinOperator,
- })
- )
-
- if (advancedConditions.length > 0) {
- if (joinOperator === "or") {
- conditions.push(or(...advancedConditions))
- } else {
- conditions.push(and(...advancedConditions))
- }
- }
- }
-
- // 전체 WHERE 조건 조합
- const finalWhere = conditions.length > 0
- ? (joinOperator === "or" ? or(...conditions) : and(...conditions))
- : undefined
-
- // 페이지네이션
- const offset = (page - 1) * perPage
-
- // 정렬 처리
- const orderBy = input.sort.length > 0
- ? input.sort.map((item) => {
- if (item.id === "createdAt") {
- return item.desc ? desc(notice.createdAt) : asc(notice.createdAt)
- } else if (item.id === "updatedAt") {
- return item.desc ? desc(notice.updatedAt) : asc(notice.updatedAt)
- } else if (item.id === "pagePath") {
- return item.desc ? desc(notice.pagePath) : asc(notice.pagePath)
- } else if (item.id === "title") {
- return item.desc ? desc(notice.title) : asc(notice.title)
- } else if (item.id === "authorId") {
- return item.desc ? desc(notice.authorId) : asc(notice.authorId)
- } else if (item.id === "isActive") {
- return item.desc ? desc(notice.isActive) : asc(notice.isActive)
- } else {
- return desc(notice.createdAt) // 기본값
- }
- })
- : [desc(notice.createdAt)]
-
- // 트랜잭션 내부에서 Repository 호출
- const { data, total } = await db.transaction(async (tx) => {
- const data = await selectNoticeLists(tx, {
- where: finalWhere,
- orderBy,
- offset,
- limit: input.perPage,
- })
-
- const total = await countNoticeLists(tx, finalWhere)
- return { data, total }
- })
-
- const pageCount = Math.ceil(total / input.perPage)
-
- return { data, pageCount, total }
- } catch (err) {
- console.error("Failed to get notice lists:", err)
- // 에러 발생 시 기본값 반환
- return { data: [], pageCount: 0, total: 0 }
- }
- },
- [JSON.stringify(input)],
- {
- revalidate: 3600,
- tags: ["notice-lists"],
- }
- )()
-}
-
-// 기존 패턴 (하위 호환성을 위해 유지)
-export async function getNoticeList(input: Partial<{ page: number; per_page: number; sort?: string; pagePath?: string; title?: string; authorId?: number; isActive?: boolean; from?: string; to?: string }> & { page: number; per_page: number }) {
- unstable_noStore()
-
+// 간단한 공지사항 목록 조회 (페이지네이션 없이 전체 조회)
+export async function getNoticeLists(): Promise<{ data: Array<Notice & { authorName: string | null; authorEmail: string | null }> }> {
try {
- const [data, total] = await Promise.all([
- selectNotice(input),
- countNotice(input)
- ])
-
- const pageCount = Math.ceil(total / input.per_page)
-
- return {
- data,
- pageCount,
- total
- }
- } catch (error) {
- console.error("Failed to get notice list:", error)
- throw new Error(getErrorMessage(error))
+ // 전체 데이터 조회 (작성자 정보 포함, 클라이언트에서 검색 처리)
+ const data = await db
+ .select({
+ id: notice.id,
+ pagePath: notice.pagePath,
+ title: notice.title,
+ content: notice.content,
+ authorId: notice.authorId,
+ isActive: notice.isActive,
+ createdAt: notice.createdAt,
+ updatedAt: notice.updatedAt,
+ authorName: users.name,
+ authorEmail: users.email,
+ })
+ .from(notice)
+ .leftJoin(users, eq(notice.authorId, users.id))
+ .orderBy(desc(notice.createdAt))
+
+ return { data }
+ } catch (err) {
+ console.error("Failed to get notice lists:", err)
+ return { data: [] }
}
}
// 페이지별 공지사항 조회 (일반 사용자용)
export async function getPageNotices(pagePath: string): Promise<Array<Notice & { authorName: string | null; authorEmail: string | null }>> {
try {
- return await getNoticesByPagePath(pagePath)
+ console.log('🔍 Notice Service - 조회 시작:', { pagePath })
+ const result = await getNoticesByPagePath(pagePath)
+ console.log('📊 Notice Service - 조회 결과:', {
+ pagePath,
+ noticesCount: result.length,
+ notices: result.map(n => ({ id: n.id, title: n.title, pagePath: n.pagePath }))
+ })
+ return result
} catch (error) {
console.error(`Failed to get notices for page ${pagePath}:`, error)
return []
}
}
-// 캐시된 페이지별 공지사항 조회
-export const getCachedPageNotices = unstable_cache(
- async (pagePath: string) => getPageNotices(pagePath),
- ["page-notices"],
- {
- tags: ["page-notices"],
- revalidate: 3600, // 1시간 캐시
- }
-)
+// 페이지별 공지사항 조회 (직접 호출용)
+export async function getPageNoticesDirect(pagePath: string) {
+ return await getPageNotices(pagePath)
+}
// 공지사항 생성
export async function createNotice(input: CreateNoticeSchema) {
try {
const result = await insertNotice(input)
- revalidateTag("page-notices")
- revalidateTag("notice-lists")
-
return {
success: true,
data: result,
@@ -225,9 +103,6 @@ export async function updateNoticeData(input: UpdateNoticeSchema) { }
}
- revalidateTag("page-notices")
- revalidateTag("notice-lists")
-
return {
success: true,
message: "공지사항이 성공적으로 수정되었습니다."
@@ -253,9 +128,6 @@ export async function deleteNotice(id: number) { }
}
- revalidateTag("page-notices")
- revalidateTag("notice-lists")
-
return {
success: true,
message: "공지사항이 성공적으로 삭제되었습니다."
@@ -274,9 +146,6 @@ export async function deleteMultipleNotices(ids: number[]) { try {
const deletedCount = await deleteNoticeByIds(ids)
- revalidateTag("page-notices")
- revalidateTag("notice-lists")
-
return {
success: true,
deletedCount,
@@ -311,7 +180,7 @@ export async function getPagePathList(): Promise<Array<{ pagePath: string; pageN })
.from(pageInformation)
.where(eq(pageInformation.isActive, true))
- .orderBy(asc(pageInformation.pagePath))
+ .orderBy(desc(pageInformation.pagePath))
return result.map(item => ({
pagePath: item.pagePath,
@@ -349,8 +218,6 @@ export async function syncNoticeFromMenuAssignments() { processedCount++;
}
- revalidateTag("notice");
-
return {
success: true,
message: `공지사항 경로 동기화 확인 완료: ${processedCount}개 확인, ${missingPaths.length}개 누락`,
|
