diff --git a/apps/admin/app/dashboard/ads/page.tsx b/apps/admin/app/dashboard/ads/page.tsx index 640e35d..f586a27 100644 --- a/apps/admin/app/dashboard/ads/page.tsx +++ b/apps/admin/app/dashboard/ads/page.tsx @@ -2,11 +2,11 @@ import { ProTable, ProTableActions } from '@/components/pro-table'; import { createAds, deleteAds, getAdsList, updateAds } from '@/services/admin/ads'; +import { formatDate } from '@/utils/common'; import { Badge } from '@workspace/ui/components/badge'; import { Button } from '@workspace/ui/components/button'; import { Switch } from '@workspace/ui/components/switch'; import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useRef, useState } from 'react'; import { toast } from 'sonner'; diff --git a/apps/admin/app/dashboard/coupon/page.tsx b/apps/admin/app/dashboard/coupon/page.tsx index ff7d11a..dc99748 100644 --- a/apps/admin/app/dashboard/coupon/page.tsx +++ b/apps/admin/app/dashboard/coupon/page.tsx @@ -10,12 +10,12 @@ import { updateCoupon, } from '@/services/admin/coupon'; import { getSubscribeList } from '@/services/admin/subscribe'; +import { formatDate } from '@/utils/common'; import { useQuery } from '@tanstack/react-query'; import { Badge } from '@workspace/ui/components/badge'; import { Button } from '@workspace/ui/components/button'; import { Switch } from '@workspace/ui/components/switch'; import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useRef, useState } from 'react'; import { toast } from 'sonner'; diff --git a/apps/admin/app/dashboard/document/page.tsx b/apps/admin/app/dashboard/document/page.tsx index a45f68f..59e7892 100644 --- a/apps/admin/app/dashboard/document/page.tsx +++ b/apps/admin/app/dashboard/document/page.tsx @@ -8,10 +8,10 @@ import { getDocumentList, updateDocument, } from '@/services/admin/document'; +import { formatDate } from '@/utils/common'; import { Button } from '@workspace/ui/components/button'; import { Switch } from '@workspace/ui/components/switch'; import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useRef, useState } from 'react'; import { toast } from 'sonner'; diff --git a/apps/admin/app/dashboard/log/balance/page.tsx b/apps/admin/app/dashboard/log/balance/page.tsx index b40e797..4da735e 100644 --- a/apps/admin/app/dashboard/log/balance/page.tsx +++ b/apps/admin/app/dashboard/log/balance/page.tsx @@ -3,7 +3,7 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { ProTable } from '@/components/pro-table'; import { filterBalanceLog } from '@/services/admin/log'; -import { formatDate } from '@workspace/ui/utils'; +import { formatDate } from '@/utils/common'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/log/commission/page.tsx b/apps/admin/app/dashboard/log/commission/page.tsx index 52c4781..1b55bd4 100644 --- a/apps/admin/app/dashboard/log/commission/page.tsx +++ b/apps/admin/app/dashboard/log/commission/page.tsx @@ -3,7 +3,7 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { ProTable } from '@/components/pro-table'; import { filterCommissionLog } from '@/services/admin/log'; -import { formatDate } from '@workspace/ui/utils'; +import { formatDate } from '@/utils/common'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/log/email/page.tsx b/apps/admin/app/dashboard/log/email/page.tsx index bf48c02..7f5f1af 100644 --- a/apps/admin/app/dashboard/log/email/page.tsx +++ b/apps/admin/app/dashboard/log/email/page.tsx @@ -2,8 +2,8 @@ import { ProTable } from '@/components/pro-table'; import { filterEmailLog } from '@/services/admin/log'; +import { formatDate } from '@/utils/common'; import { Badge } from '@workspace/ui/components/badge'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/log/gift/page.tsx b/apps/admin/app/dashboard/log/gift/page.tsx index 00617b5..9f7451d 100644 --- a/apps/admin/app/dashboard/log/gift/page.tsx +++ b/apps/admin/app/dashboard/log/gift/page.tsx @@ -3,7 +3,7 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { ProTable } from '@/components/pro-table'; import { filterGiftLog } from '@/services/admin/log'; -import { formatDate } from '@workspace/ui/utils'; +import { formatDate } from '@/utils/common'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/log/login/page.tsx b/apps/admin/app/dashboard/log/login/page.tsx index a0bf69a..913a8ee 100644 --- a/apps/admin/app/dashboard/log/login/page.tsx +++ b/apps/admin/app/dashboard/log/login/page.tsx @@ -4,8 +4,8 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { IpLink } from '@/components/ip-link'; import { ProTable } from '@/components/pro-table'; import { filterLoginLog } from '@/services/admin/log'; +import { formatDate } from '@/utils/common'; import { Badge } from '@workspace/ui/components/badge'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/log/mobile/page.tsx b/apps/admin/app/dashboard/log/mobile/page.tsx index 13c9d3a..6981389 100644 --- a/apps/admin/app/dashboard/log/mobile/page.tsx +++ b/apps/admin/app/dashboard/log/mobile/page.tsx @@ -2,8 +2,8 @@ import { ProTable } from '@/components/pro-table'; import { filterMobileLog } from '@/services/admin/log'; +import { formatDate } from '@/utils/common'; import { Badge } from '@workspace/ui/components/badge'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; export default function MobileLogPage() { diff --git a/apps/admin/app/dashboard/log/register/page.tsx b/apps/admin/app/dashboard/log/register/page.tsx index 48bc083..3456a95 100644 --- a/apps/admin/app/dashboard/log/register/page.tsx +++ b/apps/admin/app/dashboard/log/register/page.tsx @@ -4,7 +4,7 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { IpLink } from '@/components/ip-link'; import { ProTable } from '@/components/pro-table'; import { filterRegisterLog } from '@/services/admin/log'; -import { formatDate } from '@workspace/ui/utils'; +import { formatDate } from '@/utils/common'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/log/reset-subscribe/page.tsx b/apps/admin/app/dashboard/log/reset-subscribe/page.tsx index 46348ed..77cae4d 100644 --- a/apps/admin/app/dashboard/log/reset-subscribe/page.tsx +++ b/apps/admin/app/dashboard/log/reset-subscribe/page.tsx @@ -3,7 +3,7 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { ProTable } from '@/components/pro-table'; import { filterResetSubscribeLog } from '@/services/admin/log'; -import { formatDate } from '@workspace/ui/utils'; +import { formatDate } from '@/utils/common'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/log/subscribe/page.tsx b/apps/admin/app/dashboard/log/subscribe/page.tsx index aedea22..f4266c6 100644 --- a/apps/admin/app/dashboard/log/subscribe/page.tsx +++ b/apps/admin/app/dashboard/log/subscribe/page.tsx @@ -4,7 +4,7 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { IpLink } from '@/components/ip-link'; import { ProTable } from '@/components/pro-table'; import { filterSubscribeLog } from '@/services/admin/log'; -import { formatDate } from '@workspace/ui/utils'; +import { formatDate } from '@/utils/common'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/log/traffic-details/page.tsx b/apps/admin/app/dashboard/log/traffic-details/page.tsx index 2e24b57..14df1ca 100644 --- a/apps/admin/app/dashboard/log/traffic-details/page.tsx +++ b/apps/admin/app/dashboard/log/traffic-details/page.tsx @@ -3,7 +3,8 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { ProTable } from '@/components/pro-table'; import { filterTrafficLogDetails } from '@/services/admin/log'; -import { formatBytes, formatDate } from '@workspace/ui/utils'; +import { formatDate } from '@/utils/common'; +import { formatBytes } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/marketing/email/task-manager.tsx b/apps/admin/app/dashboard/marketing/email/task-manager.tsx index 2da2509..2ee6f98 100644 --- a/apps/admin/app/dashboard/marketing/email/task-manager.tsx +++ b/apps/admin/app/dashboard/marketing/email/task-manager.tsx @@ -6,6 +6,7 @@ import { getBatchSendEmailTaskStatus, stopBatchSendEmailTask, } from '@/services/admin/marketing'; +import { formatDate } from '@/utils/common'; import { Badge } from '@workspace/ui/components/badge'; import { Button } from '@workspace/ui/components/button'; import { @@ -24,7 +25,6 @@ import { SheetTrigger, } from '@workspace/ui/components/sheet'; import { Icon } from '@workspace/ui/custom-components/icon'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useState } from 'react'; import { toast } from 'sonner'; diff --git a/apps/admin/app/dashboard/order/page.tsx b/apps/admin/app/dashboard/order/page.tsx index 40cf094..c05b79b 100644 --- a/apps/admin/app/dashboard/order/page.tsx +++ b/apps/admin/app/dashboard/order/page.tsx @@ -9,13 +9,13 @@ import { Display } from '@/components/display'; import { ProTable, ProTableActions } from '@/components/pro-table'; import { getOrderList, updateOrderStatus } from '@/services/admin/order'; import { getSubscribeList } from '@/services/admin/subscribe'; +import { formatDate } from '@/utils/common'; import { Badge } from '@workspace/ui/components/badge'; import { Button } from '@workspace/ui/components/button'; import { HoverCard, HoverCardContent, HoverCardTrigger } from '@workspace/ui/components/hover-card'; import { Separator } from '@workspace/ui/components/separator'; import { Combobox } from '@workspace/ui/custom-components/combobox'; import { cn } from '@workspace/ui/lib/utils'; -import { formatDate } from '@workspace/ui/utils'; import { UserDetail } from '../user/user-detail'; export default function Page() { diff --git a/apps/admin/app/dashboard/servers/online-users-cell.tsx b/apps/admin/app/dashboard/servers/online-users-cell.tsx index 82bddb9..e5071d5 100644 --- a/apps/admin/app/dashboard/servers/online-users-cell.tsx +++ b/apps/admin/app/dashboard/servers/online-users-cell.tsx @@ -4,6 +4,7 @@ import { UserDetail } from '@/app/dashboard/user/user-detail'; import { IpLink } from '@/components/ip-link'; import { ProTable } from '@/components/pro-table'; import { getUserSubscribeById } from '@/services/admin/user'; +import { formatDate } from '@/utils/common'; import { useQuery } from '@tanstack/react-query'; import { Badge } from '@workspace/ui/components/badge'; import { @@ -13,7 +14,7 @@ import { SheetTitle, SheetTrigger, } from '@workspace/ui/components/sheet'; -import { formatBytes, formatDate } from '@workspace/ui/utils'; +import { formatBytes } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useState } from 'react'; @@ -113,7 +114,7 @@ export default function OnlineUsersCell({ status }: { status?: API.ServerStatus {ips.map((item, i) => (
{item.protocol} - +
))} diff --git a/apps/admin/app/dashboard/ticket/page.tsx b/apps/admin/app/dashboard/ticket/page.tsx index 9358fdf..418365c 100644 --- a/apps/admin/app/dashboard/ticket/page.tsx +++ b/apps/admin/app/dashboard/ticket/page.tsx @@ -7,6 +7,7 @@ import { getTicketList, updateTicketStatus, } from '@/services/admin/ticket'; +import { formatDate } from '@/utils/common'; import { useQuery } from '@tanstack/react-query'; import { Button } from '@workspace/ui/components/button'; import { @@ -23,7 +24,6 @@ import { ScrollArea } from '@workspace/ui/components/scroll-area'; import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button'; import { Icon } from '@workspace/ui/custom-components/icon'; import { cn } from '@workspace/ui/lib/utils'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useEffect, useRef, useState } from 'react'; import { toast } from 'sonner'; diff --git a/apps/admin/app/dashboard/tool/page.tsx b/apps/admin/app/dashboard/tool/page.tsx index 96372b7..8ec24b7 100644 --- a/apps/admin/app/dashboard/tool/page.tsx +++ b/apps/admin/app/dashboard/tool/page.tsx @@ -1,6 +1,7 @@ 'use client'; import { getSystemLog, getVersion, restartSystem } from '@/services/admin/tool'; +import { formatDate } from '@/utils/common'; import { useQuery } from '@tanstack/react-query'; import { Accordion, @@ -29,7 +30,6 @@ import { } from '@workspace/ui/components/card'; import { ScrollArea } from '@workspace/ui/components/scroll-area'; import { Icon } from '@workspace/ui/custom-components/icon'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { useState } from 'react'; import packageJson from '../../../../../package.json'; diff --git a/apps/admin/app/dashboard/user/page.tsx b/apps/admin/app/dashboard/user/page.tsx index 58c3c67..fe2eb31 100644 --- a/apps/admin/app/dashboard/user/page.tsx +++ b/apps/admin/app/dashboard/user/page.tsx @@ -10,6 +10,7 @@ import { getUserList, updateUserBasicInfo, } from '@/services/admin/user'; +import { formatDate } from '@/utils/common'; import { useQuery } from '@tanstack/react-query'; import { Badge } from '@workspace/ui/components/badge'; import { Button } from '@workspace/ui/components/button'; @@ -30,7 +31,6 @@ import { import { Switch } from '@workspace/ui/components/switch'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs'; import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import Link from 'next/link'; import { useSearchParams } from 'next/navigation'; diff --git a/apps/admin/app/dashboard/user/user-detail.tsx b/apps/admin/app/dashboard/user/user-detail.tsx index 931df09..fe6ba2d 100644 --- a/apps/admin/app/dashboard/user/user-detail.tsx +++ b/apps/admin/app/dashboard/user/user-detail.tsx @@ -2,10 +2,11 @@ import { Display } from '@/components/display'; import { getUserDetail, getUserSubscribeById } from '@/services/admin/user'; +import { formatDate } from '@/utils/common'; import { useQuery } from '@tanstack/react-query'; import { Button } from '@workspace/ui/components/button'; import { HoverCard, HoverCardContent, HoverCardTrigger } from '@workspace/ui/components/hover-card'; -import { formatBytes, formatDate } from '@workspace/ui/utils'; +import { formatBytes } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import Link from 'next/link'; diff --git a/apps/admin/app/dashboard/user/user-subscription/index.tsx b/apps/admin/app/dashboard/user/user-subscription/index.tsx index 7f5fb4b..12cef2e 100644 --- a/apps/admin/app/dashboard/user/user-subscription/index.tsx +++ b/apps/admin/app/dashboard/user/user-subscription/index.tsx @@ -8,6 +8,7 @@ import { getUserSubscribe, updateUserSubscribe, } from '@/services/admin/user'; +import { formatDate } from '@/utils/common'; import { Button } from '@workspace/ui/components/button'; import { DropdownMenu, @@ -16,7 +17,6 @@ import { DropdownMenuTrigger, } from '@workspace/ui/components/dropdown-menu'; import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import Link from 'next/link'; import { useRef, useState } from 'react'; diff --git a/apps/admin/app/dashboard/user/user-subscription/subscription-detail.tsx b/apps/admin/app/dashboard/user/user-subscription/subscription-detail.tsx index cf56770..0428055 100644 --- a/apps/admin/app/dashboard/user/user-subscription/subscription-detail.tsx +++ b/apps/admin/app/dashboard/user/user-subscription/subscription-detail.tsx @@ -3,6 +3,7 @@ import { IpLink } from '@/components/ip-link'; import { ProTable } from '@/components/pro-table'; import { getUserSubscribeDevices, kickOfflineByUserDevice } from '@/services/admin/user'; +import { formatDate } from '@/utils/common'; import { Badge } from '@workspace/ui/components/badge'; import { Button } from '@workspace/ui/components/button'; import { @@ -14,7 +15,6 @@ import { } from '@workspace/ui/components/sheet'; import { Switch } from '@workspace/ui/components/switch'; import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button'; -import { formatDate } from '@workspace/ui/utils'; import { useTranslations } from 'next-intl'; import { ReactNode, useState } from 'react'; import { toast } from 'sonner'; diff --git a/apps/admin/components/dashboard/statistics.tsx b/apps/admin/components/dashboard/statistics.tsx index 911fe13..7d266a8 100644 --- a/apps/admin/components/dashboard/statistics.tsx +++ b/apps/admin/components/dashboard/statistics.tsx @@ -27,14 +27,14 @@ import { UserStatisticsCard } from './user-statistics-card'; export default function Statistics() { const t = useTranslations('index'); - const { data: TicketTotal } = useQuery({ + const { data: TicketTotal, isLoading: ticketLoading } = useQuery({ queryKey: ['queryTicketWaitReply'], queryFn: async () => { const { data } = await queryTicketWaitReply(); return data.data?.count; }, }); - const { data: ServerTotal } = useQuery({ + const { data: ServerTotal, isLoading: serverLoading } = useQuery({ queryKey: ['queryServerTotalData'], queryFn: async () => { const { data } = await queryServerTotalData(); @@ -42,6 +42,8 @@ export default function Statistics() { }, }); + const isLoading = ticketLoading || serverLoading; + const [dataType, setDataType] = useState('nodes'); const [timeFrame, setTimeFrame] = useState('today'); @@ -76,61 +78,75 @@ export default function Statistics() { return ( <> -
+
{[ { title: t('onlineUsersCount'), value: ServerTotal?.online_users || 0, + subtitle: t('currentlyOnline'), icon: 'uil:users-alt', href: '/dashboard/servers', + color: 'text-blue-600 dark:text-blue-400', + iconBg: 'bg-blue-100 dark:bg-blue-900/30', }, { - title: t('onlineNodeCount'), - value: ServerTotal?.online_servers || 0, + title: t('totalServers'), + value: (ServerTotal?.online_servers || 0) + (ServerTotal?.offline_servers || 0), + subtitle: `${t('online')} ${ServerTotal?.online_servers || 0} ${t('offline')} ${ServerTotal?.offline_servers || 0}`, icon: 'uil:server-network', href: '/dashboard/servers', + color: 'text-green-600 dark:text-green-400', + iconBg: 'bg-green-100 dark:bg-green-900/30', }, { - title: t('offlineNodeCount'), - value: ServerTotal?.offline_servers || 0, - icon: 'uil:server-network-alt', - href: '/dashboard/servers', + title: t('todayTraffic'), + value: formatBytes( + (ServerTotal?.today_upload || 0) + (ServerTotal?.today_download || 0), + ), + subtitle: `↑${formatBytes(ServerTotal?.today_upload || 0)} ↓${formatBytes(ServerTotal?.today_download || 0)}`, + icon: 'uil:exchange-alt', + color: 'text-purple-600 dark:text-purple-400', + iconBg: 'bg-purple-100 dark:bg-purple-900/30', + }, + { + title: t('monthTraffic'), + value: formatBytes( + (ServerTotal?.monthly_upload || 0) + (ServerTotal?.monthly_download || 0), + ), + subtitle: `↑${formatBytes(ServerTotal?.monthly_upload || 0)} ↓${formatBytes(ServerTotal?.monthly_download || 0)}`, + icon: 'uil:cloud-data-connection', + color: 'text-orange-600 dark:text-orange-400', + iconBg: 'bg-orange-100 dark:bg-orange-900/30', }, { title: t('pendingTickets'), value: TicketTotal || 0, + subtitle: t('pending'), icon: 'uil:clipboard-notes', href: '/dashboard/ticket', - }, - { - title: t('todayUploadTraffic'), - value: formatBytes(ServerTotal?.today_upload || 0), - icon: 'uil:arrow-up', - }, - { - title: t('todayDownloadTraffic'), - value: formatBytes(ServerTotal?.today_download || 0), - icon: 'uil:arrow-down', - }, - { - title: t('monthUploadTraffic'), - value: formatBytes(ServerTotal?.monthly_upload || 0), - icon: 'uil:cloud-upload', - }, - { - title: t('monthDownloadTraffic'), - value: formatBytes(ServerTotal?.monthly_download || 0), - icon: 'uil:cloud-download', + color: 'text-red-600 dark:text-red-400', + iconBg: 'bg-red-100 dark:bg-red-900/30', }, ].map((item, index) => ( - - - - {item.title} - - - -
{item.value}
+ + + +
+
+

{item.title}

+
{item.value}
+
{item.subtitle}
+
+
+ +
+
diff --git a/apps/admin/components/dashboard/user-statistics-card.tsx b/apps/admin/components/dashboard/user-statistics-card.tsx index 9b66f83..9651c0e 100644 --- a/apps/admin/components/dashboard/user-statistics-card.tsx +++ b/apps/admin/components/dashboard/user-statistics-card.tsx @@ -192,8 +192,8 @@ export function UserStatisticsCard() { tickMargin={10} axisLine={false} tickFormatter={(value) => { - // value format: "YYYY-MM-DD" - return new Date(value).toLocaleDateString(locale, { + const [year, month, day] = value.split('-'); + return new Date(year, month - 1, day).toLocaleDateString(locale, { month: 'short', day: 'numeric', }); diff --git a/apps/admin/components/header.tsx b/apps/admin/components/header.tsx index 5cd6bc9..360f6d4 100644 --- a/apps/admin/components/header.tsx +++ b/apps/admin/components/header.tsx @@ -15,6 +15,7 @@ import { usePathname } from 'next/navigation'; import { Fragment, useMemo } from 'react'; import LanguageSwitch from './language-switch'; import ThemeSwitch from './theme-switch'; +import TimezoneSwitch from './timezone-switch'; import { UserNav } from './user-nav'; export function Header() { @@ -48,6 +49,7 @@ export function Header() {
+
diff --git a/apps/admin/components/timezone-switch.tsx b/apps/admin/components/timezone-switch.tsx new file mode 100644 index 0000000..81b1666 --- /dev/null +++ b/apps/admin/components/timezone-switch.tsx @@ -0,0 +1,129 @@ +'use client'; + +import { Button } from '@workspace/ui/components/button'; +import { Command, CommandInput, CommandItem, CommandList } from '@workspace/ui/components/command'; +import { Popover, PopoverContent, PopoverTrigger } from '@workspace/ui/components/popover'; +import { Icon } from '@workspace/ui/custom-components/icon'; +import { cn } from '@workspace/ui/lib/utils'; +import { useMemo, useState } from 'react'; + +interface TimezoneOption { + value: string; + label: string; + offset: string; +} + +function getAllTimezones(): TimezoneOption[] { + try { + const timeZones = Intl.supportedValuesOf('timeZone'); + + return [ + { + value: 'UTC', + label: 'UTC', + offset: '+00:00', + }, + ].concat( + timeZones + .map((tz) => { + const parts = tz.split('/'); + let label = tz; + + if (parts.length >= 2) { + const region = parts[0]; + const city = parts[1]?.replace(/_/g, ' ') || ''; + label = `${city} (${region})`; + } + + return { + value: tz, + label: label, + offset: getTimezoneOffset(tz), + }; + }) + .sort((a, b) => a.label.localeCompare(b.label)), + ); + } catch { + return [ + { + value: 'UTC', + label: 'UTC', + offset: '+00:00', + }, + ]; + } +} + +function getTimezoneOffset(timezone: string): string { + try { + const now = new Date(); + const utc = new Date(now.getTime() + now.getTimezoneOffset() * 60000); + const targetTime = new Date(utc.toLocaleString('en-US', { timeZone: timezone })); + const offset = (targetTime.getTime() - utc.getTime()) / (1000 * 60 * 60); + const sign = offset >= 0 ? '+' : '-'; + const hours = Math.floor(Math.abs(offset)); + const minutes = Math.floor((Math.abs(offset) - hours) * 60); + return `${sign}${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; + } catch { + return '+00:00'; + } +} + +export default function TimezoneSwitch() { + const [timezone, setTimezone] = useState('UTC'); + const [open, setOpen] = useState(false); + + const timezoneOptions = useMemo(() => getAllTimezones(), []); + + const handleTimezoneChange = (newTimezone: string) => { + setTimezone(newTimezone); + localStorage.setItem('timezone', newTimezone); + setOpen(false); + + window.dispatchEvent( + new CustomEvent('timezoneChanged', { + detail: { timezone: newTimezone }, + }), + ); + }; + + return ( + + + + + + + + + {timezoneOptions.map((option) => ( + handleTimezoneChange(option.value)} + > +
+
+ {option.label} + + {option.value} • {option.offset} + +
+ +
+
+ ))} +
+
+
+
+ ); +} diff --git a/apps/admin/locales/cs-CZ/index.json b/apps/admin/locales/cs-CZ/index.json index 61893d0..77a9291 100644 --- a/apps/admin/locales/cs-CZ/index.json +++ b/apps/admin/locales/cs-CZ/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Aktuálně online", "email": "e-mail", "month": "Tento měsíc", "monthDownloadTraffic": "Měsíční objem stažených dat", + "monthTraffic": "Trafik tohoto měsíce", "monthUploadTraffic": "Tento měsíc nahraný provoz", "newPurchase": "Nový nákup", "nodeTraffic": "Provoz uzlu", "nodes": "uzly", - "offlineNodeCount": "Počet offline uzlů", - "onlineNodeCount": "Počet online uzlů", + "offline": "Offline", + "online": "Online", + "onlineServers": "Online servery", "onlineUsersCount": "Uživatelé online", + "pending": "Čekající", "pendingTickets": "Čekající lístky", "register": "Registrovat se", "repurchase": "opětovný nákup", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Vyberte typ", "today": "Dnes", "todayDownloadTraffic": "Dnešní stahovací provoz", + "todayTraffic": "Dnešní trafik", "todayUploadTraffic": "Dnešní nahraný provoz", "total": "Celkem", "totalIncome": "Celkový příjem", + "totalServers": "Celkový počet serverů", "traffic": "provoz", "trafficRank": "Pořadí návštěvnosti", "type": "Typ", diff --git a/apps/admin/locales/de-DE/index.json b/apps/admin/locales/de-DE/index.json index 7165238..8c0443d 100644 --- a/apps/admin/locales/de-DE/index.json +++ b/apps/admin/locales/de-DE/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Derzeit Online", "email": "E-Mail", "month": "Diesen Monat", "monthDownloadTraffic": "Monatlicher Download-Traffic", + "monthTraffic": "Traffic in diesem Monat", "monthUploadTraffic": "Diesen Monat hochgeladener Datenverkehr", "newPurchase": "Neukauf", "nodeTraffic": "Knotenverkehr", "nodes": "Knoten", - "offlineNodeCount": "Anzahl der Offline-Knoten", - "onlineNodeCount": "Anzahl der Online-Knoten", + "offline": "Offline", + "online": "Online", + "onlineServers": "Online-Server", "onlineUsersCount": "Online-Benutzer", + "pending": "Ausstehend", "pendingTickets": "Ausstehende Tickets", "register": "Registrieren", "repurchase": "Wiederkauf", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Typ auswählen", "today": "Heute", "todayDownloadTraffic": "Heutiger Download-Traffic", + "todayTraffic": "Traffic heute", "todayUploadTraffic": "Heutiger Upload-Verkehr", "total": "Gesamt", "totalIncome": "Gesamteinkommen", + "totalServers": "Gesamtanzahl der Server", "traffic": "Verkehr", "trafficRank": "Verkehrsrangliste", "type": "Typ", diff --git a/apps/admin/locales/en-US/index.json b/apps/admin/locales/en-US/index.json index 8f53e2b..efeaa5d 100644 --- a/apps/admin/locales/en-US/index.json +++ b/apps/admin/locales/en-US/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Currently Online", "email": "Email", "month": "Month", "monthDownloadTraffic": "This Month's Download Traffic", + "monthTraffic": "This Month's Traffic", "monthUploadTraffic": "This Month's Upload Traffic", "newPurchase": "New Purchase", "nodeTraffic": "Node Traffic", "nodes": "Nodes", - "offlineNodeCount": "Offline Nodes", - "onlineNodeCount": "Online Nodes", + "offline": "Offline", + "online": "Online", + "onlineServers": "Online Servers", "onlineUsersCount": "Online Users", + "pending": "Pending", "pendingTickets": "Pending Tickets", "register": "Register", "repurchase": "Repurchase", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Select Type", "today": "Today", "todayDownloadTraffic": "Today's Download Traffic", + "todayTraffic": "Today's Traffic", "todayUploadTraffic": "Today's Upload Traffic", "total": "Total", "totalIncome": "Total Income", + "totalServers": "Total Servers", "traffic": "Traffic", "trafficRank": "Traffic Ranking", "type": "Type", diff --git a/apps/admin/locales/es-ES/index.json b/apps/admin/locales/es-ES/index.json index 97d30b3..c56517a 100644 --- a/apps/admin/locales/es-ES/index.json +++ b/apps/admin/locales/es-ES/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Actualmente en línea", "email": "correo electrónico", "month": "Este mes", "monthDownloadTraffic": "Tráfico de descarga del mes", + "monthTraffic": "Tráfico de este mes", "monthUploadTraffic": "Tráfico de subida del mes", "newPurchase": "Nueva compra", "nodeTraffic": "Tráfico de nodo", "nodes": "nodos", - "offlineNodeCount": "Número de nodos fuera de línea", - "onlineNodeCount": "Número de nodos en línea", + "offline": "Desconectado", + "online": "En línea", + "onlineServers": "Servidores en línea", "onlineUsersCount": "Usuarios en línea", + "pending": "Pendiente", "pendingTickets": "Tickets pendientes", "register": "registrar", "repurchase": "recompra", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Seleccionar tipo", "today": "hoy", "todayDownloadTraffic": "Tráfico de descarga de hoy", + "todayTraffic": "Tráfico de hoy", "todayUploadTraffic": "Tráfico de subida de hoy", "total": "Total", "totalIncome": "Ingresos totales", + "totalServers": "Total de servidores", "traffic": "tráfico", "trafficRank": "Clasificación de tráfico", "type": "tipo", diff --git a/apps/admin/locales/es-MX/index.json b/apps/admin/locales/es-MX/index.json index ce7cc44..11ffb20 100644 --- a/apps/admin/locales/es-MX/index.json +++ b/apps/admin/locales/es-MX/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Actualmente en línea", "email": "correo electrónico", "month": "Este mes", "monthDownloadTraffic": "Tráfico de descarga del mes", + "monthTraffic": "Tráfico de este mes", "monthUploadTraffic": "Tráfico de carga de este mes", "newPurchase": "Nueva compra", "nodeTraffic": "Tráfico de nodo", "nodes": "nodos", - "offlineNodeCount": "Número de nodos fuera de línea", - "onlineNodeCount": "Número de nodos en línea", + "offline": "Desconectado", + "online": "En línea", + "onlineServers": "Servidores en línea", "onlineUsersCount": "Usuarios en línea", + "pending": "Pendiente", "pendingTickets": "Tickets pendientes", "register": "Registrarse", "repurchase": "recompra", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Seleccionar tipo", "today": "hoy", "todayDownloadTraffic": "Tráfico de descarga de hoy", + "todayTraffic": "Tráfico de hoy", "todayUploadTraffic": "Tráfico de carga de hoy", "total": "Total", "totalIncome": "Ingreso total", + "totalServers": "Total de servidores", "traffic": "tráfico", "trafficRank": "Clasificación de tráfico", "type": "tipo", diff --git a/apps/admin/locales/fa-IR/index.json b/apps/admin/locales/fa-IR/index.json index ef5c312..d5ecfec 100644 --- a/apps/admin/locales/fa-IR/index.json +++ b/apps/admin/locales/fa-IR/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "در حال حاضر آنلاین", "email": "ایمیل", "month": "ماه", "monthDownloadTraffic": "ترافیک دانلود این ماه", + "monthTraffic": "ترافیک این ماه", "monthUploadTraffic": "ترافیک آپلود این ماه", "newPurchase": "خرید جدید", "nodeTraffic": "ترافیک نود", "nodes": "گره‌ها", - "offlineNodeCount": "گره‌های آفلاین", - "onlineNodeCount": "گره‌های آنلاین", + "offline": "آفلاین", + "online": "آنلاین", + "onlineServers": "سرورهای آنلاین", "onlineUsersCount": "کاربران آنلاین", + "pending": "در حال انتظار", "pendingTickets": "بلیط‌های در انتظار", "register": "ثبت نام", "repurchase": "بازخرید", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "نوع را انتخاب کنید", "today": "امروز", "todayDownloadTraffic": "ترافیک دانلود امروز", + "todayTraffic": "ترافیک امروز", "todayUploadTraffic": "ترافیک بارگذاری امروز", "total": "جمع کل", "totalIncome": "کل درآمد", + "totalServers": "کل سرورها", "traffic": "ترافیک", "trafficRank": "رتبه ترافیک", "type": "نوع", diff --git a/apps/admin/locales/fi-FI/index.json b/apps/admin/locales/fi-FI/index.json index c196fe6..fa9a29e 100644 --- a/apps/admin/locales/fi-FI/index.json +++ b/apps/admin/locales/fi-FI/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Tällä hetkellä verkossa", "email": "sähköposti", "month": "Tämä kuukausi", "monthDownloadTraffic": "Tämän kuukauden latausliikenne", + "monthTraffic": "Tämän kuun liikenne", "monthUploadTraffic": "Tämän kuukauden lähetysliikenne", "newPurchase": "Uusi osto", "nodeTraffic": "Solmun liikenne", "nodes": "solmut", - "offlineNodeCount": "Offline-solmujen määrä", - "onlineNodeCount": "Verkossa olevien solmujen määrä", + "offline": "Poissa käytöstä", + "online": "Verkossa", + "onlineServers": "Verkossa olevat palvelimet", "onlineUsersCount": "Verkkokäyttäjät", + "pending": "Odottaa", "pendingTickets": "Odottavat liput", "register": "Rekisteröidy", "repurchase": "uudelleenosto", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Valitse tyyppi", "today": "tänään", "todayDownloadTraffic": "Tämän päivän latausliikenne", + "todayTraffic": "Tänään liikenne", "todayUploadTraffic": "Tämän päivän lähetysliikenne", "total": "Yhteensä", "totalIncome": "Kokonaistulot", + "totalServers": "Yhteensä palvelimia", "traffic": "liikenne", "trafficRank": "Liikenteen sijoitus", "type": "tyyppi", diff --git a/apps/admin/locales/fr-FR/index.json b/apps/admin/locales/fr-FR/index.json index 680b987..a62c54c 100644 --- a/apps/admin/locales/fr-FR/index.json +++ b/apps/admin/locales/fr-FR/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Actuellement en ligne", "email": "e-mail", "month": "Ce mois-ci", "monthDownloadTraffic": "Trafic de téléchargement ce mois-ci", + "monthTraffic": "Trafic de ce mois", "monthUploadTraffic": "Trafic de téléchargement ce mois-ci", "newPurchase": "Nouvel achat", "nodeTraffic": "Trafic du nœud", "nodes": "nœuds", - "offlineNodeCount": "Nombre de nœuds hors ligne", - "onlineNodeCount": "Nombre de nœuds en ligne", + "offline": "Hors ligne", + "online": "En ligne", + "onlineServers": "Serveurs en ligne", "onlineUsersCount": "Utilisateurs en ligne", + "pending": "En attente", "pendingTickets": "Tickets en attente", "register": "S'inscrire", "repurchase": "Rachat", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Sélectionner le type", "today": "aujourd'hui", "todayDownloadTraffic": "Trafic de téléchargement d'aujourd'hui", + "todayTraffic": "Trafic d'aujourd'hui", "todayUploadTraffic": "Trafic de téléchargement d'aujourd'hui", "total": "Total", "totalIncome": "Revenu total", + "totalServers": "Total des serveurs", "traffic": "trafic", "trafficRank": "Classement du trafic", "type": "Type", diff --git a/apps/admin/locales/hi-IN/index.json b/apps/admin/locales/hi-IN/index.json index 0c248a8..aa24c03 100644 --- a/apps/admin/locales/hi-IN/index.json +++ b/apps/admin/locales/hi-IN/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "वर्तमान में ऑनलाइन", "email": "ईमेल", "month": "इस माह", "monthDownloadTraffic": "इस महीने की डाउनलोड ट्रैफिक", + "monthTraffic": "इस महीने का ट्रैफ़िक", "monthUploadTraffic": "इस महीने का अपलोड ट्रैफिक", "newPurchase": "नई खरीद", "nodeTraffic": "नोड ट्रैफिक", "nodes": "नोड्स", - "offlineNodeCount": "ऑफ़लाइन नोड की संख्या", - "onlineNodeCount": "ऑनलाइन नोड की संख्या", + "offline": "ऑफ़लाइन", + "online": "ऑनलाइन", + "onlineServers": "ऑनलाइन सर्वर", "onlineUsersCount": "ऑनलाइन उपयोगकर्ता", + "pending": "लंबित", "pendingTickets": "लंबित टिकट", "register": "पंजीकरण", "repurchase": "पुनः खरीद", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "प्रकार चुनें", "today": "आज", "todayDownloadTraffic": "आज का डाउनलोड ट्रैफिक", + "todayTraffic": "आज का ट्रैफ़िक", "todayUploadTraffic": "आज का अपलोड ट्रैफिक", "total": "कुल", "totalIncome": "कुल आय", + "totalServers": "कुल सर्वर", "traffic": "ट्रैफिक", "trafficRank": "ट्रैफिक रैंक", "type": "प्रकार", diff --git a/apps/admin/locales/hu-HU/index.json b/apps/admin/locales/hu-HU/index.json index cf07698..c3ba3be 100644 --- a/apps/admin/locales/hu-HU/index.json +++ b/apps/admin/locales/hu-HU/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Jelenleg Online", "email": "e-mail", "month": "Ez a hónap", "monthDownloadTraffic": "Havi letöltési forgalom", + "monthTraffic": "A hónap forgalma", "monthUploadTraffic": "Havi feltöltési forgalom", "newPurchase": "Új vásárlás", "nodeTraffic": "Csomópont forgalom", "nodes": "csomópontok", - "offlineNodeCount": "Offline csomópontok száma", - "onlineNodeCount": "Online csomópontok száma", + "offline": "Offline", + "online": "Online", + "onlineServers": "Online szerverek", "onlineUsersCount": "Online Felhasználók", + "pending": "Függőben", "pendingTickets": "Függőben lévő jegyek", "register": "Regisztráció", "repurchase": "újravásárlás", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Válasszon típust", "today": "ma", "todayDownloadTraffic": "Mai letöltési forgalom", + "todayTraffic": "A mai forgalom", "todayUploadTraffic": "Mai feltöltési forgalom", "total": "Összesen", "totalIncome": "Összes bevétel", + "totalServers": "Összes szerver", "traffic": "forgalom", "trafficRank": "Forgalmi rangsor", "type": "típus", diff --git a/apps/admin/locales/ja-JP/index.json b/apps/admin/locales/ja-JP/index.json index 9b35400..87fc734 100644 --- a/apps/admin/locales/ja-JP/index.json +++ b/apps/admin/locales/ja-JP/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "現在オンライン", "email": "メールアドレス", "month": "今月", "monthDownloadTraffic": "今月のダウンロードトラフィック", + "monthTraffic": "今月のトラフィック", "monthUploadTraffic": "今月のアップロードトラフィック", "newPurchase": "新規購入", "nodeTraffic": "ノードトラフィック", "nodes": "ノード", - "offlineNodeCount": "オフラインノード数", - "onlineNodeCount": "オンラインノード数", + "offline": "オフライン", + "online": "オンライン", + "onlineServers": "オンラインサーバー", "onlineUsersCount": "オンラインユーザー", + "pending": "保留中", "pendingTickets": "保留中のチケット", "register": "登録", "repurchase": "再購入", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "タイプを選択", "today": "今日", "todayDownloadTraffic": "本日のダウンロードトラフィック", + "todayTraffic": "今日のトラフィック", "todayUploadTraffic": "本日のアップロードトラフィック", "total": "合計", "totalIncome": "総収入", + "totalServers": "総サーバー数", "traffic": "トラフィック", "trafficRank": "トラフィックランキング", "type": "タイプ", diff --git a/apps/admin/locales/ko-KR/index.json b/apps/admin/locales/ko-KR/index.json index 920d9a8..76a899a 100644 --- a/apps/admin/locales/ko-KR/index.json +++ b/apps/admin/locales/ko-KR/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "현재 온라인", "email": "이메일", "month": "이번 달", "monthDownloadTraffic": "이번 달 다운로드 트래픽", + "monthTraffic": "이번 달 트래픽", "monthUploadTraffic": "이번 달 업로드 트래픽", "newPurchase": "신규 구매", "nodeTraffic": "노드 트래픽", "nodes": "노드", - "offlineNodeCount": "오프라인 노드 수", - "onlineNodeCount": "온라인 노드 수", + "offline": "오프라인", + "online": "온라인", + "onlineServers": "온라인 서버", "onlineUsersCount": "온라인 사용자", + "pending": "대기 중", "pendingTickets": "처리 대기 중인 티켓", "register": "등록", "repurchase": "재구매", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "유형 선택", "today": "오늘", "todayDownloadTraffic": "오늘 다운로드 트래픽", + "todayTraffic": "오늘의 트래픽", "todayUploadTraffic": "오늘 업로드 트래픽", "total": "총계", "totalIncome": "총수입", + "totalServers": "총 서버", "traffic": "트래픽", "trafficRank": "트래픽 순위", "type": "유형", diff --git a/apps/admin/locales/no-NO/index.json b/apps/admin/locales/no-NO/index.json index 24fc6a1..79aea74 100644 --- a/apps/admin/locales/no-NO/index.json +++ b/apps/admin/locales/no-NO/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "For øyeblikket på nett", "email": "e-post", "month": "Denne måneden", "monthDownloadTraffic": "Nedlastingstrafikk denne måneden", + "monthTraffic": "Månedens trafikk", "monthUploadTraffic": "Månedens opplastningstrafikk", "newPurchase": "Nytt kjøp", "nodeTraffic": "Nodetrafikk", "nodes": "noder", - "offlineNodeCount": "Antall frakoblede noder", - "onlineNodeCount": "Antall noder på nett", + "offline": "Av", + "online": "På nett", + "onlineServers": "Nettservere", "onlineUsersCount": "Nettbrukere", + "pending": "Venter", "pendingTickets": "Ventende billetter", "register": "Registrer", "repurchase": "gjenkjøp", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Velg type", "today": "i dag", "todayDownloadTraffic": "Dagens nedlastningstrafikk", + "todayTraffic": "Dagens trafikk", "todayUploadTraffic": "Dagens opplastningstrafikk", "total": "Totalt", "totalIncome": "Totalinntekt", + "totalServers": "Totale servere", "traffic": "trafikk", "trafficRank": "Trafikkrangering", "type": "Type", diff --git a/apps/admin/locales/pl-PL/index.json b/apps/admin/locales/pl-PL/index.json index ab4b799..54a3f13 100644 --- a/apps/admin/locales/pl-PL/index.json +++ b/apps/admin/locales/pl-PL/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Obecnie online", "email": "e-mail", "month": "Ten miesiąc", "monthDownloadTraffic": "Miesięczny ruch pobierania", + "monthTraffic": "Ruch w tym miesiącu", "monthUploadTraffic": "Miesięczny przesył danych", "newPurchase": "Nowy zakup", "nodeTraffic": "Ruch węzła", "nodes": "węzły", - "offlineNodeCount": "Liczba węzłów offline", - "onlineNodeCount": "Liczba węzłów online", + "offline": "Offline", + "online": "Online", + "onlineServers": "Serwery online", "onlineUsersCount": "Użytkownicy online", + "pending": "Oczekujące", "pendingTickets": "Oczekujące zgłoszenia", "register": "Rejestracja", "repurchase": "ponowny zakup", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Wybierz typ", "today": "Dziś", "todayDownloadTraffic": "Dzisiejszy ruch pobierania", + "todayTraffic": "Ruch dzisiaj", "todayUploadTraffic": "Dzisiejszy przesył danych", "total": "Razem", "totalIncome": "Całkowity dochód", + "totalServers": "Łączna liczba serwerów", "traffic": "ruch", "trafficRank": "Ranking ruchu", "type": "typ", diff --git a/apps/admin/locales/pt-BR/index.json b/apps/admin/locales/pt-BR/index.json index 06e4c78..5f7d1fe 100644 --- a/apps/admin/locales/pt-BR/index.json +++ b/apps/admin/locales/pt-BR/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Atualmente Online", "email": "e-mail", "month": "Este mês", "monthDownloadTraffic": "Tráfego de download do mês", + "monthTraffic": "Tráfego deste Mês", "monthUploadTraffic": "Tráfego de upload deste mês", "newPurchase": "Nova Compra", "nodeTraffic": "Tráfego do Nó", "nodes": "nós", - "offlineNodeCount": "Contagem de nós offline", - "onlineNodeCount": "Contagem de nós online", + "offline": "Offline", + "online": "Online", + "onlineServers": "Servidores Online", "onlineUsersCount": "Usuários Online", + "pending": "Pendente", "pendingTickets": "Tickets pendentes", "register": "Registrar", "repurchase": "recompra", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Selecione o tipo", "today": "hoje", "todayDownloadTraffic": "Tráfego de download de hoje", + "todayTraffic": "Tráfego de Hoje", "todayUploadTraffic": "Tráfego de upload de hoje", "total": "Total", "totalIncome": "Renda Total", + "totalServers": "Total de Servidores", "traffic": "tráfego", "trafficRank": "Classificação de Tráfego", "type": "tipo", diff --git a/apps/admin/locales/ro-RO/index.json b/apps/admin/locales/ro-RO/index.json index d483722..4856d5b 100644 --- a/apps/admin/locales/ro-RO/index.json +++ b/apps/admin/locales/ro-RO/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "În prezent online", "email": "e-mail", "month": "Luna aceasta", "monthDownloadTraffic": "Traficul de descărcare din această lună", + "monthTraffic": "Traficul din această lună", "monthUploadTraffic": "Traficul de încărcare din această lună", "newPurchase": "Achiziție nouă", "nodeTraffic": "Traficul nodului", "nodes": "noduri", - "offlineNodeCount": "Număr de noduri offline", - "onlineNodeCount": "Număr de noduri online", + "offline": "Offline", + "online": "Online", + "onlineServers": "Servere online", "onlineUsersCount": "Utilizatori online", + "pending": "În așteptare", "pendingTickets": "Tichete în așteptare", "register": "Înregistrare", "repurchase": "recomandare", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Selectați tipul", "today": "astăzi", "todayDownloadTraffic": "Traficul de descărcare de astăzi", + "todayTraffic": "Traficul de astăzi", "todayUploadTraffic": "Traficul de încărcare de astăzi", "total": "Total", "totalIncome": "Venit total", + "totalServers": "Total servere", "traffic": "trafic", "trafficRank": "Clasament trafic", "type": "tip", diff --git a/apps/admin/locales/ru-RU/index.json b/apps/admin/locales/ru-RU/index.json index 2cc1886..77989eb 100644 --- a/apps/admin/locales/ru-RU/index.json +++ b/apps/admin/locales/ru-RU/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "В данный момент онлайн", "email": "Электронная почта", "month": "Этот месяц", "monthDownloadTraffic": "Трафик загрузки за месяц", + "monthTraffic": "Трафик за этот месяц", "monthUploadTraffic": "Трафик загрузки за этот месяц", "newPurchase": "Новая покупка", "nodeTraffic": "Трафик узла", "nodes": "узлы", - "offlineNodeCount": "Количество офлайн-узлов", - "onlineNodeCount": "Количество онлайн-узлов", + "offline": "Офлайн", + "online": "Онлайн", + "onlineServers": "Онлайн-серверы", "onlineUsersCount": "Пользователи онлайн", + "pending": "В ожидании", "pendingTickets": "Ожидающие заявки", "register": "Регистрация", "repurchase": "повторная покупка", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Выберите тип", "today": "Сегодня", "todayDownloadTraffic": "Сегодняшний трафик загрузки", + "todayTraffic": "Трафик сегодня", "todayUploadTraffic": "Сегодняшний объем загруженного трафика", "total": "Итого", "totalIncome": "Общий доход", + "totalServers": "Всего серверов", "traffic": "трафик", "trafficRank": "Рейтинг трафика", "type": "Тип", diff --git a/apps/admin/locales/th-TH/index.json b/apps/admin/locales/th-TH/index.json index f54bee9..d1e0cf0 100644 --- a/apps/admin/locales/th-TH/index.json +++ b/apps/admin/locales/th-TH/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "ออนไลน์อยู่ในขณะนี้", "email": "อีเมล", "month": "เดือนนี้", "monthDownloadTraffic": "ปริมาณการดาวน์โหลดในเดือนนี้", + "monthTraffic": "การเข้าชมในเดือนนี้", "monthUploadTraffic": "ปริมาณการอัปโหลดในเดือนนี้", "newPurchase": "ซื้อใหม่", "nodeTraffic": "ปริมาณการใช้งานของโหนด", "nodes": "โหนด", - "offlineNodeCount": "จำนวนโหนดออฟไลน์", - "onlineNodeCount": "จำนวนโหนดออนไลน์", + "offline": "ออฟไลน์", + "online": "ออนไลน์", + "onlineServers": "เซิร์ฟเวอร์ออนไลน์", "onlineUsersCount": "ผู้ใช้งานออนไลน์", + "pending": "รอดำเนินการ", "pendingTickets": "บัตรงานที่รอดำเนินการ", "register": "ลงทะเบียน", "repurchase": "ซื้อซ้ำ", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "เลือกประเภท", "today": "วันนี้", "todayDownloadTraffic": "ปริมาณการดาวน์โหลดวันนี้", + "todayTraffic": "การเข้าชมวันนี้", "todayUploadTraffic": "ปริมาณการอัปโหลดวันนี้", "total": "รวมทั้งหมด", "totalIncome": "รายได้รวม", + "totalServers": "จำนวนเซิร์ฟเวอร์ทั้งหมด", "traffic": "การจราจร", "trafficRank": "อันดับการเข้าชม", "type": "ประเภท", diff --git a/apps/admin/locales/tr-TR/index.json b/apps/admin/locales/tr-TR/index.json index 38fadf6..9180875 100644 --- a/apps/admin/locales/tr-TR/index.json +++ b/apps/admin/locales/tr-TR/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Şu Anda Çevrimiçi", "email": "e-posta", "month": "Bu Ay", "monthDownloadTraffic": "Bu ayki indirme trafiği", + "monthTraffic": "Bu Ayki Trafik", "monthUploadTraffic": "Bu ayki yükleme trafiği", "newPurchase": "Yeni Satın Alma", "nodeTraffic": "Düğüm Trafiği", "nodes": "düğümler", - "offlineNodeCount": "Çevrimdışı Düğüm Sayısı", - "onlineNodeCount": "Çevrimiçi Düğüm Sayısı", + "offline": "Çevrimdışı", + "online": "Çevrimiçi", + "onlineServers": "Çevrimiçi Sunucular", "onlineUsersCount": "Çevrimiçi Kullanıcılar", + "pending": "Beklemede", "pendingTickets": "Bekleyen Biletler", "register": "Kayıt Ol", "repurchase": "yeniden satın alma", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Tür seçin", "today": "bugün", "todayDownloadTraffic": "Bugünkü indirme trafiği", + "todayTraffic": "Bugünkü Trafik", "todayUploadTraffic": "Bugün Yükleme Trafiği", "total": "Toplam", "totalIncome": "Toplam Gelir", + "totalServers": "Toplam Sunucular", "traffic": "trafik", "trafficRank": "Trafik Sıralaması", "type": "Tür", diff --git a/apps/admin/locales/uk-UA/index.json b/apps/admin/locales/uk-UA/index.json index 20ad4d6..06b6015 100644 --- a/apps/admin/locales/uk-UA/index.json +++ b/apps/admin/locales/uk-UA/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "В даний час в мережі", "email": "електронна пошта", "month": "Цього місяця", "monthDownloadTraffic": "Трафік завантажень за цей місяць", + "monthTraffic": "Трафік цього місяця", "monthUploadTraffic": "Цього місяця завантажено трафіку", "newPurchase": "Нова покупка", "nodeTraffic": "Трафік вузла", "nodes": "вузли", - "offlineNodeCount": "Кількість офлайн-вузлів", - "onlineNodeCount": "Кількість онлайн-вузлів", + "offline": "Вимкнено", + "online": "В мережі", + "onlineServers": "Сервери в мережі", "onlineUsersCount": "Користувачі онлайн", + "pending": "В очікуванні", "pendingTickets": "Невирішені заявки", "register": "Реєстрація", "repurchase": "повторна покупка", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Виберіть тип", "today": "сьогодні", "todayDownloadTraffic": "Сьогоднішній трафік завантажень", + "todayTraffic": "Трафік сьогодні", "todayUploadTraffic": "Сьогоднішній обсяг завантаження", "total": "Загалом", "totalIncome": "Загальний дохід", + "totalServers": "Всього серверів", "traffic": "трафік", "trafficRank": "Рейтинг трафіку", "type": "Тип", diff --git a/apps/admin/locales/vi-VN/index.json b/apps/admin/locales/vi-VN/index.json index b2cc4f0..9b5cce3 100644 --- a/apps/admin/locales/vi-VN/index.json +++ b/apps/admin/locales/vi-VN/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "Đang Trực Tuyến", "email": "Email", "month": "Tháng này", "monthDownloadTraffic": "Lưu lượng tải xuống tháng này", + "monthTraffic": "Lưu Lượng Tháng Này", "monthUploadTraffic": "Lưu lượng tải lên trong tháng này", "newPurchase": "Mua mới", "nodeTraffic": "Lưu lượng nút", "nodes": "nút", - "offlineNodeCount": "Số lượng nút ngoại tuyến", - "onlineNodeCount": "Số lượng nút trực tuyến", + "offline": "Ngoại Tuyến", + "online": "Trực Tuyến", + "onlineServers": "Máy Chủ Đang Trực Tuyến", "onlineUsersCount": "Người dùng trực tuyến", + "pending": "Đang Chờ", "pendingTickets": "Phiếu hỗ trợ đang chờ xử lý", "register": "Đăng ký", "repurchase": "mua lại", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "Chọn loại", "today": "Hôm nay", "todayDownloadTraffic": "Lưu lượng tải xuống hôm nay", + "todayTraffic": "Lưu Lượng Hôm Nay", "todayUploadTraffic": "Lưu lượng tải lên hôm nay", "total": "Tổng cộng", "totalIncome": "Tổng thu nhập", + "totalServers": "Tổng Số Máy Chủ", "traffic": "lưu lượng", "trafficRank": "Xếp hạng lưu lượng", "type": "Loại", diff --git a/apps/admin/locales/zh-CN/index.json b/apps/admin/locales/zh-CN/index.json index 977e923..2bcf9a6 100644 --- a/apps/admin/locales/zh-CN/index.json +++ b/apps/admin/locales/zh-CN/index.json @@ -1,14 +1,23 @@ { + "currentlyOnline": "当前在线", + "currentlyOnline": "当前在线", + "download": "↓", "email": "邮箱", "month": "本月", "monthDownloadTraffic": "本月下载流量", + "monthTraffic": "本月流量", "monthUploadTraffic": "本月上传流量", "newPurchase": "新购", "nodeTraffic": "节点流量", "nodes": "节点", - "offlineNodeCount": "离线节点数", - "onlineNodeCount": "在线节点数", + "offline": "离线", + "online": "在线", + "onlineServers": "在线服务器", + "onlineTotal": "在线/总数", + "onlineTotal": "在线/总数", "onlineUsersCount": "在线用户数", + "pending": "待处理", + "pending": "待处理", "pendingTickets": "待处理工单", "register": "注册", "repurchase": "复购", @@ -16,12 +25,15 @@ "selectTypePlaceholder": "选择类型", "today": "今日", "todayDownloadTraffic": "今日下载流量", + "todayTraffic": "今日流量", "todayUploadTraffic": "今日上传流量", "total": "总计", "totalIncome": "总收入", + "totalServers": "总服务器", "traffic": "流量", "trafficRank": "流量排行", "type": "类型", + "upload": "↑", "userTitle": "用户统计", "userTraffic": "用户流量", "users": "用户", diff --git a/apps/admin/locales/zh-HK/index.json b/apps/admin/locales/zh-HK/index.json index 39e9935..0d522d5 100644 --- a/apps/admin/locales/zh-HK/index.json +++ b/apps/admin/locales/zh-HK/index.json @@ -1,14 +1,18 @@ { + "currentlyOnline": "目前在線", "email": "電子郵件", "month": "本月", "monthDownloadTraffic": "本月下載流量", + "monthTraffic": "本月流量", "monthUploadTraffic": "本月上傳流量", "newPurchase": "新購", "nodeTraffic": "節點流量", "nodes": "節點", - "offlineNodeCount": "離線節點數", - "onlineNodeCount": "線上節點數", + "offline": "離線", + "online": "在線", + "onlineServers": "在線伺服器", "onlineUsersCount": "線上用戶數", + "pending": "待處理", "pendingTickets": "待處理工單", "register": "註冊", "repurchase": "回購", @@ -16,9 +20,11 @@ "selectTypePlaceholder": "選擇類型", "today": "今天", "todayDownloadTraffic": "今日下載流量", + "todayTraffic": "今日流量", "todayUploadTraffic": "今日上傳流量", "total": "總計", "totalIncome": "總收入", + "totalServers": "伺服器總數", "traffic": "流量", "trafficRank": "流量排行", "type": "類型", diff --git a/apps/admin/services/admin/index.ts b/apps/admin/services/admin/index.ts index bdf189b..4ebecd4 100644 --- a/apps/admin/services/admin/index.ts +++ b/apps/admin/services/admin/index.ts @@ -1,5 +1,5 @@ // @ts-ignore - + // API 更新时间: // API 唯一标识: import * as ads from './ads'; diff --git a/apps/admin/services/common/index.ts b/apps/admin/services/common/index.ts index 61ba129..73b3bda 100644 --- a/apps/admin/services/common/index.ts +++ b/apps/admin/services/common/index.ts @@ -1,5 +1,5 @@ // @ts-ignore - + // API 更新时间: // API 唯一标识: import * as auth from './auth'; diff --git a/apps/admin/utils/common.ts b/apps/admin/utils/common.ts index 1d99ab3..b19c79f 100644 --- a/apps/admin/utils/common.ts +++ b/apps/admin/utils/common.ts @@ -1,5 +1,6 @@ import { locales, NEXT_PUBLIC_DEFAULT_LANGUAGE } from '@/config/constants'; import { isBrowser } from '@workspace/ui/utils'; +import { intlFormat } from 'date-fns'; import Cookies from 'universal-cookie'; const cookies = new Cookies(null, { @@ -49,3 +50,20 @@ export function Logout() { location.href = `/`; } } + +export function formatDate(date?: Date | number, showTime: boolean = true) { + if (!date) return; + const timeZone = localStorage.getItem('timezone') || 'UTC'; + return intlFormat(date, { + year: 'numeric', + month: 'numeric', + day: 'numeric', + ...(showTime && { + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + }), + hour12: false, + timeZone, + }); +} diff --git a/apps/user/services/common/index.ts b/apps/user/services/common/index.ts index 61ba129..73b3bda 100644 --- a/apps/user/services/common/index.ts +++ b/apps/user/services/common/index.ts @@ -1,5 +1,5 @@ // @ts-ignore - + // API 更新时间: // API 唯一标识: import * as auth from './auth'; diff --git a/apps/user/services/user/index.ts b/apps/user/services/user/index.ts index 12fe8d0..f988131 100644 --- a/apps/user/services/user/index.ts +++ b/apps/user/services/user/index.ts @@ -1,5 +1,5 @@ // @ts-ignore - + // API 更新时间: // API 唯一标识: import * as announcement from './announcement';