'use client'; /** * 알림설정 페이지 * * 각 알림 유형별로 ON/OFF 토글, 알림 소리 선택, 이메일 알림 체크박스를 제공합니다. * 항목 설정 기능으로 표시할 알림 카테고리/항목을 선택할 수 있습니다. */ import { useState, useCallback } from 'react'; import { PageLayout } from '@/components/organisms/PageLayout'; import { PageHeader } from '@/components/organisms/PageHeader'; import { Bell, Save, Play, Settings } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardTitle } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; import { Switch } from '@/components/ui/switch'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { toast } from 'sonner'; import type { NotificationSettings, NotificationItem, SoundType, ItemVisibilitySettings } from './types'; import { SOUND_OPTIONS, DEFAULT_ITEM_VISIBILITY } from './types'; import { saveNotificationSettings } from './actions'; import { ItemSettingsDialog } from './ItemSettingsDialog'; // 미리듣기 함수 function playPreviewSound(soundType: SoundType) { if (soundType === 'mute') { toast.info('무음으로 설정되어 있습니다.'); return; } const soundName = soundType === 'default' ? '기본 알림음' : 'SAM 보이스'; toast.info(`${soundName} 미리듣기`); } // 알림 항목 컴포넌트 interface NotificationItemRowProps { label: string; item: NotificationItem; onChange: (item: NotificationItem) => void; disabled?: boolean; } function NotificationItemRow({ label, item, onChange, disabled }: NotificationItemRowProps) { const isDisabled = disabled || !item.enabled; return (
{label} onChange({ ...item, enabled: checked, email: checked ? item.email : false }) } disabled={disabled} />
{/* 알림 소리 선택 */}
알림 소리 선택
{/* 추가 알림 선택 */}
추가 알림 선택
); } // 알림 섹션 컴포넌트 interface NotificationSectionProps { title: string; enabled: boolean; onEnabledChange: (enabled: boolean) => void; children: React.ReactNode; } function NotificationSection({ title, enabled, onEnabledChange, children }: NotificationSectionProps) { return (
{title} { onEnabledChange(checked); }} />
{children}
); } interface NotificationSettingsManagementProps { initialData: NotificationSettings; } const ITEM_VISIBILITY_STORAGE_KEY = 'notification-item-visibility'; export function NotificationSettingsManagement({ initialData }: NotificationSettingsManagementProps) { const [settings, setSettings] = useState(initialData); // 항목 설정 (표시/숨김) const [itemVisibility, setItemVisibility] = useState(() => { if (typeof window === 'undefined') return DEFAULT_ITEM_VISIBILITY; const saved = localStorage.getItem(ITEM_VISIBILITY_STORAGE_KEY); return saved ? JSON.parse(saved) : DEFAULT_ITEM_VISIBILITY; }); // 항목 설정 모달 상태 const [isItemSettingsOpen, setIsItemSettingsOpen] = useState(false); // 항목 설정 저장 const handleItemVisibilitySave = useCallback((newSettings: ItemVisibilitySettings) => { setItemVisibility(newSettings); localStorage.setItem(ITEM_VISIBILITY_STORAGE_KEY, JSON.stringify(newSettings)); toast.success('항목 설정이 저장되었습니다.'); }, []); // 공지 알림 핸들러 const handleNoticeEnabledChange = (enabled: boolean) => { setSettings(prev => ({ ...prev, notice: { ...prev.notice, enabled, ...(enabled ? {} : { notice: { ...prev.notice.notice, enabled: false, email: false }, event: { ...prev.notice.event, enabled: false, email: false }, }), }, })); }; const handleNoticeItemChange = (key: 'notice' | 'event', item: NotificationItem) => { setSettings(prev => ({ ...prev, notice: { ...prev.notice, [key]: item }, })); }; // 일정 알림 핸들러 const handleScheduleEnabledChange = (enabled: boolean) => { setSettings(prev => ({ ...prev, schedule: { ...prev.schedule, enabled, ...(enabled ? {} : { vatReport: { ...prev.schedule.vatReport, enabled: false, email: false }, incomeTaxReport: { ...prev.schedule.incomeTaxReport, enabled: false, email: false }, }), }, })); }; const handleScheduleItemChange = (key: 'vatReport' | 'incomeTaxReport', item: NotificationItem) => { setSettings(prev => ({ ...prev, schedule: { ...prev.schedule, [key]: item }, })); }; // 거래처 알림 핸들러 const handleVendorEnabledChange = (enabled: boolean) => { setSettings(prev => ({ ...prev, vendor: { ...prev.vendor, enabled, ...(enabled ? {} : { newVendor: { ...prev.vendor.newVendor, enabled: false, email: false }, creditRating: { ...prev.vendor.creditRating, enabled: false, email: false }, }), }, })); }; const handleVendorItemChange = (key: 'newVendor' | 'creditRating', item: NotificationItem) => { setSettings(prev => ({ ...prev, vendor: { ...prev.vendor, [key]: item }, })); }; // 근태 알림 핸들러 const handleAttendanceEnabledChange = (enabled: boolean) => { setSettings(prev => ({ ...prev, attendance: { ...prev.attendance, enabled, ...(enabled ? {} : { annualLeave: { ...prev.attendance.annualLeave, enabled: false, email: false }, clockIn: { ...prev.attendance.clockIn, enabled: false, email: false }, late: { ...prev.attendance.late, enabled: false, email: false }, absent: { ...prev.attendance.absent, enabled: false, email: false }, }), }, })); }; const handleAttendanceItemChange = ( key: 'annualLeave' | 'clockIn' | 'late' | 'absent', item: NotificationItem ) => { setSettings(prev => ({ ...prev, attendance: { ...prev.attendance, [key]: item }, })); }; // 수주/발주 알림 핸들러 const handleOrderEnabledChange = (enabled: boolean) => { setSettings(prev => ({ ...prev, order: { ...prev.order, enabled, ...(enabled ? {} : { salesOrder: { ...prev.order.salesOrder, enabled: false, email: false }, purchaseOrder: { ...prev.order.purchaseOrder, enabled: false, email: false }, approvalRequest: { ...prev.order.approvalRequest, enabled: false, email: false }, }), }, })); }; const handleOrderItemChange = (key: 'salesOrder' | 'purchaseOrder' | 'approvalRequest', item: NotificationItem) => { setSettings(prev => ({ ...prev, order: { ...prev.order, [key]: item }, })); }; // 전자결재 알림 핸들러 const handleApprovalEnabledChange = (enabled: boolean) => { setSettings(prev => ({ ...prev, approval: { ...prev.approval, enabled, ...(enabled ? {} : { approvalRequest: { ...prev.approval.approvalRequest, enabled: false, email: false }, draftApproved: { ...prev.approval.draftApproved, enabled: false, email: false }, draftRejected: { ...prev.approval.draftRejected, enabled: false, email: false }, draftCompleted: { ...prev.approval.draftCompleted, enabled: false, email: false }, }), }, })); }; const handleApprovalItemChange = ( key: 'approvalRequest' | 'draftApproved' | 'draftRejected' | 'draftCompleted', item: NotificationItem ) => { setSettings(prev => ({ ...prev, approval: { ...prev.approval, [key]: item }, })); }; // 생산 알림 핸들러 const handleProductionEnabledChange = (enabled: boolean) => { setSettings(prev => ({ ...prev, production: { ...prev.production, enabled, ...(enabled ? {} : { safetyStock: { ...prev.production.safetyStock, enabled: false, email: false }, productionComplete: { ...prev.production.productionComplete, enabled: false, email: false }, }), }, })); }; const handleProductionItemChange = ( key: 'safetyStock' | 'productionComplete', item: NotificationItem ) => { setSettings(prev => ({ ...prev, production: { ...prev.production, [key]: item }, })); }; // 저장 const handleSave = async () => { const result = await saveNotificationSettings(settings); if (result.success) { toast.success('알림 설정이 저장되었습니다.'); } else { toast.error(result.error || '알림 설정 저장에 실패했습니다.'); } }; return ( {/* 상단 버튼 영역 */}
{/* 공지 알림 */} {itemVisibility.notice.enabled && ( {itemVisibility.notice.notice && ( handleNoticeItemChange('notice', item)} disabled={!settings.notice.enabled} /> )} {itemVisibility.notice.event && ( handleNoticeItemChange('event', item)} disabled={!settings.notice.enabled} /> )} )} {/* 일정 알림 */} {itemVisibility.schedule.enabled && ( {itemVisibility.schedule.vatReport && ( handleScheduleItemChange('vatReport', item)} disabled={!settings.schedule.enabled} /> )} {itemVisibility.schedule.incomeTaxReport && ( handleScheduleItemChange('incomeTaxReport', item)} disabled={!settings.schedule.enabled} /> )} )} {/* 거래처 알림 */} {itemVisibility.vendor.enabled && ( {itemVisibility.vendor.newVendor && ( handleVendorItemChange('newVendor', item)} disabled={!settings.vendor.enabled} /> )} {itemVisibility.vendor.creditRating && ( handleVendorItemChange('creditRating', item)} disabled={!settings.vendor.enabled} /> )} )} {/* 근태 알림 */} {itemVisibility.attendance.enabled && ( {itemVisibility.attendance.annualLeave && ( handleAttendanceItemChange('annualLeave', item)} disabled={!settings.attendance.enabled} /> )} {itemVisibility.attendance.clockIn && ( handleAttendanceItemChange('clockIn', item)} disabled={!settings.attendance.enabled} /> )} {itemVisibility.attendance.late && ( handleAttendanceItemChange('late', item)} disabled={!settings.attendance.enabled} /> )} {itemVisibility.attendance.absent && ( handleAttendanceItemChange('absent', item)} disabled={!settings.attendance.enabled} /> )} )} {/* 수주/발주 알림 */} {itemVisibility.order.enabled && ( {itemVisibility.order.salesOrder && ( handleOrderItemChange('salesOrder', item)} disabled={!settings.order.enabled} /> )} {itemVisibility.order.purchaseOrder && ( handleOrderItemChange('purchaseOrder', item)} disabled={!settings.order.enabled} /> )} )} {/* 전자결재 알림 */} {itemVisibility.approval.enabled && ( {itemVisibility.approval.approvalRequest && ( handleApprovalItemChange('approvalRequest', item)} disabled={!settings.approval.enabled} /> )} {itemVisibility.approval.draftApproved && ( handleApprovalItemChange('draftApproved', item)} disabled={!settings.approval.enabled} /> )} {itemVisibility.approval.draftRejected && ( handleApprovalItemChange('draftRejected', item)} disabled={!settings.approval.enabled} /> )} {itemVisibility.approval.draftCompleted && ( handleApprovalItemChange('draftCompleted', item)} disabled={!settings.approval.enabled} /> )} )} {/* 생산 알림 */} {itemVisibility.production.enabled && ( {itemVisibility.production.safetyStock && ( handleProductionItemChange('safetyStock', item)} disabled={!settings.production.enabled} /> )} {itemVisibility.production.productionComplete && ( handleProductionItemChange('productionComplete', item)} disabled={!settings.production.enabled} /> )} )}
{/* 항목 설정 모달 */} setIsItemSettingsOpen(false)} settings={itemVisibility} onSave={handleItemVisibilitySave} />
); }