Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions src/shared/converters/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import quilt from '@/assets/logos/quilt.png';

export const convertGameLoaderImage = (loader: GameLoaderOption) => {
const converter: Record<GameLoaderOption, ReactElement> = {
[GameLoaderOption.VANILLA]: <Image src={vanilla} alt="Minecraft" width={24} height={24} />,
[GameLoaderOption.FORGE]: <Image src={forge} alt="Forge" width={24} height={24} />,
[GameLoaderOption.FABRIC]: <Image src={fabric} alt="Fabric" width={24} height={24} />,
[GameLoaderOption.NEOFORGE]: <Image src={neoForge} alt="NeoForge" width={18} height={18} />,
[GameLoaderOption.QUILT]: <Image src={quilt} alt="Quilt" width={18} height={18} />,
[GameLoaderOption.VANILLA]: <Image src={vanilla} alt="Minecraft" width={24} height={24}/>,
[GameLoaderOption.FORGE]: <Image src={forge} alt="Forge" width={24} height={24}/>,
[GameLoaderOption.FABRIC]: <Image src={fabric} alt="Fabric" width={24} height={24}/>,
[GameLoaderOption.NEOFORGE]: <Image src={neoForge} alt="NeoForge" width={18} height={18}/>,
[GameLoaderOption.QUILT]: <Image src={quilt} alt="Quilt" width={18} height={18}/>,
[GameLoaderOption.LITELOADER]: (
<Image src={liteLoader} alt="Liteloader" width={24} height={24} />
<Image src={liteLoader} alt="Liteloader" width={24} height={24}/>
),
};

Expand All @@ -27,24 +27,38 @@ export const convertGameLoaderImage = (loader: GameLoaderOption) => {
export const convertApiGameLoaderImage = (loader: GameLoaderType) => {
const converter: Record<GameLoaderType, ReactElement> = {
[GameLoaderType.VANILLA]: (
<Image src={vanilla} alt="Minecraft" className="min-w-4" width={24} height={24} />
<Image src={vanilla} alt="Minecraft" className="min-w-4" width={24} height={24}/>
),
[GameLoaderType.FORGE]: (
<Image src={forge} alt="Forge" className="min-w-6" width={24} height={24} />
<Image src={forge} alt="Forge" className="min-w-6" width={24} height={24}/>
),
[GameLoaderType.FABRIC]: (
<Image src={fabric} alt="Fabric" className="min-w-4" width={24} height={24} />
<Image src={fabric} alt="Fabric" className="min-w-4" width={24} height={24}/>
),
[GameLoaderType.NEOFORGE]: (
<Image src={neoForge} alt="NeoForge" className="min-w-4" width={18} height={18} />
<Image src={neoForge} alt="NeoForge" className="min-w-4" width={18} height={18}/>
),
[GameLoaderType.QUILT]: (
<Image src={quilt} alt="Quilt" className="min-w-4" width={18} height={18} />
<Image src={quilt} alt="Quilt" className="min-w-4" width={18} height={18}/>
),
[GameLoaderType.LITELOADER]: (
<Image src={liteLoader} alt="Liteloader" className="min-w-4" width={24} height={24} />
<Image src={liteLoader} alt="Liteloader" className="min-w-4" width={24} height={24}/>
),
};

return converter[loader];
};


export const convertApiGameLoaderName = (loader: GameLoaderType) => {
const converter: Record<GameLoaderType, string> = {
[GameLoaderType.VANILLA]: 'Minecraft',
[GameLoaderType.FORGE]: 'Forge',
[GameLoaderType.FABRIC]: 'Fabric',
[GameLoaderType.NEOFORGE]: 'NeoForge',
[GameLoaderType.QUILT]: 'Quilt',
[GameLoaderType.LITELOADER]: 'Liteloader',
};

return converter[loader];
};
99 changes: 65 additions & 34 deletions src/widgets/profiles-table/lib/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Image from 'next/image';
import { useRouter } from 'next/navigation';
import { useQueryClient } from '@tanstack/react-query';
import { createColumnHelper } from '@tanstack/table-core';
import { Edit2Icon, Trash2Icon } from 'lucide-react';
import { Edit2Icon, Trash2Icon, X } from 'lucide-react';

import { ClientState } from '@/widgets/client-hub';
import { DataTableColumnHeader } from '@/entities/Table';
Expand All @@ -16,14 +16,14 @@ import { DASHBOARD_PAGES } from '@/shared/routes';
import { Icons } from '@/shared/ui/icons';
import { getFormatDate } from '@/shared/lib/utils';
import { profileKeys } from '@/shared/hooks';
import { convertApiGameLoaderImage } from '@/shared/converters';
import { convertApiGameLoaderImage, convertApiGameLoaderName } from '@/shared/converters';
import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip";

enum ColumnHeader {
ICON = '',
NAME = 'Название',
CREATED_AT = 'Дата создания',
VERSION_LAUNCHER = 'Запускаемая версия',
LOADER_LAUNCHER = '',
GAME_VERSION = 'Версия',
PRIORITY = 'Приоритет',
PROFILE_STATE = 'Статус',
Expand Down Expand Up @@ -71,86 +71,117 @@ export const useColumns = (props: UseColumnsProps) => {
enableSorting: false,
enableHiding: false,
}),


columnsHelper.accessor('iconBase64', {
size: 64,
header: ColumnHeader.ICON,
cell: ({ row }) =>
row.original.iconBase64 ? (
<Image
className="min-w-12 min-h-12 h-12 w-12"
src={`data:image/png;base64,${row.original.iconBase64}`}
alt={row.original.name || 'Profile Icon'}
width={48}
height={48}
/>
) : (
<div className="flex items-center justify-center min-w-12 min-h-12 h-12 w-12 bg-gray-200/5 rounded-xl">
{row.original.name.substring(0, 2).toUpperCase()}
cell: ({ row }) => {
const hasIcon = Boolean(row.original.iconBase64);
const hasLoader = Boolean(row.original.loader);

const loaderIcon = convertApiGameLoaderImage(row.original.loader);
const loaderName = convertApiGameLoaderName(row.original.loader);

return (
<div className="relative">
<div className="absolute bottom-[-.5rem] right-[-1rem] bg-primary rounded-full">
{hasLoader ? (
<Tooltip>
<TooltipTrigger asChild>
{loaderIcon}
</TooltipTrigger>
<TooltipContent>
{loaderName}: {row.original.launchVersion}
</TooltipContent>
</Tooltip>
) : (
<Tooltip>
<TooltipTrigger asChild>
<X/>
</TooltipTrigger>
<TooltipContent>
<p>Не загружен</p>
</TooltipContent>
</Tooltip>
)}
</div>


{hasIcon ? (
<Image
className="min-w-12 min-h-12 h-12 w-12"
src={`data:image/png;base64,${row.original.iconBase64}`}
alt={row.original.name || 'Profile Icon'}
width={48}
height={48}
/>
) : (
<div className="flex items-center justify-center min-w-12 min-h-12 h-12 w-12 bg-gray-200/5 rounded-xl">
{row.original.name.substring(0, 2).toUpperCase()}
</div>
)}
</div>
),


);
}

}),

columnsHelper.display({
size: 400,
id: 'name',
header: ({ column }) => <DataTableColumnHeader column={column} title={ColumnHeader.NAME} />,
header: ({ column }) => <DataTableColumnHeader column={column} title={ColumnHeader.NAME}/>,
cell: ({ row }) => (
<div className="flex flex-col gap-2">
<p className="text-sm text-muted-foreground">{row.original.name}</p>
<h3>{row.original.displayName}</h3>
</div>
),
}),
columnsHelper.accessor('loader', {
size: 70,
enableSorting: false,
header: ({ column }) => (
<DataTableColumnHeader column={column} title={ColumnHeader.LOADER_LAUNCHER} />
),
cell: ({ getValue }) => (getValue() ? convertApiGameLoaderImage(getValue()) : 'Не загружен'),
}),
columnsHelper.accessor('launchVersion', {
size: 500,
header: ({ column }) => (
<DataTableColumnHeader column={column} title={ColumnHeader.VERSION_LAUNCHER} />
<DataTableColumnHeader column={column} title={ColumnHeader.VERSION_LAUNCHER}/>
),
cell: ({ getValue }) => (getValue() ? getValue() : 'Не загружен'),
}),
columnsHelper.accessor('gameVersion', {
size: 100,

header: ({ column }) => (
<DataTableColumnHeader column={column} title={ColumnHeader.GAME_VERSION} />
<DataTableColumnHeader column={column} title={ColumnHeader.GAME_VERSION}/>
),
cell: ({ getValue }) => getValue(),
}),
columnsHelper.accessor('createDate', {
size: 500,
header: ({ column }) => (
<DataTableColumnHeader column={column} title={ColumnHeader.CREATED_AT} />
<DataTableColumnHeader column={column} title={ColumnHeader.CREATED_AT}/>
),
cell: ({ getValue }) => getFormatDate(getValue()),
}),
columnsHelper.accessor('priority', {
size: 150,
header: ({ column }) => (
<DataTableColumnHeader column={column} title={ColumnHeader.PRIORITY} />
<DataTableColumnHeader column={column} title={ColumnHeader.PRIORITY}/>
),
cell: ({ getValue }) => getValue(),
}),
columnsHelper.accessor('state', {
size: 270,
header: ({ column }) => (
<DataTableColumnHeader column={column} title={ColumnHeader.PROFILE_STATE} />
<DataTableColumnHeader column={column} title={ColumnHeader.PROFILE_STATE}/>
),
cell: ({ getValue }) => <ClientState state={getValue()} />,
cell: ({ getValue }) => <ClientState state={getValue()}/>,
}),
columnsHelper.display({
size: 48,
id: 'edit',
cell: ({ row }) => (
<Button variant="ghost" size="icon" onClick={onRedirectEditProfile(row.original.name)}>
<Edit2Icon size={16} />
<Edit2Icon size={16}/>
</Button>
),
}),
Expand All @@ -171,9 +202,9 @@ export const useColumns = (props: UseColumnsProps) => {
disabled={props.isPendingDelete}
>
{props.isPendingDelete ? (
<Icons.spinner className="h-4 w-4 animate-spin" />
<Icons.spinner className="h-4 w-4 animate-spin"/>
) : (
<Trash2Icon size={16} />
<Trash2Icon size={16}/>
)}
</Button>
);
Expand Down