Improved zone selection

This commit is contained in:
Sebastien Riviere
2025-08-10 18:18:25 +02:00
parent 2f5116b88a
commit 623d1c05bf
4 changed files with 75 additions and 36 deletions

View File

@@ -168,7 +168,9 @@ export default {
isRunning: false, isRunning: false,
zones: [], // A zone has to be connected space that doesn't contain an earth pole zones: [], // A zone has to be connected space that doesn't contain an earth pole
currentZone: { id: 0, timeoutId: null, endDate: null }, currentZone: { id: 0, timeoutId: null, endDate: null },
zoneType: "polygon",
settings: defaultPolygonSettings, settings: defaultPolygonSettings,
settingsToZones: polygonSettingsToZones,
start() { start() {
this.isRunning = true; this.isRunning = true;
@@ -213,7 +215,7 @@ export default {
}, },
changeSettings(settings) { changeSettings(settings) {
const zones = polygonSettingsToZones(settings); const zones = this.settingsToZones(settings);
if (!zones) return false; if (!zones) return false;
this.zones = zones; this.zones = zones;
this.settings = settings; this.settings = settings;
@@ -221,6 +223,19 @@ export default {
return true; return true;
}, },
changeZoneType(type) {
if (this.zoneType == type) return;
if (type == "circle") {
this.zoneType = "circle";
this.settings = defaultCircleSettings;
this.settingsToZones = circleSettingsToZones;
} else if (type == "polygon") {
this.zoneType = "polygon";
this.settings = defaultPolygonSettings;
this.settingsToZones = polygonSettingsToZones;
}
},
zoneBroadcast() { zoneBroadcast() {
const zone = { const zone = {
begin: this.getCurrentZone(), begin: this.getCurrentZone(),

View File

@@ -1,6 +1,5 @@
"use client"; "use client";
import GameSettings from "@/components/admin/gameSettings"; import GameSettings from "@/components/admin/gameSettings";
import PenaltySettings from "@/components/admin/penaltySettings";
import { useAdminConnexion } from "@/context/adminConnexionContext"; import { useAdminConnexion } from "@/context/adminConnexionContext";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
@@ -13,12 +12,13 @@ export default function AdminPage() {
useProtect(); useProtect();
return ( return (
<div className='min-h-full bg-gray-200 p-10 flex flex-row content-start gap-5'> <div className='h-full bg-gray-200 p-10 flex flex-row gap-5'>
<div className="h-full w-2/6"> <div className="h-full w-2/6">
<GameSettings /> <GameSettings />
</div> </div>
<div className="h-full w-full">
<ZoneSelector /> <ZoneSelector />
<PenaltySettings /> </div>
</div> </div>
); );
} }

View File

@@ -24,25 +24,27 @@ export default function GameSettings() {
} }
return ( return (
<div className='w-full h-full gap-1 bg-white p-10 flex flex-col text-center shadow-2xl overflow-y-scroll'> <div className='w-full h-full gap-5 bg-white p-10 flex flex-col text-center shadow-2xl overflow-y-scroll'>
<h2 className="text-2xl">Other settings</h2> <h2 className="text-2xl">Messages</h2>
<div> <div className='w-full gap-1 flex flex-col text-center'>
<p>Waiting message</p> <p>Game setup</p>
<TextArea value={waitingMessage} onChange={(e) => setWaitingMessage(e.target.value)} /> <TextArea style={{height: 60}} value={waitingMessage} onChange={(e) => setWaitingMessage(e.target.value)} />
</div>
<div className='w-full gap-1 flex flex-col text-center'>
<p>Team captured</p>
<TextArea style={{height: 60}} value={capturedMessage} onChange={(e) => setCapturedMessage(e.target.value)} />
</div>
<div className='w-full gap-1 flex flex-col text-center'>
<p>Game finished (winner)</p>
<TextArea style={{height: 60}} value={winnerEndMessage} onChange={(e) => setWinnerEndMessage(e.target.value)} />
</div>
<div className='w-full gap-1 flex flex-col text-center'>
<p>Game finished (loser)</p>
<TextArea style={{height: 60}} value={loserEndMessage} onChange={(e) => setLoserEndMessage(e.target.value)} />
</div> </div>
<div> <div>
<p>Captured message</p>
<TextArea value={capturedMessage} onChange={(e) => setCapturedMessage(e.target.value)} />
</div>
<div>
<p>Game finished message (winner)</p>
<TextArea value={winnerEndMessage} onChange={(e) => setWinnerEndMessage(e.target.value)} />
</div>
<div>
<p>Game finished message (loser)</p>
<TextArea value={loserEndMessage} onChange={(e) => setLoserEndMessage(e.target.value)} />
</div>
<GreenButton onClick={applySettings}>Apply</GreenButton> <GreenButton onClick={applySettings}>Apply</GreenButton>
</div> </div>
</div>
) )
} }

View File

@@ -69,7 +69,7 @@ function PolygonZonePicker({ polygons, addPolygon, removePolygon, ...props }) {
const location = useLocation(Infinity); const location = useLocation(Infinity);
return ( return (
<div className='h-96'> <div className='h-full'>
<MapContainer {...props} className='min-h-full w-full' center={location} zoom={DEFAULT_ZOOM} scrollWheelZoom={true}> <MapContainer {...props} className='min-h-full w-full' center={location} zoom={DEFAULT_ZOOM} scrollWheelZoom={true}>
<TileLayer <TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
@@ -87,13 +87,18 @@ export default function PolygonZoneMap() {
const [polygons, setPolygons] = useState([]); const [polygons, setPolygons] = useState([]);
const [durations, setDurations] = useState([]); const [durations, setDurations] = useState([]);
const {zoneSettings, changeZoneSettings} = useAdmin(); const {zoneSettings, changeZoneSettings} = useAdmin();
const {penaltySettings, changePenaltySettings} = useAdmin();
const [allowedTimeOutOfZone, setAllowedTimeOutOfZone] = useState("");
useEffect(() => { useEffect(() => {
if (zoneSettings) { if (zoneSettings) {
setPolygons(zoneSettings.polygons); setPolygons(zoneSettings.polygons);
setDurations(zoneSettings.durations); setDurations(zoneSettings.durations);
} }
}, [zoneSettings]); if (penaltySettings) {
setAllowedTimeOutOfZone(penaltySettings.allowedTimeOutOfZone.toString());
}
}, [zoneSettings, penaltySettings]);
function addPolygon(polygon) { function addPolygon(polygon) {
// Polygons // Polygons
@@ -122,21 +127,38 @@ export default function PolygonZoneMap() {
function handleSettingsSubmit() { function handleSettingsSubmit() {
const newSettings = {polygons: polygons, durations: durations}; const newSettings = {polygons: polygons, durations: durations};
changeZoneSettings(newSettings); changeZoneSettings(newSettings);
changePenaltySettings({allowedTimeOutOfZone: Number(allowedTimeOutOfZone)});
} }
return ( return (
<div className='w-2/5 h-full gap-1 bg-white p-10 flex flex-col text-center shadow-2xl overflow-y-scroll'> <div className='h-full w-full bg-white p-5 gap-5 flex flex-row shadow-2xl'>
<h2 className="text-2xl">Edit zones</h2> <div className="h-full w-full">
<PolygonZonePicker polygons={polygons} addPolygon={addPolygon} removePolygon={removePolygon} /> <PolygonZonePicker polygons={polygons} addPolygon={addPolygon} removePolygon={removePolygon} />
<ul> </div>
<div className="h-full w-1/6 flex flex-col gap-5">
<div className="w-full text-center">
<h2 className="text-xl">Reduction order</h2>
</div>
<ul className="w-full h-full bg-gray-300">
{durations.map((duration, i) => ( {durations.map((duration, i) => (
<li key={i}> <li key={i} className="w-full bg-white flex flex-row gap-2 items-center justify-between p-1">
<p>Zone {i+1}</p> <p>Zone {i+1}</p>
<div className="w-16 h-10">
<TextInput value={duration} onChange={(e) => updateDuration(i, e.target.value)}/> <TextInput value={duration} onChange={(e) => updateDuration(i, e.target.value)}/>
</div>
</li> </li>
))} ))}
</ul> </ul>
<div className="w-full flex flex-row gap-2 items-center justify-between">
<p>Timeout</p>
<div className="w-16 h-10">
<TextInput value={allowedTimeOutOfZone} onChange={(e) => setAllowedTimeOutOfZone(e.target.value)} />
</div>
</div>
<div className="w-full h-15">
<GreenButton onClick={handleSettingsSubmit}>Apply</GreenButton> <GreenButton onClick={handleSettingsSubmit}>Apply</GreenButton>
</div> </div>
</div>
</div>
); );
} }