'use client'; /** * SubscriptionClient — 대체 구독관리 컴포넌트 (SubscriptionManagement.tsx 사용 권장) * 기존 호환성 유지를 위해 보존 */ import { useState, useCallback } from 'react'; import { CreditCard, Download, AlertTriangle } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { PageLayout } from '@/components/organisms/PageLayout'; import { PageHeader } from '@/components/organisms/PageHeader'; import { toast } from 'sonner'; import { usePermission } from '@/hooks/usePermission'; import { cancelSubscription, requestDataExport } from './actions'; import type { SubscriptionInfo } from './types'; import { SUBSCRIPTION_STATUS_LABELS } from './types'; import { formatKrw, getProgressColor } from './utils'; import { formatAmountWon as formatCurrency } from '@/lib/utils/amount'; interface SubscriptionClientProps { initialData: SubscriptionInfo; } const formatDate = (dateStr: string | null): string => { if (!dateStr) return '-'; const date = new Date(dateStr); if (isNaN(date.getTime())) return '-'; return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`; }; function ColoredProgress({ value }: { value: number }) { const color = getProgressColor(value); const clamped = Math.min(value, 100); return (
); } export function SubscriptionClient({ initialData }: SubscriptionClientProps) { const { canExport } = usePermission(); const [subscription, setSubscription] = useState(initialData); const [showCancelDialog, setShowCancelDialog] = useState(false); const [isExporting, setIsExporting] = useState(false); const [isCancelling, setIsCancelling] = useState(false); const handleExportData = useCallback(async () => { setIsExporting(true); try { const result = await requestDataExport('all'); if (result.success) toast.success('내보내기 요청이 등록되었습니다.'); else toast.error(result.error || '내보내기 요청에 실패했습니다.'); } catch { toast.error('서버 오류가 발생했습니다.'); } finally { setIsExporting(false); } }, []); const handleCancelService = useCallback(async () => { if (!subscription.id) { toast.error('구독 정보를 찾을 수 없습니다.'); setShowCancelDialog(false); return; } setIsCancelling(true); try { const result = await cancelSubscription(subscription.id, '사용자 요청'); if (result.success) { toast.success('서비스가 해지되었습니다.'); setSubscription(prev => ({ ...prev, status: 'cancelled' })); } else toast.error(result.error || '서비스 해지에 실패했습니다.'); } catch { toast.error('서버 오류가 발생했습니다.'); } finally { setIsCancelling(false); setShowCancelDialog(false); } }, [subscription.id]); const userPercentage = subscription.userLimit ? (subscription.userCount / subscription.userLimit) * 100 : 30; return ( <> {canExport && ( )}
} />
요금제
{subscription.planName}
시작: {formatDate(subscription.startedAt)}
구독 상태
{SUBSCRIPTION_STATUS_LABELS[subscription.status] || subscription.status} {subscription.remainingDays != null && subscription.remainingDays > 0 && (
남은 일: {subscription.remainingDays}일
)}
구독 금액
{formatCurrency(subscription.monthlyFee)}/월
종료: {formatDate(subscription.endedAt)}
리소스 사용량
사용자 {subscription.userCount}명 / {subscription.userLimit ? `${subscription.userLimit}명` : '무제한'}
저장 공간 {subscription.storageUsedFormatted} / {subscription.storageLimitFormatted}
AI 토큰 {formatKrw(subscription.aiTokens.costKrw)}
서비스 해지} description={<>모든 데이터가 삭제되며 복구할 수 없습니다.
정말 서비스를 해지하시겠습니까?} confirmText="확인" loading={isCancelling} /> ); }