mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-02-09 10:20:16 +01:00
Delete team pageweb (obselete + useless)
This commit is contained in:
@@ -1,19 +0,0 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import { BlueButton } from "@/components/button";
|
|
||||||
import { TextInput } from "@/components/input";
|
|
||||||
|
|
||||||
export default function LoginForm({ onSubmit, title, placeholder, buttonText}) {
|
|
||||||
const [value, setValue] = useState("");
|
|
||||||
function handleSubmit(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
setValue("");
|
|
||||||
onSubmit(value);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<form className="bg-white shadow-md max-w mx-auto p-5 mx-10 flex flex-col space-y-4" onSubmit={handleSubmit}>
|
|
||||||
<h1 className="text-2xl font-bold text-center text-gray-700">{title}</h1>
|
|
||||||
<TextInput inputMode="numeric" placeholder={placeholder} value={value} onChange={(e) => setValue(e.target.value)} name="team-id"/>
|
|
||||||
<BlueButton type="submit">{buttonText}</BlueButton>
|
|
||||||
</form>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { TeamConnexionProvider } from "@/context/teamConnexionContext";
|
|
||||||
import { TeamProvider } from "@/context/teamContext";
|
|
||||||
|
|
||||||
export default function AdminLayout({ children }) {
|
|
||||||
return (
|
|
||||||
<TeamConnexionProvider>
|
|
||||||
<TeamProvider>
|
|
||||||
{children}
|
|
||||||
</TeamProvider>
|
|
||||||
</TeamConnexionProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
"use client"
|
|
||||||
import { useTeamConnexion } from "@/context/teamConnexionContext";
|
|
||||||
import LoginForm from "./components/loginForm";
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
const { login,useProtect } = useTeamConnexion();
|
|
||||||
useProtect();
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<LoginForm title={"Team login"} placeholder={"team ID"} buttonText={"Login"} onSubmit={(value) => login(parseInt(value))}/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
import { useEffect, useState } from "react"
|
|
||||||
import { BlueButton, GreenButton } from "@/components/button";
|
|
||||||
import { TextInput } from "@/components/input";
|
|
||||||
import useTeamConnexion from "@/context/teamConnexionContext";
|
|
||||||
import useGame from "@/hook/useGame";
|
|
||||||
import EnemyTeamModal from "./enemyTeamModal";
|
|
||||||
|
|
||||||
export default function ActionDrawer() {
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const [enemyCaptureCode, setEnemyCaptureCode] = useState("");
|
|
||||||
const { sendCurrentPosition, name, captureCode, capture, locationSendDeadline, penalties } = useGame();
|
|
||||||
const {logout} = useTeamConnexion();
|
|
||||||
const [timeLeftBeforePenalty, setTimeLeftBeforePenalty] = useState(0);
|
|
||||||
const [enemyModalVisible, setEnemyModalVisible] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
console.log(locationSendDeadline)
|
|
||||||
const timeLeft = locationSendDeadline - Date.now();
|
|
||||||
setTimeLeftBeforePenalty(Math.floor(timeLeft / 1000 / 60));
|
|
||||||
}, 1000);
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, [locationSendDeadline]);
|
|
||||||
|
|
||||||
function handleCapture() {
|
|
||||||
capture(enemyCaptureCode);
|
|
||||||
setEnemyCaptureCode("");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={"fixed w-screen bottom-0 z-10 bg-gray-100 flex justify-center rounded-t-2xl transition-all duration-200 flex flex-col " + (visible ? "h-full" : "h-20")}>
|
|
||||||
<img src="/icons/arrow_up.png" className={"w-full object-scale-down h-ful max-h-20 transition-all cursor-pointer duration-200 " + (visible && "rotate-180")} onClick={() => setVisible(!visible)} />
|
|
||||||
{visible && <div className="flex justify-between flex-col w-full h-full">
|
|
||||||
<div className="flex flex-row justify-around">
|
|
||||||
<img src="/icons/logout.png" onClick={logout} className='p-3 mx-2 w-14 h-14 bg-red-500 rounded-lg cursor-pointer bg-red z-20' />
|
|
||||||
</div>
|
|
||||||
<div className='shadow-2xl bg-white p-1 flex flex-col text-center mb-1 mx-auto w-4/5 rounded'>
|
|
||||||
<div>
|
|
||||||
<span className='text-2xl text-black'>{name}</span>
|
|
||||||
</div>
|
|
||||||
<div className='text-gray-700'>
|
|
||||||
<span> Capture code </span>
|
|
||||||
<span className='text-lg text-black'>{String(captureCode).padStart(4,"0")}</span>
|
|
||||||
</div>
|
|
||||||
<div className='text-gray-700'>
|
|
||||||
<span className='text-lg text-black'>{timeLeftBeforePenalty}min</span>
|
|
||||||
<span> before penalty</span>
|
|
||||||
</div>
|
|
||||||
<div className='w-1/2 flex flex-row justify-center mx-auto'>
|
|
||||||
{Array.from({ length: penalties }).map((_, i) => <div key={i} className='min-h-5 m-2 min-w-5 bg-red-400'></div>)}
|
|
||||||
{Array.from({ length: 3-penalties }).map((_, i) => <div key={i} className='min-h-5 m-2 min-w-5 bg-green-400'></div>)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="h-20">
|
|
||||||
<BlueButton onClick={sendCurrentPosition} className="h-10">Update position</BlueButton>
|
|
||||||
</div>
|
|
||||||
<div className="p-5 shadow-lg bg-white">
|
|
||||||
<div className="text-center text-2xl">Target</div>
|
|
||||||
<div className="h-20 my-1">
|
|
||||||
<GreenButton onClick={() => setEnemyModalVisible(true)}>See target info</GreenButton>
|
|
||||||
</div>
|
|
||||||
<div className="h-20 flex flex-row">
|
|
||||||
<TextInput inputMode="numeric" placeholder="Enemy code" value={enemyCaptureCode} onChange={(e) => setEnemyCaptureCode(e.target.value)} />
|
|
||||||
<GreenButton onClick={handleCapture}>Capture target</GreenButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* <div className="h-20">
|
|
||||||
<RedButton onClick={sendCurrentPosition}>Signal emergency</RedButton>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<EnemyTeamModal visible={enemyModalVisible} onClose={() => setEnemyModalVisible(false)} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import { useEffect, useRef } from "react";
|
|
||||||
import { env } from 'next-runtime-env';
|
|
||||||
import { RedButton } from "@/components/button";
|
|
||||||
import useGame from "@/hook/useGame";
|
|
||||||
|
|
||||||
|
|
||||||
export default function EnemyTeamModal({ visible, onClose }) {
|
|
||||||
const { teamId, enemyName } = useGame();
|
|
||||||
const imageRef = useRef(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (visible) {
|
|
||||||
refreshImage();
|
|
||||||
}
|
|
||||||
}, [visible]);
|
|
||||||
|
|
||||||
function refreshImage() {
|
|
||||||
imageRef.current.src = SERVER_URL + "/photo/enemy?team=" + teamId.toString() + "&t=" + new Date().getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
var protocol = "https://";
|
|
||||||
const NEXT_PUBLIC_SOCKET_HOST = env("NEXT_PUBLIC_SOCKET_HOST");
|
|
||||||
if (NEXT_PUBLIC_SOCKET_HOST == "localhost") {
|
|
||||||
protocol = "http://";
|
|
||||||
}
|
|
||||||
const SERVER_URL = protocol + NEXT_PUBLIC_SOCKET_HOST + "/back";
|
|
||||||
console.log(SERVER_URL);
|
|
||||||
return (visible &&
|
|
||||||
<>
|
|
||||||
<div className='fixed w-screen h-screen bg-black bg-opacity-50 z-10 text-center'></div>
|
|
||||||
<div className='fixed w-11/12 h-5/6 p-5 z-20 mx-auto inset-x-0 my-auto inset-y-0 flex flex-col justify-center rounded-xl transition-all shadow-xl bg-white '>
|
|
||||||
<h1 className="w-full text-center text-3xl mb-5">{enemyName}</h1>
|
|
||||||
<img ref={imageRef} src={SERVER_URL + "/photo/enemy?team=" + teamId.toString()} className='w-full h-full object-contain' />
|
|
||||||
<div className="h-20">
|
|
||||||
<RedButton onClick={onClose}>Close</RedButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
import { Circle, MapContainer, Marker, Popup, TileLayer, useMap } from 'react-leaflet'
|
|
||||||
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css'
|
|
||||||
import "leaflet-defaulticon-compatibility";
|
|
||||||
import "leaflet/dist/leaflet.css";
|
|
||||||
import useTeamContext from '@/context/teamContext';
|
|
||||||
import useGame from '@/hook/useGame';
|
|
||||||
|
|
||||||
const DEFAULT_ZOOM = 14;
|
|
||||||
|
|
||||||
// Pan to the center of the map when the position of the user is updated for the first time
|
|
||||||
function MapPan(props) {
|
|
||||||
const map = useMap();
|
|
||||||
const [initialized, setInitialized] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!initialized && props.center) {
|
|
||||||
map.flyTo(props.center, DEFAULT_ZOOM, { animate: false });
|
|
||||||
setInitialized(true)
|
|
||||||
}
|
|
||||||
}, [props.center]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function LiveZone() {
|
|
||||||
const { zone } = useTeamContext();
|
|
||||||
console.log('Zone', zone);
|
|
||||||
return zone && <Circle center={zone.center} radius={zone.radius} color='blue' fill={false} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function ZoneExtremities() {
|
|
||||||
const { zoneExtremities } = useTeamContext();
|
|
||||||
console.log('Zone extremities', zoneExtremities);
|
|
||||||
return zoneExtremities?.begin && zoneExtremities?.end && <>
|
|
||||||
{/* <Circle center={zoneExtremities.begin.center} radius={zoneExtremities.begin.radius} color='black' fill={false} /> */}
|
|
||||||
<Circle center={zoneExtremities.end.center} radius={zoneExtremities.end.radius} color='red' fill={false} />
|
|
||||||
</>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LiveMap({ ...props }) {
|
|
||||||
const { currentPosition, enemyPosition } = useGame();
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('Current position', currentPosition);
|
|
||||||
}, [currentPosition]);
|
|
||||||
return (
|
|
||||||
<MapContainer {...props} className='min-h-full z-0' center={[0, 0]} zoom={0} scrollWheelZoom={true}>
|
|
||||||
<TileLayer
|
|
||||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
||||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
||||||
/>
|
|
||||||
{currentPosition && <Marker position={currentPosition} icon={new L.Icon({
|
|
||||||
iconUrl: '/icons/location.png',
|
|
||||||
iconSize: [30, 30],
|
|
||||||
iconAnchor: [15, 15],
|
|
||||||
popupAnchor: [0, -15],
|
|
||||||
shadowSize: [30, 30],
|
|
||||||
})}>
|
|
||||||
<Popup>
|
|
||||||
Votre position
|
|
||||||
</Popup>
|
|
||||||
</Marker>}
|
|
||||||
{enemyPosition && <Marker position={enemyPosition} icon={new L.Icon({
|
|
||||||
iconUrl: '/icons/target.png',
|
|
||||||
iconSize: [30, 30],
|
|
||||||
iconAnchor: [15, 15],
|
|
||||||
popupAnchor: [0, -15],
|
|
||||||
shadowSize: [30, 30],
|
|
||||||
})}>
|
|
||||||
<Popup>
|
|
||||||
Position de l'ennemi
|
|
||||||
</Popup>
|
|
||||||
</Marker>}
|
|
||||||
<MapPan center={currentPosition} />
|
|
||||||
<LiveZone />
|
|
||||||
<ZoneExtremities />
|
|
||||||
</MapContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function PlacementMap({ ...props }) {
|
|
||||||
const { currentPosition, startingArea } = useGame();
|
|
||||||
return (
|
|
||||||
<MapContainer {...props} className='min-h-full w-full z-0' center={[0, 0]} zoom={0} scrollWheelZoom={true}>
|
|
||||||
<TileLayer
|
|
||||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
||||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
||||||
/>
|
|
||||||
{currentPosition && <Marker position={currentPosition} icon={new L.Icon({
|
|
||||||
iconUrl: '/icons/location.png',
|
|
||||||
iconSize: [30, 30],
|
|
||||||
iconAnchor: [15, 15],
|
|
||||||
popupAnchor: [0, -15],
|
|
||||||
shadowSize: [30, 30],
|
|
||||||
})}>
|
|
||||||
<Popup>
|
|
||||||
Votre position
|
|
||||||
</Popup>
|
|
||||||
</Marker>}
|
|
||||||
<MapPan center={currentPosition} />
|
|
||||||
{startingArea && <Circle center={startingArea?.center} radius={startingArea?.radius} color='blue' />}
|
|
||||||
</MapContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useSocketListener } from "@/hook/useSocketListener";
|
|
||||||
|
|
||||||
export default function Notification({ socket }) {
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const [timeoutId, setTimeoutId] = useState(null);
|
|
||||||
const [notification, setNotification] = useState(null);
|
|
||||||
|
|
||||||
useSocketListener(socket, "error", (notification) => {
|
|
||||||
console.log("error", notification);
|
|
||||||
setNotification({ type: "error", text: notification });
|
|
||||||
setVisible(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
useSocketListener(socket, "success", (notification) => {
|
|
||||||
console.log("success", notification);
|
|
||||||
setNotification({ type: "success", text: notification });
|
|
||||||
setVisible(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
useSocketListener(socket, "warning", (notification) => {
|
|
||||||
console.log("warning", notification);
|
|
||||||
setNotification({ type: "warning", text: notification });
|
|
||||||
setVisible(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Hide the notification after 5 seconds
|
|
||||||
useEffect(() => {
|
|
||||||
console.log({ visible });
|
|
||||||
if (visible && notification?.text != undefined) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
if (notification?.type == "success") {
|
|
||||||
setTimeoutId(setTimeout(() => {
|
|
||||||
setVisible(false);
|
|
||||||
}, 3000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [visible]);
|
|
||||||
|
|
||||||
const bgColorMap = {
|
|
||||||
error: "bg-red-500 text-white",
|
|
||||||
success: "bg-green-500",
|
|
||||||
warning: "bg-yellow-500"
|
|
||||||
}
|
|
||||||
|
|
||||||
const classNames = 'fixed relative w-11/12 p-5 z-30 mx-auto inset-x-0 flex justify-center rounded-xl transition-all shadow-xl ' + (visible ? "top-5 " : "-translate-y-full ");
|
|
||||||
|
|
||||||
return (
|
|
||||||
Object.keys(bgColorMap).map((key) =>
|
|
||||||
notification?.type == key &&
|
|
||||||
<div key={key} className={classNames + bgColorMap[key]} onClick={() => setVisible(false)}>
|
|
||||||
<p className="absolute top-2 right-2 p-2 rounded-l text-3xl bg-white">x</p>
|
|
||||||
<p className='text-center text-xl'>{notification?.text}</p>
|
|
||||||
</div>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import useTeamConnexion from "@/context/teamConnexionContext";
|
|
||||||
import useGame from "@/hook/useGame";
|
|
||||||
|
|
||||||
export default function PlacementOverlay() {
|
|
||||||
const { name, ready } = useGame();
|
|
||||||
const {logout} = useTeamConnexion();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<img src="/icons/logout.png" onClick={logout} className='w-12 h-12 bg-red-500 p-2 top-1 right-1 rounded-lg cursor-pointer bg-red fixed z-20' />
|
|
||||||
<div className='fixed top-0 p-3 w-full bg-gray-300 shadow-xl rounded-b-xl flex flex-col z-10 justify-center items-center'>
|
|
||||||
<div className='text-2xl my-3'>Placement</div>
|
|
||||||
<div className='text-md'>{name}</div>
|
|
||||||
{!ready && <div className='text-lg font-semibold text-red-700'>Positionez vous dans le cercle</div>}
|
|
||||||
{ready && <div className='text-lg font-semibold text-green-700 text-center'>Restez dans le cercle en attendant que la partie commence</div>}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import { useRef } from "react";
|
|
||||||
import { env } from 'next-runtime-env';
|
|
||||||
import { GreenButton, LogoutButton } from "@/components/button";
|
|
||||||
import useTeamContext from "@/context/teamContext";
|
|
||||||
import useGame from "@/hook/useGame"
|
|
||||||
|
|
||||||
export default function WaitingScreen() {
|
|
||||||
const { name, teamId } = useGame();
|
|
||||||
const { gameSettings } = useTeamContext();
|
|
||||||
const imageRef = useRef(null);
|
|
||||||
const NEXT_PUBLIC_SOCKET_HOST = env("NEXT_PUBLIC_SOCKET_HOST");
|
|
||||||
var protocol = "https://";
|
|
||||||
if (NEXT_PUBLIC_SOCKET_HOST == "localhost") {
|
|
||||||
protocol = "http://";
|
|
||||||
}
|
|
||||||
const SERVER_URL = protocol + NEXT_PUBLIC_SOCKET_HOST + "/back";
|
|
||||||
console.log(SERVER_URL);
|
|
||||||
|
|
||||||
function sendImage() {
|
|
||||||
let data = new FormData();
|
|
||||||
data.append('file', document.querySelector('input[type="file"]').files[0]);
|
|
||||||
|
|
||||||
fetch(SERVER_URL + "/upload?team=" + teamId.toString() , {
|
|
||||||
method: 'POST',
|
|
||||||
body: data
|
|
||||||
}).then((response) => {
|
|
||||||
console.log(response);
|
|
||||||
refreshImage();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshImage() {
|
|
||||||
imageRef.current.src = SERVER_URL + "/photo/my?team=" + teamId.toString() + "&t=" + new Date().getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='h-full flex flex-col items-center justify-center'>
|
|
||||||
<LogoutButton />
|
|
||||||
<div className='text-4xl mt-10 text-center'>
|
|
||||||
Equipe : {name}
|
|
||||||
</div>
|
|
||||||
<div className='text-2xl text-center'>
|
|
||||||
{gameSettings?.waitingMessage}
|
|
||||||
</div>
|
|
||||||
<div className='text-2xl text-center my-10'>
|
|
||||||
<p>Uploadez une photo où tous les membres de l'équipe sont visibles</p>
|
|
||||||
<input type="file" name="file" accept="image/*" className=" my-5 block w-full text-slate-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100"/>
|
|
||||||
<div className="h-20">
|
|
||||||
<GreenButton onClick={sendImage}>Envoyer</GreenButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{teamId && <img ref={imageRef} src={SERVER_URL + "/photo/my?team=" + teamId.toString()} className='w-screen h-1/2 object-contain' />}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import React from 'react';
|
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import { LogoutButton } from '@/components/button';
|
|
||||||
import { useSocket } from '@/context/socketContext';
|
|
||||||
import { useTeamConnexion } from '@/context/teamConnexionContext';
|
|
||||||
import { useTeamContext } from '@/context/teamContext';
|
|
||||||
import useGame from '@/hook/useGame';
|
|
||||||
import { GameState } from '@/util/gameState';
|
|
||||||
import ActionDrawer from './components/actionDrawer';
|
|
||||||
import Notification from './components/notification';
|
|
||||||
import PlacementOverlay from './components/placementOverlay';
|
|
||||||
import WaitingScreen from './components/waitingScreen';
|
|
||||||
|
|
||||||
//Load the map without SSR
|
|
||||||
const LiveMap = dynamic(() => import('./components/map').then((mod) => mod.LiveMap), {
|
|
||||||
ssr: false
|
|
||||||
});
|
|
||||||
const PlacementMap = dynamic(() => import('./components/map').then((mod) => mod.PlacementMap), {
|
|
||||||
ssr: false
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function Track() {
|
|
||||||
const { gameState, captured } = useGame();
|
|
||||||
const { gameSettings} = useTeamContext()
|
|
||||||
const { useProtect } = useTeamConnexion();
|
|
||||||
const { teamSocket: socket } = useSocket();
|
|
||||||
useProtect();
|
|
||||||
return <>
|
|
||||||
<Notification socket={socket} />
|
|
||||||
{gameState == GameState.SETUP && <WaitingScreen />}
|
|
||||||
{gameState == GameState.PLAYING && !captured && <div className='h-full'>
|
|
||||||
<LiveMap />
|
|
||||||
<ActionDrawer />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
{gameState == GameState.PLAYING && captured && <div className='h-full'>
|
|
||||||
<div className='text-center text-2xl'>Vous avez été capturé</div>
|
|
||||||
<div className='text-center text-md'>{gameSettings?.capturedMessage}</div>
|
|
||||||
</div>}
|
|
||||||
{gameState == GameState.PLACEMENT &&
|
|
||||||
<div className='h-full'>
|
|
||||||
<PlacementOverlay />
|
|
||||||
<PlacementMap />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
{gameState == GameState.FINISHED && <div className='h-full'>
|
|
||||||
<LogoutButton />
|
|
||||||
<div className='text-center text-2xl'>Partie terminée</div>
|
|
||||||
{captured && <div className='text-center text-md'>{gameSettings?.loserEndGameMessage}</div>}
|
|
||||||
{!captured && <div className='text-center text-md'>{gameSettings?.winnerEndGameMessage}</div>}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
import { useTeamConnexion } from "@/context/teamConnexionContext";
|
|
||||||
|
|
||||||
export function BlueButton({ children, ...props }) {
|
export function BlueButton({ children, ...props }) {
|
||||||
return (<button {...props} className="bg-blue-600 hover:bg-blue-500 text-lg ease-out duration-200 text-white w-full h-full p-4 shadow-sm rounded">
|
return (<button {...props} className="bg-blue-600 hover:bg-blue-500 text-lg ease-out duration-200 text-white w-full h-full p-4 shadow-sm rounded">
|
||||||
{children}
|
{children}
|
||||||
@@ -17,8 +15,3 @@ export function GreenButton({ children, ...props }) {
|
|||||||
{children}
|
{children}
|
||||||
</button>)
|
</button>)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LogoutButton() {
|
|
||||||
const { logout } = useTeamConnexion();
|
|
||||||
return <img src="/icons/logout.png" onClick={logout} className='w-12 h-12 bg-red-500 p-2 top-1 right-1 rounded-lg cursor-pointer bg-red fixed z-20' />
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,13 +5,8 @@ import { io } from 'socket.io-client';
|
|||||||
|
|
||||||
const NEXT_PUBLIC_SOCKET_HOST = env("NEXT_PUBLIC_SOCKET_HOST");
|
const NEXT_PUBLIC_SOCKET_HOST = env("NEXT_PUBLIC_SOCKET_HOST");
|
||||||
const SOCKET_URL = (NEXT_PUBLIC_SOCKET_HOST == "localhost" ? "ws://" : "wss://") + NEXT_PUBLIC_SOCKET_HOST;
|
const SOCKET_URL = (NEXT_PUBLIC_SOCKET_HOST == "localhost" ? "ws://" : "wss://") + NEXT_PUBLIC_SOCKET_HOST;
|
||||||
const USER_SOCKET_URL = SOCKET_URL + "/player";
|
|
||||||
const ADMIN_SOCKET_URL = SOCKET_URL + "/admin";
|
const ADMIN_SOCKET_URL = SOCKET_URL + "/admin";
|
||||||
|
|
||||||
export const teamSocket = io(USER_SOCKET_URL, {
|
|
||||||
path: "/back/socket.io",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const adminSocket = io(ADMIN_SOCKET_URL, {
|
export const adminSocket = io(ADMIN_SOCKET_URL, {
|
||||||
path: "/back/socket.io",
|
path: "/back/socket.io",
|
||||||
});
|
});
|
||||||
@@ -19,7 +14,8 @@ export const adminSocket = io(ADMIN_SOCKET_URL, {
|
|||||||
export const SocketContext = createContext();
|
export const SocketContext = createContext();
|
||||||
|
|
||||||
export default function SocketProvider({ children }) {
|
export default function SocketProvider({ children }) {
|
||||||
const value = useMemo(() => ({ teamSocket, adminSocket }), [teamSocket, adminSocket]);
|
const value = useMemo(() => ({ adminSocket }), [adminSocket]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SocketContext.Provider value={value}>{children}</SocketContext.Provider>
|
<SocketContext.Provider value={value}>{children}</SocketContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { createContext, useContext, useMemo } from "react";
|
|
||||||
import { useSocket } from "./socketContext";
|
|
||||||
import useSocketAuth from "@/hook/useSocketAuth";
|
|
||||||
import usePasswordProtect from "@/hook/usePasswordProtect";
|
|
||||||
|
|
||||||
const teamConnexionContext = createContext();
|
|
||||||
|
|
||||||
export function TeamConnexionProvider({ children }) {
|
|
||||||
const { teamSocket } = useSocket();
|
|
||||||
const { login, password: teamId, loggedIn, loading, logout } = useSocketAuth(teamSocket, "team_password");
|
|
||||||
const useProtect = () => usePasswordProtect("/team", "/team/track", loading, loggedIn);
|
|
||||||
|
|
||||||
const value = useMemo(() => ({ teamId, login, logout, loggedIn, loading, useProtect}), [teamId, login, loggedIn, loading]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<teamConnexionContext.Provider value={value}>
|
|
||||||
{children}
|
|
||||||
</teamConnexionContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useTeamConnexion() {
|
|
||||||
return useContext(teamConnexionContext);
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import useLocation from "@/hook/useLocation";
|
|
||||||
import useSocketListener from "@/hook/useSocketListener";
|
|
||||||
import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
||||||
import { useSocket } from "./socketContext";
|
|
||||||
import { useTeamConnexion } from "./teamConnexionContext";
|
|
||||||
import { GameState } from "@/util/gameState";
|
|
||||||
|
|
||||||
const teamContext = createContext();
|
|
||||||
|
|
||||||
export function TeamProvider({children}) {
|
|
||||||
const [teamInfos, setTeamInfos] = useState({});
|
|
||||||
const [gameState, setGameState] = useState(GameState.SETUP);
|
|
||||||
const [gameSettings, setGameSettings] = useState(null);
|
|
||||||
const [zone, setZone] = useState(null);
|
|
||||||
const [zoneExtremities, setZoneExtremities] = useState(null);
|
|
||||||
const measuredLocation = useLocation(5000);
|
|
||||||
const {teamSocket} = useSocket();
|
|
||||||
const {loggedIn} = useTeamConnexion();
|
|
||||||
const teamInfosRef = useRef();
|
|
||||||
|
|
||||||
teamInfosRef.current = teamInfos;
|
|
||||||
|
|
||||||
useSocketListener(teamSocket, "update_team", (newTeamInfos) => setTeamInfos({...teamInfosRef.current, ...newTeamInfos}) );
|
|
||||||
useSocketListener(teamSocket, "game_state", setGameState);
|
|
||||||
useSocketListener(teamSocket, "zone", setZone);
|
|
||||||
useSocketListener(teamSocket, "new_zone", setZoneExtremities);
|
|
||||||
useSocketListener(teamSocket, "game_settings", setGameSettings);
|
|
||||||
|
|
||||||
//Send the current position to the server when the user is logged in
|
|
||||||
useEffect(() => {
|
|
||||||
console.log("sending position", measuredLocation);
|
|
||||||
if(loggedIn) {
|
|
||||||
teamSocket.emit("update_position", measuredLocation);
|
|
||||||
}
|
|
||||||
}, [loggedIn, measuredLocation]);
|
|
||||||
|
|
||||||
const value = useMemo(() => ({teamInfos, gameState, zone, zoneExtremities, gameSettings}), [gameSettings, teamInfos, gameState, zone, zoneExtremities]);
|
|
||||||
return (
|
|
||||||
<teamContext.Provider value={value}>
|
|
||||||
{children}
|
|
||||||
</teamContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useTeamContext() {
|
|
||||||
return useContext(teamContext);
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { useSocket } from "@/context/socketContext";
|
|
||||||
import { useTeamConnexion } from "@/context/teamConnexionContext";
|
|
||||||
import { useTeamContext } from "@/context/teamContext";
|
|
||||||
|
|
||||||
export default function useGame() {
|
|
||||||
const { teamSocket } = useSocket();
|
|
||||||
const { teamId } = useTeamConnexion();
|
|
||||||
const { teamInfos, gameState } = useTeamContext();
|
|
||||||
|
|
||||||
function sendCurrentPosition() {
|
|
||||||
teamSocket.emit("send_position");
|
|
||||||
}
|
|
||||||
|
|
||||||
function capture(captureCode) {
|
|
||||||
teamSocket.emit("capture", captureCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {...teamInfos, sendCurrentPosition, capture, teamId, gameState};
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
|
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
@@ -7,14 +8,12 @@ const nextConfig = {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
source: '/',
|
source: '/',
|
||||||
destination: '/team',
|
destination: '/admin',
|
||||||
permanent: true,
|
permanent: true, // The browser will save the redirect in its cache, empty the cache to change the redirect
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
Reference in New Issue
Block a user