'use client'; import { useState, useEffect, useCallback } from 'react'; import { PageLayout } from '@/components/organisms/PageLayout'; import { PageHeader } from '@/components/organisms/PageHeader'; import { CalendarDays, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { ContentSkeleton } from '@/components/ui/skeleton'; import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; import { QuantityInput } from '@/components/ui/quantity-input'; import { Card, CardContent } from '@/components/ui/card'; import { Switch } from '@/components/ui/switch'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { toast } from 'sonner'; import { getLeavePolicy, updateLeavePolicy } from './actions'; import { type LeavePolicySettings, type LeaveStandardType, DEFAULT_LEAVE_POLICY, MONTH_OPTIONS, DAY_OPTIONS, } from './types'; import { isNextRedirectError } from '@/lib/utils/redirect-error'; export function LeavePolicyManagement() { const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); const [settings, setSettings] = useState(DEFAULT_LEAVE_POLICY); // 데이터 로드 const loadData = useCallback(async () => { setIsLoading(true); try { const result = await getLeavePolicy(); if (result.success && result.data) { setSettings(result.data); } } catch (error) { console.error('Failed to load leave policy:', error); toast.error('휴가 정책을 불러오는데 실패했습니다.'); } finally { setIsLoading(false); } }, []); // 초기 로드 useEffect(() => { loadData(); }, [loadData]); // 저장 const handleSave = async () => { setIsSaving(true); try { const result = await updateLeavePolicy(settings); if (result.success) { toast.success('휴가 정책이 저장되었습니다.'); if (result.data) { setSettings(result.data); } } else { toast.error(result.error || '저장에 실패했습니다.'); } } catch (error) { console.error('Failed to save leave policy:', error); toast.error('저장 중 오류가 발생했습니다.'); } finally { setIsSaving(false); } }; // 필드 업데이트 const updateField = ( field: K, value: LeavePolicySettings[K] ) => { setSettings(prev => ({ ...prev, [field]: value })); }; if (isLoading) { return ( ); } return ( {/* 헤더 */} {/* 저장 버튼 */}
{/* 기본 정보 카드 */}

기준 설정

{/* 기준 셀렉트 */}
{/* 기준일 셀렉트 (월/일) */}
{/* 안내 문구 */}

! 휴가 기준일 설정에 따라서 휴가 조회 범위 및 자동 휴가 부여 정책의 기본 값이 변경됩니다.

  • 입사일 기준: 사원의 입사일 기준으로 휴가를 부여하고 조회할 수 있습니다.
  • 회계연도 기준: 회사의 회계연도 기준으로 휴가를 부여하고 조회할 수 있습니다.
{/* 연차 설정 카드 */}

연차 설정

{/* 기본 연차 일수 */}
updateField('defaultAnnualLeave', value ?? 0)} className="w-20" />
{/* 근속년수당 추가 연차 */}
updateField('additionalLeavePerYear', value ?? 0)} className="w-20" />
{/* 최대 연차 일수 */}
updateField('maxAnnualLeave', value ?? 0)} className="w-20" />
{/* 안내 문구 */}

! 신규 입사자에게 기본 연차가 부여되며, 근속년수에 따라 추가 연차가 부여됩니다.

{/* 이월 설정 카드 */}

이월 설정

{/* 이월 허용 여부 */}

미사용 연차를 다음 해로 이월할 수 있습니다.

updateField('carryOverEnabled', checked)} />
{settings.carryOverEnabled && (
{/* 최대 이월 일수 */}
updateField('carryOverMaxDays', value ?? 0)} className="w-20" />
{/* 이월 연차 소멸 기간 */}
updateField('carryOverExpiryMonths', value ?? 0)} className="w-20" /> 개월
)} {/* 안내 문구 */} {settings.carryOverEnabled && (

! 이월된 연차는 설정된 기간 내에 사용하지 않으면 자동으로 소멸됩니다.

)}
); }