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>
|
||||
}
|
||||
</>
|
||||
}
|
||||
Reference in New Issue
Block a user