From 4e5ab9ffaf9b14bf81368658ea522f6c38d62e53 Mon Sep 17 00:00:00 2001 From: toximu Date: Sat, 13 Jun 2026 13:04:36 +0300 Subject: [PATCH 1/2] add updating submissions by websocket --- src/pages/WorkspacePage.jsx | 10 +++++----- src/pages/useMatchSession.js | 18 +++++++++++++++++- src/pages/useMatchStore.js | 7 +++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/pages/WorkspacePage.jsx b/src/pages/WorkspacePage.jsx index e58fb85..d8f873f 100644 --- a/src/pages/WorkspacePage.jsx +++ b/src/pages/WorkspacePage.jsx @@ -3,7 +3,6 @@ import SettingsModal from './components/ui/SettingsModal'; import { useState, useEffect } from 'react'; import { PanelGroup, PanelResizeHandle } from "react-resizable-panels"; import {useNavigate, useParams} from 'react-router-dom'; -import { useParcelPolling } from './useParcelPolling'; import Header from './components/layout/Header'; import Footer from './components/layout/Footer'; import LeftWorkspace from './components/workspace/LeftWorkspace'; @@ -11,6 +10,7 @@ import RightWorkspace from './components/workspace/RightWorkspace'; import './WorkspacePage.css'; import MatchResultOverlay from './MatchResultOverlay'; import { useMatchStore } from "./useMatchStore.js"; +import {useMatchSession} from "./useMatchSession.js"; function WorkspacePage() { const {matchId} = useParams(); @@ -19,7 +19,7 @@ function WorkspacePage() { const [isDarkMode, setIsDarkMode] = useState(true); const [isSwapped, setIsSwapped] = useState(false); const [showSettings, setShowSettings] = useState(false); - const { submissions } = useParcelPolling(); + const { userSubmissions } = useMatchSession(); const matchResult = useMatchStore((state) => state.matchResult); @@ -43,9 +43,9 @@ function WorkspacePage() {
{isSwapped ? ( - + ) : ( - + )} @@ -55,7 +55,7 @@ function WorkspacePage() { {isSwapped ? ( ) : ( - + )}
diff --git a/src/pages/useMatchSession.js b/src/pages/useMatchSession.js index 46a6a58..9601351 100644 --- a/src/pages/useMatchSession.js +++ b/src/pages/useMatchSession.js @@ -16,6 +16,11 @@ export const useMatchSession = (matchId) => { const [opponent, setOpponent] = useState(null); const {user} = useUser(); const [sessionData, setSessionData] = useState(null); + const matchSubmissions = useMatchStore((state) => state.matchSubmissions); + const userSubmissions = matchSubmissions + .filter(sub => sub.userId === user?.id); + + useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect setSessionData(draftSessionDTO?.draftSession); @@ -51,9 +56,20 @@ export const useMatchSession = (matchId) => { } }, [isRedirect, matchId, navigate, resetStore]); + useEffect(() => { + if (matchSubmissions.length === 0) return; + + const lastSubmission = matchSubmissions[0]; + + if (lastSubmission.userId !== user?.id) { + toast.success("Оппонент попытался решить задачу"); + } + + }, [matchSubmissions.length]); + const sendBan = (category, value) => { publish(`/app/${matchId}/ban`, {category: category, banObject: value}); }; - return {sessionData, opponent, error, sendBan, isConnected}; + return {sessionData, opponent, error, sendBan, isConnected, userSubmissions}; }; diff --git a/src/pages/useMatchStore.js b/src/pages/useMatchStore.js index 85c294a..0143ec1 100644 --- a/src/pages/useMatchStore.js +++ b/src/pages/useMatchStore.js @@ -6,6 +6,7 @@ export const useMatchStore = create((set) => ({ error: { stage: null, message: null }, matchStarted: false, matchResult: null, + matchSubmissions : [], handleIncomingMessage: (payload) => { switch (payload.status) { @@ -18,6 +19,12 @@ export const useMatchStore = create((set) => ({ case 'MATCH_FINISHED': set({ matchResult: payload.payload }); break; + + case 'SUBMISSION': + set((state) => ({ + matchSubmissions: [ payload.payload, ...state.matchSubmissions] + })); + break; } }, From ffebe4220f307fbd6e6f9df7b079a06851033822 Mon Sep 17 00:00:00 2001 From: toximu Date: Tue, 16 Jun 2026 22:43:30 +0300 Subject: [PATCH 2/2] fix submissions and draft page --- src/pages/BattlePage.jsx | 10 ++++- src/pages/DraftPage.jsx | 50 ++++++++++++------------ src/pages/WorkspacePage.jsx | 74 ++++++++++++++++++------------------ src/pages/useMatchSession.js | 11 ++++-- src/pages/useMatchStore.js | 2 +- 5 files changed, 79 insertions(+), 68 deletions(-) diff --git a/src/pages/BattlePage.jsx b/src/pages/BattlePage.jsx index e726ca6..824e4ee 100644 --- a/src/pages/BattlePage.jsx +++ b/src/pages/BattlePage.jsx @@ -6,6 +6,7 @@ import Footer from './components/layout/Footer'; import SettingsModal from './components/ui/SettingsModal'; import QueueModal from './components/ui/QueueModal'; import { useQueueSSE } from './useQueueSSE'; +import {useMatchStore} from "./useMatchStore.js"; import './BattlePage.css'; if (typeof global === 'undefined') { @@ -16,10 +17,15 @@ export default function BattlePage() { const navigate = useNavigate(); const { logout } = useUser(); const [showSettings, setShowSettings] = useState(false); - + const resetStore = useMatchStore((state) => state.resetStore); const { isModalOpen, queueSize, waitSeconds, isConnecting, enterQueue, leaveQueue } = useQueueSSE(); + const enterQueueAndResetStore = () => { + resetStore(); + enterQueue(); + } + const handleLogout = () => { logout(); navigate('/login'); @@ -37,7 +43,7 @@ export default function BattlePage() { - ); - }) + // Копируем массив через [...] и сортируем по свойству option (строка с именем) + [...options] + .sort((a, b) => a.option.localeCompare(b.option)) + .map(({ option, banned }) => { + const isClickable = active && !banned; + + let btnClass = "draft-ban-btn"; + if (banned) { + btnClass += " banned"; + } else if (isCategoryFinished) { + btnClass += " selected-winner"; + } + + return ( + + ); + }) ) : (

Опций не осталось

)} diff --git a/src/pages/WorkspacePage.jsx b/src/pages/WorkspacePage.jsx index d8f873f..d532e30 100644 --- a/src/pages/WorkspacePage.jsx +++ b/src/pages/WorkspacePage.jsx @@ -37,48 +37,48 @@ function WorkspacePage() { }; return ( -
-
setShowSettings(true)} /> +
+
setShowSettings(true)} /> -
- - {isSwapped ? ( - - ) : ( - - )} - - -
-
- - {isSwapped ? ( - - ) : ( - - )} -
-
+
+ + {isSwapped ? ( + + ) : ( + + )} -
+ +
+
- setShowSettings(false)} - onLogout={handleLogout} - themeConfig={{ isDarkMode, setIsDarkMode }} - workspaceConfig={{ isSwapped, setIsSwapped }} - /> + {isSwapped ? ( + + ) : ( + + )} + +
- {matchResult && ( - - )} +
-
+ setShowSettings(false)} + onLogout={handleLogout} + themeConfig={{ isDarkMode, setIsDarkMode }} + workspaceConfig={{ isSwapped, setIsSwapped }} + /> + + {matchResult && ( + + )} + +
); } diff --git a/src/pages/useMatchSession.js b/src/pages/useMatchSession.js index 9601351..f408ed3 100644 --- a/src/pages/useMatchSession.js +++ b/src/pages/useMatchSession.js @@ -19,7 +19,7 @@ export const useMatchSession = (matchId) => { const matchSubmissions = useMatchStore((state) => state.matchSubmissions); const userSubmissions = matchSubmissions .filter(sub => sub.userId === user?.id); - + console.log(`user id : ${user?.id}`); useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect @@ -32,7 +32,11 @@ export const useMatchSession = (matchId) => { const amIFirstUser = user.id === sessionData.firstUserId; const opponentId = amIFirstUser ? sessionData.secondUserId : sessionData.firstUserId; - if (!opponentId) return; + if (!opponentId) { + console.log(`session data: ${sessionData}`); + console.log(`opponent id : ${opponentId}`); + return; + }; api.get(`user/info/${opponentId}`) .then(response => { @@ -60,8 +64,9 @@ export const useMatchSession = (matchId) => { if (matchSubmissions.length === 0) return; const lastSubmission = matchSubmissions[0]; - + console.log(`submission id: ${lastSubmission.userId}`); if (lastSubmission.userId !== user?.id) { + toast.success("Оппонент попытался решить задачу"); } diff --git a/src/pages/useMatchStore.js b/src/pages/useMatchStore.js index 0143ec1..8c209d6 100644 --- a/src/pages/useMatchStore.js +++ b/src/pages/useMatchStore.js @@ -32,5 +32,5 @@ export const useMatchStore = create((set) => ({ set({ error: { stage: null, message: payload.message } }); }, - resetStore: () => set({ matchStarted: null, error: null, matchResult: null }), + resetStore: () => set({ matchStarted: false, error: {stage : null, message : null}, matchResult: null, draftSessionDTO : null, matchSubmissions : [] }), })); \ No newline at end of file