From cb534ed1aaa44d6e197b666968fd80ecdb6e90f4 Mon Sep 17 00:00:00 2001 From: Sebastien Riviere Date: Thu, 28 Aug 2025 00:06:14 +0200 Subject: [PATCH] =?UTF-8?q?R=C3=A9organisation=20des=20dossiers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- traque-front/app/admin/components/buttons.jsx | 15 + .../admin/components}/liveMap.jsx | 6 +- .../admin/components/teamSidePanel.jsx} | 6 +- .../admin/components}/teamViewer.jsx | 1 - traque-front/app/admin/layout.js | 1 - .../admin/login/components}/loginForm.jsx | 4 +- traque-front/app/admin/login/page.js | 3 +- traque-front/app/admin/page.js | 90 ++---- .../parameters/components}/circleZoneMap.jsx | 42 +-- .../admin/parameters/components/messages.jsx} | 18 +- .../parameters/components}/polygonZoneMap.jsx | 10 +- .../parameters/components}/teamManager.jsx | 4 +- traque-front/app/admin/parameters/page.js | 25 +- traque-front/app/admin/teams/page.js | 28 -- .../app/team/components/loginForm.jsx | 19 ++ traque-front/app/team/page.js | 2 +- .../team/track/components}/actionDrawer.jsx | 6 +- .../team/track/components}/enemyTeamModal.jsx | 5 +- .../team/track/components}/map.jsx | 2 +- .../team/track/components}/notification.jsx | 2 +- .../track/components}/placementOverlay.jsx | 2 +- .../team/track/components}/waitingScreen.jsx | 6 +- traque-front/app/team/track/page.js | 18 +- traque-front/components/admin/mapPicker.jsx | 268 ------------------ .../components/admin/placementMap.jsx | 32 --- traque-front/components/admin/teamEdit.jsx | 122 -------- traque-front/components/admin/teamList.jsx | 72 ----- traque-front/components/{util => }/button.jsx | 0 .../components/{admin => }/mapUtils.jsx | 2 +- .../components/{util => }/section.jsx | 0 .../components/{util => }/textInput.jsx | 0 31 files changed, 134 insertions(+), 677 deletions(-) create mode 100644 traque-front/app/admin/components/buttons.jsx rename traque-front/{components/admin => app/admin/components}/liveMap.jsx (98%) rename traque-front/{components/admin/teamInformation.jsx => app/admin/components/teamSidePanel.jsx} (98%) rename traque-front/{components/admin => app/admin/components}/teamViewer.jsx (98%) rename traque-front/{components/team => app/admin/login/components}/loginForm.jsx (87%) rename traque-front/{components/admin => app/admin/parameters/components}/circleZoneMap.jsx (74%) rename traque-front/{components/admin/gameSettings.jsx => app/admin/parameters/components/messages.jsx} (81%) rename traque-front/{components/admin => app/admin/parameters/components}/polygonZoneMap.jsx (97%) rename traque-front/{components/admin => app/admin/parameters/components}/teamManager.jsx (100%) delete mode 100644 traque-front/app/admin/teams/page.js create mode 100644 traque-front/app/team/components/loginForm.jsx rename traque-front/{components/team => app/team/track/components}/actionDrawer.jsx (97%) rename traque-front/{components/team => app/team/track/components}/enemyTeamModal.jsx (96%) rename traque-front/{components/team => app/team/track/components}/map.jsx (100%) rename traque-front/{components/team => app/team/track/components}/notification.jsx (100%) rename traque-front/{components/team => app/team/track/components}/placementOverlay.jsx (96%) rename traque-front/{components/team => app/team/track/components}/waitingScreen.jsx (97%) delete mode 100644 traque-front/components/admin/mapPicker.jsx delete mode 100644 traque-front/components/admin/placementMap.jsx delete mode 100644 traque-front/components/admin/teamEdit.jsx delete mode 100644 traque-front/components/admin/teamList.jsx rename traque-front/components/{util => }/button.jsx (100%) rename traque-front/components/{admin => }/mapUtils.jsx (100%) rename traque-front/components/{util => }/section.jsx (100%) rename traque-front/components/{util => }/textInput.jsx (100%) diff --git a/traque-front/app/admin/components/buttons.jsx b/traque-front/app/admin/components/buttons.jsx new file mode 100644 index 0000000..4acd5c1 --- /dev/null +++ b/traque-front/app/admin/components/buttons.jsx @@ -0,0 +1,15 @@ +export function MapButton({ icon, title }) { + return ( + + ); +} + +export function ControlButton({ icon, title }) { + return ( + + ); +} diff --git a/traque-front/components/admin/liveMap.jsx b/traque-front/app/admin/components/liveMap.jsx similarity index 98% rename from traque-front/components/admin/liveMap.jsx rename to traque-front/app/admin/components/liveMap.jsx index d85da6d..509d34a 100644 --- a/traque-front/components/admin/liveMap.jsx +++ b/traque-front/app/admin/components/liveMap.jsx @@ -1,10 +1,10 @@ -import useLocation from "@/hook/useLocation"; import { useEffect, useState } from "react"; -import "leaflet/dist/leaflet.css"; import { MapContainer, Marker, TileLayer, Tooltip, Polyline, Polygon } from "react-leaflet"; +import "leaflet/dist/leaflet.css"; +import { MapPan } from "@/components/mapUtils"; +import useLocation from "@/hook/useLocation"; import useAdmin from "@/hook/useAdmin"; import { GameState } from "@/util/gameState"; -import { MapPan } from "./mapUtils"; const DEFAULT_ZOOM = 14; const positionIcon = new L.Icon({ diff --git a/traque-front/components/admin/teamInformation.jsx b/traque-front/app/admin/components/teamSidePanel.jsx similarity index 98% rename from traque-front/components/admin/teamInformation.jsx rename to traque-front/app/admin/components/teamSidePanel.jsx index b0e96c0..9ed4f87 100644 --- a/traque-front/components/admin/teamInformation.jsx +++ b/traque-front/app/admin/components/teamSidePanel.jsx @@ -1,7 +1,7 @@ +import { env } from 'next-runtime-env'; +import { useEffect, useState } from "react"; import useAdmin from "@/hook/useAdmin"; import { GameState } from '@/util/gameState'; -import { useEffect, useState } from "react"; -import { env } from 'next-runtime-env'; function DotLine({ label, value }) { return ( @@ -49,7 +49,7 @@ function getStatus(team, gamestate) { } } -export default function TeamInformation({ selectedTeamId, onClose }) { +export default function TeamSidePanel({ selectedTeamId, onClose }) { const { getTeam, getTeamName, startDate, gameState } = useAdmin(); const [imgSrc, setImgSrc] = useState(""); const team = getTeam(selectedTeamId); diff --git a/traque-front/components/admin/teamViewer.jsx b/traque-front/app/admin/components/teamViewer.jsx similarity index 98% rename from traque-front/components/admin/teamViewer.jsx rename to traque-front/app/admin/components/teamViewer.jsx index 8d4ff3f..7706e18 100644 --- a/traque-front/components/admin/teamViewer.jsx +++ b/traque-front/app/admin/components/teamViewer.jsx @@ -1,6 +1,5 @@ import useAdmin from '@/hook/useAdmin'; import { GameState } from '@/util/gameState'; -import React from 'react'; const TEAM_STATUS = { playing: { label: "En jeu", color: "text-custom-green" }, diff --git a/traque-front/app/admin/layout.js b/traque-front/app/admin/layout.js index cce9e8a..f20789a 100644 --- a/traque-front/app/admin/layout.js +++ b/traque-front/app/admin/layout.js @@ -1,6 +1,5 @@ import { AdminConnexionProvider } from "@/context/adminConnexionContext"; import { AdminProvider } from "@/context/adminContext"; -import Link from "next/link"; export default function AdminLayout({ children }) { return ( diff --git a/traque-front/components/team/loginForm.jsx b/traque-front/app/admin/login/components/loginForm.jsx similarity index 87% rename from traque-front/components/team/loginForm.jsx rename to traque-front/app/admin/login/components/loginForm.jsx index 4556bdc..da40b9e 100644 --- a/traque-front/components/team/loginForm.jsx +++ b/traque-front/app/admin/login/components/loginForm.jsx @@ -1,6 +1,6 @@ import { useState } from "react"; -import { BlueButton } from "../util/button"; -import { TextInput } from "../util/textInput"; +import { BlueButton } from "@/components/button"; +import { TextInput } from "@/components/textInput"; export default function LoginForm({ onSubmit, title, placeholder, buttonText}) { const [value, setValue] = useState(""); diff --git a/traque-front/app/admin/login/page.js b/traque-front/app/admin/login/page.js index 4bfb99f..0b7633c 100644 --- a/traque-front/app/admin/login/page.js +++ b/traque-front/app/admin/login/page.js @@ -1,7 +1,6 @@ "use client"; -import LoginForm from '@/components/team/loginForm' import { useAdminConnexion } from '@/context/adminConnexionContext'; -import React from 'react' +import LoginForm from './components/loginForm'; export default function AdminLoginPage() { const {login, useProtect} = useAdminConnexion(); diff --git a/traque-front/app/admin/page.js b/traque-front/app/admin/page.js index d8adede..63c694b 100644 --- a/traque-front/app/admin/page.js +++ b/traque-front/app/admin/page.js @@ -1,14 +1,15 @@ "use client"; -import { useAdminConnexion } from "@/context/adminConnexionContext"; +import React, { useState } from 'react'; import dynamic from "next/dynamic"; -import TeamList from '@/components/admin/teamViewer'; -import React, { useState } from 'react' import Link from "next/link"; -import { Section } from "@/components/util/section"; -import TeamInformation from "@/components/admin/teamInformation"; +import { Section } from "@/components/section"; +import { useAdminConnexion } from "@/context/adminConnexionContext"; +import TeamSidePanel from "./components/teamSidePanel"; +import TeamList from './components/teamViewer'; +import { MapButton, ControlButton } from './components/buttons'; // Imported at runtime and not at compile time -const LiveMap = dynamic(() => import('@/components/admin/liveMap'), { ssr: false }); +const LiveMap = dynamic(() => import('./components/liveMap'), { ssr: false }); export default function AdminPage() { const { useProtect } = useAdminConnexion(); @@ -33,32 +34,13 @@ export default function AdminPage() {
- - + + - - - - + + + +
@@ -70,46 +52,18 @@ export default function AdminPage() {
- setSelectedTeamId(null)}/> + setSelectedTeamId(null)}/>
- - - - - - - + + + + + + +
) -} \ No newline at end of file +} diff --git a/traque-front/components/admin/circleZoneMap.jsx b/traque-front/app/admin/parameters/components/circleZoneMap.jsx similarity index 74% rename from traque-front/components/admin/circleZoneMap.jsx rename to traque-front/app/admin/parameters/components/circleZoneMap.jsx index bda9760..c9585ee 100644 --- a/traque-front/components/admin/circleZoneMap.jsx +++ b/traque-front/app/admin/parameters/components/circleZoneMap.jsx @@ -1,12 +1,12 @@ import { useEffect, useState } from "react"; -import { BlueButton, GreenButton, RedButton } from "../util/button"; -import { TextInput } from "../util/textInput"; +import { Circle, MapContainer, TileLayer } from "react-leaflet"; +import "leaflet/dist/leaflet.css"; +import { BlueButton, GreenButton, RedButton } from "@/components/button"; +import { TextInput } from "@/components/textInput"; +import { MapPan, MapEventListener } from "@/components/mapUtils"; import useAdmin from "@/hook/useAdmin"; import useLocation from "@/hook/useLocation"; -import "leaflet/dist/leaflet.css"; -import { Circle, MapContainer, TileLayer } from "react-leaflet"; import useMapCircleDraw from "@/hook/useMapCircleDraw"; -import { MapPan, MapEventListener } from "./mapUtils"; const DEFAULT_ZOOM = 14; const EditMode = { @@ -94,25 +94,27 @@ export default function CircleZoneMap() { useEffect(() => { if(editMode == EditMode.MIN) { setEditMode(EditMode.MAX); - }else { + } else { setEditMode(EditMode.MIN); } }, [minZone, maxZone]); - return
-

Edit zones

- {editMode == EditMode.MIN && setEditMode(EditMode.MAX)}>Click to edit first zone} - {editMode == EditMode.MAX && setEditMode(EditMode.MIN)}>Click to edit last zone} - -
-

Number of zones

- setReductionCount(e.target.value)}> + return ( +
+

Edit zones

+ {editMode == EditMode.MIN && setEditMode(EditMode.MAX)}>Click to edit first zone} + {editMode == EditMode.MAX && setEditMode(EditMode.MIN)}>Click to edit last zone} + +
+

Number of zones

+ setReductionCount(e.target.value)}> +
+
+

Duration of a zone

+ setDuration(e.target.value)}> +
+ Apply
-
-

Duration of a zone

- setDuration(e.target.value)}> -
- Apply -
+ ); } diff --git a/traque-front/components/admin/gameSettings.jsx b/traque-front/app/admin/parameters/components/messages.jsx similarity index 81% rename from traque-front/components/admin/gameSettings.jsx rename to traque-front/app/admin/parameters/components/messages.jsx index ee96411..b827565 100644 --- a/traque-front/components/admin/gameSettings.jsx +++ b/traque-front/app/admin/parameters/components/messages.jsx @@ -1,7 +1,6 @@ -import useAdmin from "@/hook/useAdmin"; -import { GreenButton } from "../util/button"; -import { Section } from "../util/section"; import { useEffect, useState } from "react"; +import { Section } from "@/components/section"; +import useAdmin from "@/hook/useAdmin"; function MessageInput({title, ...props}) { return ( @@ -12,7 +11,7 @@ function MessageInput({title, ...props}) { ); } -export default function GameSettings() { +export default function Messages() { const {gameSettings, changeGameSettings} = useAdmin(); const [capturedMessage, setCapturedMessage] = useState(""); const [winnerEndMessage, setWinnerEndMessage] = useState(""); @@ -35,13 +34,10 @@ export default function GameSettings() { return (
- setWaitingMessage(e.target.value)}/> - setCapturedMessage(e.target.value)} /> - setWinnerEndMessage(e.target.value)} /> - setLoserEndMessage(e.target.value)} /> -
- Apply -
+ setWaitingMessage(e.target.value)} onBlur={applySettings}/> + setCapturedMessage(e.target.value)} onBlur={applySettings}/> + setWinnerEndMessage(e.target.value)} onBlur={applySettings}/> + setLoserEndMessage(e.target.value)} onBlur={applySettings}/>
); diff --git a/traque-front/components/admin/polygonZoneMap.jsx b/traque-front/app/admin/parameters/components/polygonZoneMap.jsx similarity index 97% rename from traque-front/components/admin/polygonZoneMap.jsx rename to traque-front/app/admin/parameters/components/polygonZoneMap.jsx index 2a8d9f1..c1b3382 100644 --- a/traque-front/components/admin/polygonZoneMap.jsx +++ b/traque-front/app/admin/parameters/components/polygonZoneMap.jsx @@ -1,12 +1,12 @@ import { useEffect, useState } from "react"; -import { GreenButton } from "../util/button"; -import { TextInput } from "../util/textInput"; +import { MapContainer, TileLayer, Polyline, Polygon, CircleMarker } from "react-leaflet"; +import "leaflet/dist/leaflet.css"; +import { GreenButton } from "@/components/button"; +import { TextInput } from "@/components/textInput"; +import { MapPan, MapEventListener } from "@/components/mapUtils"; import useAdmin from "@/hook/useAdmin"; import useLocation from "@/hook/useLocation"; -import "leaflet/dist/leaflet.css"; -import { MapContainer, TileLayer, Polyline, Polygon, CircleMarker } from "react-leaflet"; import useMapPolygonDraw from "@/hook/useMapPolygonDraw"; -import { MapPan, MapEventListener } from "./mapUtils"; const DEFAULT_ZOOM = 14; diff --git a/traque-front/components/admin/teamManager.jsx b/traque-front/app/admin/parameters/components/teamManager.jsx similarity index 100% rename from traque-front/components/admin/teamManager.jsx rename to traque-front/app/admin/parameters/components/teamManager.jsx index fc0db8b..0c93d9e 100644 --- a/traque-front/components/admin/teamManager.jsx +++ b/traque-front/app/admin/parameters/components/teamManager.jsx @@ -1,6 +1,6 @@ -import useAdmin from '@/hook/useAdmin'; -import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'; import React, { useState } from 'react' +import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'; +import useAdmin from '@/hook/useAdmin'; function reorder(list, startIndex, endIndex) { const result = Array.from(list); diff --git a/traque-front/app/admin/parameters/page.js b/traque-front/app/admin/parameters/page.js index 119bc94..71afbae 100644 --- a/traque-front/app/admin/parameters/page.js +++ b/traque-front/app/admin/parameters/page.js @@ -1,21 +1,19 @@ "use client"; import { useState, useEffect } from "react"; -import GameSettings from "@/components/admin/gameSettings"; -import { useAdminConnexion } from "@/context/adminConnexionContext"; import dynamic from "next/dynamic"; -import TeamList from '@/components/admin/teamManager'; -import useAdmin from '@/hook/useAdmin'; import Link from "next/link"; -import { GreenButton } from "@/components/util/button"; -import { TextInput } from "@/components/util/textInput"; -import { Section } from "@/components/util/section"; +import { TextInput } from "@/components/textInput"; +import { Section } from "@/components/section"; +import { useAdminConnexion } from "@/context/adminConnexionContext"; +import useAdmin from '@/hook/useAdmin'; +import Messages from "./components/messages"; +import TeamList from './components/teamManager'; // Imported at runtime and not at compile time -const ZoneSelector = dynamic(() => import('@/components/admin/polygonZoneMap'), { ssr: false }); +const ZoneSelector = dynamic(() => import('./components/polygonZoneMap'), { ssr: false }); export default function AdminPage() { const {penaltySettings, changePenaltySettings} = useAdmin(); - const { addTeam } = useAdmin(); const { useProtect } = useAdminConnexion(); const [allowedTimeBetweenUpdates, setAllowedTimeBetweenUpdates] = useState(""); @@ -42,19 +40,16 @@ export default function AdminPage() {

Paramètres

- +

Interval between position updates

- setAllowedTimeBetweenUpdates(e.target.value)} /> + setAllowedTimeBetweenUpdates(e.target.value)} onBlur={applySettings} />
-
- Apply -
@@ -63,4 +58,4 @@ export default function AdminPage() { ); -} \ No newline at end of file +} diff --git a/traque-front/app/admin/teams/page.js b/traque-front/app/admin/teams/page.js deleted file mode 100644 index d1deca9..0000000 --- a/traque-front/app/admin/teams/page.js +++ /dev/null @@ -1,28 +0,0 @@ -"use client"; -import TeamAddForm from '@/components/admin/teamAdd'; -import TeamEdit from '@/components/admin/teamEdit'; -import TeamList from '@/components/admin/teamManager'; -import { useAdminConnexion } from '@/context/adminConnexionContext'; -import useAdmin from '@/hook/useAdmin'; -import React, { useState } from 'react' - -export default function TeamAdminPage() { - const [selectedTeamId, setSelectedTeamId] = useState(null); - const { addTeam } = useAdmin(); - const { useProtect } = useAdminConnexion(); - - useProtect(); - - return ( -
-
-

Team list

- - -
-
- {selectedTeamId && } -
-
- ) -} diff --git a/traque-front/app/team/components/loginForm.jsx b/traque-front/app/team/components/loginForm.jsx new file mode 100644 index 0000000..da40b9e --- /dev/null +++ b/traque-front/app/team/components/loginForm.jsx @@ -0,0 +1,19 @@ +import { useState } from "react"; +import { BlueButton } from "@/components/button"; +import { TextInput } from "@/components/textInput"; + +export default function LoginForm({ onSubmit, title, placeholder, buttonText}) { + const [value, setValue] = useState(""); + function handleSubmit(e) { + e.preventDefault(); + setValue(""); + onSubmit(value); + } + return ( +
+

{title}

+ setValue(e.target.value)} name="team-id"/> + {buttonText} + + ) +} diff --git a/traque-front/app/team/page.js b/traque-front/app/team/page.js index f6ab21d..27200d7 100644 --- a/traque-front/app/team/page.js +++ b/traque-front/app/team/page.js @@ -1,6 +1,6 @@ "use client" -import LoginForm from "@/components/team/loginForm"; import { useTeamConnexion } from "@/context/teamConnexionContext"; +import LoginForm from "./components/loginForm"; export default function Home() { const { login,useProtect } = useTeamConnexion(); diff --git a/traque-front/components/team/actionDrawer.jsx b/traque-front/app/team/track/components/actionDrawer.jsx similarity index 97% rename from traque-front/components/team/actionDrawer.jsx rename to traque-front/app/team/track/components/actionDrawer.jsx index 3a17036..9fe90dd 100644 --- a/traque-front/components/team/actionDrawer.jsx +++ b/traque-front/app/team/track/components/actionDrawer.jsx @@ -1,8 +1,8 @@ -import useGame from "@/hook/useGame"; import { useEffect, useState } from "react" -import { BlueButton, GreenButton } from "../util/button"; -import { TextInput } from "../util/textInput"; +import { BlueButton, GreenButton } from "@/components/button"; +import { TextInput } from "@/components/textInput"; import useTeamConnexion from "@/context/teamConnexionContext"; +import useGame from "@/hook/useGame"; import EnemyTeamModal from "./enemyTeamModal"; export default function ActionDrawer() { diff --git a/traque-front/components/team/enemyTeamModal.jsx b/traque-front/app/team/track/components/enemyTeamModal.jsx similarity index 96% rename from traque-front/components/team/enemyTeamModal.jsx rename to traque-front/app/team/track/components/enemyTeamModal.jsx index 7c4c576..b65dd5b 100644 --- a/traque-front/components/team/enemyTeamModal.jsx +++ b/traque-front/app/team/track/components/enemyTeamModal.jsx @@ -1,7 +1,8 @@ -import useGame from "@/hook/useGame"; -import { RedButton } from "../util/button"; 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(); diff --git a/traque-front/components/team/map.jsx b/traque-front/app/team/track/components/map.jsx similarity index 100% rename from traque-front/components/team/map.jsx rename to traque-front/app/team/track/components/map.jsx index cd613b5..6172cfc 100644 --- a/traque-front/components/team/map.jsx +++ b/traque-front/app/team/track/components/map.jsx @@ -3,8 +3,8 @@ import { Circle, MapContainer, Marker, Popup, TileLayer, useMap } from 'react-le import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css' import "leaflet-defaulticon-compatibility"; import "leaflet/dist/leaflet.css"; -import useGame from '@/hook/useGame'; import useTeamContext from '@/context/teamContext'; +import useGame from '@/hook/useGame'; const DEFAULT_ZOOM = 14; diff --git a/traque-front/components/team/notification.jsx b/traque-front/app/team/track/components/notification.jsx similarity index 100% rename from traque-front/components/team/notification.jsx rename to traque-front/app/team/track/components/notification.jsx index c002406..50e0a26 100644 --- a/traque-front/components/team/notification.jsx +++ b/traque-front/app/team/track/components/notification.jsx @@ -1,5 +1,5 @@ -import { useSocketListener } from "@/hook/useSocketListener"; import { useEffect, useState } from "react"; +import { useSocketListener } from "@/hook/useSocketListener"; export default function Notification({ socket }) { const [visible, setVisible] = useState(false); diff --git a/traque-front/components/team/placementOverlay.jsx b/traque-front/app/team/track/components/placementOverlay.jsx similarity index 96% rename from traque-front/components/team/placementOverlay.jsx rename to traque-front/app/team/track/components/placementOverlay.jsx index d0e53ad..07684f4 100644 --- a/traque-front/components/team/placementOverlay.jsx +++ b/traque-front/app/team/track/components/placementOverlay.jsx @@ -1,5 +1,5 @@ import useTeamConnexion from "@/context/teamConnexionContext"; -import useGame from "@/hook/useGame" +import useGame from "@/hook/useGame"; export default function PlacementOverlay() { const { name, ready } = useGame(); diff --git a/traque-front/components/team/waitingScreen.jsx b/traque-front/app/team/track/components/waitingScreen.jsx similarity index 97% rename from traque-front/components/team/waitingScreen.jsx rename to traque-front/app/team/track/components/waitingScreen.jsx index 3062f49..36615bf 100644 --- a/traque-front/components/team/waitingScreen.jsx +++ b/traque-front/app/team/track/components/waitingScreen.jsx @@ -1,8 +1,8 @@ -import useGame from "@/hook/useGame" -import { GreenButton, LogoutButton } from "../util/button"; import { useRef } from "react"; -import useTeamContext from "@/context/teamContext"; 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(); diff --git a/traque-front/app/team/track/page.js b/traque-front/app/team/track/page.js index a54889b..774f1b5 100644 --- a/traque-front/app/team/track/page.js +++ b/traque-front/app/team/track/page.js @@ -1,22 +1,22 @@ "use client"; -import ActionDrawer from '@/components/team/actionDrawer'; -import Notification from '@/components/team/notification'; -import PlacementOverlay from '@/components/team/placementOverlay'; -import WaitingScreen from '@/components/team/waitingScreen'; -import { LogoutButton } from '@/components/util/button'; +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 dynamic from 'next/dynamic'; -import React from 'react' +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/team/map').then((mod) => mod.LiveMap), { +const LiveMap = dynamic(() => import('./components/map').then((mod) => mod.LiveMap), { ssr: false }); -const PlacementMap = dynamic(() => import('@/components/team/map').then((mod) => mod.PlacementMap), { +const PlacementMap = dynamic(() => import('./components/map').then((mod) => mod.PlacementMap), { ssr: false }); diff --git a/traque-front/components/admin/mapPicker.jsx b/traque-front/components/admin/mapPicker.jsx deleted file mode 100644 index 1833362..0000000 --- a/traque-front/components/admin/mapPicker.jsx +++ /dev/null @@ -1,268 +0,0 @@ -"use client"; -import { useLocation } from "@/hook/useLocation"; -import { useEffect, useState, useRef, useCallback } from "react"; -import "leaflet/dist/leaflet.css"; -import { Circle, MapContainer, Marker, TileLayer, useMap, Tooltip, Polyline } from "react-leaflet"; -import { useMapCircleDraw } from "@/hook/mapDrawing"; -import useAdmin from "@/hook/useAdmin"; -import { GameState } from "@/util/gameState"; -import L from "leaflet"; -import { createPortal } from "react-dom"; -import TeamInformation from "@/components/admin/teamInformation"; - - -function MapActionControl({ onClick, children }) { - const map = useMap(); - - useEffect(() => { - const controlDiv = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom'); - controlDiv.style.background = 'rgba(0,0,0,0.25)'; - controlDiv.style.borderRadius = '9999px'; - controlDiv.style.padding = '8px'; - controlDiv.style.border = 'none'; - controlDiv.title = "Plein écran"; - controlDiv.style.display = "flex"; - controlDiv.style.alignItems = "center"; - controlDiv.style.justifyContent = "center"; - controlDiv.style.width = "56px"; - controlDiv.style.height = "56px"; - controlDiv.onclick = onClick; - controlDiv.innerHTML = ``; - const customControl = L.control({ position: 'bottomleft' }); - customControl.onAdd = () => controlDiv; - customControl.addTo(map); - - return () => { - customControl.remove(); - }; - }, [map, onClick, children]); - - return null; -} - -function LeafletSidePanel({ show, onClose, children }) { - const map = useMap(); - const panelRef = useRef(document.createElement("div")); - - useEffect(() => { - const panelDiv = panelRef.current; - panelDiv.className = "leaflet-control leaflet-control-custom"; - - - const control = L.control({ position: "topright" }); - control.onAdd = () => panelDiv; - if (show) control.addTo(map); - - return () => { - control.remove(); - }; - }, [map, show]); - - if (!show) return null; - - return createPortal( - <> - - {children} - , - panelRef.current - ); -} - -const positionIcon = new L.Icon({ - iconUrl: '/icons/location.png', - iconSize: [30, 30], - iconAnchor: [15, 15], - popupAnchor: [0, -15], - shadowSize: [30, 30], -}); - -function MapPan(props) { - const map = useMap(); - const [initialized, setInitialized] = useState(false); - - useEffect(() => { - if (!initialized && props.center) { - map.flyTo(props.center, props.zoom, { animate: false }); - setInitialized(true) - } - }, [props.center]); - return null; -} - -function MapEventListener({ onClick, onMouseMove }) { - const map = useMap(); - useEffect(() => { - map.on('click', onClick); - return () => { - map.off('click', onClick); - } - }, [onClick]); - useEffect(() => { - map.on('mousemove', onMouseMove); - return () => { - map.off('mousemove', onMouseMove); - } - }); - return null; -} - -const DEFAULT_ZOOM = 14; -export function CircularAreaPicker({ area, setArea, markerPosition, ...props }) { - const location = useLocation(Infinity); - const { handleClick, handleMouseMove, center, radius } = useMapCircleDraw(area, setArea); - return ( - - - {center && radius && } - {markerPosition && - } - - - ) -} -export const EditMode = { - MIN: 0, - MAX: 1 -} -export function ZonePicker({ minZone, setMinZone, maxZone, setMaxZone, editMode, ...props }) { - const location = useLocation(Infinity); - const { handleClick: maxClick, handleMouseMove: maxHover, center: maxCenter, radius: maxRadius } = useMapCircleDraw(minZone, setMinZone); - const { handleClick: minClick, handleMouseMove: minHover, center: minCenter, radius: minRadius } = useMapCircleDraw(maxZone, setMaxZone); - function handleClick(e) { - if (editMode == EditMode.MAX) { - maxClick(e); - } else { - minClick(e); - } - } - function handleMouseMove(e) { - if (editMode == EditMode.MAX) { - maxHover(e); - } else { - minHover(e); - } - } - - return ( -
-
- - - {minCenter && minRadius && } - {maxCenter && maxRadius && } - - - -
- { maxCenter && minCenter && typeof maxCenter.distanceTo === 'function' - && maxRadius + maxCenter.distanceTo(minCenter) >= minRadius - &&

La zone de fin doit être incluse dans celle de départ

} -
- - ) -} - -export function LiveMap({ selectedTeamId, setSelectedTeamId }) { - const location = useLocation(Infinity); - const [timeLeftNextZone, setTimeLeftNextZone] = useState(null); - const { zone, zoneExtremities, teams, nextZoneDate, isShrinking , getTeam, gameState } = useAdmin(); - - function handleMarkerClick(teamId) { - setSelectedTeamId(teamId); - } - - const mapWrapperRef = useRef(null); - - const handleFullscreen = useCallback(() => { - const el = mapWrapperRef.current; - if (!el) return; - if (!document.fullscreenElement) { - el.requestFullscreen(); - } else { - document.exitFullscreen(); - } - }, []); - - // Remaining time before sending position - useEffect(() => { - const updateTime = () => { - setTimeLeftNextZone(Math.max(0, Math.floor((nextZoneDate - Date.now()) / 1000))); - }; - - updateTime(); - const interval = setInterval(updateTime, 1000); - - return () => clearInterval(interval); - }, [nextZoneDate]); - - function formatTime(time) { - // time is in seconds - if (time < 0) return "00:00"; - const minutes = Math.floor(time / 60); - const seconds = Math.floor(time % 60); - return String(minutes).padStart(2,"0") + ":" + String(seconds).padStart(2,"0"); - } - - function Arrow({pos1, pos2}) { - if (pos1 && pos2) { - return ( - - ) - } else { - return null; - } - } - - return ( -
- {gameState == GameState.PLAYING &&

{`${isShrinking ? "Fin" : "Début"} du rétrécissement de la zone dans : ${formatTime(timeLeftNextZone)}`}

} - - - - {gameState == GameState.PLAYING && zone && } - {gameState == GameState.PLAYING && zoneExtremities && } - {gameState == GameState.PLAYING && zoneExtremities && } - {teams.map((team) => team.currentLocation && !team.captured && - - {team.name} - - - )} - - {selectedTeamId && ( - setSelectedTeamId(null)}> - setSelectedTeamId(null)} - /> - - )} - -
- ) -} \ No newline at end of file diff --git a/traque-front/components/admin/placementMap.jsx b/traque-front/components/admin/placementMap.jsx deleted file mode 100644 index 1b52772..0000000 --- a/traque-front/components/admin/placementMap.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import useLocation from "@/hook/useLocation"; -import "leaflet/dist/leaflet.css"; -import { Circle, MapContainer, Marker, TileLayer } from "react-leaflet"; -import useMapCircleDraw from "@/hook/useMapCircleDraw"; -import { MapPan, MapEventListener } from "./mapUtils"; - -const DEFAULT_ZOOM = 14; -const positionIcon = new L.Icon({ - iconUrl: '/icons/location.png', - iconSize: [30, 30], - iconAnchor: [15, 15], - popupAnchor: [0, -15], - shadowSize: [30, 30], -}); - -export default function CircularAreaPicker({ area, setArea, markerPosition, ...props }) { - const location = useLocation(Infinity); - const { center, radius, handleLeftClick, handleRightClick, handleMouseMove } = useMapCircleDraw(area, setArea); - - return ( - - - {center && radius && } - {markerPosition && } - - - - ); -} diff --git a/traque-front/components/admin/teamEdit.jsx b/traque-front/components/admin/teamEdit.jsx deleted file mode 100644 index a32eeb8..0000000 --- a/traque-front/components/admin/teamEdit.jsx +++ /dev/null @@ -1,122 +0,0 @@ -import React, { useEffect, useRef, useState } from 'react' -import { TextInput } from '../util/textInput' -import { BlueButton, RedButton } from '../util/button'; -import useAdmin from '@/hook/useAdmin'; -import dynamic from 'next/dynamic'; -import { env } from 'next-runtime-env'; -import { GameState } from '@/util/gameState'; - -// Imported at runtime and not at compile time -const PlacementMap = dynamic(() => import('./placementMap'), { ssr: false }); - -export default function TeamEdit({ selectedTeamId, setSelectedTeamId }) { - const teamImage = useRef(null); - const [avgSpeed, setAvgSpeed] = useState(0); // Speed in m/s - const [newTeamName, setNewTeamName] = React.useState(''); - const { updateTeam, getTeamName, removeTeam, getTeam, teams, gameState, startDate } = useAdmin(); - const [team, setTeam] = useState({}); - - const NEXT_PUBLIC_SOCKET_HOST = env("NEXT_PUBLIC_SOCKET_HOST"); - const SERVER_URL = (NEXT_PUBLIC_SOCKET_HOST == "localhost" ? "http://" : "https://") + NEXT_PUBLIC_SOCKET_HOST + "/back"; - - useEffect(() => { - let team = getTeam(selectedTeamId); - if (team != undefined) { - setNewTeamName(team.name); - setTeam(team); - } - teamImage.current.src = SERVER_URL + "/photo/my?team=" + selectedTeamId + "&t=" + new Date().getTime(); - }, [selectedTeamId, teams]) - - // Update the average speed - useEffect(() => { - const time = Math.floor((team.finishDate ? team.finishDate - startDate : Date.now() - startDate) / 1000); - setAvgSpeed(team.distance/time); - }, [team.distance, team.finishDate]); - - function handleRename(e) { - e.preventDefault(); - updateTeam(team.id, { name: newTeamName }); - } - - function handleRemove() { - removeTeam(team.id); - setSelectedTeamId(null); - } - - function handleAddPenalty(increment) { - let newPenalties = team.penalties + increment; - newPenalties = Math.max(0, newPenalties); - newPenalties = Math.min(3, newPenalties); - updateTeam(team.id, { penalties: newPenalties }); - } - - function formatTimeHours(time) { - // time is in seconds - if (!Number.isInteger(time)) return "Inconnue"; - if (time < 0) time = 0; - const hours = Math.floor(time / 3600); - const minutes = Math.floor(time / 60); - const seconds = Math.floor(time % 60); - return String(hours).padStart(2,"0") + ":" + String(minutes).padStart(2,"0") + ":" + String(seconds).padStart(2,"0"); - } - - return (team && -
-
-

Actions

-
-
- setNewTeamName(e.target.value)} /> -
-
- Rename -
-
-
- {updateTeam(team.id, { captured: !team.captured }); team.finishDate = Date.now()}}>{team.captured ? "Revive" : "Capture"} - Remove -
-

Starting zone

- updateTeam(team.id, { startingArea })} markerPosition={team?.currentLocation} /> -
-
-

Team details

-
- {e.target.src = "/images/missing_image.jpg"}} /> -
-
-
-

Secret : {String(team.id).padStart(6, '0').replace(/(\d{3})(\d{3})/, '$1 $2')}

-

Capture code : {String(team.captureCode).padStart(4, '0')}

-
-
-

Chasing : {getTeamName(team.chasing)}

-

Chased by : {getTeamName(team.chased)}

-
- {gameState == GameState.PLAYING && -
-

Distance: { (team.distance / 1000).toFixed(1) }km

-

Time : {formatTimeHours(Math.floor((team.finishDate ? team.finishDate - startDate : Date.now() - startDate) / 1000))}

-

Average speed : {(avgSpeed*3.6).toFixed(1)}km/h

-

Captures : {team.nCaptures}

-

Sent location : {team.nSentLocation}

-

Oberved : {team.nObserved}

-
- } -
-

Phone model : {team.phoneModel ?? "Unknown"}

-

Phone name : {team.phoneName ?? "Unknown"}

-

Battery: {team.battery ? team.battery + "%" : "Unknown"}

-
-
-

Penalties :

- -

{team.penalties}

- -
-
-
-
- ); -} diff --git a/traque-front/components/admin/teamList.jsx b/traque-front/components/admin/teamList.jsx deleted file mode 100644 index ea796ef..0000000 --- a/traque-front/components/admin/teamList.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import useAdmin from '@/hook/useAdmin'; -import { GameState } from '@/util/gameState'; -import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'; -import React from 'react' - -function reorder(list, startIndex, endIndex) { - const result = Array.from(list); - const [removed] = result.splice(startIndex, 1); - result.splice(endIndex, 0, removed); - return result; -}; - -const TEAM_STATUS = { - playing: { label: "En jeu", color: "text-custom-green" }, - captured: { label: "Capturée", color: "text-custom-red" }, - outofzone: { label: "Hors zone", color: "text-custom-orange" }, - ready: { label: "Prête", color: "text-custom-blue" }, - notready: { label: "En préparation", color: "text-custom-grey" }, -}; - -function TeamListItem({ team, index, onSelected, itemSelected, gamestate }) { - console.log(gamestate === GameState.PLAYING ? "En jeu" : "En préparation"); - const status = gamestate === GameState.PLAYING ? (team.captured ? TEAM_STATUS.captured : (team.outofzone ? TEAM_STATUS.outofzone : TEAM_STATUS.playing)) : (team.ready ? TEAM_STATUS.ready : TEAM_STATUS.notready); - return ( - onSelected(team.id)}> - {provided => ( -
-
- - - - -
-
-

{team.name}

-

- {status.label} -

-
-
- - )} -
- ); -} - -export default function TeamList({selectedTeamId, onSelected}) { - const {teams, reorderTeams, gameState} = useAdmin(); - function onDragEnd(result) { - if (!result.destination) return; - if (result.destination.index === result.source.index) return; - const newTeams = reorder(teams, result.source.index, result.destination.index); - reorderTeams(newTeams); - } - - return ( - - - {provided => ( -
    - {teams.map((team, i) => ( -
  • onSelected(team.id)}> - -
  • - ))} - {provided.placeholder} -
- )} -
-
- ); -} diff --git a/traque-front/components/util/button.jsx b/traque-front/components/button.jsx similarity index 100% rename from traque-front/components/util/button.jsx rename to traque-front/components/button.jsx diff --git a/traque-front/components/admin/mapUtils.jsx b/traque-front/components/mapUtils.jsx similarity index 100% rename from traque-front/components/admin/mapUtils.jsx rename to traque-front/components/mapUtils.jsx index c1f001a..9a1c0d7 100644 --- a/traque-front/components/admin/mapUtils.jsx +++ b/traque-front/components/mapUtils.jsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; -import "leaflet/dist/leaflet.css"; import { useMap } from "react-leaflet"; +import "leaflet/dist/leaflet.css"; export function MapPan(props) { const map = useMap(); diff --git a/traque-front/components/util/section.jsx b/traque-front/components/section.jsx similarity index 100% rename from traque-front/components/util/section.jsx rename to traque-front/components/section.jsx diff --git a/traque-front/components/util/textInput.jsx b/traque-front/components/textInput.jsx similarity index 100% rename from traque-front/components/util/textInput.jsx rename to traque-front/components/textInput.jsx