mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-06 17:46:23 +00:00
fix: align dynamic pricing style with log details dialog sections
This commit is contained in:
+58
-13
@@ -59,6 +59,11 @@ type DynamicPricingBreakdownProps = {
|
|||||||
* call they are inspecting. Defaults to false (show all configured prices).
|
* call they are inspecting. Defaults to false (show all configured prices).
|
||||||
*/
|
*/
|
||||||
hideCacheColumns?: boolean
|
hideCacheColumns?: boolean
|
||||||
|
/**
|
||||||
|
* Dense rendering for the usage-log details dialog: drops the colored
|
||||||
|
* icon header and uses the dialog's small text sizes. Defaults to false.
|
||||||
|
*/
|
||||||
|
compact?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const VAR_LABELS: Record<string, string> = {
|
const VAR_LABELS: Record<string, string> = {
|
||||||
@@ -152,6 +157,7 @@ export function DynamicPricingBreakdown({
|
|||||||
billingExpr,
|
billingExpr,
|
||||||
matchedTierLabel,
|
matchedTierLabel,
|
||||||
hideCacheColumns = false,
|
hideCacheColumns = false,
|
||||||
|
compact = false,
|
||||||
}: DynamicPricingBreakdownProps) {
|
}: DynamicPricingBreakdownProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const expr = billingExpr || ''
|
const expr = billingExpr || ''
|
||||||
@@ -190,7 +196,8 @@ export function DynamicPricingBreakdown({
|
|||||||
|
|
||||||
if (!hasTiers) {
|
if (!hasTiers) {
|
||||||
return (
|
return (
|
||||||
<section className='min-w-0 py-4'>
|
<section className={cn('min-w-0', !compact && 'py-4')}>
|
||||||
|
{!compact && (
|
||||||
<div className='mb-3 flex items-center gap-2'>
|
<div className='mb-3 flex items-center gap-2'>
|
||||||
<span className='inline-flex size-6 items-center justify-center rounded-lg bg-amber-100 text-amber-700 shadow-sm dark:bg-amber-500/20 dark:text-amber-300'>
|
<span className='inline-flex size-6 items-center justify-center rounded-lg bg-amber-100 text-amber-700 shadow-sm dark:bg-amber-500/20 dark:text-amber-300'>
|
||||||
<TagIcon className='size-3.5' />
|
<TagIcon className='size-3.5' />
|
||||||
@@ -204,6 +211,7 @@ export function DynamicPricingBreakdown({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
<div className='text-muted-foreground mb-1 text-[10px] font-medium tracking-wider uppercase'>
|
<div className='text-muted-foreground mb-1 text-[10px] font-medium tracking-wider uppercase'>
|
||||||
{t('Raw expression')}
|
{t('Raw expression')}
|
||||||
</div>
|
</div>
|
||||||
@@ -223,7 +231,8 @@ export function DynamicPricingBreakdown({
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className='min-w-0 py-3 sm:py-4'>
|
<section className={cn('min-w-0', !compact && 'py-3 sm:py-4')}>
|
||||||
|
{!compact && (
|
||||||
<div className='mb-3 flex items-start gap-2 sm:mb-4'>
|
<div className='mb-3 flex items-start gap-2 sm:mb-4'>
|
||||||
<span className='mt-0.5 inline-flex size-6 items-center justify-center rounded-lg bg-amber-100 text-amber-700 shadow-sm dark:bg-amber-500/20 dark:text-amber-300'>
|
<span className='mt-0.5 inline-flex size-6 items-center justify-center rounded-lg bg-amber-100 text-amber-700 shadow-sm dark:bg-amber-500/20 dark:text-amber-300'>
|
||||||
<TagIcon className='size-3.5' />
|
<TagIcon className='size-3.5' />
|
||||||
@@ -237,10 +246,17 @@ export function DynamicPricingBreakdown({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{hasTiers && (
|
{hasTiers && (
|
||||||
<div className='mb-3 sm:mb-4'>
|
<div className={cn(compact ? cn(hasRules && 'mb-2') : 'mb-3 sm:mb-4')}>
|
||||||
<div className='text-foreground mb-2 text-sm font-semibold'>
|
<div
|
||||||
|
className={
|
||||||
|
compact
|
||||||
|
? 'text-muted-foreground mb-1.5 text-xs font-medium'
|
||||||
|
: 'text-foreground mb-2 text-sm font-semibold'
|
||||||
|
}
|
||||||
|
>
|
||||||
{t('Tiered price table')}
|
{t('Tiered price table')}
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-1.5 sm:hidden'>
|
<div className='space-y-1.5 sm:hidden'>
|
||||||
@@ -289,7 +305,12 @@ export function DynamicPricingBreakdown({
|
|||||||
<div className='text-muted-foreground truncate text-[10px] font-medium tracking-wider uppercase'>
|
<div className='text-muted-foreground truncate text-[10px] font-medium tracking-wider uppercase'>
|
||||||
{t(v.shortLabel)}
|
{t(v.shortLabel)}
|
||||||
</div>
|
</div>
|
||||||
<div className='truncate font-mono text-sm font-semibold'>
|
<div
|
||||||
|
className={cn(
|
||||||
|
'truncate font-mono',
|
||||||
|
compact ? 'text-xs' : 'text-sm font-semibold'
|
||||||
|
)}
|
||||||
|
>
|
||||||
{value > 0
|
{value > 0
|
||||||
? `${symbol}${(value * rate).toFixed(4)}`
|
? `${symbol}${(value * rate).toFixed(4)}`
|
||||||
: '-'}
|
: '-'}
|
||||||
@@ -304,7 +325,11 @@ export function DynamicPricingBreakdown({
|
|||||||
</div>
|
</div>
|
||||||
<StaticDataTable
|
<StaticDataTable
|
||||||
className='hidden rounded-none border-0 sm:block'
|
className='hidden rounded-none border-0 sm:block'
|
||||||
tableClassName='text-sm'
|
tableClassName={
|
||||||
|
compact
|
||||||
|
? '[&_td]:text-xs [&_td_*]:text-xs [&_th]:text-xs [&_th_*]:text-xs'
|
||||||
|
: 'text-sm'
|
||||||
|
}
|
||||||
headerRowClassName='hover:bg-transparent'
|
headerRowClassName='hover:bg-transparent'
|
||||||
data={tiers}
|
data={tiers}
|
||||||
getRowKey={(_tier, index) => `tier-${index}`}
|
getRowKey={(_tier, index) => `tier-${index}`}
|
||||||
@@ -321,8 +346,11 @@ export function DynamicPricingBreakdown({
|
|||||||
{
|
{
|
||||||
id: 'tier',
|
id: 'tier',
|
||||||
header: t('Tier'),
|
header: t('Tier'),
|
||||||
className: 'text-muted-foreground py-2 font-medium',
|
className: cn(
|
||||||
cellClassName: 'py-2.5 align-top',
|
'text-muted-foreground py-2 font-medium',
|
||||||
|
compact && 'h-8'
|
||||||
|
),
|
||||||
|
cellClassName: cn('align-top', compact ? 'py-2' : 'py-2.5'),
|
||||||
cell: (tier) => {
|
cell: (tier) => {
|
||||||
const condSummary = formatConditionSummary(tier.conditions, t)
|
const condSummary = formatConditionSummary(tier.conditions, t)
|
||||||
const isMatched =
|
const isMatched =
|
||||||
@@ -359,14 +387,20 @@ export function DynamicPricingBreakdown({
|
|||||||
...visiblePriceFields.map((v, index) => ({
|
...visiblePriceFields.map((v, index) => ({
|
||||||
id: v.field ?? `price-${index}`,
|
id: v.field ?? `price-${index}`,
|
||||||
header: t(v.shortLabel),
|
header: t(v.shortLabel),
|
||||||
className: 'text-muted-foreground py-2 text-right font-medium',
|
className: cn(
|
||||||
cellClassName: 'py-2.5 text-right align-top font-mono',
|
'text-muted-foreground py-2 text-right font-medium',
|
||||||
|
compact && 'h-8'
|
||||||
|
),
|
||||||
|
cellClassName: cn(
|
||||||
|
'text-right align-top font-mono',
|
||||||
|
compact ? 'py-2' : 'py-2.5'
|
||||||
|
),
|
||||||
cell: (tier: ParsedTier) => {
|
cell: (tier: ParsedTier) => {
|
||||||
const value = Number(
|
const value = Number(
|
||||||
tier[v.field as string as keyof ParsedTier] || 0
|
tier[v.field as string as keyof ParsedTier] || 0
|
||||||
)
|
)
|
||||||
return value > 0 ? (
|
return value > 0 ? (
|
||||||
<span className='font-semibold'>
|
<span className={cn(!compact && 'font-semibold')}>
|
||||||
{`${symbol}${(value * rate).toFixed(4)}`}
|
{`${symbol}${(value * rate).toFixed(4)}`}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
@@ -381,7 +415,13 @@ export function DynamicPricingBreakdown({
|
|||||||
|
|
||||||
{hasRules && (
|
{hasRules && (
|
||||||
<div>
|
<div>
|
||||||
<div className='text-foreground mb-2 text-sm font-semibold'>
|
<div
|
||||||
|
className={
|
||||||
|
compact
|
||||||
|
? 'text-muted-foreground mb-1.5 text-xs font-medium'
|
||||||
|
: 'text-foreground mb-2 text-sm font-semibold'
|
||||||
|
}
|
||||||
|
>
|
||||||
{t('Conditional multipliers')}
|
{t('Conditional multipliers')}
|
||||||
</div>
|
</div>
|
||||||
<ul className='space-y-1.5'>
|
<ul className='space-y-1.5'>
|
||||||
@@ -390,7 +430,12 @@ export function DynamicPricingBreakdown({
|
|||||||
key={`group-${gi}`}
|
key={`group-${gi}`}
|
||||||
className='bg-muted/50 flex items-center justify-between gap-3 rounded-md px-3 py-2'
|
className='bg-muted/50 flex items-center justify-between gap-3 rounded-md px-3 py-2'
|
||||||
>
|
>
|
||||||
<span className='text-foreground text-sm break-all'>
|
<span
|
||||||
|
className={cn(
|
||||||
|
'text-foreground break-all',
|
||||||
|
compact ? 'text-xs' : 'text-sm'
|
||||||
|
)}
|
||||||
|
>
|
||||||
{describeGroup(group, t)}
|
{describeGroup(group, t)}
|
||||||
</span>
|
</span>
|
||||||
<Badge
|
<Badge
|
||||||
|
|||||||
@@ -966,13 +966,14 @@ export function DetailsDialog(props: DetailsDialogProps) {
|
|||||||
|
|
||||||
{/* Tiered pricing breakdown (when billing_mode is tiered_expr) */}
|
{/* Tiered pricing breakdown (when billing_mode is tiered_expr) */}
|
||||||
{isTieredBilling && other?.expr_b64 && (
|
{isTieredBilling && other?.expr_b64 && (
|
||||||
<div className='bg-muted/30 min-w-0 overflow-hidden rounded-md border px-3 max-sm:px-2'>
|
<DetailSection label={t('Dynamic Pricing')}>
|
||||||
<DynamicPricingBreakdown
|
<DynamicPricingBreakdown
|
||||||
|
compact
|
||||||
billingExpr={decodeBillingExprB64(other.expr_b64)}
|
billingExpr={decodeBillingExprB64(other.expr_b64)}
|
||||||
matchedTierLabel={other.matched_tier}
|
matchedTierLabel={other.matched_tier}
|
||||||
hideCacheColumns={!hasAnyCacheTokens(other)}
|
hideCacheColumns={!hasAnyCacheTokens(other)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</DetailSection>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Admin billing mode indicator for non-consume */}
|
{/* Admin billing mode indicator for non-consume */}
|
||||||
|
|||||||
Reference in New Issue
Block a user