Skip to content

Commit b3ab2a7

Browse files
committed
feat(users-table): add QR code button to default view of action buttons and adjust layout for improved user experience
1 parent 0178eb2 commit b3ab2a7

File tree

3 files changed

+40
-34
lines changed

3 files changed

+40
-34
lines changed

dashboard/src/components/users/action-buttons.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,18 @@ const ActionButtons: FC<ActionButtonsProps> = ({ user, isModalHost = true, rende
676676
</DropdownMenu>
677677
<TooltipContent>{copied ? t('usersTable.copied') : t('usersTable.copyConfigs')}</TooltipContent>
678678
</Tooltip>
679+
<Tooltip>
680+
<TooltipTrigger asChild>
681+
<div>
682+
<Button type="button" size="icon" variant="ghost" aria-label={t('qrcodeDialog.title')} onClick={onOpenSubscriptionModal}>
683+
<QrCode className='h-4 w-4' />
684+
</Button>
685+
</div>
686+
</TooltipTrigger>
687+
<TooltipContent>
688+
{t('qrcodeDialog.title')}
689+
</TooltipContent>
690+
</Tooltip>
679691
</TooltipProvider>
680692
<DropdownMenu modal={false} open={isActionsMenuOpen} onOpenChange={setActionsMenuOpen}>
681693
<DropdownMenuTrigger asChild>
@@ -695,12 +707,6 @@ const ActionButtons: FC<ActionButtonsProps> = ({ user, isModalHost = true, rende
695707
<span>{t('edit')}</span>
696708
</DropdownMenuItem>
697709

698-
{/* QR Code */}
699-
<DropdownMenuItem onSelect={onOpenSubscriptionModal}>
700-
<QrCode className="mr-2 h-4 w-4" />
701-
<span>{t('qrcodeDialog.title')}</span>
702-
</DropdownMenuItem>
703-
704710
{/* Set Owner: only for sudo admins */}
705711
{currentAdmin?.is_sudo && (
706712
<DropdownMenuItem onSelect={handleSetOwner}>

dashboard/src/components/users/columns.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,9 @@ export const setupColumns = ({
224224
)
225225
},
226226
cell: ({ row }: { row: Row<UserResponse> }) => (
227-
<div className="flex max-w-[420px] py-1 items-center justify-between gap-1">
227+
<div className="flex py-1 items-center justify-between gap-1">
228228
<UsageSliderCompact total={row.original.data_limit} used={row.original.used_traffic} totalUsedTraffic={row.original.lifetime_used_traffic} status={row.original.status} />
229-
<div className="hidden w-[188px] px-2 py-1 md:block">
229+
<div className="hidden w-[215px] px-2 py-1 md:block">
230230
<ActionButtons user={row.original} isModalHost={false} />
231231
</div>
232232
</div>

dashboard/src/components/users/data-table.tsx

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,23 @@ interface DataTableProps<TData extends UserResponse, TValue> {
2222
}
2323

2424
const ExpandedRowContent = memo(({ row }: { row: { original: UserResponse } }) => (
25-
<div className="flex flex-col gap-y-4 p-4">
25+
<div className="flex flex-col gap-y-4 p-4 border-b">
2626
<UsageSliderCompact isMobile status={row.original.status} total={row.original.data_limit} totalUsedTraffic={row.original.lifetime_used_traffic} used={row.original.used_traffic} />
2727
<div className="flex flex-col gap-y-2">
28-
<div className="flex items-center justify-between">
29-
<div className="flex items-center">
30-
<StatusBadge showOnlyExpiry expiryDate={row.original.expire} status={row.original.status} showExpiry />
31-
</div>
28+
<div className="flex items-center justify-end">
3229
<div onClick={e => e.stopPropagation()}>
3330
<ActionButtons user={row.original} isModalHost={false} />
3431
</div>
3532
</div>
36-
<div className="flex items-center gap-x-1">
37-
<span className="flex items-center gap-x-0.5">
38-
<Rss className="h-3 w-3 text-muted-foreground" />
39-
<span className="text-muted-foreground">:</span>
40-
</span>
41-
<OnlineStatus lastOnline={row.original.online_at} />
33+
<div className="flex flex-col gap-1.5">
34+
<StatusBadge showOnlyExpiry expiryDate={row.original.expire} status={row.original.status} showExpiry />
35+
<div className="flex items-center gap-x-1">
36+
<span className="flex items-center gap-x-0.5">
37+
<Rss className="h-3 w-3 text-muted-foreground" />
38+
<span className="text-muted-foreground">:</span>
39+
</span>
40+
<OnlineStatus lastOnline={row.original.online_at} />
41+
</div>
4242
</div>
4343
</div>
4444
</div>
@@ -152,7 +152,7 @@ export const DataTable = memo(<TData extends UserResponse, TValue>({ columns, da
152152
header.id === 'select' && 'w-8 !px-1 py-1.5',
153153
header.id === 'username' && 'w-auto md:w-auto',
154154
header.id === 'status' && 'max-w-[70px] !px-0 md:w-auto',
155-
header.id === 'details' && 'px-1 md:w-[450px]',
155+
header.id === 'details' && 'px-1 md:w-[440px]',
156156
!['select', 'username', 'status', 'details', 'chevron'].includes(header.id) && 'hidden md:table-cell',
157157
header.id === 'chevron' && 'table-cell md:hidden',
158158
)}
@@ -168,16 +168,16 @@ export const DataTable = memo(<TData extends UserResponse, TValue>({ columns, da
168168
? LoadingState
169169
: table.getRowModel().rows?.length
170170
? table.getRowModel().rows.map(row => {
171-
const isRowSelected = row.getIsSelected()
171+
const isRowSelected = row.getIsSelected()
172172

173-
return (
173+
return (
174174
<React.Fragment key={row.id}>
175-
<TableRow
176-
className={cn(
177-
'cursor-pointer border-b md:cursor-default',
178-
179-
expandedRow === row.original.id && 'border-transparent',
180-
)}
175+
<TableRow
176+
className={cn(
177+
'cursor-pointer border-b md:cursor-default',
178+
179+
expandedRow === row.original.id && 'border-transparent',
180+
)}
181181
onClick={e => handleEditModal(e, row.original)}
182182
data-state={isRowSelected ? 'selected' : undefined}
183183
>
@@ -192,8 +192,7 @@ export const DataTable = memo(<TData extends UserResponse, TValue>({ columns, da
192192
cell.column.id !== 'details' && 'py-1.5',
193193
cell.column.id === 'username' && cn('max-w-[calc(100vw-50px-32px-100px-60px)]', hasSelectionColumn && '!px-0'),
194194
cell.column.id === "status" && '!px-0',
195-
cell.column.id === 'details' && 'max-w-full !px-1 md:w-[450px]',
196-
cell.column.id === 'select' && 'w-8 !px-1',
195+
cell.column.id === 'select' && 'w-8 !px-1 !py-5',
197196
cell.column.id === 'chevron' && 'w-4 !p-0',
198197
!['select', 'username', 'status', 'details', 'chevron'].includes(cell.column.id) && 'hidden !p-0 md:table-cell',
199198
cell.column.id === 'chevron' && 'table-cell md:hidden',
@@ -208,7 +207,7 @@ export const DataTable = memo(<TData extends UserResponse, TValue>({ columns, da
208207
handleRowToggle(row.original.id)
209208
}}
210209
>
211-
<ChevronDown className={cn('h-3 w-3', expandedRow === row.original.id && 'rotate-180')} />
210+
<ChevronDown className={cn('h-3.5 w-3.5', expandedRow === row.original.id && 'rotate-180')} />
212211
</div>
213212
) : (
214213
flexRender(cell.column.columnDef.cell, cell.getContext())
@@ -217,14 +216,15 @@ export const DataTable = memo(<TData extends UserResponse, TValue>({ columns, da
217216
))}
218217
</TableRow>
219218
{expandedRow === row.original.id && (
220-
<TableRow className={cn('border-b md:hidden', 'border-transparent')} data-state={isRowSelected ? 'selected' : undefined}>
221-
<TableCell colSpan={columns.length} className={cn('p-0 text-sm', )}>
219+
<TableRow className={cn('border-b md:hidden', 'border-transparent')} data-state={isRowSelected ? 'selected' : undefined}>
220+
<TableCell colSpan={columns.length} className={cn('p-0 text-sm',)}>
222221
<ExpandedRowContent row={row} />
223222
</TableCell>
224223
</TableRow>
225224
)}
226225
</React.Fragment>
227-
)})
226+
)
227+
})
228228
: EmptyState}
229229
</TableBody>
230230
</Table>

0 commit comments

Comments
 (0)