diff --git a/src/components/Ingame.vue b/src/components/Ingame.vue
new file mode 100644
index 0000000..0036a68
--- /dev/null
+++ b/src/components/Ingame.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/ingame/GameInfo.vue b/src/components/ingame/GameInfoC.vue
similarity index 100%
rename from src/components/ingame/GameInfo.vue
rename to src/components/ingame/GameInfoC.vue
diff --git a/src/components/ingame/Hand.vue b/src/components/ingame/HandC.vue
similarity index 100%
rename from src/components/ingame/Hand.vue
rename to src/components/ingame/HandC.vue
diff --git a/src/components/ingame/PlayedCards.vue b/src/components/ingame/PlayedCardsC.vue
similarity index 100%
rename from src/components/ingame/PlayedCards.vue
rename to src/components/ingame/PlayedCardsC.vue
diff --git a/src/components/ingame/Scoreboard.vue b/src/components/ingame/ScoreboardC.vue
similarity index 100%
rename from src/components/ingame/Scoreboard.vue
rename to src/components/ingame/ScoreboardC.vue
diff --git a/src/components/ingame/Turn.vue b/src/components/ingame/TurnC.vue
similarity index 100%
rename from src/components/ingame/Turn.vue
rename to src/components/ingame/TurnC.vue
diff --git a/src/composables/useIngame.ts b/src/composables/useIngame.ts
new file mode 100644
index 0000000..459d505
--- /dev/null
+++ b/src/composables/useIngame.ts
@@ -0,0 +1,29 @@
+import { defineStore } from 'pinia'
+import {ref, type Ref} from 'vue'
+import type {GameInfo, LobbyInfo, TieInfo, TrumpInfo, WonInfo} from "@/types/GameTypes.ts";
+import axios from "axios";
+
+const api = window?.__RUNTIME_CONFIG__?.API_URL;
+
+export const useIngame = defineStore('ingame', () => {
+ const state: Ref<'Lobby' | 'InGame' | 'SelectTrump' | 'TieBreak' | 'FinishedMatch' | null> = ref(null);
+ const data: Ref = ref(null);
+
+ function setIngame(newState: 'Lobby' | 'InGame' | 'SelectTrump' | 'TieBreak' | 'FinishedMatch', newData: GameInfo | LobbyInfo | TieInfo | TrumpInfo | WonInfo) {
+ state.value = newState;
+ data.value = newData;
+ }
+
+ function requestGame(gameId: string) {
+ axios.get(`${api}/status/${gameId}`, {withCredentials: true}).then((response) => {
+ setIngame(response.data.state, response.data.data);
+ });
+ }
+
+ function clearIngame() {
+ state.value = null;
+ data.value = null;
+ }
+
+ return { state, data, requestGame, setIngame, clearIngame };
+});
diff --git a/src/composables/useUserInfo.ts b/src/composables/useUserInfo.ts
index 220796d..781ba8a 100644
--- a/src/composables/useUserInfo.ts
+++ b/src/composables/useUserInfo.ts
@@ -1,19 +1,40 @@
import { defineStore } from 'pinia'
import {ref, type Ref} from 'vue'
+import axios from "axios";
+
+const api = window?.__RUNTIME_CONFIG__?.API_URL;
export const useUserInfo = defineStore('userInfo', () => {
const username: Ref = ref(null);
const userId: Ref = ref(null);
+ const gameId: Ref = ref(null);
function setUserInfo(name: string, id: number) {
username.value = name;
userId.value = id;
}
+ function setGameId(id: string) {
+ gameId.value = id;
+ }
+
+ function requestState() {
+ axios.get(`${api}/status`, {withCredentials: true}).then((response) => {
+ username.value = response.data.username;
+ if (response.data.ingame) {
+ gameId.value = response.data.gameId;
+ }
+ });
+ }
+
function clearUserInfo() {
username.value = null;
userId.value = null;
}
- return { username, userId, setUserInfo, clearUserInfo };
+ function clearGameId() {
+ gameId.value = null;
+ }
+
+ return { username, userId, gameId, setUserInfo, requestState, clearUserInfo, setGameId, clearGameId };
});
diff --git a/src/composables/useWebsocket.ts b/src/composables/useWebsocket.ts
index 8de496d..12d721a 100644
--- a/src/composables/useWebsocket.ts
+++ b/src/composables/useWebsocket.ts
@@ -6,8 +6,13 @@ import {
sendEventAndWait,
onEvent,
isWebSocketConnected,
+ setDefaultHandler,
} from "@/services/ws";
+function defaultEventHandler(data: (data: T) => void) {
+ setDefaultHandler(data);
+}
+
export function useWebSocket() {
const isConnected = ref(isWebSocketConnected());
const lastMessage = ref(null);
@@ -51,5 +56,6 @@ export function useWebSocket() {
sendAndWait: sendEventAndWait,
useEvent,
+ defaultEventHandler
};
}
diff --git a/src/services/ws.ts b/src/services/ws.ts
index 220aa72..7b59a09 100644
--- a/src/services/ws.ts
+++ b/src/services/ws.ts
@@ -1,3 +1,6 @@
+import {useIngame} from "@/composables/useIngame.ts";
+import type {GameInfo, LobbyInfo, TieInfo, TrumpInfo, WonInfo} from "@/types/GameTypes.ts";
+
const api = window.__RUNTIME_CONFIG__?.API_URL;
// ---------- Types ---------------------------------------------------------
@@ -6,6 +9,8 @@ export type ServerMessage = {
id?: string;
event?: string;
status?: "success" | "error";
+ state?: "Lobby" | "InGame" | "SelectTrump" | "TieBreak" | "FinishedMatch";
+ stateData?: GameInfo | LobbyInfo | TieInfo | TrumpInfo | WonInfo;
data?: T;
error?: string;
};
@@ -28,9 +33,12 @@ let ws: WebSocket | null = null;
const pending = new Map();
const handlers = new Map();
+const uState = useIngame();
let heartbeatTimer: ReturnType | null = null;
+let defaultHandler: HandlerFn | null = null;
+
function uuid(): string {
return crypto.randomUUID();
}
@@ -73,7 +81,7 @@ function setupSocketHandlers(socket: WebSocket) {
return;
}
- const { id, event, status, data } = msg;
+ const { id, event, state, stateData, status, data } = msg;
// RPC response branch
if (id && status) {
@@ -91,6 +99,10 @@ function setupSocketHandlers(socket: WebSocket) {
return;
}
+ if (state && stateData) {
+ uState.setIngame(state, stateData);
+ }
+
// Server event → handler branch
if (id && event) {
const handler = handlers.get(event);
@@ -103,7 +115,17 @@ function setupSocketHandlers(socket: WebSocket) {
if (!handler) {
console.warn("[WS] No handler for event:", event);
- reply("error", `No handler for '${event}'`);
+ if (defaultHandler) {
+ try {
+ await defaultHandler(data ?? {});
+ reply("success");
+ } catch (err) {
+ reply("error", (err as Error).message);
+
+ }
+ } else {
+ reply("error", `No handler for '${event}'`);
+ }
return;
}
@@ -232,5 +254,9 @@ export function onEvent(event: string, handler: HandlerFn) {
handlers.set(event, handler);
}
+export function setDefaultHandler(handler: HandlerFn) {
+ defaultHandler = handler;
+}
+
export const isWebSocketConnected = () =>
!!ws && ws.readyState === WebSocket.OPEN;
diff --git a/src/views/Game.vue b/src/views/Game.vue
new file mode 100644
index 0000000..ccc2934
--- /dev/null
+++ b/src/views/Game.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+