diff --git a/dashboard/package.json b/dashboard/package.json
@@ -68,6 +68,7 @@
"lucide-react": "^0.359.0",
"next-themes": "^0.3.0",
"ofetch": "^1.3.3",
+ "pretty-bytes": "^6.1.1",
"react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0",
"react-day-picker": "^8.10.0",
diff --git a/dashboard/pnpm-lock.yaml b/dashboard/pnpm-lock.yaml
@@ -164,6 +164,9 @@ dependencies:
ofetch:
specifier: ^1.3.3
version: 1.3.3
+ pretty-bytes:
+ specifier: ^6.1.1
+ version: 6.1.1
react:
specifier: ^18.2.0
version: 18.2.0
@@ -8598,6 +8601,11 @@ packages:
hasBin: true
dev: true
+ /pretty-bytes@6.1.1:
+ resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
+ engines: {node: ^14.13.1 || >=16.0.0}
+ dev: false
+
/pretty-format@27.5.1:
resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
diff --git a/dashboard/src/features/users/components/index.ts b/dashboard/src/features/users/components/index.ts
@@ -2,3 +2,4 @@ export * from './users-status'
export * from './services-card'
export * from './date-field'
export * from './online-status'
+export * from './used-user-traffic'
diff --git a/dashboard/src/features/users/components/used-user-traffic.tsx b/dashboard/src/features/users/components/used-user-traffic.tsx
@@ -0,0 +1,33 @@
+import { FC } from 'react'
+import { UserType } from '@marzneshin/features/users';
+import { CircularProgress } from '@nextui-org/progress';
+import prettyBytes from 'pretty-bytes';
+
+
+interface UserUsedTrafficProps {
+ user: UserType
+}
+
+export const UserUsedTraffic: FC<UserUsedTrafficProps> = (
+ { user }
+) => {
+ return (
+ user.data_limit ? (
+ <div className="flex gap-x-5 justify-start items-center">
+ <CircularProgress
+ value={user.used_traffic / user.data_limit * 100}
+ size='sm'
+ showValueLabel
+ />
+ <div>
+ <p className="text-sm font-medium text-gray-900 dark:text-gray-50">
+ {prettyBytes(user.used_traffic)}
+ </p>
+ <p className="text-sm text-gray-500 dark:text-gray-500">
+ {prettyBytes(user.data_limit)}
+ </p>
+ </div>
+ </div>
+ ) : ("No Traffic")
+ );
+}
diff --git a/dashboard/src/features/users/tables/users/columns.tsx b/dashboard/src/features/users/tables/users/columns.tsx
@@ -1,6 +1,12 @@
import { ColumnDef } from "@tanstack/react-table"
-import { UsersStatusBadge, UserType, UsersStatus, OnlineStatus } from "@marzneshin/features/users"
+import {
+ UsersStatusBadge,
+ UserType,
+ UsersStatus,
+ OnlineStatus,
+ UserUsedTraffic
+} from "@marzneshin/features/users"
import { DataTableColumnHeader } from "@marzneshin/components/data-table/column-header"
import i18n from "@marzneshin/features/i18n"
import {
@@ -8,11 +14,9 @@ import {
DataTableActionsCell,
buttonVariants
} from "@marzneshin/components"
-import { CircularProgress } from "@nextui-org/progress"
import { LinkIcon } from "lucide-react"
import { getSubscriptionLink } from "@marzneshin/utils"
-
interface ColumnAction {
onDelete: (user: UserType) => void;
onOpen: (user: UserType) => void;
@@ -40,30 +44,23 @@ export const columns = (actions: ColumnAction): ColumnDef<UserType>[] => ([
{
accessorKey: "used_traffic",
header: ({ column }) => <DataTableColumnHeader title={i18n.t('page.users.used_traffic')} column={column} />,
- cell: ({ row }) => {
- if (row.original.data_limit)
- return (
- <CircularProgress
- value={row.original.used_traffic / row.original.data_limit * 100}
- size='sm'
- showValueLabel
- />
- )
- else
- return "No Traffic"
- }
+ cell: ({ row }) => <UserUsedTraffic user={row.original} />
},
{
id: "actions",
- cell: ({ row }) => <div className="flex flex-row gap-2 items-center" onClick={(e) => e.stopPropagation()}>
- <CopyToClipboardButton
- text={getSubscriptionLink(row.original.subscription_url)}
- successMessage={i18n.t('page.users.settings.subscription_link.copied')}
- copyIcon={LinkIcon}
- className={buttonVariants({ variant: "ghost", className: "h-8 w-8" })}
- tooltipMsg={i18n.t('page.users.settings.subscription_link.copy')}
- />
- <DataTableActionsCell {...actions} row={row} />
- </div>
+ cell: ({ row }) => {
+ return (
+ <div className="flex flex-row gap-2 items-center" onClick={(e) => e.stopPropagation()}>
+ <CopyToClipboardButton
+ text={getSubscriptionLink(row.original.subscription_url)}
+ successMessage={i18n.t('page.users.settings.subscription_link.copied')}
+ copyIcon={LinkIcon}
+ className={buttonVariants({ variant: "ghost", className: "h-8 w-8" })}
+ tooltipMsg={i18n.t('page.users.settings.subscription_link.copy')}
+ />
+ <DataTableActionsCell {...actions} row={row} />
+ </div>
+ )
+ }
},
]);