From 7d97ad12eef336669a4bdc4f004aa645cfd619c8 Mon Sep 17 00:00:00 2001 From: jkrumm Date: Mon, 15 Jan 2024 19:36:47 +0100 Subject: [PATCH] feat(v2): room state persisted in Redis & TRPC endpoints to update state This way the clients don't confuse each other with individual problems or race conditions. Closes #65 --- .gitignore | 1 + src/components/room/interactions.tsx | 135 +++++------- src/components/room/room-wrapper.tsx | 53 +++-- src/components/room/room.tsx | 47 ++++ src/components/room/table.tsx | 169 +++++--------- src/components/room/username-model.tsx | 1 - src/components/room/websocket-receiver.tsx | 123 ----------- src/env.mjs | 8 + src/hooks/use-heartbeat.hook.ts | 40 ++++ src/hooks/use-room-state.hook.ts | 55 +++++ src/hooks/use-tracking.hook.ts | 23 +- src/pages/api/ably-token.ts | 7 +- src/server/api/root.ts | 2 + src/server/room-state/room-state.entity.ts | 208 ++++++++++++++++++ .../room-state/room-state.repository.ts | 106 +++++++++ src/server/room-state/room-state.router.ts | 175 +++++++++++++++ src/store/local-storage.store.ts | 12 +- src/store/room-state.store.ts | 74 +++++++ src/store/ws.store.ts | 150 ------------- src/styles/globals.css | 6 + 20 files changed, 889 insertions(+), 506 deletions(-) create mode 100644 src/components/room/room.tsx delete mode 100644 src/components/room/websocket-receiver.tsx create mode 100644 src/hooks/use-heartbeat.hook.ts create mode 100644 src/hooks/use-room-state.hook.ts create mode 100644 src/server/room-state/room-state.entity.ts create mode 100644 src/server/room-state/room-state.repository.ts create mode 100644 src/server/room-state/room-state.router.ts create mode 100644 src/store/room-state.store.ts delete mode 100644 src/store/ws.store.ts diff --git a/.gitignore b/.gitignore index e713fbb..e73f7a0 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ yarn-error.log* # do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables .env .env*.local +.envrc # vercel .vercel diff --git a/src/components/room/interactions.tsx b/src/components/room/interactions.tsx index bc52f56..630b323 100644 --- a/src/components/room/interactions.tsx +++ b/src/components/room/interactions.tsx @@ -1,56 +1,47 @@ import { Button, Switch } from "@mantine/core"; import { notifications } from "@mantine/notifications"; -import { type PresenceUpdate, useWsStore } from "fpp/store/ws.store"; -import { useEffect, useRef } from "react"; +import { useRef } from "react"; import { useRouter } from "next/router"; -import { useLocalstorageStore } from "fpp/store/local-storage.store"; import { fibonacciSequence } from "fpp/constants/fibonacci.constant"; import { type Logger } from "next-axiom"; import { logMsg, roomEvent } from "fpp/constants/logging.constant"; import { RouteType } from "fpp/server/db/schema"; +import { useRoomStateStore } from "fpp/store/room-state.store"; +import { useLocalstorageStore } from "fpp/store/local-storage.store"; +import { api } from "fpp/utils/api"; export const Interactions = ({ roomId, roomReadable, - username, + userId, logger, }: { roomId: number; roomReadable: string; - username: string; + userId: string; logger: Logger; }) => { const router = useRouter(); - const clientId = useWsStore((store) => store.clientId); - const channel = useWsStore((store) => store.channel); - - const userId = useLocalstorageStore((state) => state.userId); - const voting = useLocalstorageStore((store) => store.voting); - const setVoting = useLocalstorageStore((store) => store.setVoting); - const setSpectator = useLocalstorageStore((store) => store.setSpectator); const setRoomId = useLocalstorageStore((store) => store.setRoomId); const setRoomReadable = useLocalstorageStore( (store) => store.setRoomReadable, ); - const votes = useWsStore((store) => store.votes); - const spectators = useWsStore((store) => store.spectators); - const presences = useWsStore((store) => store.presences); - const flipped = useWsStore((store) => store.flipped); - const autoShow = useWsStore((store) => store.autoShow); + // User state + const estimation = useRoomStateStore((store) => store.estimation); + const estimateMutation = api.roomState.estimate.useMutation(); + const isSpectator = useRoomStateStore((store) => store.isSpectator); + const setIsSpectator = useLocalstorageStore((store) => store.setIsSpectator); + const spectatorMutation = api.roomState.spectator.useMutation(); + const leaveMutation = api.roomState.leave.useMutation(); - useEffect(() => { - if (!channel || !clientId) return; - const presenceUpdate: PresenceUpdate = { - username, - voting, - spectator: spectators.includes(clientId), - presencesLength: presences.length, - }; - logger.debug("SEND OWN PRESENCE ON INIT", presenceUpdate); - channel.presence.update(presenceUpdate); - }, [channel]); + // Room state + const isFlipped = useRoomStateStore((store) => store.isFlipped); + const resetMutation = api.roomState.reset.useMutation(); + const isAutoFlip = useRoomStateStore((store) => store.isAutoFlip); + const autoFlipMutation = api.roomState.autoFlip.useMutation(); + const resetRoomState = useRoomStateStore((store) => store.reset); const roomRef = useRef(null); @@ -67,16 +58,15 @@ export const Interactions = ({

({})} - // eslint-disable-next-line @typescript-eslint/no-misused-promises - onClick={async () => { + onClick={() => { if (!window.location) { return; } if ("clipboard" in navigator) { - await navigator.clipboard.writeText( - window.location.toString(), - ); + navigator.clipboard + .writeText(window.location.toString()) + .then(() => ({})) + .catch(() => ({})); } else { document.execCommand( "copy", @@ -102,15 +92,16 @@ export const Interactions = ({