Expand AITURK Turkish settings and desktop surfaces for beta 5
This commit is contained in:
1 parent
237d1e2060
commit
5e76f58637
108 files changed
+6675
-1034
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import type { BillingRefusal } from './api'
|
||||
import { type BillingCopy, DEFAULT_BILLING_COPY } from './copy'
|
||||
|
||||
export interface BillingRefusalPresentation {
|
||||
action: { type: 'none' } | { type: 'portal'; url?: string } | { type: 'retry' } | { type: 'step_up' }
|
||||
@@ -8,51 +9,51 @@ export interface BillingRefusalPresentation {
|
||||
|
||||
const portalAction = (url?: string): BillingRefusalPresentation['action'] => ({ type: 'portal', url })
|
||||
|
||||
const retryMessage = (refusal: BillingRefusal): string => {
|
||||
const mins = refusal.retryAfter ? ` (try again in ~${Math.max(1, Math.round(refusal.retryAfter / 60))} min)` : ''
|
||||
const retryMessage = (refusal: BillingRefusal, copy: BillingCopy): string => {
|
||||
const mins = refusal.retryAfter ? copy.retryAfter(Math.max(1, Math.round(refusal.retryAfter / 60))) : ''
|
||||
|
||||
return `🟡 Too many charges right now${mins}. This isn't a payment failure.`
|
||||
return copy.rateLimited(mins)
|
||||
}
|
||||
|
||||
const stripeRetryMessage = (refusal: BillingRefusal): string => {
|
||||
const mins = refusal.retryAfter ? ` (try again in ~${Math.max(1, Math.round(refusal.retryAfter / 60))} min)` : ''
|
||||
const stripeRetryMessage = (refusal: BillingRefusal, copy: BillingCopy): string => {
|
||||
const mins = refusal.retryAfter ? copy.retryAfter(Math.max(1, Math.round(refusal.retryAfter / 60))) : ''
|
||||
|
||||
return `Stripe is having trouble — try again shortly${mins}`
|
||||
return copy.stripeRetry(mins)
|
||||
}
|
||||
|
||||
export const resolveRefusal = (refusal: BillingRefusal): BillingRefusalPresentation => {
|
||||
export const resolveRefusal = (
|
||||
refusal: BillingRefusal,
|
||||
copy: BillingCopy = DEFAULT_BILLING_COPY
|
||||
): BillingRefusalPresentation => {
|
||||
switch (refusal.kind) {
|
||||
case 'consent_required':
|
||||
return {
|
||||
action: portalAction(refusal.portalUrl),
|
||||
message: 'Confirm this card for terminal charges in the portal',
|
||||
title: 'Card confirmation needed'
|
||||
message: copy.confirmCardMessage,
|
||||
title: copy.confirmCardTitle
|
||||
}
|
||||
|
||||
case 'insufficient_scope':
|
||||
return {
|
||||
action: { type: 'step_up' },
|
||||
message: 'This needs Remote Spending allowed. Start a top-up to allow it, then retry.',
|
||||
title: 'Remote Spending needs approval'
|
||||
message: copy.spendingApprovalMessage,
|
||||
title: copy.spendingApprovalTitle
|
||||
}
|
||||
case 'remote_spending_revoked': {
|
||||
const who =
|
||||
refusal.actor === 'admin'
|
||||
? 'An admin stopped remote spending for this terminal.'
|
||||
: 'You stopped remote spending for this terminal.'
|
||||
const who = refusal.actor === 'admin' ? copy.adminRevoked : copy.userRevoked
|
||||
|
||||
return {
|
||||
action: portalAction(refusal.portalUrl),
|
||||
message: `${who} Reconnect from Settings → Gateway to re-authorize this device.`,
|
||||
title: 'Remote spending was stopped'
|
||||
message: copy.reauthorize(who),
|
||||
title: copy.spendingRevoked
|
||||
}
|
||||
}
|
||||
|
||||
case 'session_revoked':
|
||||
return {
|
||||
action: portalAction(refusal.portalUrl),
|
||||
message: 'Your session was logged out. Sign in again from Settings → Gateway.',
|
||||
title: 'Session logged out'
|
||||
message: copy.sessionRevokedMessage,
|
||||
title: copy.sessionRevokedTitle
|
||||
}
|
||||
|
||||
case 'cli_billing_disabled':
|
||||
@@ -60,50 +61,44 @@ export const resolveRefusal = (refusal: BillingRefusal): BillingRefusalPresentat
|
||||
case 'remote_spending_disabled':
|
||||
return {
|
||||
action: portalAction(refusal.portalUrl),
|
||||
message:
|
||||
"Remote spending is off for this account — a billing admin can turn it on from the portal's Hermes Agent page.",
|
||||
title: 'Remote spending is off'
|
||||
message: copy.spendingDisabledMessage,
|
||||
title: copy.spendingDisabledTitle
|
||||
}
|
||||
|
||||
case 'role_required':
|
||||
return {
|
||||
action: portalAction(refusal.portalUrl),
|
||||
message: 'Adding funds needs an org admin/owner. Ask an admin, or manage on the portal.',
|
||||
title: 'Admin role required'
|
||||
message: copy.adminRequiredMessage,
|
||||
title: copy.adminRequiredTitle
|
||||
}
|
||||
|
||||
case 'idempotency_conflict':
|
||||
return {
|
||||
action: { type: 'none' },
|
||||
message: '🔴 That charge key was already used for a different amount. Start a fresh top-up.',
|
||||
title: 'Start a fresh top-up'
|
||||
message: copy.conflictingChargeMessage,
|
||||
title: copy.conflictingChargeTitle
|
||||
}
|
||||
|
||||
case 'no_payment_method':
|
||||
return {
|
||||
action: portalAction(refusal.portalUrl),
|
||||
message:
|
||||
'💳 No saved card for terminal charges yet. Set one up on the portal ' +
|
||||
"(one-time credit buys don't save a reusable card).",
|
||||
title: 'No saved card'
|
||||
message: copy.noSavedCardMessage,
|
||||
title: copy.noSavedCard
|
||||
}
|
||||
|
||||
case 'org_access_denied':
|
||||
return {
|
||||
action: { type: 'none' },
|
||||
message: "This token isn't bound to an org you can manage",
|
||||
title: 'Org access denied'
|
||||
message: copy.orgDeniedMessage,
|
||||
title: copy.orgDeniedTitle
|
||||
}
|
||||
case 'monthly_cap_exceeded': {
|
||||
const remaining = refusal.payload?.remainingUsd
|
||||
|
||||
return {
|
||||
action: portalAction(refusal.portalUrl),
|
||||
message:
|
||||
remaining != null
|
||||
? `🔴 Monthly spend cap reached — $${remaining} headroom left.`
|
||||
: '🔴 Monthly spend cap reached.',
|
||||
title: 'Monthly spend cap reached'
|
||||
message: remaining != null ? copy.monthlyRemaining(String(remaining)) : copy.monthlyReached,
|
||||
title: copy.monthlyReachedTitle
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,52 +107,50 @@ export const resolveRefusal = (refusal: BillingRefusal): BillingRefusalPresentat
|
||||
case 'temporarily_unavailable':
|
||||
return {
|
||||
action: { type: 'retry' },
|
||||
message: retryMessage(refusal),
|
||||
title: 'Too many charges right now'
|
||||
message: retryMessage(refusal, copy),
|
||||
title: copy.rateLimitedTitle
|
||||
}
|
||||
|
||||
case 'stripe_unavailable':
|
||||
return {
|
||||
action: { type: 'retry' },
|
||||
message: stripeRetryMessage(refusal),
|
||||
title: 'Stripe is having trouble'
|
||||
message: stripeRetryMessage(refusal, copy),
|
||||
title: copy.stripeTitle
|
||||
}
|
||||
|
||||
case 'upgrade_cap_exceeded':
|
||||
return {
|
||||
action: { type: 'none' },
|
||||
message: 'Daily plan-change limit reached — try again tomorrow',
|
||||
title: 'Daily plan-change limit reached'
|
||||
message: copy.dailyLimitMessage,
|
||||
title: copy.dailyLimitTitle
|
||||
}
|
||||
|
||||
case 'endpoint_unavailable':
|
||||
return {
|
||||
action: { type: 'retry' },
|
||||
message:
|
||||
refusal.message ||
|
||||
'Billing endpoint returned a non-JSON response (it may not be available on this deployment).',
|
||||
title: 'Billing endpoint unavailable'
|
||||
message: refusal.message || copy.endpointMessage,
|
||||
title: copy.endpointTitle
|
||||
}
|
||||
|
||||
case 'timeout':
|
||||
return {
|
||||
action: { type: 'retry' },
|
||||
message: refusal.message || 'Billing request timed out.',
|
||||
title: 'Billing request timed out'
|
||||
message: refusal.message || copy.requestTimeoutMessage,
|
||||
title: copy.requestTimeoutTitle
|
||||
}
|
||||
|
||||
case 'transport':
|
||||
return {
|
||||
action: { type: 'retry' },
|
||||
message: refusal.message || 'Billing request failed before reaching the gateway.',
|
||||
title: 'Billing connection failed'
|
||||
message: refusal.message || copy.connectionFailedMessage,
|
||||
title: copy.connectionFailedTitle
|
||||
}
|
||||
|
||||
default:
|
||||
return {
|
||||
action: { type: 'none' },
|
||||
message: refusal.message || 'Billing request failed.',
|
||||
title: 'Billing request failed'
|
||||
message: refusal.message || copy.requestFailedMessage,
|
||||
title: copy.requestFailedTitle
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user