new-api/web/default/src/features/subscriptions/components/subscriptions-columns.tsx

192 lines
5.8 KiB
TypeScript
Vendored

import { useMemo } from 'react'
import { type ColumnDef } from '@tanstack/react-table'
import { useTranslation } from 'react-i18next'
import { DataTableColumnHeader } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
import { StatusBadge } from '@/components/status-badge'
import { formatDuration, formatResetPeriod } from '../lib'
import type { PlanRecord } from '../types'
import { DataTableRowActions } from './data-table-row-actions'
export function useSubscriptionsColumns(): ColumnDef<PlanRecord>[] {
const { t } = useTranslation()
return useMemo(
(): ColumnDef<PlanRecord>[] => [
{
accessorFn: (row) => row.plan.id,
id: 'id',
meta: { label: 'ID', mobileHidden: true },
header: ({ column }) => (
<DataTableColumnHeader column={column} title='ID' />
),
cell: ({ row }) => (
<span className='text-muted-foreground'>#{row.original.plan.id}</span>
),
size: 60,
},
{
accessorFn: (row) => row.plan.title,
id: 'title',
meta: { label: t('Plan'), mobileTitle: true },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Plan')} />
),
cell: ({ row }) => {
const plan = row.original.plan
return (
<div className='max-w-[200px]'>
<div className='truncate font-medium'>{plan.title}</div>
{plan.subtitle && (
<div className='text-muted-foreground truncate text-xs'>
{plan.subtitle}
</div>
)}
</div>
)
},
size: 200,
},
{
accessorFn: (row) => row.plan.price_amount,
id: 'price',
meta: { label: t('Price') },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Price')} />
),
cell: ({ row }) => (
<span className='font-semibold text-emerald-600'>
${Number(row.original.plan.price_amount || 0).toFixed(2)}
</span>
),
size: 100,
},
{
id: 'duration',
meta: { label: t('Validity') },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Validity')} />
),
cell: ({ row }) => (
<span className='text-muted-foreground'>
{formatDuration(row.original.plan, t)}
</span>
),
size: 100,
},
{
id: 'reset',
meta: { label: t('Quota Reset'), mobileHidden: true },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Quota Reset')} />
),
cell: ({ row }) => (
<span className='text-muted-foreground'>
{formatResetPeriod(row.original.plan, t)}
</span>
),
size: 80,
},
{
accessorFn: (row) => row.plan.sort_order,
id: 'sort_order',
meta: { label: t('Priority'), mobileHidden: true },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Priority')} />
),
cell: ({ row }) => (
<span className='text-muted-foreground'>
{row.original.plan.sort_order}
</span>
),
size: 80,
},
{
accessorFn: (row) => row.plan.enabled,
id: 'enabled',
meta: { label: t('Status'), mobileBadge: true },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Status')} />
),
cell: ({ row }) =>
row.original.plan.enabled ? (
<StatusBadge
label={t('Enable')}
variant='success'
copyable={false}
/>
) : (
<StatusBadge
label={t('Disable')}
variant='neutral'
copyable={false}
/>
),
size: 80,
},
{
id: 'payment',
meta: { label: t('Payment Channel'), mobileHidden: true },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Payment Channel')} />
),
cell: ({ row }) => {
const plan = row.original.plan
return (
<div className='flex gap-1'>
{plan.stripe_price_id && (
<StatusBadge
label='Stripe'
variant='neutral'
copyable={false}
/>
)}
{plan.creem_product_id && (
<StatusBadge label='Creem' variant='neutral' copyable={false} />
)}
</div>
)
},
size: 140,
},
{
id: 'total_amount',
meta: { label: t('Total Quota'), mobileHidden: true },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Total Quota')} />
),
cell: ({ row }) => {
const total = Number(row.original.plan.total_amount || 0)
return (
<span className='text-muted-foreground'>
{total > 0 ? total : t('Unlimited')}
</span>
)
},
size: 100,
},
{
id: 'upgrade_group',
meta: { label: t('Upgrade Group'), mobileHidden: true },
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Upgrade Group')} />
),
cell: ({ row }) => {
const group = row.original.plan.upgrade_group
if (!group) {
return <span className='text-muted-foreground'>{t('No Upgrade')}</span>
}
return <GroupBadge group={group} />
},
size: 100,
},
{
id: 'actions',
cell: ({ row }) => <DataTableRowActions row={row} />,
size: 80,
},
],
[t]
)
}