summaryrefslogtreecommitdiff
path: root/lib/qna/table/utils.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-02 00:45:49 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-02 00:45:49 +0000
commit2acf5f8966a40c1c9a97680c8dc263ee3f1ad3d1 (patch)
treef406b5c86f563347c7fd088a85fd1a82284dc5ff /lib/qna/table/utils.tsx
parent6a9ca20deddcdcbe8495cf5a73ec7ea5f53f9b55 (diff)
(대표님/최겸) 20250702 변경사항 업데이트
Diffstat (limited to 'lib/qna/table/utils.tsx')
-rw-r--r--lib/qna/table/utils.tsx329
1 files changed, 329 insertions, 0 deletions
diff --git a/lib/qna/table/utils.tsx b/lib/qna/table/utils.tsx
new file mode 100644
index 00000000..f7f9effe
--- /dev/null
+++ b/lib/qna/table/utils.tsx
@@ -0,0 +1,329 @@
+import {
+ CheckCircle2,
+ AlertCircle,
+ TrendingUp,
+ Building2,
+ Wrench,
+ Shield,
+ User,
+ Users,
+ Crown,
+ MessageSquare,
+ MessageCircle,
+ Clock,
+ Calendar,
+ Eye,
+ EyeOff,
+ } from "lucide-react"
+
+ /**
+ * Q&A 상태에 따른 아이콘 반환
+ */
+ export function getQnaStatusIcon(status: string) {
+ switch (status) {
+ case "answered":
+ return CheckCircle2
+ case "unanswered":
+ return AlertCircle
+ case "popular":
+ return TrendingUp
+ default:
+ return MessageSquare
+ }
+ }
+
+ /**
+ * 벤더 타입에 따른 아이콘 반환
+ */
+ export function getVendorTypeIcon(vendorType: string) {
+ switch (vendorType) {
+ case "vendor":
+ return Building2
+ case "techVendor":
+ return Wrench
+ default:
+ return Building2
+ }
+ }
+
+ /**
+ * 사용자 도메인에 따른 아이콘 반환
+ */
+ export function getDomainIcon(domain: string) {
+ switch (domain) {
+ case "partners":
+ return Users
+ case "tech":
+ return Wrench
+ case "admin":
+ return Shield
+ default:
+ return User
+ }
+ }
+
+ /**
+ * Q&A 상태에 따른 배지 색상 반환
+ */
+ export function getQnaStatusBadge(qna: {
+ hasAnswers: boolean
+ isPopular: boolean
+ totalAnswers: number
+ totalComments: number
+ }) {
+ const badges = []
+
+ if (qna.hasAnswers) {
+ badges.push({
+ label: "답변됨",
+ variant: "secondary" as const,
+ icon: CheckCircle2,
+ })
+ } else {
+ badges.push({
+ label: "답변 대기",
+ variant: "outline" as const,
+ icon: AlertCircle,
+ })
+ }
+
+ if (qna.isPopular) {
+ badges.push({
+ label: "인기",
+ variant: "default" as const,
+ icon: TrendingUp,
+ })
+ }
+
+ return badges
+ }
+
+ /**
+ * 도메인에 따른 사용자 라벨 반환
+ */
+ export function getDomainLabel(domain: string) {
+ switch (domain) {
+ case "partners":
+ return "협력업체"
+ case "tech":
+ return "기술업체"
+ case "admin":
+ return "관리자"
+ default:
+ return domain
+ }
+ }
+
+ /**
+ * 벤더 타입에 따른 라벨 반환
+ */
+ export function getVendorTypeLabel(vendorType: string) {
+ switch (vendorType) {
+ case "vendor":
+ return "일반 벤더"
+ case "techVendor":
+ return "기술 벤더"
+ default:
+ return vendorType
+ }
+ }
+
+ /**
+ * Q&A 활동 통계 포맷팅
+ */
+ export function formatQnaStats(qna: {
+ totalAnswers: number
+ totalComments: number
+ lastActivityAt?: Date | null
+ }) {
+ const stats = []
+
+ if (qna.totalAnswers > 0) {
+ stats.push(`답변 ${qna.totalAnswers}개`)
+ }
+
+ if (qna.totalComments > 0) {
+ stats.push(`댓글 ${qna.totalComments}개`)
+ }
+
+ if (stats.length === 0) {
+ return "활동 없음"
+ }
+
+ return stats.join(" • ")
+ }
+
+ /**
+ * 상대적 시간 포맷팅 (예: "3시간 전", "2일 전")
+ */
+ export function formatRelativeTime(date: Date | string) {
+ const now = new Date()
+ const targetDate = new Date(date)
+ const diffInMilliseconds = now.getTime() - targetDate.getTime()
+ const diffInSeconds = Math.floor(diffInMilliseconds / 1000)
+ const diffInMinutes = Math.floor(diffInSeconds / 60)
+ const diffInHours = Math.floor(diffInMinutes / 60)
+ const diffInDays = Math.floor(diffInHours / 24)
+ const diffInMonths = Math.floor(diffInDays / 30)
+ const diffInYears = Math.floor(diffInDays / 365)
+
+ if (diffInSeconds < 60) {
+ return "방금 전"
+ } else if (diffInMinutes < 60) {
+ return `${diffInMinutes}분 전`
+ } else if (diffInHours < 24) {
+ return `${diffInHours}시간 전`
+ } else if (diffInDays < 30) {
+ return `${diffInDays}일 전`
+ } else if (diffInMonths < 12) {
+ return `${diffInMonths}개월 전`
+ } else {
+ return `${diffInYears}년 전`
+ }
+ }
+
+ /**
+ * Q&A 우선순위 계산 (정렬용)
+ */
+ export function calculateQnaPriority(qna: {
+ hasAnswers: boolean
+ isPopular: boolean
+ totalAnswers: number
+ totalComments: number
+ lastActivityAt?: Date | null
+ createdAt: Date
+ }) {
+ let priority = 0
+
+ // 답변이 없는 질문에 높은 우선순위
+ if (!qna.hasAnswers) {
+ priority += 100
+ }
+
+ // 인기 질문에 우선순위 추가
+ if (qna.isPopular) {
+ priority += 50
+ }
+
+ // 최근 활동에 따른 우선순위
+ if (qna.lastActivityAt) {
+ const daysSinceActivity = Math.floor(
+ (new Date().getTime() - new Date(qna.lastActivityAt).getTime()) / (1000 * 60 * 60 * 24)
+ )
+ priority += Math.max(0, 30 - daysSinceActivity) // 최근 30일 내 활동
+ }
+
+ // 활동량에 따른 우선순위
+ priority += Math.min(qna.totalAnswers * 2, 20) // 답변 수 (최대 20점)
+ priority += Math.min(qna.totalComments, 10) // 댓글 수 (최대 10점)
+
+ return priority
+ }
+
+ /**
+ * Q&A 텍스트 요약 (미리보기용)
+ */
+ export function truncateQnaContent(content: string, maxLength: number = 100) {
+ // HTML 태그 제거
+ const textContent = content.replace(/<[^>]*>/g, "").trim()
+
+ if (textContent.length <= maxLength) {
+ return textContent
+ }
+
+ return textContent.slice(0, maxLength).trim() + "..."
+ }
+
+ /**
+ * Q&A 검색 키워드 하이라이팅
+ */
+ export function highlightSearchKeywords(text: string, keywords: string) {
+ if (!keywords.trim()) return text
+
+ const keywordList = keywords.trim().split(/\s+/)
+ let highlightedText = text
+
+ keywordList.forEach(keyword => {
+ const regex = new RegExp(`(${keyword})`, "gi")
+ highlightedText = highlightedText.replace(
+ regex,
+ '<mark class="bg-yellow-200 dark:bg-yellow-800">$1</mark>'
+ )
+ })
+
+ return highlightedText
+ }
+
+ /**
+ * Q&A 필터 조건 검증
+ */
+ export function validateQnaFilters(filters: {
+ search?: string
+ authorDomain?: string[]
+ vendorType?: string[]
+ hasAnswers?: string
+ dateRange?: { from?: Date; to?: Date }
+ }) {
+ const errors: string[] = []
+
+ // 검색어 길이 체크
+ if (filters.search && filters.search.length > 100) {
+ errors.push("검색어는 100자 이하로 입력해주세요.")
+ }
+
+ // 날짜 범위 체크
+ if (filters.dateRange?.from && filters.dateRange?.to) {
+ if (filters.dateRange.from > filters.dateRange.to) {
+ errors.push("시작 날짜가 종료 날짜보다 늦을 수 없습니다.")
+ }
+ }
+
+ return {
+ isValid: errors.length === 0,
+ errors,
+ }
+ }
+
+ /**
+ * Q&A URL 생성 유틸리티
+ */
+ export function generateQnaUrls(qnaId: number) {
+ const baseUrl = typeof window !== "undefined" ? window.location.origin : ""
+
+ return {
+ detail: `${baseUrl}/qna/${qnaId}`,
+ edit: `${baseUrl}/qna/${qnaId}/edit`,
+ share: `${baseUrl}/qna/${qnaId}?shared=true`,
+ }
+ }
+
+ /**
+ * Q&A 메타데이터 생성 (SEO용)
+ */
+ export function generateQnaMetadata(qna: {
+ title: string
+ content: string
+ authorName: string
+ companyName?: string | null
+ totalAnswers: number
+ createdAt: Date
+ }) {
+ const description = truncateQnaContent(qna.content, 160)
+ const keywords = [
+ "Q&A",
+ "질문",
+ "답변",
+ qna.authorName,
+ qna.companyName,
+ ...qna.title.split(" ").slice(0, 5), // 제목의 첫 5단어
+ ].filter(Boolean).join(", ")
+
+ return {
+ title: `${qna.title} - Q&A`,
+ description,
+ keywords,
+ author: qna.authorName,
+ publishedTime: qna.createdAt.toISOString(),
+ articleTag: ["Q&A", "질문", "답변"],
+ }
+ } \ No newline at end of file