192 lines
5.8 KiB
TypeScript
Vendored
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]
|
|
)
|
|
}
|