diff --git a/components/useTranslations.js b/components/useTranslations.js
index 5e5c10e5..4127338d 100644
--- a/components/useTranslations.js
+++ b/components/useTranslations.js
@@ -1,5 +1,46 @@
+import en from '../public/locales/en/common.json';
+import es from '../public/locales/es/common.json';
+import fr from '../public/locales/fr/common.json';
+import de from '../public/locales/de/common.json';
+import ru from '../public/locales/ru/common.json';
+import { useRouter } from 'next/router';
+
export function useTranslation() {
- return {t: (key) => {
- return key;
+ const router = useRouter();
+ return {t: (key, vars) => {
+
+
+
+ let language = "en";
+
+ // if /ru or /es or /fr or /de, ignore query params in url
+ let path = router.asPath;
+ if(path.includes("/ru")) {
+ language = "ru";
+ } else if(path.includes("/es")) {
+ language = "es";
+ } else if(path.includes("/fr")) {
+ language = "fr";
+ } else if(path.includes("/de")) {
+ language = "de";
+ }
+
+ let langObj = language === "en" ? en : language === "es" ? es : language === "fr" ? fr : language === "de" ? de : language === "ru" ? ru : en;
+ let string = langObj[key];
+ if(!string) {
+ return en[key] || key;
+ }
+
+ // {{variable}}
+ // vars => {variable: "value"}
+ if(vars) {
+ for(let v in vars) {
+ string = string.replace(`{{${v}}}`, vars[v]);
+ }
+ }
+
+ return string;
+
+
}}
}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index a00032df..d1cb3e3c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"bad-words": "^4.0.0",
"colors": "^1.4.0",
"coordinate_to_country": "^1.1.0",
+ "cors": "^2.8.5",
"countries-code": "^1.1.1",
"cross-env": "^7.0.3",
"discord-webhook-node": "^1.1.8",
@@ -1884,6 +1885,18 @@
"geojson-geometries-lookup": "^0.5.0"
}
},
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/countries-code": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/countries-code/-/countries-code-1.1.1.tgz",
@@ -4720,7 +4733,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
diff --git a/package.json b/package.json
index ff4234bc..8e8ec26c 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"bad-words": "^4.0.0",
"colors": "^1.4.0",
"coordinate_to_country": "^1.1.0",
+ "cors": "^2.8.5",
"countries-code": "^1.1.1",
"cross-env": "^7.0.3",
"discord-webhook-node": "^1.1.8",
diff --git a/pages/de.js b/pages/de.js
new file mode 100644
index 00000000..754d6741
--- /dev/null
+++ b/pages/de.js
@@ -0,0 +1,5 @@
+import LocalizedHome from "@/components/localizedHome";
+
+export default function IndexPage() {
+ return
;
+}
\ No newline at end of file
diff --git a/pages/en.js b/pages/en.js
new file mode 100644
index 00000000..740f5db2
--- /dev/null
+++ b/pages/en.js
@@ -0,0 +1,5 @@
+import LocalizedHome from "@/components/localizedHome";
+
+export default function IndexPage() {
+ return
;
+}
\ No newline at end of file
diff --git a/pages/es.js b/pages/es.js
new file mode 100644
index 00000000..c6fcc50b
--- /dev/null
+++ b/pages/es.js
@@ -0,0 +1,5 @@
+import LocalizedHome from "@/components/localizedHome";
+
+export default function IndexPage() {
+ return
;
+}
\ No newline at end of file
diff --git a/pages/fr.js b/pages/fr.js
new file mode 100644
index 00000000..50514e01
--- /dev/null
+++ b/pages/fr.js
@@ -0,0 +1,5 @@
+import LocalizedHome from "@/components/localizedHome";
+
+export default function IndexPage() {
+ return
;
+}
\ No newline at end of file
diff --git a/pages/index.js b/pages/index.js
index 9bd2d473..24c03134 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -1,1907 +1,5 @@
-import HeadContent from "@/components/headContent";
-import { Jockey_One, Roboto } from 'next/font/google';
-import { FaDiscord, FaGithub } from "react-icons/fa";
-import { FaGear,FaRankingStar, FaYoutube } from "react-icons/fa6";
-import { signOut, useSession } from "@/components/auth/auth";
-import 'react-responsive-modal/styles.css';
-import { useEffect, useState, useRef } from "react";
-import Navbar from "@/components/ui/navbar";
-import GameUI from "@/components/gameUI";
-import BannerText from "@/components/bannerText";
-import findLatLongRandom from "@/components/findLatLong";
-import Link from "next/link";
-import MultiplayerHome from "@/components/multiplayerHome";
-import AccountModal from "@/components/accountModal";
-import SetUsernameModal from "@/components/setUsernameModal";
-import ChatBox from "@/components/chatBox";
-import React from "react";
-import countryMaxDists from '../public/countryMaxDists.json';
-import { useTranslation } from '@/components/useTranslations'
-import useWindowDimensions from "@/components/useWindowDimensions";
-import Ad from "@/components/bannerAd";
-import Script from "next/script";
-import SettingsModal from "@/components/settingsModal";
-import sendEvent from "@/components/utils/sendEvent";
-import initWebsocket from "@/components/utils/initWebsocket";
-import 'react-toastify/dist/ReactToastify.css';
-
-import NextImage from "next/image";
-import OnboardingText from "@/components/onboardingText";
-import RoundOverScreen from "@/components/roundOverScreen";
-import msToTime from "@/components/msToTime";
-import SuggestAccountModal from "@/components/suggestAccountModal";
-import FriendsModal from "@/components/friendModal";
-import { toast, ToastContainer } from "react-toastify";
-import InfoModal from "@/components/infoModal";
-import { inIframe, isForbiddenIframe } from "@/components/utils/inIframe";
-import moment from 'moment-timezone';
-import MapsModal from "@/components/maps/mapsModal";
-import { useRouter } from "next/router";
-import { fromLonLat } from "ol/proj";
-import { boundingExtent } from "ol/extent";
-
-import countries from "@/public/countries.json";
-import officialCountryMaps from "@/public/officialCountryMaps.json";
-
-import fixBranding from "@/components/utils/fixBranding";
-import gameStorage from "@/components/utils/localStorage";
-import DiscordModal from "@/components/discordModal";
-import MerchModal from "@/components/merchModal";
-import clientConfig from "@/clientConfig";
-
-const jockey = Jockey_One({ subsets: ['latin'], weight: "400", style: 'normal' });
-const roboto = Roboto({ subsets: ['cyrillic'], weight: "400", style: 'normal' });
-const initialMultiplayerState = {
- connected: false,
- connecting: false,
- shouldConnect: false,
- gameQueued: false,
- inGame: false,
- nextGameQueued: false,
- creatingGame: false,
- enteringGameCode: false,
- createOptions: {
- rounds: 5,
- timePerRound: 30,
- location: "all",
- displayLocation: "All countries",
- progress: false
- },
- joinOptions: {
- gameCode: null,
- progress: false,
- error: false
- }
-}
-
-export default function Home({ locale }) {
- const { width, height } = useWindowDimensions();
-
- const [session, setSession] = useState(null);
- const { data: mainSession } = useSession();
- const [accountModalOpen, setAccountModalOpen] = useState(false);
- const [screen, setScreen] = useState("home");
- const [loading, setLoading] = useState(false);
- // game state
- const [latLong, setLatLong] = useState({ lat: 0, long: 0 })
- const [streetViewShown, setStreetViewShown] = useState(false)
- const [gameOptionsModalShown, setGameOptionsModalShown] = useState(false);
- // location aka map slug
- const [gameOptions, setGameOptions] = useState({ location: "all", maxDist: 20000, official: true, countryMap: false, communityMapName: "", extent: null });
- const [showAnswer, setShowAnswer] = useState(false)
- const [pinPoint, setPinPoint] = useState(null)
- const [hintShown, setHintShown] = useState(false)
- const [xpEarned, setXpEarned] = useState(0)
- const [countryStreak, setCountryStreak] = useState(0)
- const [settingsModal, setSettingsModal] = useState(false)
- const [mapModal, setMapModal] = useState(false)
- const [friendsModal, setFriendsModal] = useState(false)
- const [merchModal, setMerchModal] = useState(false)
- const [timeOffset, setTimeOffset] = useState(0)
- const [loginQueued, setLoginQueued] = useState(false);
- const [options, setOptions] = useState({
- });
-
- const [isApp, setIsApp] = useState(false);
- const [inCrazyGames, setInCrazyGames] = useState(false);
- const [maintenance, setMaintenance] = useState(false);
-
- const [legacyMapLoader, setLegacyMapLoader] = useState(false);
-
- useEffect(() => {
- if (mainSession && !inCrazyGames) {
- setSession(mainSession)
- }
- }, [JSON.stringify(mainSession), inCrazyGames])
-
- const [config, setConfig] = useState(null);
-
- useEffect(() => {
- const clientConfigData = clientConfig();
- setConfig(clientConfigData);
-
- if(window.location.search.includes("app=true")) {
- setIsApp(true);
- }
- if(window.location.search.includes("instantJoin=true")) {
- // crazygames
- }
-
-
- async function crazyAuthListener() {
- const user = await window.CrazyGames.SDK.user.getUser();
- if(user) {
- const token = await window.CrazyGames.SDK.user.getUserToken();
- if(token && user.username) {
- // /api/crazyAuth
- fetch(clientConfigData+"/api/crazyAuth", {
- method: "POST",
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({ token, username: user.username })
- }).then((res) => res.json()).then((data) => {
- console.log("crazygames auth", token, user, data)
- try {
- window.CrazyGames.SDK.game.loadingStop();
- } catch(e) {}
- if(data.secret && data.username) {
- setSession({ token: { secret: data.secret, username: data.username } })
- // verify the ws
- console.log("sending verify", ws)
- setWs((prev) => {
- if(prev) {
- prev.send(JSON.stringify({ type: "verify", secret: data.secret, username: data.username }))
- }
- return prev;
- });
- } else {
- toast.error("CrazyGames auth failed")
- }
- }).catch((e) => {
- try {
- window.CrazyGames.SDK.game.loadingStop();
- } catch(e) {}
- console.error("crazygames auth failed", e)
- });
-
- }
- }
- }
-
- function finish() {
- const onboardingCompletedd = gameStorage.getItem("onboarding");
- console.log("onboarding", onboardingCompletedd)
- if(onboardingCompletedd !== "done") startOnboarding();
- else setOnboardingCompleted(true)
- }
- if(window.location.search.includes("crazygames")) {
- setInCrazyGames(true);
- window.inCrazyGames = true;
- // initialize the sdk
- try {
- console.log("init crazygames sdk")
- setLoading(true)
-
- window.CrazyGames.SDK.init().then(async () => {
- console.log("sdk initialized")
- setLoading(false)
- try {
- window.CrazyGames.SDK.game.loadingStart();
- } catch(e) {}
-
- crazyAuthListener().then(() => {
- // check if onboarding is done
- finish()
- })
-
-
- window.CrazyGames.SDK.user.addAuthListener(crazyAuthListener);
-
- }).catch((e) => {
- finish()
- console.error("crazygames sdk init failed", e)
- setLoading(false)
- })
- } catch(e) {}
- }
- initialMultiplayerState.createOptions.displayLocation = text("allCountries")
-
- return () => {
- try {
- window.CrazyGames.SDK.user.removeAuthListener(crazyAuthListener);
- } catch(e){}
- }
-
- }, []);
-
- const [onboarding, setOnboarding] = useState(null);
- const [onboardingCompleted, setOnboardingCompleted] = useState(null);
- const [otherOptions, setOtherOptions] = useState([]); // for country guesser
- const [showCountryButtons, setShowCountryButtons] = useState(true);
- const [countryGuesserCorrect, setCountryGuesserCorrect] = useState(false);
-
- const [showSuggestLoginModal, setShowSuggestLoginModal] = useState(false);
- const [showDiscordModal, setShowDiscordModal] = useState(false);
- const [singlePlayerRound, setSinglePlayerRound] = useState(null);
-
- useEffect(() => {
- if(screen === "singleplayer") {
- // start the single player game
- setSinglePlayerRound({
- round: 1,
- totalRounds: 5,
- locations: [],
- })
- }
- }, [screen])
-
- const [allLocsArray, setAllLocsArray] = useState([]);
- function startOnboarding() {
-
- if(inCrazyGames) {
- // make sure its not an invite link
- const code = window.CrazyGames.SDK.game.getInviteParam("code")
- if(code && code.length === 6) {
- return;
- }
- }
-
-setScreen("onboarding")
-
-let onboardingLocations = [
- { lat: 40.7598687, long: -73.9764681, country: "US", otherOptions: ["GB", "JP"] },
-{ lat: 27.1719752, long: 78.0422793, country: "IN", otherOptions: ["ZA", "FR"] },
-{ lat: 51.5080896, long: -0.087694, country: "GB", otherOptions: ["US", "DE"] },
- { lat: 55.7495807, long: 37.616477, country: "RU", otherOptions: ["CN", "PL"] },
- // pyramid of giza 29.9773337,31.1321796
- { lat: 29.9773337, long: 31.1321796, country: "EG", otherOptions: ["TR", "BR"] },
- // eiffel tower 48.8592946,2.2927855
- { lat: 48.8592946, long: 2.2927855, country: "FR", otherOptions: ["IT", "ES"] },
- // statue of liberty 40.6909253,-74.0552998
- { lat: 40.6909253, long: -74.0552998, country: "US", otherOptions: ["CA", "AU"] },
- // brandenburg gate 52.5161999,13.3756414
- { lat: 52.5161999, long: 13.3756414, country: "DE", otherOptions: ["RU", "JP"] },
-
-]
-
-// pick 5 random locations no repeats
-const locations = [];
-while (locations.length < 5) {
- const loc = onboardingLocations[Math.floor(Math.random() * onboardingLocations.length)]
- if (!locations.find((l) => l.country === loc.country)) {
- locations.push(loc)
- }
-}
-
-setOnboarding({
- round: 1,
- locations: locations,
- startTime: Date.now(),
-})
-sendEvent("tutorial_begin")
-setShowCountryButtons(false)
-}
- function openMap(mapSlug) {
- const country = countries.find((c) => c === mapSlug.toUpperCase());
- let officialCountryMap = null;
- if(country) {
- officialCountryMap = officialCountryMaps.find((c) => c.countryCode === mapSlug);
- }
- setAllLocsArray([])
-
- if(!country && mapSlug !== gameOptions.location) {
- if( ((window?.lastPlayTrack||0) + 20000 < Date.now())) {
-
- fetch(config.apiUrl+`/mapPlay/${mapSlug}`, {method: "POST"})
- }
-
- try {
- window.lastPlayTrack = Date.now();
- } catch(e) {}
- }
-
- setGameOptions((prev) => ({
- ...prev,
- location: mapSlug,
- official: country ? true : false,
- countryMap: country,
- maxDist: country ? countryMaxDists[country] : 20000,
- extent: country && officialCountryMap && officialCountryMap.extent ? officialCountryMap.extent : null
- }))
- }
-
- useEffect(() => {
- if(onboarding?.round >1) {
- loadLocation()
- }
- }, [onboarding?.round])
-
- useEffect(() => {
- if(onboarding?.completed) {
- setOnboardingCompleted(true)
- }
- }, [onboarding?.completed])
- useEffect(() => {
- try {
- const onboarding = gameStorage.getItem("onboarding");
- // check url
- const specifiedMapSlug = window.location.search.includes("map=");
- console.log("onboarding", onboarding, specifiedMapSlug)
- // make it false just for testing
- // gameStorage.setItem("onboarding", null)
- if(onboarding && onboarding === "done") setOnboardingCompleted(true)
- else if(specifiedMapSlug) setOnboardingCompleted(true)
- else setOnboardingCompleted(false)
- } catch(e) {
- console.error(e, "onboard");
- setOnboardingCompleted(true);
- }
- // setOnboardingCompleted(false)
- }, [])
-
-
-
- useEffect(() => {
-
- // check if pirated
- if(isForbiddenIframe() && !window.blocked) {
- // display a message
- window.blocked = true;
- document.write(`
-
-
-
-
-
-
Play WorldGuessr
-
-
-
-
-
-
-`)
- sendEvent("blocked_iframe")
- }
- // check if learn mode
- if(window.location.search.includes("learn=true")) {
- window.learnMode = true;
-
- // immediately open single player
- setScreen("singleplayer")
- }
- // check if from map screen
- if(window.location.search.includes("map=")) {
- // get map slug map=slug from url
- const params = new URLSearchParams(window.location.search);
- const mapSlug = params.get("map");
- setScreen("singleplayer")
-
- openMap(mapSlug)
- }
-
- if(window.location.search.includes("createPrivateGame=true")) {
- }
- }, [])
-
- useEffect(() => {
-
-// check if learn mode
- if(window.location.search.includes("learn=true")) {
- setOnboardingCompleted(true)
- }
-
-
- if(onboardingCompleted === false) {
- if(onboardingCompleted===null)return;
- if (!loading) {
-
-
- // const isPPC = window.location.search.includes("cpc=true");
- if(inIframe() && window.adBreak && !inCrazyGames) {
- console.log("trying to show preroll")
- window.onboardPrerollEnd = false;
- setLoading(true)
- window.adBreak({
- type: "preroll",
- adBreakDone: function(e) {
- if(window.onboardPrerollEnd) return;
- setLoading(false)
- window.onboardPrerollEnd = true;
- sendEvent("interstitial", { type: "preroll", ...e })
- startOnboarding()
- }
- })
-
- setTimeout(() => {
- if(!window.onboardPrerollEnd) {
- window.onboardPrerollEnd = true;
- console.log("preroll timeout")
- setLoading(false)
- startOnboarding()
- }
- }, 3000)
- } else if(!inCrazyGames) {
-
- startOnboarding()
- }
- }
- }
- }, [onboardingCompleted])
-
- useEffect(() => {
- if(session && session.token && session.token.username && !inCrazyGames) {
- setOnboardingCompleted(true)
- try {
- gameStorage.setItem("onboarding", 'done')
- } catch(e) {}
- }
- }, [session])
-
- const loadOptions =async () => {
-
- // try to fetch options from localstorage
- try {
- const options = gameStorage.getItem("options");
-
-
- if (options) {
- setOptions(JSON.parse(options))
- } else {
- let json;
-
- try {
- const res = await fetch("https://ipapi.co/json/");
- json = await res.json();
- }catch(e){}
-
- const countryCode = json?.country_code;
- let system = "metric";
- if(countryCode && ["US", "LR", "MM", "UK"].includes(countryCode)) system = "imperial";
-
-
- setOptions({
- units: system,
- mapType: "m" //m for normal
- })
- }
- } catch(e) {}
-
- }
- useEffect(()=>{loadOptions()}, [])
-
- useEffect(() => {
- if(options && options.units && options.mapType) {
- try {
- gameStorage.setItem("options", JSON.stringify(options))
- } catch(e) {}
- }
- }, [options])
-
- useEffect(() => {
- window.disableVideoAds = options?.disableVideoAds;
- }, [options?.disableVideoAds]);
-
- // multiplayer stuff
- const [ws, setWs] = useState(null);
- const [multiplayerState, setMultiplayerState] = useState(
- initialMultiplayerState
- );
- const [multiplayerChatOpen, setMultiplayerChatOpen] = useState(false);
- const [multiplayerChatEnabled, setMultiplayerChatEnabled] = useState(false);
-
- const { t: text } = useTranslation("common");
-
- useEffect(( ) => {
-
- if(multiplayerState?.joinOptions?.error) {
- setTimeout(() => {
- setMultiplayerState((prev) => ({ ...prev, joinOptions: { ...prev.joinOptions, error: null } }))
- }, 1000)
- }
-
- }, [multiplayerState?.joinOptions?.error]);
-
-
- function handleMultiplayerAction(action, ...args) {
- if (!ws || !multiplayerState.connected || multiplayerState.gameQueued || multiplayerState.connecting) return;
-
- if (action === "publicDuel") {
- setScreen("multiplayer")
- setMultiplayerState((prev) => ({
- ...prev,
- gameQueued: "publicDuel",
- nextGameQueued: false
- }))
- sendEvent("multiplayer_request_duel")
- ws.send(JSON.stringify({ type: "publicDuel" }))
- }
-
- if (action === "joinPrivateGame") {
-
- if (args[0]) {
- setScreen("multiplayer")
-
- setMultiplayerState((prev) => ({
- ...prev,
- joinOptions: {
- ...prev.joinOptions,
- error: false,
- progress: true
- }
- }));
- // join private game
- ws.send(JSON.stringify({ type: "joinPrivateGame", gameCode: args[0] }))
- sendEvent("multiplayer_join_private_game", { gameCode: args[0] })
-
- } else {
- setScreen("multiplayer")
- setMultiplayerState((prev) => {
- return {
- ...initialMultiplayerState,
- connected: true,
- enteringGameCode: true,
- playerCount: prev.playerCount,
- guestName: prev.guestName
- }
-
- })
- }
- }
-
- if (action === "createPrivateGame") {
- if (!args[0]) {
- setScreen("multiplayer")
-
- setMultiplayerState((prev) => {
- return {
- ...initialMultiplayerState,
- connected: true,
- creatingGame: true,
- playerCount: prev.playerCount,
- guestName: prev.guestName
- }
- })
- } else {
-
- const maxDist = args[0].location === "all" ? 20000 : countryMaxDists[args[0].location];
- // setMultiplayerState((prev) => ({
- // ...prev,
- // createOptions: {
- // ...prev.createOptions,
- // progress: 0
- // }
- // }));
- // (async () => {
- // const locations = [];
- // for (let i = 0; i < args[0].rounds; i++) {
-
- // const loc = await findLatLongRandom({ location: multiplayerState.createOptions.location });
- // locations.push(loc)
- // setMultiplayerState((prev) => ({
- // ...prev,
- // createOptions: {
- // ...prev.createOptions,
- // progress: i + 1
- // }
- // }))
- // }
-
- setMultiplayerState((prev) => ({
- ...prev,
- createOptions: {
- ...prev.createOptions,
- progress: true
- }
- }));
-
- // send ws
- // ws.send(JSON.stringify({ type: "createPrivateGame", rounds: args[0].rounds, timePerRound: args[0].timePerRound, locations, maxDist }))
- ws.send(JSON.stringify({ type: "createPrivateGame", rounds: args[0].rounds, timePerRound: args[0].timePerRound, location: args[0].location, maxDist }))
- sendEvent("multiplayer_create_private_game", { rounds: args[0].rounds, timePerRound: args[0].timePerRound, location: args[0].location, maxDist })
- // })()
- }
- }
-
- if (action === 'startGameHost' && multiplayerState?.inGame && multiplayerState?.gameData?.host && multiplayerState?.gameData?.state === "waiting") {
- ws.send(JSON.stringify({ type: "startGameHost" }))
- sendEvent("multiplayer_start_game_host")
- }
-
- if(action === 'screen') {
- ws.send(JSON.stringify({ type: "screen", screen: args[0] }))
- }
-
-
- }
-
- useEffect(() => {
- (async() => {
-
-
- if (!ws && !multiplayerState.connecting && !multiplayerState.connected && !window?.dontReconnect) {
-
- setMultiplayerState((prev) => ({
- ...prev,
- connecting: true,
- shouldConnect: false
- }))
- const ws = await initWebsocket(clientConfig().websocketUrl, null, 5000, 20)
- if(ws && ws.readyState === 1) {
- setWs(ws)
- setMultiplayerState((prev)=>({
- ...prev,
- error: false
- }))
-
-
- if(!inCrazyGames && !window.location.search.includes("crazygames")) {
-
- const tz = moment.tz.guess();
- let secret = "not_logged_in";
- if(session?.token?.secret) {
- secret = session.token.secret;
- }
-
- console.log("sending verify with secret", secret)
- ws.send(JSON.stringify({ type: "verify", secret, tz}))
- } else {
-
-
- }
- } else {
- alert("could not connect to server")
- }
-
- }
- })();
- }, [multiplayerState, ws, screen])
-
- useEffect(() => {
-
- if(inCrazyGames) {
- if(screen === "home") {
- try {
- window.CrazyGames.SDK.game.gameplayStop();
- } catch(e) {}
- } else {
- try {
- window.CrazyGames.SDK.game.gameplayStart();
- } catch(e) {}
- }
- }
- }, [screen, inCrazyGames])
-
- useEffect(() => {
- if(multiplayerState?.connected && inCrazyGames) {
-
- // check if joined via invite link
- try {
- let code = window.CrazyGames.SDK.game.getInviteParam("code")
- let instantJoin = window.location.search.includes("instantJoin");
-
-
-
- if(code || instantJoin) {
-
- if(typeof code === "string") {
- try {
- code = parseInt(code)
- } catch(e) {
- }
- }
-
- setOnboardingCompleted(true)
- setOnboarding(null)
- setLoading(false)
- setScreen("home")
- if(code) {
-
- // join private game
- handleMultiplayerAction("joinPrivateGame")
- // set the code
- setMultiplayerState((prev) => ({
- ...prev,
- joinOptions: {
- ...prev.joinOptions,
- gameCode: code,
- progress: true
- }
- }))
- // press go
- setTimeout(() => {
- handleMultiplayerAction("joinPrivateGame", code)
- }, 1000)
- } else {
- // create private game
- handleMultiplayerAction("createPrivateGame")
- }
-
- }
-
- } catch(e) {}
-
- }
- }, [multiplayerState?.connected, inCrazyGames])
-
- useEffect(() => {
- if (multiplayerState?.inGame && multiplayerState?.gameData?.state === "end") {
- // save the final players
- setMultiplayerState((prev) => ({
- ...prev,
- gameData: {
- ...prev.gameData,
- finalPlayers: prev.gameData.players
- }
- }))
- }
- }, [multiplayerState?.gameData?.state])
-
- useEffect(() => {
- if (!multiplayerState?.inGame) {
- setMultiplayerChatEnabled(false)
- setMultiplayerChatOpen(false)
- }
- if (!ws) return;
-
-
- ws.onmessage = (msg) => {
- const data = JSON.parse(msg.data);
-
- if(data.type === "restartQueued") {
- setMaintenance(data.value ? true : false)
- if(data.value) {
- toast.info(text("maintenanceModeStarted"))
- } else if(!data.value && window.maintenance) {
- toast.info(text("maintenanceModeEnded"))
- }
- window.maintenance = data.value ? true : false;
-
- }
- if (data.type === "t") {
- const offset = data.t - Date.now();
- if (Math.abs(offset) > 1000 && ((Math.abs(offset) < Math.abs(timeOffset)) || !timeOffset)) {
- setTimeOffset(offset)
- }
- }
-
- if (data.type === "cnt") {
- setMultiplayerState((prev) => ({
- ...prev,
- playerCount: data.c
- }))
- } else if (data.type === "verify") {
- setMultiplayerState((prev) => ({
- ...prev,
- connected: true,
- connecting: false,
- guestName: data.guestName
- }))
- } else if (data.type === "error") {
- setMultiplayerState((prev) => ({
- ...prev,
- connecting: false,
- connected: false,
- shouldConnect: false,
- error: data.message
- }))
- // disconnect
- if(data.message === "uac")
- {
- window.dontReconnect = true;
- }
- if(data.failedToLogin) {
- window.dontReconnect = true;
- // logout
- signOut()
-
- }
- ws.close();
-
- toast(data.message==='uac'?text('userAlreadyConnected'):data.message, { type: 'error' });
-
- } else if (data.type === "game") {
- setScreen("multiplayer")
- setMultiplayerState((prev) => {
-
-
- try {
- if(data.state === "waiting" && inCrazyGames && data.host) {
- const link = window.CrazyGames.SDK.game.showInviteButton({ code: data.code });
- } else {
- window.CrazyGames.SDK.game.hideInviteButton();
- }
- } catch(e) {}
-
-
- if (data.state === "getready") {
- setMultiplayerChatEnabled(true)
-
- if(data.map !== "all" && !countries.map((c) => c?.toLowerCase()).includes(data.map?.toLowerCase()) && !gameOptions?.extent) {
- // calculate extent
-
- fetch(`/mapLocations/${data.map}`).then((res) => res.json()).then((data) => {
- if(data.ready) {
-
- const mappedLatLongs = data.locations.map((l) => fromLonLat([l.lng, l.lat], "EPSG:4326"));
- let extent = boundingExtent(mappedLatLongs);
- console.log("extent", extent)
-
- setGameOptions((prev) => ({
- ...prev,
- extent
- }))
-
- }
- })
- }
-
- } else if (data.state === "guess") {
- const didIguess = (data.players ?? prev.gameData?.players)?.find((p) => p.id === prev.gameData?.myId)?.final;
- if (didIguess) {
- setMultiplayerChatEnabled(true)
- } else {
- setMultiplayerChatEnabled(false)
- }
- }
-
- if ((!prev.gameData || (prev?.gameData?.state === "getready")) && data.state === "guess") {
- setPinPoint(null)
- if (!prev?.gameData?.locations && data.locations) {
- setLatLong(data.locations[data.curRound - 1])
-
- } else {
- setLatLong(prev?.gameData?.locations[data.curRound - 1])
- }
- }
-
- return {
- ...prev,
- gameQueued: false,
- inGame: true,
- gameData: {
- ...prev.gameData,
- ...data,
- type: undefined
- },
- enteringGameCode: false,
- creatingGame: false,
- joinOptions: initialMultiplayerState.joinOptions,
- createOptions: initialMultiplayerState.createOptions,
- }
- })
-
- if (data.state === "getready") {
- setStreetViewShown(false)
- } else if (data.state === "guess") {
- setStreetViewShown(true)
- }
- } else if(data.type === "maxDist") {
- const maxDist = data.maxDist;
- console.log("got new max dist", maxDist)
- setMultiplayerState((prev) => ({
- ...prev,
- gameData: {
- ...prev.gameData,
- maxDist
- }
- }))
-
- } else if (data.type === "player") {
- if (data.action === "remove") {
- setMultiplayerState((prev) => ({
- ...prev,
- gameData: {
- ...prev.gameData,
- players: prev.gameData.players.filter((p) => p.id !== data.id)
- }
- }))
- } else if (data.action === "add") {
- setMultiplayerState((prev) => ({
- ...prev,
- gameData: {
- ...prev.gameData,
- players: [...prev.gameData.players, data.player]
- }
- }))
- }
- } else if (data.type === "place") {
- const id = data.id;
- if (id === multiplayerState.gameData.myId) {
- setMultiplayerChatEnabled(true)
- }
-
- const player = multiplayerState.gameData.players.find((p) => p.id === id);
- if (player) {
- player.final = data.final;
- player.latLong = data.latLong;
- }
- } else if (data.type === "gameOver") {
- setLatLong(null)
- setGameOptions((prev) => ({
- ...prev,
- extent: null
- }))
-
- } else if (data.type === "gameShutdown") {
- setScreen("home")
- setMultiplayerState((prev) => {
- return {
- ...initialMultiplayerState,
- connected: true,
- nextGameQueued: prev.nextGameQueued,
- playerCount: prev.playerCount,
- guestName: prev.guestName
- }
- });
- setGameOptions((prev) => ({
- ...prev,
- extent: null
- }))
- } else if (data.type === "gameJoinError" && multiplayerState.enteringGameCode) {
- setMultiplayerState((prev) => {
- return {
- ...prev,
- joinOptions: {
- ...prev.joinOptions,
- error: data.error,
- progress: false
- }
- }
- })
- } else if(data.type === 'generating') {
- // location generation before round
- setMultiplayerState((prev) => {
- return {
- ...prev,
- gameData: {
- ...prev.gameData,
- generated: data.generated
- }
- }
- })
- } else if(data.type === "friendReq") {
- const from = data.name;
- const id = data.id;
- const toAccept = (closeToast) => {
- ws.send(JSON.stringify({ type: 'acceptFriend', id }))
- closeToast()
- }
- const toDecline = (closeToast) => {
- ws.send(JSON.stringify({ type: 'declineFriend', id }))
- closeToast()
- }
- const toastComponent = function({closeToast}){
- return (
-
- {text("youGotFriendReq", { from })}
-
- toAccept(closeToast)} className={"accept-button"}>✔
-
- toDecline(closeToast)} className={"decline-button"}>✖
-
- )
- }
-
- toast(toastComponent, { type: 'info', theme: "dark" })
-
-
- } else if(data.type === 'toast') {
- toast(text(data.key, data), { type: data.toastType ?? 'info', theme: "dark", closeOnClick: data.closeOnClick ?? false, autoClose: data.autoClose ?? 5000 })
- } else if(data.type === 'invite') {
- // code, invitedByName, invitedById
- const { code, invitedByName, invitedById } = data;
-
- const toAccept = (closeToast) => {
- ws.send(JSON.stringify({ type: 'acceptInvite', code, invitedById }))
- closeToast()
- }
- const toDecline = (closeToast) => {
- closeToast()
- }
- const toastComponent = function({closeToast}){
- return (
-
- {text("youGotInvite", { from: invitedByName })}
-
- toAccept(closeToast)} className={"accept-button"}>{text("join")}
-
- toDecline(closeToast)} className={"decline-button"}>{text("decline")}
-
- )
- }
-
- toast(toastComponent, { type: 'info', theme: "dark", autoClose: 10000 })
- } else if(data.type === 'streak') {
- const streak = data.streak;
-
- if(streak === 0) {
- toast(text("streakLost"), { type: 'info', theme: "dark", autoClose: 5000, closeOnClick: true })
- } else if(streak === 1) {
- toast(text("streakStarted"), { type: 'info', theme: "dark", autoClose: 5000, closeOnClick: true })
- } else {
- toast(text("streakGained", { streak }), { type: 'info', theme: "dark", autoClose: 5000, closeOnClick: true })
- }
- }
- }
-
- // ws on disconnect
- ws.onclose = () => {
- setWs(null)
- console.log("ws closed")
- sendEvent("multiplayer_disconnect")
-
- setMultiplayerState((prev) => ({
- ...initialMultiplayerState,
- error: text("connectionLost")
- }));
- }
-
- ws.onerror = () => {
- setWs(null)
- console.log("ws error")
- sendEvent("multiplayer_disconnect")
-
- setMultiplayerState((prev) => ({
- ...initialMultiplayerState,
- error: text("connectionLost")
- }));
- }
-
-
- return () => {
- ws.onmessage = null;
- }
- }, [ws, multiplayerState, timeOffset, gameOptions?.extent]);
-
- useEffect(() => {
- if (multiplayerState?.connected && !multiplayerState?.inGame && multiplayerState?.nextGameQueued) {
- handleMultiplayerAction("publicDuel");
- }
- }, [multiplayerState, timeOffset])
-
- useEffect(() => {
- if (multiplayerState?.connected) {
- handleMultiplayerAction("screen", screen);
- }
- }, [screen]);
-
-
- // useEffect(() => {
- // if (multiplayerState.inGame && multiplayerState.gameData?.state === "guess" && pinPoint) {
- // // send guess
- // console.log("pinpoint1", pinPoint)
- // const pinpointLatLong = [pinPoint.lat, pinPoint.lng];
- // ws.send(JSON.stringify({ type: "place", latLong: pinpointLatLong, final: false }))
- // }
- // }, [multiplayerState, pinPoint])
-
- function guessMultiplayer(send) {
- if (!send) return;
- if (!multiplayerState.inGame || multiplayerState.gameData?.state !== "guess" || !pinPoint) return;
- const pinpointLatLong = [pinPoint.lat, pinPoint.lng];
-
- ws.send(JSON.stringify({ type: "place", latLong: pinpointLatLong, final: true }))
- }
-
- function sendInvite(id) {
- if(!ws || !multiplayerState?.connected) return;
- ws.send(JSON.stringify({ type: 'inviteFriend', friendId: id }))
- }
-
- useEffect(() => {
- try {
- const streak = gameStorage.getItem("countryStreak");
- if (streak) {
- setCountryStreak(parseInt(streak))
- }
-
- // preload/cache src.png and dest.png
- const img = new Image();
- img.src = "/src.png";
- const img2 = new Image();
- img2.src = "/dest.png";
- } catch(e) {}
-
- }, [])
-
- function reloadBtnPressed() {
- if(window.reloadLoc) {
- window.reloadLoc()
- }
- }
-
- function crazyMidgame(adFinished = () => {}) {
- if(window.inCrazyGames && window.CrazyGames.SDK.environment !== "disabled") {
- try {
- const callbacks = {
- adFinished: () => adFinished(),
- adError: (error) => adFinished(),
- adStarted: () => console.log("Start midgame ad"),
- };
- window.CrazyGames.SDK.ad.requestAd("midgame", callbacks);
- } catch(e) {}
- } else {
- adFinished()
- }
- }
-
- function backBtnPressed(queueNextGame = false) {
-
-
-
- if (loading) setLoading(false);
-
- if(window.learnMode) {
- // redirect to home
- window.location.href = "/"
- return;
- }
-
- if(screen === "onboarding") {
- setScreen("home")
- setOnboarding(null)
- setOnboardingCompleted(true)
- gameStorage.setItem("onboarding", 'done')
-
- crazyMidgame()
-
- return;
- }
-
- setStreetViewShown(false)
-
- if (multiplayerState?.inGame) {
- ws.send(JSON.stringify({
- type: 'leaveGame'
- }))
-
- if(inCrazyGames) {
- try {
- window.CrazyGames.SDK.game.hideInviteButton();
- } catch(e) {}
- }
-
- setMultiplayerState((prev) => {
- return {
- ...prev,
- nextGameQueued: queueNextGame === true
- }
- })
- setScreen("home")
-
- if(["getready", "guess"].includes(multiplayerState?.gameData?.state)) {
- crazyMidgame()
- }
-
- } else if ((multiplayerState?.creatingGame || multiplayerState?.enteringGameCode) && multiplayerState?.connected) {
-
- setMultiplayerState((prev) => {
- return {
- ...initialMultiplayerState,
- connected: true,
- playerCount: prev.playerCount,
- guestName: prev.guestName
-
- }
- })
- setScreen("home")
-
- } else if(multiplayerState?.gameQueued) {
- console.log("gameQueued")
- ws.send(JSON.stringify({ type: "leaveQueue" }))
-
- setMultiplayerState((prev) => {
- return {
- ...prev,
- gameQueued: false
- }
- });
- setScreen("home")
-
- } else {
- setScreen("home");
- setGameOptions((prev) => ({
- ...prev,
- extent: null
- }))
- clearLocation();
-
- if(screen === "singleplayer") {
- crazyMidgame()
-
- }
- }
- }
-
- function clearLocation() {
- setLatLong({ lat: 0, long: 0 })
- setStreetViewShown(false)
- setShowAnswer(false)
- setPinPoint(null)
- setHintShown(false)
- }
-
- function loadLocation() {
- if (loading) return;
-
- console.log("loading location")
- setLoading(true)
- setShowAnswer(false)
- setPinPoint(null)
- setLatLong(null)
- setHintShown(false)
- if(screen === "onboarding") {
- setLatLong(onboarding.locations[onboarding.round - 1]);
- let options = JSON.parse(JSON.stringify(onboarding.locations[onboarding.round - 1].otherOptions));
- options.push(onboarding.locations[onboarding.round - 1].country)
- // shuffle
- options = options.sort(() => Math.random() - 0.5)
- setOtherOptions(options)
- } else {
- function defaultMethod() {
- findLatLongRandom(gameOptions).then((latLong) => {
- setLatLong(latLong)
- });
- }
- function fetchMethod() {
- console.log("fetching")
- fetch((gameOptions.location==="all")?`/${window?.learnMode ? 'clue': 'all'}Countries.json`:`/mapLocations/${gameOptions.location}`).then((res) => res.json()).then((data) => {
- if(data.ready) {
- // this uses long for lng
- for(let i = 0; i < data.locations.length; i++) {
- if(data.locations[i].lng && !data.locations[i].long) {
- data.locations[i].long = data.locations[i].lng;
- delete data.locations[i].lng;
- }
- }
-
- setAllLocsArray(data.locations)
-
- if(gameOptions.location === "all") {
- const loc = data.locations[0]
- setLatLong(loc)
- } else {
- let loc = data.locations[Math.floor(Math.random() * data.locations.length)];
-
- while(loc.lat === latLong.lat && loc.long === latLong.long) {
- loc = data.locations[Math.floor(Math.random() * data.locations.length)];
- }
-
- setLatLong(loc)
- if(data.name) {
-
- // calculate extent (for openlayers)
- const mappedLatLongs = data.locations.map((l) => fromLonLat([l.long, l.lat], 'EPSG:4326'));
- let extent = boundingExtent(mappedLatLongs);
- console.log("extent", extent)
- // convert extent from EPSG:4326 to EPSG:3857 (for openlayers)
-
- setGameOptions((prev) => ({
- ...prev,
- communityMapName: data.name,
- official: data.official ?? false,
- maxDist: data.maxDist ?? 20000,
- extent: extent
- }))
-
- }
- }
-
- } else {
- if(gameOptions.location !== "all") {
- toast(text("errorLoadingMap"), { type: 'error' })
- }
- defaultMethod()
- }
- }).catch((e) => {
- console.error(e)
- toast(text("errorLoadingMap"), { type: 'error' })
- defaultMethod()
- });
- }
- if(gameOptions.countryMap && gameOptions.official) {
- defaultMethod()
- } else {
- if(allLocsArray.length===0) {
- fetchMethod()
- } else if(allLocsArray.length>0) {
- const locIndex = allLocsArray.findIndex((l) => l.lat === latLong.lat && l.long === latLong.long);
- if((locIndex === -1) || allLocsArray.length === 1) {
- console.log("could not find location in array", locIndex, allLocsArray)
- fetchMethod()
- } else {
- if(gameOptions.location === "all") {
- const loc = allLocsArray[locIndex+1] ?? allLocsArray[0];
- setLatLong(loc)
- } else {
- // prevent repeats: remove the prev location from the array
- setAllLocsArray((prev) => {
- const newArr = prev.filter((l) => l.lat !== latLong.lat && l.long !== latLong.long)
-
-
- // community maps are randomized
- const loc = newArr[Math.floor(Math.random() * newArr.length)];
-
-
- setLatLong(loc)
- return newArr;
- })
-
- }
- }
-
- }
-}
- }
-
- }
-
- function onNavbarLogoPress() {
- if(screen === "onboarding") return;
-
- if (screen !== "home" && !loading) {
- if (screen==="multiplayer" && multiplayerState?.connected && !multiplayerState?.inGame) {
- return;
- }
- if (!multiplayerState?.inGame) loadLocation()
- else if (multiplayerState?.gameData?.state === "guess") {
-
- }
- }
- }
-
- const ChatboxMemo = React.useMemo(() =>
setMultiplayerChatOpen(!multiplayerChatOpen)} enabled={multiplayerChatEnabled} myId={multiplayerState?.gameData?.myId} inGame={multiplayerState?.inGame} />, [multiplayerChatOpen, multiplayerChatEnabled, ws, multiplayerState?.gameData?.myId, multiplayerState?.inGame])
-
- // Send pong every 10 seconds if websocket is connected
- useEffect(() => {
- const pongInterval = setInterval(() => {
- if (ws && ws.readyState === WebSocket.OPEN) {
- ws.send(JSON.stringify({ type: 'pong' }));
- }
- }, 10000); // Send pong every 10 seconds
-
- return () => clearInterval(pongInterval);
- }, [ws]);
- const panoramaRef = useRef(null);
- const [showPanoOnResult, setShowPanoOnResult] = useState(false);
-
- useEffect(() => {
- // const map = new google.maps.Map(document.getElementById("map"), {
- // center: fenway,
- // zoom: 14,
- // });
- if(legacyMapLoader) {
- setLoading(false)
-
- // kill the element that has div[dir="ltr"]
- const elem = document.querySelector('div[dir="ltr"]');
- console.log("elem", elem)
-
- return;
- }
- if(!latLong || (latLong.lat === 0 && latLong.long === 0)) return;
- if(!document.getElementById("googlemaps")) return;
-
- if(!panoramaRef.current) {
-
-
-
- panoramaRef.current = new google.maps.StreetViewPanorama(
- document.getElementById("googlemaps"),
- {
- position: { lat: latLong.lat, lng: latLong.long },
- pov: {
- heading: 0,
- pitch: 0,
- },
- motionTracking: false,
- linksControl: gameOptions?.nm ? false:true,
- clickToGo: gameOptions?.nm ? false:true,
-
- panControl: gameOptions?.npz ? false:true,
- zoomControl: gameOptions?.npz ? false:true,
- showRoadLabels: gameOptions?.showRoadName===true?true:false,
- disableDefaultUI: true,
- },
- );
-
- window.reloadLoc = () => {
- panoramaRef.current.setPosition({ lat: latLong.lat, lng: latLong.long });
- }
- window.panorama = panoramaRef.current;
- } else {
-
- panoramaRef.current.setPosition({ lat: latLong.lat, lng: latLong.long });
-
- window.reloadLoc = () => {
- panoramaRef.current.setPosition({ lat: latLong.lat, lng: latLong.long });
- }
- }
-
-
- // pano onload
-
- function fixPitch() {
- // point towards road
-
- panoramaRef.current.setPov(panoramaRef.current.getPhotographerPov());
- panoramaRef.current.setZoom(0);
-
- // if localhost log the location
- if(window.location.hostname === "localhost") {
- console.log("[DEV] country:", latLong.country);
- }
- }
-
-
- let loaded = false;
- function onChangeListener(e) {
- if(loaded) return;
- loaded = true;
-
- setTimeout(() => {
- setLoading(false)
- setStreetViewShown(true)
- // Select all tags with the attribute http-equiv="origin-trial"
- const metaTags = document.querySelectorAll('meta[http-equiv="origin-trial"]');
-
- // Loop through the NodeList and remove each tag
- metaTags.forEach(meta => meta.remove());
- }, 500)
- fixBranding();
-
- fixPitch();
- }
- panoramaRef.current.addListener("pano_changed", onChangeListener);
-
-
- return () => {
- if(!panoramaRef.current) return;
- google.maps.event.clearListeners(panoramaRef.current, 'pano_changed');
- }
-
-
- }, [latLong, gameOptions?.nm, gameOptions?.npz, gameOptions?.showRoadName, legacyMapLoader])
-
-// useEffect(() => {
-// //!(latLong && multiplayerState?.gameData?.state !== 'end')) || (!streetViewShown || loading || (showAnswer && !showPanoOnResult) || (multiplayerState?.gameData?.state === 'getready') || !latLong)
-// // debug this condition:
-// console.log("isHidden", !(latLong && multiplayerState?.gameData?.state !== 'end')) || (!streetViewShown || loading || (showAnswer && !showPanoOnResult) || (multiplayerState?.gameData?.state === 'getready') || !latLong)
-
-// console.log("latLong", latLong)
-// console.log("multiplayerState?.gameData?.state", multiplayerState?.gameData?.state)
-// console.log("streetViewShown", streetViewShown)
-// console.log("loading", loading)
-// console.log("showAnswer", showAnswer)
-// console.log("showPanoOnResult", showPanoOnResult)
-
-
-// }, [latLong, multiplayerState?.gameData?.state, streetViewShown, loading, showAnswer, showPanoOnResult])
-
- useEffect(() => {
-
- if(panoramaRef.current) {
- panoramaRef.current.setOptions({
- linksControl: gameOptions?.nm ? false:true,
- clickToGo: gameOptions?.nm ? false:true,
-
- panControl: true,
-
- zoomControl: gameOptions?.npz ? false:true,
- showRoadLabels: gameOptions?.showRoadName===true?true:false,
- })
- }
- }, [gameOptions?.nm, gameOptions?.npz, gameOptions?.showRoadName])
-
-
- return (
- <>
-
-
-
-
-
-
- setMerchModal(false)} session={session} />
-
- {ChatboxMemo}
-
-
-
-
-
-
{text("videoAdThanks")} {text("enjoyGameplay")}
-
-
-
-
-
-{screen === "home" && !mapModal && !merchModal && !friendsModal && !accountModalOpen && (
-
-
- { !isApp && (
- <>
- { !inCrazyGames && (
- <>
-
-
-
- >
- )}
-
-
-
- >
- )}
-
- setSettingsModal(true)}>
-
-
- )}
-
-
-
-
-
-
-
- { latLong && latLong?.lat && latLong?.long && legacyMapLoader ? (
-<>
-
-
-
-{/* put something in the top left to cover the address */}
-
-
-
- >
-
- ) : (
-
- )}
-
-
-
-
- setFriendsModal(true)} loginQueued={loginQueued} setLoginQueued={setLoginQueued} inGame={multiplayerState?.inGame || screen === "singleplayer"} openAccountModal={() => setAccountModalOpen(true)} session={session} shown={true} reloadBtnPressed={reloadBtnPressed} backBtnPressed={backBtnPressed} setGameOptionsModalShown={setGameOptionsModalShown} onNavbarPress={() => onNavbarLogoPress()} gameOptions={gameOptions} screen={screen} multiplayerState={multiplayerState} />
-
-{/* merch button */}
-{screen === "home" && !mapModal && session && session?.token?.secret && !inCrazyGames && !session?.token?.supporter && (
- {setMerchModal(true)}}>
- Remove Ads
-
-)}
-
-
-
-
-
- { onboardingCompleted===null ? (
- <>
-
- >
- ) : (
- <>
-
-
- { onboardingCompleted && (
-
WorldGuessr
- )}
-
-
-
- { onboardingCompleted && (
-
- <>
-
-
- {/*
{
- if (!loading) setScreen("singleplayer")
- }} /> */}
- {
- if (!loading) {
- // setScreen("singleplayer")
- crazyMidgame(() => setScreen("singleplayer"))
- }
- }} >{text("singleplayer")}
- {/* {text("playOnline")} */}
- handleMultiplayerAction("publicDuel")}
- disabled={!multiplayerState.connected || maintenance}>{text("findDuel")}
-
-
- {/* {text("playFriends")} */}
-
- handleMultiplayerAction("createPrivateGame")}>{text("createGame")}
- handleMultiplayerAction("joinPrivateGame")}>{text("joinGame")}
-
-
-
-
-{/* { !isApp && (
- <>
-
-
-
- >
- )}
- setSettingsModal(true)}>
- */}
- { !inCrazyGames && (
- setMapModal(true)}>{text("communityMaps")}
- )}
-
-
- >
- )}
-
-
-
-
- { !loading && screen === "home" && !inCrazyGames &&(!session?.token?.supporter) && (
-
- )}
-
-
-
- >
- )}
-
-
-
-
-
-
- {setMapModal(false);setGameOptionsModalShown(false)}} text={text}
- customChooseMapCallback={(gameOptionsModalShown&&screen==="singleplayer")?(map)=> {
- console.log("map", map)
- openMap(map.countryMap||map.slug);
- setGameOptionsModalShown(false)
- }:null}
- showAllCountriesOption={(gameOptionsModalShown&&screen==="singleplayer")}
- singleplayer={screen==="singleplayer"}
- gameOptions={gameOptions} setGameOptions={setGameOptions} />
-
- setSettingsModal(false)} />
-
- setFriendsModal(false)} session={session} canSendInvite={
- // send invite if in a private multiplayer game, dont need to be host or in game waiting just need to be in a private game
- multiplayerState?.inGame && !multiplayerState?.gameData?.public
- } sendInvite={sendInvite} />
-
- {screen === "singleplayer" &&
-
-
}
-
- {screen === "onboarding" && onboarding?.round &&
-
-
}
-
- {screen === "onboarding" && onboarding?.completed &&
-
- {
- try {
- gameStorage.setItem("onboarding", 'done')
- } catch(e) {}
- setOnboarding((prev)=>{
- return {
- ...prev,
- finalOnboardingShown: true
- }
- })
- }} shown={!onboarding?.finalOnboardingShown} />
- {
- if(onboarding) sendEvent("tutorial_end");
-
- setOnboarding(null)
- if(!window.location.search.includes("app=true") && !inCrazyGames) {
- setShowSuggestLoginModal(true)
- }
- setScreen("home")
- }}/>
-
-
-}
-
- {screen === "multiplayer" &&
-
-
}
-
- {multiplayerState.inGame && ["guess", "getready", "end"].includes(multiplayerState.gameData?.state) && (
- { }} gameOptions={{ location: "all", maxDist: 20000, extent: gameOptions?.extent }} setGameOptions={() => { }} showAnswer={(multiplayerState?.gameData?.curRound !== 1) && multiplayerState?.gameData?.state === 'getready'} setShowAnswer={guessMultiplayer} />
- )}
-
-
-
-
-
- >
- )
-}
+import LocalizedHome from "@/components/localizedHome";
+export default function IndexPage() {
+ return ;
+}
\ No newline at end of file
diff --git a/pages/leaderboard/index.js b/pages/leaderboard/index.js
index 3dcd7554..a4ea035a 100644
--- a/pages/leaderboard/index.js
+++ b/pages/leaderboard/index.js
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import Head from 'next/head';
import { useSession } from '@/components/auth/auth';
import { useTranslation } from '@/components/useTranslations'
+import config from '@/clientConfig';
const Leaderboard = ({ }) => {
const { t: text } = useTranslation("common");
@@ -17,6 +18,7 @@ const Leaderboard = ({ }) => {
}, []);
useEffect(() => {
+ const configData = config();
const fetchData = async () => {
try {
const params = {
@@ -24,7 +26,7 @@ const Leaderboard = ({ }) => {
pastDay: pastDay ? true : undefined
};
const queryParams = new URLSearchParams(params).toString();
- const response = await fetch(`/api/leaderboard${queryParams ? `?${queryParams}` : ''}`);
+ const response = await fetch(configData.apiUrl+`/api/leaderboard${queryParams ? `?${queryParams}` : ''}`);
const data = await response.json();
setLeaderboardData(data);
} catch (error) {
diff --git a/pages/learn.js b/pages/learn.js
index 533444a5..94abb657 100644
--- a/pages/learn.js
+++ b/pages/learn.js
@@ -7,13 +7,15 @@ const roboto = Roboto({ subsets: ['cyrillic'], weight: "400", style: 'normal' })
import NextImage from "next/image";
import Link from 'next/link';
import Head from 'next/head';
+import config from '@/clientConfig';
export default function Learn({ locale }) {
const [clueCnt, setClueCnt] = React.useState(0);
const [displayCount, setDisplayCount] = React.useState(0);
React.useEffect(() => {
- fetch('/api/clues/getCluesCount').then(res => res.json()).then(data => {
+ const configData = config();
+ fetch(configData.apiUrl+'/api/clues/getCluesCount').then(res => res.json()).then(data => {
setClueCnt(data.count);
});
}, []);
diff --git a/pages/map/[slug].js b/pages/map.js
similarity index 76%
rename from pages/map/[slug].js
rename to pages/map.js
index 6a7af3fa..2250add9 100644
--- a/pages/map/[slug].js
+++ b/pages/map.js
@@ -4,6 +4,7 @@ import { useRouter } from 'next/router';
import styles from '@/styles/MapPage.module.css'; // Import CSS module for styling
import Navbar from '@/components/ui/navbar';
import { useTranslation } from '@/components/useTranslations'
+import config from '@/clientConfig';
// export async function getServerSideProps(context) {
@@ -68,17 +69,45 @@ export default function MapPage({ }) {
const [locationUrls, setLocationUrls] = useState([]);
const [fadeClass, setFadeClass] = useState(styles.iframe);
const { t: text } = useTranslation('common');
+ const [mapData, setMapData] = useState({});
+
+ // const mapData = {
+ // name: "United States",
+ // description_short: "Explore the United States of America",
+ // description_long: "Explore the United States of America on WorldGuessr, a free GeoGuessr clone. This map features locations from all 50 states, including landmarks, cities, and natural wonders.",
+ // created_by: "WorldGuessr",
+ // created_at: "1 year",
+ // in_review: false,
+ // rejected: false,
+ // countryCode: "US",
+ // };
+
+ useEffect(() => {
+ const {apiUrl} = config()
+ // slug can either be in two forms
+ // /map/:slug (path param)
+ // /map?s=slug (query param)
+
+ const queryParams = new URLSearchParams(window.location.search);
+ const slug = router.query.s || router.query.slug || queryParams.get('s') || queryParams.get('slug');
+
+ if (!slug) return;
+
+ console.log('fetching map data for', slug);
+ fetch(apiUrl+`/api/map/publicData?slug=${slug}`).then(async res => {
+ if (res.ok) {
+ const data = await res.json();
+ console.log('fetched map data:', data);
+ setMapData(data.mapData);
+ } else {
+ console.error('Failed to fetch map data:', res);
+ if(res.status === 404) {
+ router.push('/404');
+ }
+ }
+ });
+ }, []);
- const mapData = {
- name: "United States",
- description_short: "Explore the United States of America",
- description_long: "Explore the United States of America on WorldGuessr, a free GeoGuessr clone. This map features locations from all 50 states, including landmarks, cities, and natural wonders.",
- created_by: "WorldGuessr",
- created_at: "1 year",
- in_review: false,
- rejected: false,
- countryCode: "US",
- };
useEffect(() => {
if (!mapData.data) return;
@@ -106,8 +135,8 @@ export default function MapPage({ }) {
return (
-
{mapData.name + " - Play Free on WorldGuessr"}
-
+
{mapData?.name + " - Play Free on WorldGuessr"}
+
@@ -122,6 +151,9 @@ export default function MapPage({ }) {
+ {mapData?.name && (
+ <>
+
{mapData.in_review && (
⏳ This map is currently under review.
@@ -134,6 +166,9 @@ export default function MapPage({ }) {
)}
+>
+ )}
+
WorldGuessr
@@ -143,6 +178,16 @@ export default function MapPage({ }) {
+ {!mapData.name && (
+
+ )}
+
+
+ { mapData.name && (
{locationUrls.length > 0 && (
@@ -166,6 +211,10 @@ export default function MapPage({ }) {
{mapData.description_short}
+ )}
+
+{ mapData?.name && (
+ <>
PLAY
@@ -202,6 +251,8 @@ export default function MapPage({ }) {
)}
+ >
+)}
);
diff --git a/pages/maps.js b/pages/maps.js
index 910aaad5..ab4368cb 100644
--- a/pages/maps.js
+++ b/pages/maps.js
@@ -1,14 +1,22 @@
// pages/maps.js
-import React from "react";
+import React, { useEffect } from "react";
import { useRouter } from "next/router";
import MapView from "@/components/maps/mapView";
import { useTranslation } from '@/components/useTranslations'
+import config from "@/clientConfig";
+
+import { useSession } from "@/components/auth/auth";
+import Head from "next/head";
export default function MapsPage({ }) {
const router = useRouter();
const { t: text } = useTranslation("common");
const { data: session, status } = useSession();
+ useEffect(() => {
+ window.cConfig = config();
+ }, []);
+
const handleMapClick = (map) => {
router.push(`/map/${map.slug}`);
};
@@ -56,6 +64,3 @@ const styles = {
},
};
-
-import { useSession } from "@/components/auth/auth";
-import Head from "next/head";
\ No newline at end of file
diff --git a/pages/ru.js b/pages/ru.js
new file mode 100644
index 00000000..9d319fee
--- /dev/null
+++ b/pages/ru.js
@@ -0,0 +1,5 @@
+import LocalizedHome from "@/components/localizedHome";
+
+export default function IndexPage() {
+ return