diff --git a/frontend/src/pages/clients/ClientsPage.css b/frontend/src/pages/clients/ClientsPage.css index 085ce490..7081c2cc 100644 --- a/frontend/src/pages/clients/ClientsPage.css +++ b/frontend/src/pages/clients/ClientsPage.css @@ -62,6 +62,26 @@ .dot-orange { background: var(--ant-color-warning); } .dot-gray { background: var(--ant-color-text-quaternary); } +.online-dot { + display: inline-block; + width: 7px; + height: 7px; + border-radius: 50%; + margin-inline-end: 5px; + vertical-align: middle; + background: var(--ant-color-success); + animation: online-blink 1.1s ease-in-out infinite; +} + +@keyframes online-blink { + 0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(82, 196, 26, 0.55); } + 50% { opacity: 0.35; box-shadow: 0 0 0 4px rgba(82, 196, 26, 0); } +} + +@media (prefers-reduced-motion: reduce) { + .online-dot { animation: none; } +} + .status-tag { margin: 0 0 0 4px; font-size: 11px; diff --git a/frontend/src/pages/clients/ClientsPage.tsx b/frontend/src/pages/clients/ClientsPage.tsx index 5ceefa06..adb8f323 100644 --- a/frontend/src/pages/clients/ClientsPage.tsx +++ b/frontend/src/pages/clients/ClientsPage.tsx @@ -626,10 +626,17 @@ export default function ClientsPage() { render: (_v, record) => { const bucket = clientBucket(record); if (bucket === 'depleted') return {t('depleted')}; - if (record.enable && isOnline(record.email)) return {t('pages.clients.online')}; + if (record.enable && isOnline(record.email)) return ( + {t('pages.clients.online')} + ); if (!record.enable) return {t('disabled')}; if (bucket === 'expiring') return {t('depletingSoon')}; - return {t('pages.clients.offline')}; + const lastOnline = record.traffic?.lastOnline ?? 0; + return ( + 0 ? IntlUtil.formatDate(lastOnline, datepicker) : '-'}`}> + {t('pages.clients.offline')} + + ); }, }, { @@ -732,7 +739,7 @@ export default function ClientsPage() { ), }, // eslint-disable-next-line react-hooks/exhaustive-deps - ], [t, togglingEmail, clientBucket, isOnline, inboundsById, filters, allGroups]); + ], [t, togglingEmail, clientBucket, isOnline, inboundsById, filters, allGroups, datepicker]); const tablePagination = { current: currentPage,