mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-02-27 17:20:17 +01:00
Fixs
This commit is contained in:
@@ -11,9 +11,9 @@ Problèmes
|
|||||||
[ ] Une équipe perdait sans arrêt la connection avec le serveur
|
[ ] Une équipe perdait sans arrêt la connection avec le serveur
|
||||||
[ ] La position en arrière plan, téléphone éteint par exemple, n'avait pas l'air de fonctionner (une équipe n'avait pas de notif)
|
[ ] La position en arrière plan, téléphone éteint par exemple, n'avait pas l'air de fonctionner (une équipe n'avait pas de notif)
|
||||||
[ ] La photo d'une des équipes ne parvenait pas jusqu'au serveur. Tout semblait normal pour l'équipe.
|
[ ] La photo d'une des équipes ne parvenait pas jusqu'au serveur. Tout semblait normal pour l'équipe.
|
||||||
[ ] Le focus sur une équipe dans la page principale des admins est à revoir. Par exemple, le zoom seul devrait désactiver le focus
|
[x] Le focus sur une équipe dans la page principale des admins est à revoir. Par exemple, le zoom seul devrait désactiver le focus
|
||||||
automatique.
|
automatique.
|
||||||
[ ] Il est pas évident de voir qu'elles équipes sont encore en jeu sur la page principale admin. Notamment, on voudrait que les
|
[x] Il est pas évident de voir qu'elles équipes sont encore en jeu sur la page principale admin. Notamment, on voudrait que les
|
||||||
voyants des équipes encore en jeu soit mis en avant.
|
voyants des équipes encore en jeu soit mis en avant.
|
||||||
[x] La visibilité des éléments de la map en calque satellite est mauvaise. Il faut revoir les couleurs.
|
[x] La visibilité des éléments de la map en calque satellite est mauvaise. Il faut revoir les couleurs.
|
||||||
[ ] Les zones polygonales s'affichent mal sur la version prod de l'app mobile. Les anciennes n'ont pas l'air de disparaitre.
|
[ ] Les zones polygonales s'affichent mal sur la version prod de l'app mobile. Les anciennes n'ont pas l'air de disparaitre.
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ qu'un seul téléphone connecté.
|
|||||||
[ ] La photo d'une des équipes ne parvenait pas jusqu'au serveur. Tout semblait normal pour l'équipe.
|
[ ] La photo d'une des équipes ne parvenait pas jusqu'au serveur. Tout semblait normal pour l'équipe.
|
||||||
[ ] Il y a apparement eu un problème de synchronisation de l'affichage entre admin concernant les zones de départs. Il s'est résolu
|
[ ] Il y a apparement eu un problème de synchronisation de l'affichage entre admin concernant les zones de départs. Il s'est résolu
|
||||||
de lui même. Peut être un problème passager de connection.
|
de lui même. Peut être un problème passager de connection.
|
||||||
[ ] Le focus sur une équipe dans la page principale des admins est à revoir. Par exemple, le zoom seul devrait désactiver le focus
|
[x] Le focus sur une équipe dans la page principale des admins est à revoir. Par exemple, le zoom seul devrait désactiver le focus
|
||||||
automatique.
|
automatique.
|
||||||
[ ] Il est pas évident de voir qu'elles équipes sont encore en jeu sur la page principale admin. Notamment, on voudrait que les
|
[x] Il est pas évident de voir qu'elles équipes sont encore en jeu sur la page principale admin. Notamment, on voudrait que les
|
||||||
voyants des équipes encore en jeu soit mis en avant.
|
voyants des équipes encore en jeu soit mis en avant.
|
||||||
[x] La visibilité des éléments de la map en calque satellite est mauvaise. Il faut revoir les couleurs.
|
[x] La visibilité des éléments de la map en calque satellite est mauvaise. Il faut revoir les couleurs.
|
||||||
[ ] Les zones polygonales s'affichent mal sur la version prod de l'app mobile. Les anciennes n'ont pas l'air de disparaitre.
|
[ ] Les zones polygonales s'affichent mal sur la version prod de l'app mobile. Les anciennes n'ont pas l'air de disparaitre.
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
"android": {
|
"android": {
|
||||||
"package": "com.anonymous.traqueapp",
|
"package": "net.rezel.traque",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"ACCESS_FINE_LOCATION",
|
"ACCESS_FINE_LOCATION",
|
||||||
"ACCESS_COARSE_LOCATION",
|
"ACCESS_COARSE_LOCATION",
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ios": {
|
"ios": {
|
||||||
"bundleIdentifier": "com.anonymous.traqueapp",
|
"bundleIdentifier": "net.rezel.traque",
|
||||||
"infoPlist": {
|
"infoPlist": {
|
||||||
"UIBackgroundModes": [
|
"UIBackgroundModes": [
|
||||||
"location"
|
"location"
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ export default function Display() {
|
|||||||
if (!Number.isInteger(time)) return "Inconnue";
|
if (!Number.isInteger(time)) return "Inconnue";
|
||||||
if (time < 0) time = 0;
|
if (time < 0) time = 0;
|
||||||
const hours = Math.floor(time / 3600);
|
const hours = Math.floor(time / 3600);
|
||||||
const minutes = Math.floor(time / 60);
|
const minutes = Math.floor(time / 60 % 60);
|
||||||
const seconds = 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 String(hours).padStart(2,"0") + ":" + String(minutes).padStart(2,"0") + ":" + String(seconds).padStart(2,"0");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { createContext, useContext, useMemo } from "react";
|
import { createContext, useContext, useMemo } from "react";
|
||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
import { URLS } from "../util/urls"
|
|
||||||
|
|
||||||
const SOCKET_URL = `wss://${URLS.HOST}/player`;
|
const SOCKET_URL = `ws://172.16.1.180/player`;
|
||||||
const SERVER_URL = `https://${URLS.HOST}/back`;
|
const SERVER_URL = `http://172.16.1.180/back`;
|
||||||
|
|
||||||
export const teamSocket = io(SOCKET_URL, {
|
export const teamSocket = io(SOCKET_URL, {
|
||||||
path: "/back/socket.io",
|
path: "/back/socket.io",
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
export const URLS = {
|
|
||||||
HOST: 'traque.rezel.net'
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsF
|
|||||||
const [timeLeftNextZone, setTimeLeftNextZone] = useState(null);
|
const [timeLeftNextZone, setTimeLeftNextZone] = useState(null);
|
||||||
const [isFullScreen, setIsFullScreen] = useState(false);
|
const [isFullScreen, setIsFullScreen] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (nextZoneDate) {
|
if (nextZoneDate) {
|
||||||
const updateTime = () => {
|
const updateTime = () => {
|
||||||
@@ -38,13 +37,13 @@ export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsF
|
|||||||
switch (zoneType) {
|
switch (zoneType) {
|
||||||
case ZoneTypes.CIRCLE:
|
case ZoneTypes.CIRCLE:
|
||||||
return (<>
|
return (<>
|
||||||
<CircleZone circle={zoneExtremities.begin} color="red" />
|
<CircleZone circle={zoneExtremities.begin} color={mapStyle.currentZoneColor} />
|
||||||
<CircleZone circle={zoneExtremities.end} color="green" />
|
<CircleZone circle={zoneExtremities.end} color={mapStyle.nextZoneColor} />
|
||||||
</>);
|
</>);
|
||||||
case ZoneTypes.POLYGON:
|
case ZoneTypes.POLYGON:
|
||||||
return (<>
|
return (<>
|
||||||
<PolygonZone polygon={zoneExtremities.begin?.polygon} color="red" />
|
<PolygonZone polygon={zoneExtremities.begin?.polygon} color={mapStyle.currentZoneColor} />
|
||||||
<PolygonZone polygon={zoneExtremities.end?.polygon} color="green" />
|
<PolygonZone polygon={zoneExtremities.end?.polygon} color={mapStyle.nextZoneColor} />
|
||||||
</>);
|
</>);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@@ -55,14 +54,14 @@ export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsF
|
|||||||
<div className={`${isFullScreen ? "fixed inset-0 z-[9999]" : "relative h-full w-full"}`}>
|
<div className={`${isFullScreen ? "fixed inset-0 z-[9999]" : "relative h-full w-full"}`}>
|
||||||
<CustomMapContainer mapStyle={mapStyle}>
|
<CustomMapContainer mapStyle={mapStyle}>
|
||||||
{isFocusing && <MapPan center={getTeam(selectedTeamId)?.currentLocation} zoom={mapZooms.high} animate />}
|
{isFocusing && <MapPan center={getTeam(selectedTeamId)?.currentLocation} zoom={mapZooms.high} animate />}
|
||||||
<MapEventListener onDragStart={() => setIsFocusing(false)}/>
|
<MapEventListener onDragStart={() => setIsFocusing(false)} onWheel={() => setIsFocusing(false)} />
|
||||||
<Zones/>
|
<Zones/>
|
||||||
{teams.map((team) => team && <Fragment key={team.id}>
|
{teams.map((team) => team && <Fragment key={team.id}>
|
||||||
<CircleZone circle={team.startingArea} color="blue" display={gameState == GameState.PLACEMENT && showZones}>
|
<CircleZone circle={team.startingArea} color={mapStyle.placementZoneColor} display={gameState == GameState.PLACEMENT && showZones}>
|
||||||
<Tag text={team.name} display={showNames} />
|
<Tag text={team.name} display={showNames} />
|
||||||
</CircleZone>
|
</CircleZone>
|
||||||
<Arrow pos1={team.currentLocation} pos2={getTeam(team.chasing)?.currentLocation} display={showArrows}/>
|
<Arrow pos1={team.currentLocation} pos2={getTeam(team.chasing)?.currentLocation} color={mapStyle.arrowColor} display={showArrows}/>
|
||||||
<Position position={team.currentLocation} color={"blue"} onClick={() => onSelected(team.id)} display={!team.captured}>
|
<Position position={team.currentLocation} color={mapStyle.playerColor} onClick={() => onSelected(team.id)} display={!team.captured}>
|
||||||
<Tag text={team.name} display={showNames} />
|
<Tag text={team.name} display={showNames} />
|
||||||
</Position>
|
</Position>
|
||||||
</Fragment>)}
|
</Fragment>)}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { List } from '@/components/list';
|
import { List } from '@/components/list';
|
||||||
import useAdmin from '@/hook/useAdmin';
|
import useAdmin from '@/hook/useAdmin';
|
||||||
import { getStatus } from '@/util/functions';
|
import { getStatus } from '@/util/functions';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
function TeamViewerItem({ team }) {
|
function TeamViewerItem({ team }) {
|
||||||
const { gameState } = useAdmin();
|
const { gameState } = useAdmin();
|
||||||
@@ -8,7 +9,7 @@ function TeamViewerItem({ team }) {
|
|||||||
const NO_VALUE = "XX";
|
const NO_VALUE = "XX";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'w-full flex flex-row gap-3 p-2 bg-white justify-between'}>
|
<div className={`w-full flex flex-row gap-3 p-2 ${team.captured ? 'bg-gray-200' : 'bg-white'} justify-between`}>
|
||||||
<div className='flex flex-row items-center gap-3'>
|
<div className='flex flex-row items-center gap-3'>
|
||||||
<div className='flex flex-row gap-1'>
|
<div className='flex flex-row gap-1'>
|
||||||
<img src={`/icons/user/${team.sockets.length > 0 ? "green" : "red"}.png`} className="w-4 h-4" />
|
<img src={`/icons/user/${team.sockets.length > 0 ? "green" : "red"}.png`} className="w-4 h-4" />
|
||||||
@@ -27,8 +28,16 @@ function TeamViewerItem({ team }) {
|
|||||||
export default function TeamViewer({selectedTeamId, onSelected}) {
|
export default function TeamViewer({selectedTeamId, onSelected}) {
|
||||||
const { teams } = useAdmin();
|
const { teams } = useAdmin();
|
||||||
|
|
||||||
|
// Uncaptured teams first
|
||||||
|
const sortedTeams = useMemo(() => {
|
||||||
|
return [...teams].sort((a,b) => {
|
||||||
|
if (a.captured === b.captured) return 0;
|
||||||
|
return a.captured ? 1 : -1;
|
||||||
|
});
|
||||||
|
}, [teams]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List array={teams} selectedId={selectedTeamId} onSelected={onSelected} >
|
<List array={sortedTeams} selectedId={selectedTeamId} onSelected={onSelected} >
|
||||||
{(team) => (
|
{(team) => (
|
||||||
<TeamViewerItem team={team}/>
|
<TeamViewerItem team={team}/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ import { Marker, Tooltip, CircleMarker, Circle, Polygon, useMap } from "react-le
|
|||||||
import "leaflet/dist/leaflet.css";
|
import "leaflet/dist/leaflet.css";
|
||||||
import 'leaflet-polylinedecorator';
|
import 'leaflet-polylinedecorator';
|
||||||
|
|
||||||
export function Node({position, nodeSize = 5, color = 'black', display = true}) {
|
export function Node({position, color = 'black', display = true}) {
|
||||||
|
const nodeSize = 5;
|
||||||
|
const fillOpacity = 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
display && position && <CircleMarker center={position} radius={nodeSize} pathOptions={{ color: color, fillColor: color, fillOpacity: 1 }} />
|
display && position && <CircleMarker center={position} radius={nodeSize} pathOptions={{ color: color, fillColor: color, fillOpacity: fillOpacity }} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Label({position, label, color, size = 24, display = true}) {
|
export function Label({position, label = "", color = "black", display = true}) {
|
||||||
|
const size = 24;
|
||||||
|
|
||||||
const labelIcon = L.divIcon({
|
const labelIcon = L.divIcon({
|
||||||
html: `<div style="
|
html: `<div style="
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -18,7 +23,7 @@ export function Label({position, label, color, size = 24, display = true}) {
|
|||||||
color: ${color};
|
color: ${color};
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: ${size}px;
|
font-size: ${size}px;
|
||||||
">${label || ""}</div>`,
|
">${label}</div>`,
|
||||||
className: 'custom-label-icon',
|
className: 'custom-label-icon',
|
||||||
iconSize: [size, size],
|
iconSize: [size, size],
|
||||||
iconAnchor: [size / 2, size / 2]
|
iconAnchor: [size / 2, size / 2]
|
||||||
@@ -29,13 +34,19 @@ export function Label({position, label, color, size = 24, display = true}) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Tag({text, display = true}) {
|
export function Tag({text = "", display = true}) {
|
||||||
|
const offset = [0.5, -15];
|
||||||
|
const opacity = 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
display && <Tooltip permanent direction="top" offset={[0.5, -15]} className="custom-tooltip">{text || ""}</Tooltip>
|
display && <Tooltip permanent direction="top" offset={offset} opacity={opacity} className="custom-tooltip">{text}</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CircleZone({circle, color, opacity = '0.1', border = 3, display = true, children}) {
|
export function CircleZone({circle, color = "black", display = true, children}) {
|
||||||
|
const opacity = '0.1';
|
||||||
|
const border = 3;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
display && circle &&
|
display && circle &&
|
||||||
<Circle center={circle.center} radius={circle.radius} pathOptions={{ color: color, fillColor: color, fillOpacity: opacity, weight: border }}>
|
<Circle center={circle.center} radius={circle.radius} pathOptions={{ color: color, fillColor: color, fillOpacity: opacity, weight: border }}>
|
||||||
@@ -44,7 +55,10 @@ export function CircleZone({circle, color, opacity = '0.1', border = 3, display
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PolygonZone({polygon, color, opacity = '0.1', border = 3, display = true, children}) {
|
export function PolygonZone({polygon, color = "black", display = true, children}) {
|
||||||
|
const opacity = '0.1';
|
||||||
|
const border = 3;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
display && polygon && polygon.length >= 3 &&
|
display && polygon && polygon.length >= 3 &&
|
||||||
<Polygon positions={polygon} pathOptions={{ color: color, fillColor: color, fillOpacity: opacity, weight: border }}>
|
<Polygon positions={polygon} pathOptions={{ color: color, fillColor: color, fillOpacity: opacity, weight: border }}>
|
||||||
@@ -53,7 +67,7 @@ export function PolygonZone({polygon, color, opacity = '0.1', border = 3, displa
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Position({position, color, onClick, display = true, children}) {
|
export function Position({position, color = "blue", onClick = () => {}, display = true, children}) {
|
||||||
|
|
||||||
const positionIcon = new L.Icon({
|
const positionIcon = new L.Icon({
|
||||||
iconUrl: `/icons/marker/${color}.png`,
|
iconUrl: `/icons/marker/${color}.png`,
|
||||||
@@ -71,7 +85,10 @@ export function Position({position, color, onClick, display = true, children}) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Arrow({ pos1, pos2, color = 'black', weight = 5, arrowSize = 20, insetPixels = 25, display = true }) {
|
export function Arrow({ pos1, pos2, color = 'black', display = true }) {
|
||||||
|
const weight = 5;
|
||||||
|
const arrowSize = 20;
|
||||||
|
const insetPixels = 25;
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
const [insetPositions, setInsetPositions] = useState(null);
|
const [insetPositions, setInsetPositions] = useState(null);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function MapPan({center, zoom, animate=false}) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MapEventListener({ onLeftClick, onRightClick, onMouseMove, onDragStart }) {
|
export function MapEventListener({ onLeftClick, onRightClick, onMouseMove, onDragStart, onWheel }) {
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
// TODO use useMapEvents instead of this + detect when zoom
|
// TODO use useMapEvents instead of this + detect when zoom
|
||||||
|
|
||||||
@@ -93,6 +93,17 @@ export function MapEventListener({ onLeftClick, onRightClick, onMouseMove, onDra
|
|||||||
map.off('dragstart', onDragStart);
|
map.off('dragstart', onDragStart);
|
||||||
}
|
}
|
||||||
}, [onDragStart]);
|
}, [onDragStart]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!onWheel) return;
|
||||||
|
|
||||||
|
const container = map.getContainer();
|
||||||
|
container.addEventListener('wheel', onWheel);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
container.removeEventListener('wheel', onWheel);
|
||||||
|
}
|
||||||
|
}, [onWheel]);
|
||||||
|
|
||||||
// Prevent right click context menu
|
// Prevent right click context menu
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -12,11 +12,21 @@ export const mapZooms = {
|
|||||||
export const mapStyles = {
|
export const mapStyles = {
|
||||||
default: {
|
default: {
|
||||||
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||||
|
arrowColor: "black",
|
||||||
|
currentZoneColor: "red",
|
||||||
|
nextZoneColor: "green",
|
||||||
|
placementZoneColor: "blue",
|
||||||
|
playerColor: "blue"
|
||||||
},
|
},
|
||||||
satellite: {
|
satellite: {
|
||||||
url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
|
url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
|
||||||
attribution: 'Tiles © Esri'
|
attribution: 'Tiles © Esri',
|
||||||
|
arrowColor: "white",
|
||||||
|
currentZoneColor: "red",
|
||||||
|
nextZoneColor: "#0F0",
|
||||||
|
placementZoneColor: "#0FF",
|
||||||
|
playerColor: "blue"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user