// src/renderer/components/LicenseTab.tsx
// 구독 기반 라이선스 탭 — 클라우드 인증 + Payple 결제 연동
import {
Box,
Divider,
LinearProgress,
} from '@mui/material'
import CheckCircleIcon from '@mui/icons-material/CheckCircle'
import CancelIcon from '@mui/icons-material/Cancel'
import { Led, PhosphorText, PhysicalButton, MetalCard } from '@d3ro/ui/components/ds'
import { d3roPalette, d3roFontMono, d3roTypo, d3roRadius } from '@d3ro/ui/theme'
import { useI18n } from '@d3ro/i18n'
import { PREMIUM_MODEL_LIMITS } from '@d3ro/core/constants'
import { useLicenseState } from '../hooks/useLicenseState'
export function LicenseTab(): React.ReactElement {
const { t } = useI18n()
const {
licenseInfo, usage, comparison, cloud,
currentTier, isFree, isPro,
handleUpgrade, handleOpenBilling, openCloudSettings,
} = useLicenseState()
return (
{/* ── 현재 플랜 + 계정 상태 ── */}
{t('license.currentTier')}
{cloud.authenticated && cloud.userEmail && (
{cloud.userEmail}
)}
{/* ── 구독 관리 / 업그레이드 ── */}
{/* ── 일일 사용량 ── */}
{/* ── 티어 비교표 ── */}
)
}
// ── 하위 컴포넌트 ──────────────────────────────────────
function TierLabel({ tier, t }: { tier: string; t: (k: string) => string }): React.ReactElement {
const color = tier === 'pro_plus'
? d3roPalette.tag.purple
: tier === 'pro'
? d3roPalette.tag.green
: d3roPalette.accent.amber
const label = tier === 'pro_plus' ? t('license.proPlus') : tier === 'pro' ? t('license.pro') : t('license.free')
return {label}
}
interface SubscriptionSectionProps {
t: (k: string) => string
authenticated: boolean
isFree: boolean
isPro: boolean
currentTier: string
onUpgrade: (tier: 'pro' | 'pro_plus') => void
onManage: () => void
onSignIn: () => void
}
function SubscriptionSection({ t, authenticated, isFree, isPro, onUpgrade, onManage, onSignIn }: SubscriptionSectionProps): React.ReactElement {
if (!authenticated) {
return (
{t('license.signInRequired')}
{t('license.signInToUpgrade')}
)
}
if (isFree) {
return (
{t('license.subscribe')}
{t('license.upgradeToProDesc')}
)
}
if (isPro) {
return (
{t('license.subscriptionManage')}
)
}
// Pro+
return (
{t('license.subscriptionManage')}
)
}
function ActivePlanIndicator({ label, color }: { label: string; color: string }): React.ReactElement {
return (
{label}
)
}
function UpgradeButton({ tier, t, onUpgrade }: { tier: 'pro' | 'pro_plus'; t: (k: string) => string; onUpgrade: (t: 'pro' | 'pro_plus') => void }): React.ReactElement {
const planLabel = tier === 'pro_plus' ? t('license.proPlusPlan') : t('license.proPlan')
return (
onUpgrade(tier)} sx={{ width: '100%' }}>
{t('license.upgrade')} — {planLabel}
)
}
function UsageSection({ t, usage, currentTier }: { t: (k: string) => string; usage: Array<{ feature: string; used: number; limit: number; remaining: number }>; currentTier: string }): React.ReactElement | null {
if (usage.length === 0) return null
return (
<>
{t('license.dailyUsage')}
{usage.map((q) => (
))}
{/* Premium 모델별 쿼터 */}
{PREMIUM_MODEL_LIMITS[currentTier as keyof typeof PREMIUM_MODEL_LIMITS]?.length > 0 && (
<>
{t('license.premiumQuota')}
{PREMIUM_MODEL_LIMITS[currentTier as keyof typeof PREMIUM_MODEL_LIMITS].map((m) => (
{t(m.i18nKey)}
{m.limit === -1
? t('license.unlimited')
: `${m.limit}/${t(m.period === 'weekly' ? 'license.quotaWeekly' : 'license.quotaDaily')}`}
{m.limit > 0 && (
)}
))}
>
)}
>
)
}
function QuotaBar({ t, feature, used, limit, remaining }: { t: (k: string, p?: Record) => string; feature: string; used: number; limit: number; remaining: number }): React.ReactElement {
return (
{t(`license.feature.${feature}`)}
{limit === -1
? t('license.unlimited')
: t('license.quotaUsed', { used: String(used), limit: String(limit) })}
{limit > 0 && (
= limit ? d3roPalette.tag.red : d3roPalette.accent.amber,
borderRadius: d3roRadius.xs,
},
}}
/>
)}
)
}
function ComparisonTable({ t, comparison }: { t: (k: string) => string; comparison: Array<{ feature: string; featureLabel: string; free: boolean | string; pro: boolean | string; proPlus: boolean | string }> }): React.ReactElement | null {
if (comparison.length === 0) return null
return (
<>
{t('license.tierComparison')}
| {''} |
{t('license.free')} |
{t('license.pro')} |
{t('license.proPlus')} |
{comparison.map((row) => (
| {t(row.featureLabel)} |
|
|
|
))}
>
)
}
function TierCell({ value }: { value: boolean | string }): React.ReactElement {
if (value === true) {
return
}
if (value === false) {
return
}
return (
{value}
)
}