setHovered(true)}
129 | onMouseLeave={() => setHovered(false)}
130 | >
131 | {player.name}
132 | {hovered ? (
133 |
{
139 | delete gameState.players[props.playerId];
140 | setGameState(gameState);
141 | }}
142 | >
143 |
144 |
145 | ) : (
146 |
147 | )}
148 |
149 | );
150 | }
151 |
--------------------------------------------------------------------------------
/src/serviceWorker.ts:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === "localhost" ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === "[::1]" ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | type Config = {
24 | onSuccess?: (registration: ServiceWorkerRegistration) => void;
25 | onUpdate?: (registration: ServiceWorkerRegistration) => void;
26 | };
27 |
28 | export function register(config?: Config) {
29 | if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
30 | // The URL constructor is available in all browsers that support SW.
31 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
32 | if (publicUrl.origin !== window.location.origin) {
33 | // Our service worker won't work if PUBLIC_URL is on a different origin
34 | // from what our page is served on. This might happen if a CDN is used to
35 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
36 | return;
37 | }
38 |
39 | window.addEventListener("load", () => {
40 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
41 |
42 | if (isLocalhost) {
43 | // This is running on localhost. Let's check if a service worker still exists or not.
44 | checkValidServiceWorker(swUrl, config);
45 |
46 | // Add some additional logging to localhost, pointing developers to the
47 | // service worker/PWA documentation.
48 | navigator.serviceWorker.ready.then(() => {
49 | console.log(
50 | "This web app is being served cache-first by a service " +
51 | "worker. To learn more, visit https://bit.ly/CRA-PWA"
52 | );
53 | });
54 | } else {
55 | // Is not localhost. Just register service worker
56 | registerValidSW(swUrl, config);
57 | }
58 | });
59 | }
60 | }
61 |
62 | function registerValidSW(swUrl: string, config?: Config) {
63 | navigator.serviceWorker
64 | .register(swUrl)
65 | .then((registration) => {
66 | registration.onupdatefound = () => {
67 | const installingWorker = registration.installing;
68 | if (installingWorker == null) {
69 | return;
70 | }
71 | installingWorker.onstatechange = () => {
72 | if (installingWorker.state === "installed") {
73 | if (navigator.serviceWorker.controller) {
74 | // At this point, the updated precached content has been fetched,
75 | // but the previous service worker will still serve the older
76 | // content until all client tabs are closed.
77 | console.log(
78 | "New content is available and will be used when all " +
79 | "tabs for this page are closed. See https://bit.ly/CRA-PWA."
80 | );
81 |
82 | // Execute callback
83 | if (config && config.onUpdate) {
84 | config.onUpdate(registration);
85 | }
86 | } else {
87 | // At this point, everything has been precached.
88 | // It's the perfect time to display a
89 | // "Content is cached for offline use." message.
90 | console.log("Content is cached for offline use.");
91 |
92 | // Execute callback
93 | if (config && config.onSuccess) {
94 | config.onSuccess(registration);
95 | }
96 | }
97 | }
98 | };
99 | };
100 | })
101 | .catch((error) => {
102 | console.error("Error during service worker registration:", error);
103 | });
104 | }
105 |
106 | function checkValidServiceWorker(swUrl: string, config?: Config) {
107 | // Check if the service worker can be found. If it can't reload the page.
108 | fetch(swUrl, {
109 | headers: { "Service-Worker": "script" },
110 | })
111 | .then((response) => {
112 | // Ensure service worker exists, and that we really are getting a JS file.
113 | const contentType = response.headers.get("content-type");
114 | if (
115 | response.status === 404 ||
116 | (contentType != null && contentType.indexOf("javascript") === -1)
117 | ) {
118 | // No service worker found. Probably a different app. Reload the page.
119 | navigator.serviceWorker.ready.then((registration) => {
120 | registration.unregister().then(() => {
121 | window.location.reload();
122 | });
123 | });
124 | } else {
125 | // Service worker found. Proceed as normal.
126 | registerValidSW(swUrl, config);
127 | }
128 | })
129 | .catch(() => {
130 | console.log(
131 | "No internet connection found. App is running in offline mode."
132 | );
133 | });
134 | }
135 |
136 | export function unregister() {
137 | if ("serviceWorker" in navigator) {
138 | navigator.serviceWorker.ready
139 | .then((registration) => {
140 | registration.unregister();
141 | })
142 | .catch((error) => {
143 | console.error(error.message);
144 | });
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/components/gameplay/ViewScore.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { GetScore } from "../../state/GetScore";
3 | import { CenteredColumn, CenteredRow } from "../common/LayoutElements";
4 | import { Spectrum } from "../common/Spectrum";
5 | import { Button } from "../common/Button";
6 | import {
7 | GameType,
8 | Team,
9 | InitialGameState,
10 | TeamName,
11 | TeamReverse,
12 | } from "../../state/GameState";
13 | import { GameModelContext } from "../../state/GameModelContext";
14 | import { NewRound } from "../../state/NewRound";
15 | import { Info } from "../common/Info";
16 |
17 | import { Trans, useTranslation } from "react-i18next";
18 |
19 | export function ViewScore() {
20 | const { t } = useTranslation();
21 | const { gameState, clueGiver, spectrumCard } = useContext(GameModelContext);
22 |
23 | if (!clueGiver) {
24 | return null;
25 | }
26 |
27 | let score = GetScore(gameState.spectrumTarget, gameState.guess);
28 | let bonusCoopTurn = false;
29 | if (gameState.gameType === GameType.Cooperative && score === 4) {
30 | score = 3;
31 | bonusCoopTurn = true;
32 | }
33 |
34 | const wasCounterGuessCorrect =
35 | (gameState.counterGuess === "left" &&
36 | gameState.spectrumTarget < gameState.guess) ||
37 | (gameState.counterGuess === "right" &&
38 | gameState.spectrumTarget > gameState.guess);
39 |
40 | return (
41 |
42 |
47 |
48 |
49 | {t("viewscore.player_clue", { givername: clueGiver.name })}:{" "}
50 | {gameState.clue}
51 |
52 |
53 | {t("viewscore.score")}: {score} {t("viewscore.points")}!
54 |
55 | {gameState.gameType === GameType.Teams && (
56 |
57 | {TeamName(TeamReverse(clueGiver.team), t)} {t("viewscore.got")}{" "}
58 | {wasCounterGuessCorrect
59 | ? t("viewscore.1_point_correct_guess")
60 | : t("viewscore.0_point_wrong_guess")}
61 |
62 | )}
63 | {bonusCoopTurn && (
64 | ,
68 | }}
69 | />
70 | )}
71 |
72 |
73 |
74 | );
75 | }
76 |
77 | function NextTurnOrEndGame() {
78 | const { t, i18n } = useTranslation();
79 | const cardsTranslation = useTranslation("spectrum-cards");
80 | const { gameState, localPlayer, clueGiver, setGameState } =
81 | useContext(GameModelContext);
82 |
83 | if (!clueGiver) {
84 | return null;
85 | }
86 |
87 | const resetButton = (
88 |