"use client" import * as React from "react" import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" import { useParams } from "next/navigation" import { useTranslation } from "@/i18n/client" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Input } from "@/components/ui/input" import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "@/components/ui/sheet" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Switch } from "@/components/ui/switch" import { updateNoticeSchema, type UpdateNoticeSchema } from "@/lib/notice/validations" import type { Notice } from "@/db/schema/notice" import { updateNoticeData } from "@/lib/notice/service" import TiptapEditor from "@/components/qna/tiptap-editor" import { Calendar } from "@/components/ui/calendar" import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" import { CalendarIcon } from "lucide-react" import { format } from "date-fns" import { ko } from "date-fns/locale" import { cn } from "@/lib/utils" type NoticeWithAuthor = Notice & { authorName: string | null authorEmail: string | null } interface UpdateNoticeSheetProps { open: boolean onOpenChange: (open: boolean) => void notice: NoticeWithAuthor | null pagePathOptions: Array<{ value: string; label: string }> onSuccess?: () => void } export function UpdateNoticeSheet({ open, onOpenChange, notice, pagePathOptions, onSuccess }: UpdateNoticeSheetProps) { 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 [isUpdatePending, startUpdateTransition] = React.useTransition() const form = useForm({ resolver: zodResolver(updateNoticeSchema), defaultValues: { id: 0, pagePath: "", title: "", content: "", isActive: true, isPopup: false, startAt: undefined, endAt: undefined, dontShowDuration: "never", // 기본값을 영구로 설정 }, }) // notice 데이터가 변경될 때 폼 초기화 React.useEffect(() => { if (notice) { form.reset({ id: notice.id, pagePath: notice.pagePath, title: notice.title, content: notice.content, isActive: notice.isActive, isPopup: notice.isPopup || false, startAt: notice.startAt || undefined, endAt: notice.endAt || undefined, dontShowDuration: notice.dontShowDuration as 'day' | 'never' || "never", // 기본값을 영구로 설정 }) } }, [notice, form]) function onSubmit(input: UpdateNoticeSchema) { if (!notice) return startUpdateTransition(async () => { try { const result = await updateNoticeData(input) if (result.success) { toast.success(result.message || "공지사항이 성공적으로 수정되었습니다.") if (onSuccess) onSuccess() onOpenChange(false) } else { toast.error(result.message || "공지사항 수정에 실패했습니다.") } } catch (error) { toast.error("예기치 못한 오류가 발생했습니다.") console.error("공지사항 수정 오류:", error) } }) } return ( 공지사항 수정 공지사항의 제목과 내용을 수정할 수 있습니다. 수정된 내용은 즉시 반영됩니다.
{/* 공지사항 정보 표시 */} {notice && (
공지사항 정보
작성자: {notice.authorName} ({notice.authorEmail})
작성일: {new Date(notice.createdAt).toLocaleDateString("ko-KR")}
수정일: {new Date(notice.updatedAt).toLocaleDateString("ko-KR")}
상태: {notice.isActive ? "활성" : "비활성"}
)} {/* 페이지 경로 선택 */} ( 페이지 경로 * )} /> {/* 제목 입력 */} ( 제목 * )} /> {/* 활성 상태 */} (
활성 상태
활성화하면 해당 페이지에서 공지사항이 표시됩니다.
)} /> {/* 팝업 여부 */} (
팝업 공지사항
팝업으로 표시할 공지사항인 경우 체크하세요.
)} /> {/* 유효기간 설정 (팝업인 경우에만 표시) */} {form.watch('isPopup') && (
( 게시 시작 일시 { if (date) { const dateTime = new Date(date) if (field.value) { dateTime.setHours(field.value.getHours()) dateTime.setMinutes(field.value.getMinutes()) } else { dateTime.setHours(0, 0, 0, 0) } field.onChange(dateTime) } }} disabled={(date) => date < new Date("1900-01-01") } initialFocus />
{ if (field.value && e.target.value) { const [hours, minutes] = e.target.value.split(':') const newDate = new Date(field.value) newDate.setHours(parseInt(hours), parseInt(minutes)) field.onChange(newDate) } }} disabled={isUpdatePending} />
)} /> ( 게시 종료 일시 { if (date) { const dateTime = new Date(date) if (field.value) { dateTime.setHours(field.value.getHours()) dateTime.setMinutes(field.value.getMinutes()) } else { dateTime.setHours(23, 59, 59, 999) } field.onChange(dateTime) } }} disabled={(date) => date < new Date("1900-01-01") } initialFocus />
{ if (field.value && e.target.value) { const [hours, minutes] = e.target.value.split(':') const newDate = new Date(field.value) newDate.setHours(parseInt(hours), parseInt(minutes)) field.onChange(newDate) } }} disabled={isUpdatePending} />
)} />
)} {/* 다시 보지 않기 설정 (팝업인 경우에만 표시) */} {/* {form.watch('isPopup') && ( ( '다시 보지 않기' 기간 설정
사용자가 '다시 보지 않기'를 체크하면 설정한 기간 동안 해당 공지사항이 표시되지 않습니다.
)} /> )} */} {/* 내용 입력 (리치텍스트 에디터) */} ( 내용 * )} />
) }