diff --git a/src/shared/api/contracts/user/UserBaseEntitry.ts b/src/shared/api/contracts/user/UserBaseEntitry.ts index 10501ad..2e75232 100644 --- a/src/shared/api/contracts/user/UserBaseEntitry.ts +++ b/src/shared/api/contracts/user/UserBaseEntitry.ts @@ -31,6 +31,8 @@ export interface PlayerBaseEntity { expiredDate: string; textureSkinUrl: string; textureCloakUrl: string; + externalTextureSkinUrl: string; + externalTextureCloakUrl: string; textureSkinGuid: string; textureCloakGuid: string; fullSkinUrl?: any; diff --git a/src/widgets/players-table/lib/columns.tsx b/src/widgets/players-table/lib/columns.tsx index 8b538d0..031cdc9 100644 --- a/src/widgets/players-table/lib/columns.tsx +++ b/src/widgets/players-table/lib/columns.tsx @@ -3,7 +3,18 @@ import React, { useMemo, useState } from 'react'; import { createColumnHelper } from '@tanstack/table-core'; import { format } from 'date-fns'; -import { Ban as BanIcon, GavelIcon, MoreVertical, ShieldCheck, Trash, User, Monitor, Laptop, Smartphone, Tablet } from 'lucide-react'; +import { + Ban as BanIcon, + GavelIcon, + Laptop, + Monitor, + MoreVertical, + ShieldCheck, + Smartphone, + Tablet, + Trash, + User, +} from 'lucide-react'; import { DataTableColumnHeader } from '@/entities/Table'; import { PlayerBaseEntity } from '@/shared/api/contracts'; @@ -129,144 +140,153 @@ function PlayerDetailsDialog({ {/* Tabs layout for player card */}
- - Обзор - Текстуры - Авторизации - Сети/IP - Сервер - + + Обзор + Текстуры + Авторизации + Сети/IP + Сервер + -
- -
-
-
-
Статус
-
- {player.isBanned ? ( - - Заблокирован - - ) : ( - - Не заблокирован - +
+ +
+
+
+
Статус
+
+ {player.isBanned ? ( + + Заблокирован + + ) : ( + + Не заблокирован + + )} +
+ {player.isLauncherStarted && ( +
+ + + Лаунчер запущен + +
+ )} +
+
+
Сессия истекает
+
{sessionStr}
+
+
+
+ {addresses.length > 0 && ( +
+
IP адреса
+
{addresses.join(', ')}
+
)}
- {player.isLauncherStarted && ( -
- - Лаунчер запущен -
- )}
+
+ +
-
Сессия истекает
-
{sessionStr}
+
Текстуры
+
+ {player.externalTextureSkinUrl && ( + skin + )} + {player.externalTextureCloakUrl && ( + cloak + )} + {!player.externalTextureSkinUrl && !player.externalTextureCloakUrl && ( +
Нет текстур.
+ )} +
-
-
- {addresses.length > 0 && ( -
-
IP адреса
-
{addresses.join(', ')}
+ + + +
+
Авторизации
+
+ {(player.authHistory || []).map((h, idx) => ( +
+
{getDeviceIcon(h.device)}
+
+
+
+ {h.device || 'Неизвестное устройство'} +
+ {h.hwid && ( + + HWID: {h.hwid} + + )} +
+
+ {h.address || '-'} +
+
+ {timeAgo(h.date)} + + {h.protocol} + +
+
+
+ ))} + {(!player.authHistory || player.authHistory.length === 0) && ( +
Нет данных.
+ )}
- )} -
-
- +
+ - -
-
Текстуры
-
- {player.textureSkinUrl && ( - skin - )} - {player.textureCloakUrl && ( - cloak - )} - {!player.textureSkinUrl && !player.textureCloakUrl && ( -
Нет текстур.
+ + {addresses.length > 0 ? ( +
+ {addresses.map((a) => ( + + {a} + + ))} +
+ ) : ( +
Нет IP адресов.
)} -
-
-
+ - -
-
Авторизации
-
- {(player.authHistory || []).map((h, idx) => ( -
-
- {getDeviceIcon(h.device)} -
-
-
-
- {h.device || 'Неизвестное устройство'} -
- {h.hwid && ( - - HWID: {h.hwid} - - )} -
-
- {h.address || '-'} -
-
- {timeAgo(h.date)} - {h.protocol} -
-
+ + {Array.isArray((player as any).serverJoinHistory) ? ( +
+ {(player as any).serverJoinHistory?.length || 0} записей
- ))} - {(!player.authHistory || player.authHistory.length === 0) && ( + ) : (
Нет данных.
)} -
+
- - - - {addresses.length > 0 ? ( -
- {addresses.map((a) => ( - - {a} - - ))} -
- ) : ( -
Нет IP адресов.
- )} -
- - - {Array.isArray((player as any).serverJoinHistory) ? ( -
- {(player as any).serverJoinHistory?.length || 0} записей -
- ) : ( -
Нет данных.
- )} -
-
- +