From 87e85ed52f95119bd7a0aeb48e7aa12e46517f84 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Tue, 14 Feb 2023 11:45:39 -0600 Subject: [PATCH] Display "active clue" --- package.json | 2 +- src/Contestant.tsx | 16 ++++++---------- src/Host.tsx | 6 +++++- src/host/ActiveClue.tsx | 27 +++++++++++++++++++++++++++ src/host/CluesDisplay.tsx | 11 ++++++++++- src/socket.ts | 7 ++++++- src/store/cluesSlice.ts | 30 +++++++++++++++++++++++------- src/utils.ts | 4 ++++ vite.config.ts | 18 +++++++++++++----- 9 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 src/host/ActiveClue.tsx create mode 100644 src/utils.ts diff --git a/package.json b/package.json index 158cdd8..715b6c7 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "start": "vite --host", + "start": "vite", "build": "tsc && vite build", "preview": "vite preview", "pretty": "prettier -w src", diff --git a/src/Contestant.tsx b/src/Contestant.tsx index 0f58314..7fdb421 100644 --- a/src/Contestant.tsx +++ b/src/Contestant.tsx @@ -1,7 +1,7 @@ import { useEffect } from "react"; import { useParams } from "react-router-dom"; -import { debounce } from "lodash"; +import { debounce } from "./utils"; import { socket } from "./socket"; import { useAppSelector } from "./hooks"; import { selectCanBuzz, selectSignature } from "./store/contestantSlice"; @@ -16,15 +16,11 @@ const Contestant = () => { socket.emit("contestant-join", { room, signature }); }, []); - const handleBuzz = debounce( - () => { - if (canBuzz) { - socket.emit("buzz"); - } - }, - 1000, - { leading: true, trailing: false } - ); + const handleBuzz = debounce(() => { + if (canBuzz) { + socket.emit("buzz"); + } + }); return (
diff --git a/src/Host.tsx b/src/Host.tsx index edff46f..deda5ef 100644 --- a/src/Host.tsx +++ b/src/Host.tsx @@ -3,13 +3,15 @@ import { useParams } from "react-router-dom"; import { socket } from "./socket"; import { useAppSelector } from "./hooks"; -import { selectCategories } from "./store/cluesSlice"; +import { selectCategories, selectActiveClue } from "./store/cluesSlice"; import Pregame from "./host/Pregame"; +import ActiveClue from "./host/ActiveClue"; import CluesDisplay from "./host/CluesDisplay"; const Host = () => { const { room } = useParams(); + const activeClue = useAppSelector(selectActiveClue); const categories = useAppSelector(selectCategories); useEffect(() => { @@ -18,6 +20,8 @@ const Host = () => { if (categories.length < 6) { return ; + } else if (activeClue) { + return ; } else { return ; } diff --git a/src/host/ActiveClue.tsx b/src/host/ActiveClue.tsx new file mode 100644 index 0000000..1914a74 --- /dev/null +++ b/src/host/ActiveClue.tsx @@ -0,0 +1,27 @@ +import { Container, Stack, Button } from "react-bootstrap"; + +import { useAppDispatch } from "../hooks"; +import { setActiveClue } from "../store/cluesSlice"; +import type { Clue } from "../store/cluesSlice"; + +interface Props { + activeClue: Clue; +} + +// TODO implement timer + +const ActiveClue = ({ activeClue }: Props) => { + const dispatch = useAppDispatch(); + return ( + +

{activeClue.question}

+ + + +
+ ); +}; + +export default ActiveClue; diff --git a/src/host/CluesDisplay.tsx b/src/host/CluesDisplay.tsx index 86b6bf7..15348f7 100644 --- a/src/host/CluesDisplay.tsx +++ b/src/host/CluesDisplay.tsx @@ -3,9 +3,16 @@ import { Container, Button, Stack } from "react-bootstrap"; import { useAppSelector } from "../hooks"; import { selectCategories } from "../store/cluesSlice"; +import { socket } from "../socket"; +import { debounce } from "../utils"; const CluesDisplay = () => { const categories = useAppSelector(selectCategories); + + const activateClue = debounce((name: string, value: number) => { + socket.emit("activate-clue", { name, value }); + }); + return ( @@ -13,7 +20,9 @@ const CluesDisplay = () => {

{name}

{[200, 400, 600, 800, 1000].map((value) => ( - + ))}
))} diff --git a/src/socket.ts b/src/socket.ts index 3d74d1d..9c2eb03 100644 --- a/src/socket.ts +++ b/src/socket.ts @@ -2,7 +2,8 @@ import { io } from "socket.io-client"; import store from "./store"; import { setRoomCode } from "./store/socketSlice"; import { addContestant } from "./store/displaySlice"; -import { setCategories } from "./store/cluesSlice"; +import { setCategories, setActiveClue } from "./store/cluesSlice"; +import type { Clue } from "./store/cluesSlice"; export const socket = io(`${window.location.hostname}:5000`); @@ -25,4 +26,8 @@ export const setup = () => { socket.on("categories", (data: Record) => { store.dispatch(setCategories(data)); }); + + socket.on("active-clue", (data: Clue) => { + store.dispatch(setActiveClue(data)); + }); }; diff --git a/src/store/cluesSlice.ts b/src/store/cluesSlice.ts index 5daba1a..a102ee8 100644 --- a/src/store/cluesSlice.ts +++ b/src/store/cluesSlice.ts @@ -1,32 +1,48 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import type { RootState } from "./"; +interface CluesState { + activeClue: Clue | null; + categories: Category[]; +} + interface Category { name: string; clues: Clue[]; } -interface Clue { +export interface Clue { value: number; question: string; answer: string; } -const initialState: Category[] = []; +const initialState: CluesState = { + activeClue: null, + categories: [], +}; export const cluesSlice = createSlice({ name: "clues", initialState, reducers: { - setCategories: (state, action: PayloadAction>) => - Object.entries(action.payload).map(([name, clues]) => ({ + setCategories: ( + state, + { payload }: PayloadAction> + ) => { + state.categories = Object.entries(payload).map(([name, clues]) => ({ name, clues, - })), + })); + }, + setActiveClue: (state, { payload }: PayloadAction) => { + state.activeClue = payload; + }, }, }); -export const { setCategories } = cluesSlice.actions; -export const selectCategories = (state: RootState) => state.clues; +export const { setCategories, setActiveClue } = cluesSlice.actions; +export const selectCategories = (state: RootState) => state.clues.categories; +export const selectActiveClue = (state: RootState) => state.clues.activeClue; export default cluesSlice.reducer; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..2f1cada --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,4 @@ +import { debounce as lodashDebounce } from "lodash"; + +export const debounce = (fn: (...args: unknown[]) => unknown) => + lodashDebounce(fn, 1000, { leading: true, trailing: false }); diff --git a/vite.config.ts b/vite.config.ts index 5f53b69..02ea9a5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,11 +1,19 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; -import eslint from 'vite-plugin-eslint'; +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import eslint from "vite-plugin-eslint"; // https://vitejs.dev/config/ export default defineConfig({ + server: { + host: true, + }, plugins: [ - {...react(), ...eslint(), apply: 'build'}, - {...react(), ...eslint({ failOnWarning: false, failOnError: false }), apply: 'serve', enforce: 'post'}, + { ...react(), ...eslint(), apply: "build" }, + { + ...react(), + ...eslint({ failOnWarning: false, failOnError: true }), + apply: "serve", + enforce: "post", + }, ], });