refactor(desktop): 라이선스 UI 빅뱅 — 키 입력 제거, 구독 기반 전환

- LicenseTab/LicenseModal: LemonSqueezy 키 입력 삭제, Payple 구독 UI로 전환
- useLicenseState 훅: 라이선스+클라우드 인증 공용 상태 관리 추출
- PREMIUM_MODEL_LIMITS: 3곳 중복 → @d3ro/core/constants 단일 소스
- i18n: LemonSqueezy 전용 키 18개 삭제, 구독 관련 키 13개 추가 (12 locale)
- DashboardPage: dashboard.model* → license.model* 키 통일
This commit is contained in:
윤찬 2026-04-12 19:54:04 +09:00
parent 68881bf0d0
commit 996def683b
17 changed files with 633 additions and 537 deletions

View file

@ -11,25 +11,9 @@ import { useI18n } from '@d3ro/i18n'
import { formatRecordingTime, formatRecordingTimeUnit, formatNumber, getDateKey } from '../utils/formatters'
import { formatHotkeyLabel } from '../utils/format-hotkey'
import { FileDropZone } from '../components/FileDropZone'
import { PREMIUM_MODEL_LIMITS } from '@d3ro/core/constants'
import type { StatsSummary, HistoryEntry, HotkeyBinding, CaptionState, LicenseTier, UsageQuota } from '@d3ro/core/types'
// ── Premium 쿼터 모델별 한도 (서버 quota.ts / LicenseService QUOTA_LIMITS 와 동기) ──
const PREMIUM_MODEL_LIMITS: Record<LicenseTier, Array<{ model: string; i18nKey: string; limit: number; period: 'daily' | 'weekly' }>> = {
free: [
{ model: 'llm_haiku', i18nKey: 'dashboard.modelHaiku', limit: 250, period: 'weekly' },
],
pro: [
{ model: 'llm_haiku', i18nKey: 'dashboard.modelHaiku', limit: 1500, period: 'daily' },
{ model: 'llm_sonnet', i18nKey: 'dashboard.modelSonnet', limit: 300, period: 'daily' },
{ model: 'llm_opus', i18nKey: 'dashboard.modelOpus', limit: 50, period: 'daily' },
],
pro_plus: [
{ model: 'llm_haiku', i18nKey: 'dashboard.modelHaiku', limit: -1, period: 'daily' },
{ model: 'llm_sonnet', i18nKey: 'dashboard.modelSonnet', limit: 1500, period: 'daily' },
{ model: 'llm_opus', i18nKey: 'dashboard.modelOpus', limit: 300, period: 'daily' },
],
}
// ── 메인 컴포넌트 ─────────────────────────────────────
export function DashboardPage(): React.ReactElement {
@ -362,7 +346,7 @@ export function DashboardPage(): React.ReactElement {
{premiumStatus?.backend === 'premium' && PREMIUM_MODEL_LIMITS[licenseTier].length > 0 && (
<>
<PhosphorText variant="label" sx={{ mt: 1.5, mb: 0.5, display: 'block', color: d3roPalette.tag.green }}>
{t('dashboard.premiumQuota').toUpperCase()}
{t('license.premiumQuota').toUpperCase()}
</PhosphorText>
{PREMIUM_MODEL_LIMITS[licenseTier].map((m) => (
<Box key={m.model} sx={{ mb: 1 }}>
@ -373,7 +357,7 @@ export function DashboardPage(): React.ReactElement {
<PhosphorText variant="small" sx={{ color: d3roPalette.accent.amber }}>
{m.limit === -1
? t('license.unlimited')
: `${m.limit}/${t(m.period === 'weekly' ? 'dashboard.quotaWeekly' : 'dashboard.quotaDaily')}`}
: `${m.limit}/${t(m.period === 'weekly' ? 'license.quotaWeekly' : 'license.quotaDaily')}`}
</PhosphorText>
</Box>
{m.limit > 0 && (