feat: second header checkbox for bulk subscription selection

Add green checkbox in table header next to the user checkbox for
mass-selecting all visible subscriptions. Shows filled/partial/empty
states matching user checkbox pattern. Only visible in multi-tariff
mode. Wider select column (56px) to fit both checkboxes.
This commit is contained in:
Fringg
2026-04-24 07:03:53 +03:00
parent 3cb15177cc
commit eeda567622

View File

@@ -1756,28 +1756,56 @@ export default function AdminBulkActions() {
() => [ () => [
{ {
id: 'select', id: 'select',
size: 40, size: 56,
header: ({ table }) => ( header: ({ table }) => {
<div className="flex items-center justify-center"> const allSubsSelected =
<button allVisibleSubscriptionIds.length > 0 &&
onClick={table.getToggleAllRowsSelectedHandler()} allVisibleSubscriptionIds.every((id) => subscriptionSelection[id]);
className={cn( const someSubsSelected =
'flex h-5 w-5 items-center justify-center rounded-md border-2 transition-all duration-150', !allSubsSelected && allVisibleSubscriptionIds.some((id) => subscriptionSelection[id]);
table.getIsAllRowsSelected() return (
? 'border-accent-500 bg-accent-500 shadow-[0_0_8px_rgba(var(--color-accent-500),0.4)]' <div className="flex items-center justify-center gap-1.5">
: table.getIsSomeRowsSelected() {/* Select all users */}
? 'border-accent-500 bg-accent-500/30' <button
: 'border-dark-500 bg-dark-700/60 hover:border-accent-500/50 hover:bg-dark-600/60', onClick={table.getToggleAllRowsSelectedHandler()}
className={cn(
'flex h-5 w-5 items-center justify-center rounded-md border-2 transition-all duration-150',
table.getIsAllRowsSelected()
? 'border-accent-500 bg-accent-500 shadow-[0_0_8px_rgba(var(--color-accent-500),0.4)]'
: table.getIsSomeRowsSelected()
? 'border-accent-500 bg-accent-500/30'
: 'border-dark-500 bg-dark-700/60 hover:border-accent-500/50 hover:bg-dark-600/60',
)}
aria-label={t('admin.bulkActions.selectAll')}
title={t('admin.bulkActions.selectAll')}
>
{table.getIsAllRowsSelected() && <CheckIcon />}
{table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected() && (
<div className="h-0.5 w-2 rounded-full bg-white" />
)}
</button>
{/* Select all subscriptions */}
{isMultiTariff && allVisibleSubscriptionIds.length > 0 && (
<button
onClick={toggleAllSubscriptions}
className={cn(
'flex h-5 w-5 items-center justify-center rounded-md border-2 transition-all duration-150',
allSubsSelected
? 'border-success-500 bg-success-500 shadow-[0_0_8px_rgba(34,197,94,0.4)]'
: someSubsSelected
? 'border-success-500 bg-success-500/30'
: 'border-dark-500 bg-dark-700/60 hover:border-success-500/50 hover:bg-dark-600/60',
)}
aria-label={t('admin.bulkActions.selectAllSubs')}
title={t('admin.bulkActions.selectAllSubs')}
>
{allSubsSelected && <CheckIcon />}
{someSubsSelected && <div className="h-0.5 w-2 rounded-full bg-white" />}
</button>
)} )}
aria-label={t('admin.bulkActions.selectAll')} </div>
> );
{table.getIsAllRowsSelected() && <CheckIcon />} },
{table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected() && (
<div className="h-0.5 w-2 rounded-full bg-white" />
)}
</button>
</div>
),
cell: ({ row }) => { cell: ({ row }) => {
const userName = const userName =
row.original.full_name || row.original.username || String(row.original.telegram_id); row.original.full_name || row.original.username || String(row.original.telegram_id);