From 8967c9bac27a125b30232a3010813c608b30eb04 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 10 Jan 2026 00:42:18 +0300 Subject: [PATCH] fixes --- admin/package-lock.json | 62 +++++++++++++++++++ admin/package.json | 1 + .../src/components/CreateAdminRoomDialog.tsx | 2 - admin/src/components/ThemeEditorDialog.tsx | 2 - admin/src/components/ui/tabs.tsx | 56 +++++++++++++++++ admin/src/pages/ThemesPage.tsx | 4 +- backend/package-lock.json | 21 +++++++ backend/package.json | 1 + .../src/admin/rooms/admin-rooms.service.ts | 8 ++- .../src/admin/themes/admin-themes.service.ts | 25 +++++++- 10 files changed, 171 insertions(+), 11 deletions(-) create mode 100644 admin/src/components/ui/tabs.tsx diff --git a/admin/package-lock.json b/admin/package-lock.json index 353d480..02b0ad1 100644 --- a/admin/package-lock.json +++ b/admin/package-lock.json @@ -15,6 +15,7 @@ "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", "@tanstack/react-query": "^5.90.11", "autoprefixer": "^10.4.22", "axios": "^1.13.2", @@ -1844,6 +1845,37 @@ } } }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-select": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", @@ -1923,6 +1955,36 @@ } } }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", diff --git a/admin/package.json b/admin/package.json index a8663d7..f6d8f59 100644 --- a/admin/package.json +++ b/admin/package.json @@ -18,6 +18,7 @@ "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", "@tanstack/react-query": "^5.90.11", "autoprefixer": "^10.4.22", "axios": "^1.13.2", diff --git a/admin/src/components/CreateAdminRoomDialog.tsx b/admin/src/components/CreateAdminRoomDialog.tsx index 38bfcc4..dd44cb5 100644 --- a/admin/src/components/CreateAdminRoomDialog.tsx +++ b/admin/src/components/CreateAdminRoomDialog.tsx @@ -60,8 +60,6 @@ export function CreateAdminRoomDialog({ }, }) - const [showAdvanced, setShowAdvanced] = useState(false) - // Fetch data const { data: usersData } = useQuery({ queryKey: ['users', 1], diff --git a/admin/src/components/ThemeEditorDialog.tsx b/admin/src/components/ThemeEditorDialog.tsx index 570c673..07a87e6 100644 --- a/admin/src/components/ThemeEditorDialog.tsx +++ b/admin/src/components/ThemeEditorDialog.tsx @@ -19,7 +19,6 @@ import { DialogTitle, } from '@/components/ui/dialog' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { Eye, EyeOff } from 'lucide-react' interface ThemeEditorDialogProps { open: boolean @@ -81,7 +80,6 @@ export function ThemeEditorDialog({ const [isPublic, setIsPublic] = useState(false) const [colors, setColors] = useState(DEFAULT_THEME_COLORS) const [settings, setSettings] = useState(DEFAULT_THEME_SETTINGS) - const [showPreview, setShowPreview] = useState(false) useEffect(() => { if (theme) { diff --git a/admin/src/components/ui/tabs.tsx b/admin/src/components/ui/tabs.tsx new file mode 100644 index 0000000..87eeec5 --- /dev/null +++ b/admin/src/components/ui/tabs.tsx @@ -0,0 +1,56 @@ +"use client" + +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +const Tabs = TabsPrimitive.Root + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsList.displayName = TabsPrimitive.List.displayName + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsContent.displayName = TabsPrimitive.Content.displayName + +export { Tabs, TabsList, TabsTrigger, TabsContent } + diff --git a/admin/src/pages/ThemesPage.tsx b/admin/src/pages/ThemesPage.tsx index a1762c7..4f5dfea 100644 --- a/admin/src/pages/ThemesPage.tsx +++ b/admin/src/pages/ThemesPage.tsx @@ -4,8 +4,6 @@ import { toast } from 'sonner' import { themesApi, isThemesApiError, - DEFAULT_THEME_COLORS, - DEFAULT_THEME_SETTINGS, type ThemePreview, type ThemeColors, type ThemeSettings, @@ -35,7 +33,7 @@ import { } from '@/components/ui/alert-dialog' import { Label } from '@/components/ui/label' import { Checkbox } from '@/components/ui/checkbox' -import { Plus, Search, Edit, Trash2, ChevronLeft, ChevronRight, Eye } from 'lucide-react' +import { Plus, Search, Edit, Trash2, ChevronLeft, ChevronRight } from 'lucide-react' import { ThemeEditorDialog } from '@/components/ThemeEditorDialog' export default function ThemesPage() { diff --git a/backend/package-lock.json b/backend/package-lock.json index 4a756e2..0f06296 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -13,6 +13,7 @@ "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.0.1", "@nestjs/jwt": "^11.0.2", + "@nestjs/mapped-types": "^2.1.0", "@nestjs/passport": "^11.0.5", "@nestjs/platform-express": "^11.0.1", "@nestjs/platform-socket.io": "^11.1.11", @@ -2179,6 +2180,26 @@ "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" } }, + "node_modules/@nestjs/mapped-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", + "integrity": "sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/passport": { "version": "11.0.5", "license": "MIT", diff --git a/backend/package.json b/backend/package.json index e630b09..9609dee 100644 --- a/backend/package.json +++ b/backend/package.json @@ -27,6 +27,7 @@ "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.0.1", "@nestjs/jwt": "^11.0.2", + "@nestjs/mapped-types": "^2.1.0", "@nestjs/passport": "^11.0.5", "@nestjs/platform-express": "^11.0.1", "@nestjs/platform-socket.io": "^11.1.11", diff --git a/backend/src/admin/rooms/admin-rooms.service.ts b/backend/src/admin/rooms/admin-rooms.service.ts index dfdb085..8a3218b 100644 --- a/backend/src/admin/rooms/admin-rooms.service.ts +++ b/backend/src/admin/rooms/admin-rooms.service.ts @@ -4,6 +4,7 @@ import { RoomFiltersDto } from './dto/room-filters.dto'; import { CreateAdminRoomDto } from './dto/create-admin-room.dto'; import { RoomPackService } from '../../room-pack/room-pack.service'; import { customAlphabet } from 'nanoid'; +import { Prisma } from '@prisma/client'; const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 6); @@ -175,7 +176,9 @@ export class AdminRoomsService { activeFrom: dto.activeFrom ? new Date(dto.activeFrom) : null, activeTo: dto.activeTo ? new Date(dto.activeTo) : null, themeId: dto.themeId || null, - uiControls: dto.uiControls || null, + uiControls: dto.uiControls + ? (dto.uiControls as Prisma.InputJsonValue) + : undefined, questionPackId: dto.questionPackId || null, maxPlayers: maxPlayers || 10, allowSpectators: allowSpectators !== undefined ? allowSpectators : true, @@ -208,7 +211,8 @@ export class AdminRoomsService { }); // Создать участника-хоста - const hostName = dto.hostName || room.host.name || 'Ведущий'; + const hostName = + dto.hostName || (room.host ? room.host.name : null) || 'Ведущий'; await this.prisma.participant.create({ data: { userId: dto.hostId, diff --git a/backend/src/admin/themes/admin-themes.service.ts b/backend/src/admin/themes/admin-themes.service.ts index f5d137c..314c45f 100644 --- a/backend/src/admin/themes/admin-themes.service.ts +++ b/backend/src/admin/themes/admin-themes.service.ts @@ -3,6 +3,7 @@ import { PrismaService } from '../../prisma/prisma.service'; import { ThemeFiltersDto } from './dto/theme-filters.dto'; import { CreateThemeDto } from './dto/create-theme.dto'; import { UpdateThemeDto } from './dto/update-theme.dto'; +import { Prisma } from '@prisma/client'; @Injectable() export class AdminThemesService { @@ -81,8 +82,11 @@ export class AdminThemesService { async create(createThemeDto: CreateThemeDto, createdBy: string) { return this.prisma.theme.create({ data: { - ...createThemeDto, + name: createThemeDto.name, + isPublic: createThemeDto.isPublic, createdBy, + colors: JSON.parse(JSON.stringify(createThemeDto.colors)) as Prisma.InputJsonValue, + settings: JSON.parse(JSON.stringify(createThemeDto.settings)) as Prisma.InputJsonValue, }, include: { creator: { @@ -105,9 +109,26 @@ export class AdminThemesService { throw new NotFoundException('Theme not found'); } + const updateData: Prisma.ThemeUpdateInput = { + ...(updateThemeDto.name !== undefined && { name: updateThemeDto.name }), + ...(updateThemeDto.isPublic !== undefined && { + isPublic: updateThemeDto.isPublic, + }), + ...(updateThemeDto.colors && { + colors: JSON.parse( + JSON.stringify(updateThemeDto.colors), + ) as Prisma.InputJsonValue, + }), + ...(updateThemeDto.settings && { + settings: JSON.parse( + JSON.stringify(updateThemeDto.settings), + ) as Prisma.InputJsonValue, + }), + }; + return this.prisma.theme.update({ where: { id }, - data: updateThemeDto, + data: updateData, include: { creator: { select: {