mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-04-11 00:30:19 +02:00
Refactoring
This commit is contained in:
@@ -1,16 +1,16 @@
|
|||||||
// Expo
|
// Expo
|
||||||
import { Slot } from 'expo-router';
|
import { Slot } from 'expo-router';
|
||||||
// Contexts
|
// Contexts
|
||||||
import { TeamConnexionProvider } from "../src/context/teamConnexionContext";
|
import { AuthProvider } from "../src/contexts/authContext";
|
||||||
import { TeamProvider } from "../src/context/teamContext";
|
import { TeamProvider } from "../src/contexts/teamContext";
|
||||||
|
|
||||||
const Layout = () => {
|
const Layout = () => {
|
||||||
return (
|
return (
|
||||||
<TeamConnexionProvider>
|
<AuthProvider>
|
||||||
<TeamProvider>
|
<TeamProvider>
|
||||||
<Slot/>
|
<Slot/>
|
||||||
</TeamProvider>
|
</TeamProvider>
|
||||||
</TeamConnexionProvider>
|
</AuthProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,18 +8,18 @@ import { CustomButton } from '../src/components/button';
|
|||||||
import { CustomImage } from '../src/components/image';
|
import { CustomImage } from '../src/components/image';
|
||||||
import { CustomTextInput } from '../src/components/input';
|
import { CustomTextInput } from '../src/components/input';
|
||||||
// Contexts
|
// Contexts
|
||||||
import { useTeamConnexion } from "../src/context/teamConnexionContext";
|
import { useAuth } from "../src/contexts/authContext";
|
||||||
// Hooks
|
// Hooks
|
||||||
import { usePickImage } from '../src/hook/usePickImage';
|
import { usePickImage } from '../src/hooks/usePickImage';
|
||||||
// Services
|
// Services
|
||||||
import { uploadTeamImage } from '../src/services/imageService';
|
import { uploadTeamImage } from '../src/services/api/image';
|
||||||
import { getLocationAuthorization, stopLocationTracking } from '../src/services/backgroundLocationTask';
|
import { getLocationAuthorization, stopLocationTracking } from '../src/services/tasks/backgroundLocation';
|
||||||
// Constants
|
// Constants
|
||||||
import { COLORS } from '../src/constants';
|
import { COLORS } from '../src/constants';
|
||||||
|
|
||||||
const Index = () => {
|
const Index = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { login, loggedIn } = useTeamConnexion();
|
const { loggedIn, login } = useAuth();
|
||||||
const { image, pickImage } = usePickImage();
|
const { image, pickImage } = usePickImage();
|
||||||
const [teamId, setTeamId] = useState("");
|
const [teamId, setTeamId] = useState("");
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|||||||
@@ -8,24 +8,23 @@ import { CustomMap } from '../src/components/map';
|
|||||||
import { Drawer } from '../src/components/drawer';
|
import { Drawer } from '../src/components/drawer';
|
||||||
import { TimerMMSS } from '../src/components/timer';
|
import { TimerMMSS } from '../src/components/timer';
|
||||||
// Contexts
|
// Contexts
|
||||||
import { useTeamConnexion } from '../src/context/teamConnexionContext';
|
import { useAuth } from '../src/contexts/authContext';
|
||||||
import { useTeamContext } from '../src/context/teamContext';
|
import { useTeam } from '../src/contexts/teamContext';
|
||||||
// Hooks
|
// Hooks
|
||||||
import { useGame } from '../src/hook/useGame';
|
import { useTimeDifference } from '../src/hooks/useTimeDifference';
|
||||||
import { useTimeDifference } from '../src/hook/useTimeDifference';
|
|
||||||
// Services
|
// Services
|
||||||
import { startLocationTracking } from '../src/services/backgroundLocationTask';
|
import { emitSendPosition } from '../src/services/socket/emitters';
|
||||||
|
import { startLocationTracking } from '../src/services/tasks/backgroundLocation';
|
||||||
// Util
|
// Util
|
||||||
import { secondsToMMSS } from '../src/util/functions';
|
import { secondsToMMSS } from '../src/utils/functions';
|
||||||
// Constants
|
// Constants
|
||||||
import { GAME_STATE, COLORS } from '../src/constants';
|
import { GAME_STATE, COLORS } from '../src/constants';
|
||||||
|
|
||||||
const Interface = () => {
|
const Interface = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {teamInfos, messages, nextZoneDate, isShrinking, gameState} = useTeamContext();
|
const {teamInfos, messages, nextZoneDate, gameState} = useTeam();
|
||||||
const {name, ready, captured, locationSendDeadline, outOfZone, outOfZoneDeadline, hasHandicap, enemyHasHandicap} = teamInfos;
|
const {name, ready, captured, locationSendDeadline, outOfZone, outOfZoneDeadline, hasHandicap, enemyHasHandicap} = teamInfos;
|
||||||
const {loggedIn, logout} = useTeamConnexion();
|
const { loggedIn, logout } = useAuth();
|
||||||
const {sendCurrentPosition} = useGame();
|
|
||||||
const [timeLeftSendLocation] = useTimeDifference(locationSendDeadline, 1000);
|
const [timeLeftSendLocation] = useTimeDifference(locationSendDeadline, 1000);
|
||||||
const [timeLeftNextZone] = useTimeDifference(nextZoneDate, 1000);
|
const [timeLeftNextZone] = useTimeDifference(nextZoneDate, 1000);
|
||||||
const [timeLeftOutOfZone] = useTimeDifference(outOfZoneDeadline, 1000);
|
const [timeLeftOutOfZone] = useTimeDifference(outOfZoneDeadline, 1000);
|
||||||
@@ -87,7 +86,7 @@ const Interface = () => {
|
|||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
{ gameState == GAME_STATE.PLAYING && !captured && <Fragment>
|
{ gameState == GAME_STATE.PLAYING && !captured && <Fragment>
|
||||||
<TimerMMSS style={{width: "50%"}} title={isShrinking ? "Réduction de la zone" : "Durée de la zone"} seconds={-timeLeftNextZone} />
|
<TimerMMSS style={{width: "50%"}} title={"Réduction de la zone dans"} seconds={-timeLeftNextZone} />
|
||||||
<TimerMMSS style={{width: "50%"}} title={"Position envoyée dans"} seconds={!hasHandicap ? -timeLeftSendLocation: 0} />
|
<TimerMMSS style={{width: "50%"}} title={"Position envoyée dans"} seconds={!hasHandicap ? -timeLeftSendLocation: 0} />
|
||||||
</Fragment>}
|
</Fragment>}
|
||||||
</View>
|
</View>
|
||||||
@@ -98,7 +97,7 @@ const Interface = () => {
|
|||||||
<View style={styles.bottomContainer} onLayout={(event) => setBottomContainerHeight(event.nativeEvent.layout.height)}>
|
<View style={styles.bottomContainer} onLayout={(event) => setBottomContainerHeight(event.nativeEvent.layout.height)}>
|
||||||
<CustomMap/>
|
<CustomMap/>
|
||||||
{ gameState == GAME_STATE.PLAYING && !captured && !hasHandicap &&
|
{ gameState == GAME_STATE.PLAYING && !captured && !hasHandicap &&
|
||||||
<TouchableOpacity style={styles.updatePosition} onPress={sendCurrentPosition}>
|
<TouchableOpacity style={styles.updatePosition} onPress={emitSendPosition}>
|
||||||
<Image source={require("../src/assets/images/update_position.png")} style={{width: 40, height: 40}} resizeMode="contain"></Image>
|
<Image source={require("../src/assets/images/update_position.png")} style={{width: 40, height: 40}} resizeMode="contain"></Image>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,25 +8,24 @@ import { CustomImage } from './image';
|
|||||||
import { CustomTextInput } from './input';
|
import { CustomTextInput } from './input';
|
||||||
import { Stat } from './stat';
|
import { Stat } from './stat';
|
||||||
// Contexts
|
// Contexts
|
||||||
import { useTeamConnexion } from '../context/teamConnexionContext';
|
import { useAuth } from '../contexts/authContext';
|
||||||
import { useTeamContext } from '../context/teamContext';
|
import { useTeam } from '../contexts/teamContext';
|
||||||
// Hooks
|
// Hooks
|
||||||
import { useTimeDifference } from '../hook/useTimeDifference';
|
import { useTimeDifference } from '../hooks/useTimeDifference';
|
||||||
import { useGame } from '../hook/useGame';
|
|
||||||
// Services
|
// Services
|
||||||
import { enemyImage } from '../services/imageService';
|
import { emitCapture } from '../services/socket/emitters';
|
||||||
|
import { enemyImage } from '../services/api/image';
|
||||||
// Util
|
// Util
|
||||||
import { secondsToHHMMSS } from '../util/functions';
|
import { secondsToHHMMSS } from '../utils/functions';
|
||||||
// Constants
|
// Constants
|
||||||
import { GAME_STATE, COLORS } from '../constants';
|
import { GAME_STATE, COLORS } from '../constants';
|
||||||
|
|
||||||
export const Drawer = ({ height }) => {
|
export const Drawer = ({ height }) => {
|
||||||
const { teamId } = useTeamConnexion();
|
const { teamId } = useAuth();
|
||||||
const [collapsibleState, setCollapsibleState] = useState(true);
|
const [collapsibleState, setCollapsibleState] = useState(true);
|
||||||
const [enemyCaptureCode, setEnemyCaptureCode] = useState("");
|
const [enemyCaptureCode, setEnemyCaptureCode] = useState("");
|
||||||
const {teamInfos, gameState, startDate} = useTeamContext();
|
const {teamInfos, gameState, startDate} = useTeam();
|
||||||
const {enemyName, captureCode, name, distance, finishDate, nCaptures, nSentLocation, hasHandicap} = teamInfos;
|
const {enemyName, captureCode, name, distance, finishDate, nCaptures, nSentLocation, hasHandicap} = teamInfos;
|
||||||
const {capture} = useGame();
|
|
||||||
const [timeSinceStart] = useTimeDifference(startDate, 1000);
|
const [timeSinceStart] = useTimeDifference(startDate, 1000);
|
||||||
const [captureStatus, setCaptureStatus] = useState(0); // 0 : no capture | 1 : waiting for response from server | 2 : capture failed | 3 : capture succesful
|
const [captureStatus, setCaptureStatus] = useState(0); // 0 : no capture | 1 : waiting for response from server | 2 : capture failed | 3 : capture succesful
|
||||||
const captureStatusColor = {0: "#777", 1: "#FFA500", 2: "#FF6B6B", 3: "#81C784"};
|
const captureStatusColor = {0: "#777", 1: "#FFA500", 2: "#FF6B6B", 3: "#81C784"};
|
||||||
@@ -53,7 +52,7 @@ export const Drawer = ({ height }) => {
|
|||||||
const handleCapture = () => {
|
const handleCapture = () => {
|
||||||
if (captureStatus != 1) {
|
if (captureStatus != 1) {
|
||||||
setCaptureStatus(1);
|
setCaptureStatus(1);
|
||||||
capture(enemyCaptureCode)
|
emitCapture(enemyCaptureCode)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.hasCaptured) {
|
if (response.hasCaptured) {
|
||||||
setCaptureStatus(3);
|
setCaptureStatus(3);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// React
|
// React
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
import { Polygon } from 'react-native-maps';
|
import { Polygon } from 'react-native-maps';
|
||||||
import { circleToPolygon } from '../util/functions';
|
import { circleToPolygon } from '../utils/functions';
|
||||||
|
|
||||||
export const InvertedPolygon = ({id, coordinates, fillColor}) => {
|
export const InvertedPolygon = ({id, coordinates, fillColor}) => {
|
||||||
// We create 3 rectangles covering earth, with the first rectangle centered on the hole
|
// We create 3 rectangles covering earth, with the first rectangle centered on the hole
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ import LinearGradient from 'react-native-linear-gradient';
|
|||||||
// Components
|
// Components
|
||||||
import { DashedCircle, InvertedCircle, InvertedPolygon } from './layer';
|
import { DashedCircle, InvertedCircle, InvertedPolygon } from './layer';
|
||||||
// Contexts
|
// Contexts
|
||||||
import { useTeamContext } from '../context/teamContext';
|
import { useTeam } from '../contexts/teamContext';
|
||||||
// Hook
|
// Hook
|
||||||
import { useLocation } from '../hook/useLocation';
|
import { useLocation } from '../hooks/useLocation';
|
||||||
// Util
|
// Util
|
||||||
import { ZONE_TYPES, INITIAL_REGIONS, GAME_STATE } from '../constants';
|
import { ZONE_TYPES, INITIAL_REGIONS, GAME_STATE } from '../constants';
|
||||||
|
|
||||||
export const CustomMap = () => {
|
export const CustomMap = () => {
|
||||||
const { location } = useLocation();
|
const { location } = useLocation();
|
||||||
const {teamInfos, zoneType, zoneExtremities, gameState} = useTeamContext();
|
const {teamInfos, zoneType, zoneExtremities, gameState} = useTeam();
|
||||||
const {enemyLocation, startingArea, lastSentLocation, hasHandicap} = teamInfos;
|
const {enemyLocation, startingArea, lastSentLocation, hasHandicap} = teamInfos;
|
||||||
const [centerMap, setCenterMap] = useState(true);
|
const [centerMap, setCenterMap] = useState(true);
|
||||||
const mapRef = useRef(null);
|
const mapRef = useRef(null);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// React
|
// React
|
||||||
import { View, Text, StyleSheet } from 'react-native';
|
import { View, Text, StyleSheet } from 'react-native';
|
||||||
// Util
|
// Util
|
||||||
import { secondsToMMSS } from '../util/functions';
|
import { secondsToMMSS } from '../utils/functions';
|
||||||
|
|
||||||
export const TimerMMSS = ({ title, seconds, style }) => {
|
export const TimerMMSS = ({ title, seconds, style }) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
// React
|
|
||||||
import { createContext, useContext, useMemo } from "react";
|
|
||||||
// Hook
|
|
||||||
import { useSocketAuth } from "../hook/useSocketAuth";
|
|
||||||
|
|
||||||
const TeamConnexionContext = createContext();
|
|
||||||
|
|
||||||
export const TeamConnexionProvider = ({ children }) => {
|
|
||||||
const { login, password: teamId, loggedIn, logout } = useSocketAuth();
|
|
||||||
|
|
||||||
const value = useMemo(() => ({ teamId, login, logout, loggedIn}), [teamId, login, logout, loggedIn]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TeamConnexionContext.Provider value={value}>
|
|
||||||
{children}
|
|
||||||
</TeamConnexionContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useTeamConnexion = () => {
|
|
||||||
return useContext(TeamConnexionContext);
|
|
||||||
};
|
|
||||||
80
mobile/traque-app/src/contexts/authContext.jsx
Normal file
80
mobile/traque-app/src/contexts/authContext.jsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// React
|
||||||
|
import { createContext, useContext, useState, useEffect, useCallback, useMemo } from "react";
|
||||||
|
import DeviceInfo from 'react-native-device-info';
|
||||||
|
// Hook
|
||||||
|
import { useLocalStorage } from '../hooks/useLocalStorage';
|
||||||
|
// Services
|
||||||
|
import { emitLogin, emitLogout, emitBattery, emitDeviceInfo } from "../services/socket/emitters";
|
||||||
|
|
||||||
|
const AuthContext = createContext();
|
||||||
|
|
||||||
|
export const AuthProvider = ({ children }) => {
|
||||||
|
const [loggedIn, setLoggedIn] = useState(false);
|
||||||
|
const [teamId, setTeamId] = useLocalStorage("team_id", null);
|
||||||
|
|
||||||
|
const login = useCallback(async (password) => {
|
||||||
|
if (loggedIn != false) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await emitLogin(password);
|
||||||
|
setLoggedIn(response.isLoggedIn);
|
||||||
|
if (response.isLoggedIn) setTeamId(password);
|
||||||
|
return response.isLoggedIn;
|
||||||
|
} catch (error) {
|
||||||
|
setLoggedIn(false);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}, [loggedIn, setTeamId]);
|
||||||
|
|
||||||
|
const logout = useCallback(() => {
|
||||||
|
if (loggedIn != true) return;
|
||||||
|
|
||||||
|
setLoggedIn(false);
|
||||||
|
setTeamId(null);
|
||||||
|
emitLogout();
|
||||||
|
}, [loggedIn, setTeamId]);
|
||||||
|
|
||||||
|
// Try to log in with saved teamId
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loggedIn && teamId) {
|
||||||
|
login(teamId);
|
||||||
|
}
|
||||||
|
}, [loggedIn, teamId, login]);
|
||||||
|
|
||||||
|
// Emit battery level and phone model at log in
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loggedIn) return;
|
||||||
|
|
||||||
|
const sendInfo = async () => {
|
||||||
|
const [brand, model, name] = await Promise.all([
|
||||||
|
DeviceInfo.getBrand(),
|
||||||
|
DeviceInfo.getModel(),
|
||||||
|
DeviceInfo.getDeviceName()
|
||||||
|
]);
|
||||||
|
emitDeviceInfo({model: brand + " " + model, name: name});
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendBattery = async () => {
|
||||||
|
const level = await DeviceInfo.getBatteryLevel();
|
||||||
|
emitBattery(Math.round(level * 100));
|
||||||
|
};
|
||||||
|
|
||||||
|
sendInfo();
|
||||||
|
sendBattery();
|
||||||
|
const batteryCheckInterval = setInterval(() => sendBattery(), 5*60*1000); // 5 minutes
|
||||||
|
|
||||||
|
return () => clearInterval(batteryCheckInterval);
|
||||||
|
}, [loggedIn]);
|
||||||
|
|
||||||
|
const value = useMemo(() => ({ teamId, loggedIn, login, logout}), [teamId, loggedIn, login, logout]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</AuthContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAuth = () => {
|
||||||
|
return useContext(AuthContext);
|
||||||
|
};
|
||||||
@@ -1,26 +1,25 @@
|
|||||||
// React
|
// React
|
||||||
import { createContext, useContext, useMemo, useState, useEffect } from "react";
|
import { createContext, useContext, useMemo, useState, useEffect } from "react";
|
||||||
// Context
|
// Context
|
||||||
import { useTeamConnexion } from "./teamConnexionContext";
|
import { useAuth } from "./authContext";
|
||||||
// Hook
|
|
||||||
import { useSendDeviceInfo } from "../hook/useSendDeviceInfo";
|
|
||||||
// Services
|
// Services
|
||||||
import { socket } from "../services/socket";
|
import { socket } from "../services/socket/connection";
|
||||||
// Constants
|
// Constants
|
||||||
import { GAME_STATE } from "../constants";
|
import { GAME_STATE } from "../constants";
|
||||||
|
|
||||||
const TeamContext = createContext();
|
const TeamContext = createContext();
|
||||||
|
|
||||||
const useSocketListener = (event, callback) => {
|
const useOnEvent = (event, callback) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
socket.on(event, callback);
|
socket.on(event, callback);
|
||||||
return () => {
|
return () => {
|
||||||
socket.off(event, callback);
|
socket.off(event, callback);
|
||||||
};
|
};
|
||||||
}, [callback, event]);
|
}, [event, callback]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TeamProvider = ({children}) => {
|
export const TeamProvider = ({children}) => {
|
||||||
|
const { logout } = useAuth();
|
||||||
// update_team
|
// update_team
|
||||||
const [teamInfos, setTeamInfos] = useState({});
|
const [teamInfos, setTeamInfos] = useState({});
|
||||||
// game_state
|
// game_state
|
||||||
@@ -32,21 +31,17 @@ export const TeamProvider = ({children}) => {
|
|||||||
// settings
|
// settings
|
||||||
const [messages, setMessages] = useState(null);
|
const [messages, setMessages] = useState(null);
|
||||||
const [zoneType, setZoneType] = useState(null);
|
const [zoneType, setZoneType] = useState(null);
|
||||||
// logout
|
|
||||||
const { logout } = useTeamConnexion();
|
|
||||||
|
|
||||||
useSendDeviceInfo();
|
useOnEvent("update_team", (data) => {
|
||||||
|
|
||||||
useSocketListener("update_team", (data) => {
|
|
||||||
setTeamInfos(teamInfos => ({...teamInfos, ...data}));
|
setTeamInfos(teamInfos => ({...teamInfos, ...data}));
|
||||||
});
|
});
|
||||||
|
|
||||||
useSocketListener("game_state", (data) => {
|
useOnEvent("game_state", (data) => {
|
||||||
setGAME_STATE(data.state);
|
setGAME_STATE(data.state);
|
||||||
setStartDate(data.date);
|
setStartDate(data.date);
|
||||||
});
|
});
|
||||||
|
|
||||||
useSocketListener("settings", (data) => {
|
useOnEvent("settings", (data) => {
|
||||||
setMessages(data.messages);
|
setMessages(data.messages);
|
||||||
setZoneType(data.zone.type);
|
setZoneType(data.zone.type);
|
||||||
//TODO
|
//TODO
|
||||||
@@ -54,12 +49,12 @@ export const TeamProvider = ({children}) => {
|
|||||||
//setOutOfZoneDelay(data.outOfZoneDelay);
|
//setOutOfZoneDelay(data.outOfZoneDelay);
|
||||||
});
|
});
|
||||||
|
|
||||||
useSocketListener("current_zone", (data) => {
|
useOnEvent("current_zone", (data) => {
|
||||||
setZoneExtremities({begin: data.begin, end: data.end});
|
setZoneExtremities({begin: data.begin, end: data.end});
|
||||||
setNextZoneDate(data.endDate);
|
setNextZoneDate(data.endDate);
|
||||||
});
|
});
|
||||||
|
|
||||||
useSocketListener("logout", logout);
|
useOnEvent("logout", logout);
|
||||||
|
|
||||||
const value = useMemo(() => (
|
const value = useMemo(() => (
|
||||||
{teamInfos, gameState, startDate, zoneType, zoneExtremities, nextZoneDate, messages}
|
{teamInfos, gameState, startDate, zoneType, zoneExtremities, nextZoneDate, messages}
|
||||||
@@ -72,6 +67,6 @@ export const TeamProvider = ({children}) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useTeamContext = () => {
|
export const useTeam = () => {
|
||||||
return useContext(TeamContext);
|
return useContext(TeamContext);
|
||||||
};
|
};
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
// React
|
|
||||||
import { useCallback } from "react";
|
|
||||||
// Services
|
|
||||||
import { emitSendPosition, emitCapture } from "../services/socketEmitter";
|
|
||||||
|
|
||||||
export const useGame = () => {
|
|
||||||
|
|
||||||
const sendCurrentPosition = useCallback(() => {
|
|
||||||
emitSendPosition();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const capture = useCallback((captureCode) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
console.warn("Server timeout: capture", captureCode);
|
|
||||||
reject(new Error("Timeout"));
|
|
||||||
}, 3000);
|
|
||||||
|
|
||||||
emitCapture(captureCode, (response) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
resolve(response);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return { sendCurrentPosition, capture };
|
|
||||||
};
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
// React
|
|
||||||
import { useEffect, useRef } from 'react';
|
|
||||||
import DeviceInfo from 'react-native-device-info';
|
|
||||||
// Context
|
|
||||||
import { useTeamConnexion } from "../context/teamConnexionContext";
|
|
||||||
// Services
|
|
||||||
import { emitBattery, emitDeviceInfo } from "../services/socketEmitter";
|
|
||||||
|
|
||||||
export const useSendDeviceInfo = () => {
|
|
||||||
const { loggedIn } = useTeamConnexion();
|
|
||||||
const isMounted = useRef(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
isMounted.current = true;
|
|
||||||
|
|
||||||
if (!loggedIn) return;
|
|
||||||
|
|
||||||
const sendInfo = async () => {
|
|
||||||
const [brand, model, name] = await Promise.all([
|
|
||||||
DeviceInfo.getBrand(),
|
|
||||||
DeviceInfo.getModel(),
|
|
||||||
DeviceInfo.getDeviceName()
|
|
||||||
]);
|
|
||||||
if (!isMounted) return;
|
|
||||||
emitDeviceInfo({model: brand + " " + model, name: name});
|
|
||||||
};
|
|
||||||
|
|
||||||
const sendBattery = async () => {
|
|
||||||
const level = await DeviceInfo.getBatteryLevel();
|
|
||||||
if (!isMounted) return;
|
|
||||||
emitBattery(Math.round(level * 100));
|
|
||||||
};
|
|
||||||
|
|
||||||
sendInfo();
|
|
||||||
sendBattery();
|
|
||||||
|
|
||||||
const batteryCheckInterval = setInterval(() => sendBattery(), 5*60*1000); // 5 minutes
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
isMounted.current = false;
|
|
||||||
clearInterval(batteryCheckInterval);
|
|
||||||
};
|
|
||||||
}, [loggedIn]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
// React
|
|
||||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
||||||
// Hook
|
|
||||||
import { useLocalStorage } from './useLocalStorage';
|
|
||||||
// Services
|
|
||||||
import { emitLogin, emitLogout } from "../services/socketEmitter";
|
|
||||||
|
|
||||||
export const useSocketAuth = () => {
|
|
||||||
const [loggedIn, setLoggedIn] = useState(false);
|
|
||||||
const [savedPassword, setSavedPassword] = useLocalStorage("team_password", null);
|
|
||||||
const isMounted = useRef(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
isMounted.current = true;
|
|
||||||
return () => {
|
|
||||||
isMounted.current = false;
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const login = useCallback((password) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
if (!isMounted.current) return;
|
|
||||||
console.warn("Server did not respond to login emit.");
|
|
||||||
reject();
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
emitLogin(password, (response) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
|
|
||||||
if (!isMounted.current) return;
|
|
||||||
|
|
||||||
if (response.isLoggedIn) {
|
|
||||||
console.log("Log in accepted.");
|
|
||||||
setLoggedIn(true);
|
|
||||||
setSavedPassword(password);
|
|
||||||
resolve(response);
|
|
||||||
} else {
|
|
||||||
console.log("Log in refused.");
|
|
||||||
setLoggedIn(false);
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, [setSavedPassword]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!loggedIn && savedPassword) {
|
|
||||||
login(savedPassword);
|
|
||||||
}
|
|
||||||
}, [loggedIn, login, savedPassword]);
|
|
||||||
|
|
||||||
const logout = useCallback(() => {
|
|
||||||
setLoggedIn(false);
|
|
||||||
setSavedPassword(null);
|
|
||||||
emitLogout();
|
|
||||||
}, [setSavedPassword]);
|
|
||||||
|
|
||||||
return {login, logout, password: savedPassword, loggedIn};
|
|
||||||
};
|
|
||||||
@@ -6,21 +6,16 @@ export const useLocalStorage = (key, initialValue) => {
|
|||||||
const [storedValue, setStoredValue] = useState(initialValue);
|
const [storedValue, setStoredValue] = useState(initialValue);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let isMounted = true;
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const item = await AsyncStorage.getItem(key);
|
const item = await AsyncStorage.getItem(key);
|
||||||
if (isMounted && item !== null) {
|
if (item !== null) setStoredValue(JSON.parse(item));
|
||||||
setStoredValue(JSON.parse(item));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error loading key "${key}":`, error);
|
console.error(`Error loading key "${key}":`, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchData();
|
fetchData();
|
||||||
return () => { isMounted = false; };
|
|
||||||
}, [key]);
|
}, [key]);
|
||||||
|
|
||||||
const setValue = useCallback(async (value) => {
|
const setValue = useCallback(async (value) => {
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
// React
|
// React
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If refTime is in the past, time will be positive
|
||||||
|
* If refTime is in the future, time will be negative
|
||||||
|
* The time is updated every timeout milliseconds
|
||||||
|
*/
|
||||||
export const useTimeDifference = (refTime, timeout) => {
|
export const useTimeDifference = (refTime, timeout) => {
|
||||||
// If refTime is in the past, time will be positive
|
|
||||||
// If refTime is in the future, time will be negative
|
|
||||||
// The time is updated every timeout milliseconds
|
|
||||||
const [time, setTime] = useState(0);
|
const [time, setTime] = useState(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// Constants
|
// Constants
|
||||||
import { SERVER_URL } from "../constants";
|
import { SERVER_URL } from "../../constants";
|
||||||
|
|
||||||
export const uploadTeamImage = async (id, imageUri) => {
|
export const uploadTeamImage = async (id, imageUri) => {
|
||||||
if (!imageUri || !id) return;
|
if (!imageUri || !id) return;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Socket
|
// Socket
|
||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
// Constants
|
// Constants
|
||||||
import { SOCKET_URL } from "../constants";
|
import { SOCKET_URL } from "../../constants";
|
||||||
|
|
||||||
export const socket = io(SOCKET_URL, {
|
export const socket = io(SOCKET_URL, {
|
||||||
path: "/back/socket.io"
|
path: "/back/socket.io"
|
||||||
55
mobile/traque-app/src/services/socket/emitters.js
Normal file
55
mobile/traque-app/src/services/socket/emitters.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Services
|
||||||
|
import { socket } from "./connection";
|
||||||
|
|
||||||
|
const customEmit = (event, ...args) => {
|
||||||
|
if (!socket?.connected) return false;
|
||||||
|
console.log("Emit", event);
|
||||||
|
socket.emit(event, ...args);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const customEmitCallback = (event, ...args) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!socket?.connected) return reject(new Error("Socket not connected"));
|
||||||
|
|
||||||
|
console.log("Emit", event);
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
console.warn("Server timeout");
|
||||||
|
reject(new Error("Timeout"));
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
socket.emit(event, ...args, (response) => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
resolve(response.length > 1 ? response : response[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emitLogin = (password) => {
|
||||||
|
return customEmitCallback("login", password);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emitLogout = () => {
|
||||||
|
return customEmit("logout");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emitSendPosition = () => {
|
||||||
|
return customEmit("send_position");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emitUpdatePosition = (location) => {
|
||||||
|
return customEmit("update_position", location);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emitCapture = (captureCode) => {
|
||||||
|
return customEmitCallback("capture", captureCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emitBattery = (level) => {
|
||||||
|
return customEmit("battery_update", level);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emitDeviceInfo = (infos) => {
|
||||||
|
return customEmit("device_info", infos);
|
||||||
|
};
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
// Services
|
|
||||||
import { socket } from "./socket";
|
|
||||||
|
|
||||||
export const emitLogin = (password, callback) => {
|
|
||||||
if (!socket?.connected) return;
|
|
||||||
console.log("Try to log in with :", password);
|
|
||||||
socket.emit("login", password, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const emitLogout = () => {
|
|
||||||
if (!socket?.connected) return;
|
|
||||||
console.log("Logout.");
|
|
||||||
socket.emit("logout");
|
|
||||||
};
|
|
||||||
|
|
||||||
export const emitSendPosition = () => {
|
|
||||||
if (!socket?.connected) return;
|
|
||||||
console.log("Reveal position.");
|
|
||||||
socket.emit("send_position");
|
|
||||||
};
|
|
||||||
|
|
||||||
export const emitUpdatePosition = (location) => {
|
|
||||||
if (!socket?.connected) return;
|
|
||||||
console.log("Update position :", location);
|
|
||||||
socket.emit("update_position", location);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const emitCapture = (captureCode, callback) => {
|
|
||||||
if (!socket?.connected) return;
|
|
||||||
console.log("Try to capture :", captureCode);
|
|
||||||
socket.emit("capture", captureCode, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const emitBattery = (level) => {
|
|
||||||
if (!socket?.connected) return;
|
|
||||||
console.log("Send battery level.");
|
|
||||||
socket.emit('battery_update', level);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const emitDeviceInfo = (infos) => {
|
|
||||||
if (!socket?.connected) return;
|
|
||||||
console.log("Send device infos.");
|
|
||||||
socket.emit('device_info', infos);
|
|
||||||
};
|
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import { defineTask, isTaskRegisteredAsync } from "expo-task-manager";
|
import { defineTask, isTaskRegisteredAsync } from "expo-task-manager";
|
||||||
import * as Location from 'expo-location';
|
import * as Location from 'expo-location';
|
||||||
// Services
|
// Services
|
||||||
import { emitUpdatePosition } from "./socketEmitter";
|
import { emitUpdatePosition } from "../socket/emitters";
|
||||||
// Constants
|
// Constants
|
||||||
import { TASKS, LOCATION_PARAMETERS } from "../constants";
|
import { TASKS, LOCATION_PARAMETERS } from "../../constants";
|
||||||
|
|
||||||
|
|
||||||
// Task
|
// Task
|
||||||
Reference in New Issue
Block a user