feat(web): manage dictionaries and teams from the console
The console could not create dictionary entries, and team pages showed a static member list with no record of who changed what. Dictionary management, a knowledge upload form, and a team activity feed are now available, alongside a download center that links the published desktop installer feed rather than repository-local paths that no deploy ships. Red-team e2e coverage was added for the account and team flows touched here.
This commit is contained in:
parent
f6a29db95a
commit
cfc58458a8
21 changed files with 985 additions and 125 deletions
|
|
@ -167,7 +167,7 @@ export default async function BillingPage({ searchParams }: BillingPageProps): P
|
|||
<Box sx={{ display: 'inline-flex', alignItems: 'center', gap: 1, mb: 1.5 }}>
|
||||
<TactileBadge ledColor="amber" tone="accent">D3RO VOICE PRO</TactileBadge>
|
||||
</Box>
|
||||
<Typography component="h1" sx={{ fontSize: 28, fontWeight: 500, color: '#fff', letterSpacing: '-0.02em', mb: 1 }}>
|
||||
<Typography component="h1" sx={{ fontSize: 28, fontWeight: 500, color: 'var(--d3-text-inverse)', letterSpacing: '-0.02em', mb: 1 }}>
|
||||
구독 및 결제
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: 14, color: 'var(--d3-text-label)' }}>
|
||||
|
|
@ -195,7 +195,7 @@ export default async function BillingPage({ searchParams }: BillingPageProps): P
|
|||
CURRENT SUBSCRIPTION
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, flexWrap: 'wrap' }}>
|
||||
<Typography data-testid="billing-current-tier" sx={{ fontSize: 28, fontWeight: 600, color: '#fff' }}>
|
||||
<Typography data-testid="billing-current-tier" sx={{ fontSize: 28, fontWeight: 600, color: 'var(--d3-text-inverse)' }}>
|
||||
{tierLabel(subscription.tier)}
|
||||
</Typography>
|
||||
<Chip
|
||||
|
|
@ -210,7 +210,7 @@ export default async function BillingPage({ searchParams }: BillingPageProps): P
|
|||
결제 계정: {state.email}
|
||||
</Typography>
|
||||
{cancellationDate ? (
|
||||
<Typography data-testid="billing-cancel-at" sx={{ mt: 1, color: '#ffb000', fontSize: 12 }}>
|
||||
<Typography data-testid="billing-cancel-at" sx={{ mt: 1, color: 'var(--d3-status-warning)', fontSize: 12 }}>
|
||||
{cancellationDate}에 구독이 종료됩니다.
|
||||
</Typography>
|
||||
) : periodEnd && isPaid ? (
|
||||
|
|
@ -282,7 +282,7 @@ function PlanCard({
|
|||
border: active
|
||||
? '2px solid var(--d3-accent-main)'
|
||||
: plan.highlight
|
||||
? '1px solid rgba(59,130,246,0.45)'
|
||||
? '1px solid var(--d3-accent-glow)'
|
||||
: undefined
|
||||
}}
|
||||
>
|
||||
|
|
@ -290,7 +290,7 @@ function PlanCard({
|
|||
<Typography sx={{ fontFamily: d3roFontMono, fontSize: 11, color: active ? 'var(--d3-accent-main)' : 'var(--d3-text-label)', mb: 0.75 }}>
|
||||
{active ? 'CURRENT PLAN' : plan.highlight ? 'RECOMMENDED' : 'PLAN'}
|
||||
</Typography>
|
||||
<Typography component="h2" sx={{ fontSize: 24, fontWeight: 600, color: '#fff' }}>{plan.name}</Typography>
|
||||
<Typography component="h2" sx={{ fontSize: 24, fontWeight: 600, color: 'var(--d3-text-inverse)' }}>{plan.name}</Typography>
|
||||
<Typography sx={{ mt: 0.5, mb: 3, color: plan.tier === 'free' ? 'var(--d3-text-label)' : 'var(--d3-accent-main)', fontFamily: d3roFontMono, fontSize: 16 }}>
|
||||
{priceLabel}
|
||||
</Typography>
|
||||
|
|
@ -315,7 +315,7 @@ function PlanCard({
|
|||
) : canPurchase && catalogPrices.length > 0 ? (
|
||||
<BillingCheckoutOptions tier={plan.tier} prices={catalogPrices} />
|
||||
) : canPurchase ? (
|
||||
<Typography data-testid={`billing-price-unavailable-${plan.tier}`} sx={{ py: 1.5, textAlign: 'center', color: '#ffb000', fontSize: 12 }}>
|
||||
<Typography data-testid={`billing-price-unavailable-${plan.tier}`} sx={{ py: 1.5, textAlign: 'center', color: 'var(--d3-status-warning)', fontSize: 12 }}>
|
||||
검증된 가격을 불러온 뒤 결제할 수 있습니다.
|
||||
</Typography>
|
||||
) : (
|
||||
|
|
@ -332,7 +332,7 @@ function SubscriptionManagement({ subscription }: { subscription: BillingSubscri
|
|||
return <Typography sx={{ color: 'var(--d3-text-label)', fontSize: 12 }}>활성 유료 구독이 없습니다.</Typography>
|
||||
}
|
||||
if (subscription.cancel_at || subscription.auto_renewing === false) {
|
||||
return <Typography sx={{ color: '#ffb000', fontSize: 12 }}>자동 갱신이 해지되었습니다.</Typography>
|
||||
return <Typography sx={{ color: 'var(--d3-status-warning)', fontSize: 12 }}>자동 갱신이 해지되었습니다.</Typography>
|
||||
}
|
||||
if (subscription.provider === 'payple') return <PaypleManageButton />
|
||||
if (subscription.provider === 'stripe') return <PortalButton />
|
||||
|
|
@ -354,7 +354,9 @@ function BillingLoadError(): React.ReactElement {
|
|||
<Alert severity="error" data-testid="billing-load-error" sx={{ mb: 2 }}>
|
||||
구독 정보를 불러오지 못했습니다. 결제를 시작하지 않았습니다.
|
||||
</Alert>
|
||||
<Button component={Link} href="/billing" variant="outlined">다시 시도</Button>
|
||||
<Link href="/billing" style={{ textDecoration: 'none' }}>
|
||||
<Button variant="outlined">다시 시도</Button>
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue