Compare commits

...

4 Commits

Author SHA1 Message Date
mohamed 964f0e2ba8 import réussi
2 years ago
mohamed a3d83b19fd avancement
2 years ago
mohamed 448ad0f5dd fix quelques bug. ajout images points.
2 years ago
mohamed 2d684c1640 début import
2 years ago

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

17240
R-Dash/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -16,18 +16,22 @@
"@reduxjs/toolkit": "^1.9.3", "@reduxjs/toolkit": "^1.9.3",
"@rneui/base": "^4.0.0-rc.7", "@rneui/base": "^4.0.0-rc.7",
"expo": "~48.0.6", "expo": "~48.0.6",
"expo-document-picker": "~11.2.1", "expo-document-picker": "~11.2.2",
"expo-status-bar": "~1.4.4", "expo-status-bar": "~1.4.4",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.71.3", "react-native": "0.71.4",
"react-native-document-picker": "^8.1.4", "react-native-document-picker": "^8.2.0",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "^2.9.0", "react-native-gesture-handler": "^2.9.0",
"react-native-maps": "1.3.2", "react-native-maps": "1.3.2",
"react-native-safe-area-context": "^4.5.0", "react-native-safe-area-context": "^4.5.0",
"react-redux": "^8.0.5", "react-redux": "^8.0.5",
"redux": "^4.2.1", "redux": "^4.2.1",
"typescript": "^4.9.4" "typescript": "^4.9.4",
"react-native-web": "~0.18.10",
"react-dom": "18.2.0",
"@expo/webpack-config": "^18.0.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",

@ -3,3 +3,5 @@ export const FETCH_TEAMS = 'FETCH_TEAMS';
export const FETCH_SESSIONS = 'FETCH_SESSIONS'; export const FETCH_SESSIONS = 'FETCH_SESSIONS';
export const ADD_TEAM = 'ADD_TEAM'; export const ADD_TEAM = 'ADD_TEAM';
export const ADD_FILE = 'ADD_FILE'; export const ADD_FILE = 'ADD_FILE';
//export const server_link = "https://codefirst.iut.uca.fr/containers/enzojolys-r-dash_container";
export const server_link = "https://r-dash.azurewebsites.net";

@ -1,4 +1,4 @@
import { configureStore } from '@reduxjs/toolkit' import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
import appReducer from './reducers/appReducer'; import appReducer from './reducers/appReducer';
// Reference here all your application reducers // Reference here all your application reducers
@ -6,9 +6,13 @@ const reducer = {
appReducer: appReducer, appReducer: appReducer,
} }
// @ts-ignore const middleware = getDefaultMiddleware({
const store = configureStore({ serializableCheck: false, // Disable serializableCheck
reducer, immutableCheck: false
}); });
const store = configureStore({
reducer,
middleware,
});
export default store; export default store;

@ -1,9 +1,10 @@
import { Alert } from "react-native";
import { Geocalisation } from "../../core/Geocalisation"; import { Geocalisation } from "../../core/Geocalisation";
import { Lap } from "../../core/Lap"; import { Lap } from "../../core/Lap";
import { Point } from "../../core/Point"; import { Point } from "../../core/Point";
import { Session } from "../../core/Session"; import { Session } from "../../core/Session";
import { User } from "../../core/User"; import { User } from "../../core/User";
import { FETCH_SESSIONS } from "../Constants"; import { FETCH_SESSIONS, server_link } from "../Constants";
export const setSessionsList = (sessionsList: Session[]) => { export const setSessionsList = (sessionsList: Session[]) => {
return { return {
@ -12,26 +13,46 @@ export const setSessionsList = (sessionsList: Session[]) => {
}; };
} }
export const addXlsFile = async (file: File) => { // export const addXlsFile = async (file: File) => {
try { // try {
const formData = new FormData(); // const formData = new FormData();
formData.append('file', file); // formData.append('file', file);
const response = await fetch( // const response = await fetch(
'https://r-dash.azurewebsites.net/File?' + "pseudoPilote=test_PILOTE" + "&Email=test@gmail.com" + "&password=test123" + "&nameSession=test_SESSION" + "&nameCircuit=test_CIRCUIT" + "&typeSession=Unknown", { // 'https://r-dash.azurewebsites.net/File?' + "pseudoPilote=test_PILOTE" + "&Email=test@gmail.com" + "&password=test123" + "&nameSession=test_SESSION" + "&nameCircuit=test_CIRCUIT" + "&typeSession=Unknown", {
method: 'POST', // method: 'POST',
body: formData // body: formData
}); // });
const data = await response.json(); // const data = await response.json();
return data; // return data;
} catch (error) { // } catch (error) {
console.log('Error---------', error); // console.log('Error---------', error);
// }
// };
export const addXlsFile = (file: File, pseudoPilote: string, email: string, password: string, nameSession: string, nameCircuit: string, typeSession: string) => {
return async dispatch => {
try {
const formData = new FormData();
formData.append('file', file);
const response = await fetch(
server_link+`/File?pseudoPilote=${pseudoPilote}&Email=${email}&password=${password}&nameSession=${nameSession}&nameCircuit=${nameCircuit}&typeSession=${typeSession}`,
{
method: 'POST',
body: formData
}
);
const data = await response.json();
return data;
} catch (error) {
console.log('Error - POST FILE', error);
Alert.alert('Error', 'An error occured while adding a session. (server might be down)');
}
} }
}; };
export const getSessionsList = () => { export const getSessionsList = () => {
return async dispatch => { return async dispatch => {
try { try {
const sessionsPromise = await fetch('https://r-dash.azurewebsites.net/FullSession'); const sessionsPromise = await fetch(server_link+'/FullSession');
const sessionsListJson = await sessionsPromise.json(); const sessionsListJson = await sessionsPromise.json();
const sessionsList: Session[] = sessionsListJson.map(elt => { const sessionsList: Session[] = sessionsListJson.map(elt => {
const laps: Lap[] = elt["tours"].map(lap => { const laps: Lap[] = elt["tours"].map(lap => {
@ -39,13 +60,14 @@ export const getSessionsList = () => {
const geo = new Geocalisation(point["longitude"], point["latitude"]); const geo = new Geocalisation(point["longitude"], point["latitude"]);
return new Point(geo, point["timer"] , point["distance"], point["nGear"], point["pBrakeF"], point["aSteer"], point["rPedal"], point["gLong"], point["gLat"], point["vCar"]); return new Point(geo, point["timer"] , point["distance"], point["nGear"], point["pBrakeF"], point["aSteer"], point["rPedal"], point["gLong"], point["gLat"], point["vCar"]);
}); });
return new Lap(lap["temps"], points, lap["temps"]); return new Lap(lap["numero"], points, lap["temps"]);
}); });
return new Session(elt["name"], laps, elt["type"]); return new Session(elt["name"], laps, elt["type"]);
}); });
dispatch(setSessionsList(sessionsList)); dispatch(setSessionsList(sessionsList));
} catch (error) { } catch (error) {
console.log('Error---------', error); console.log('Error -- GET SESSIONS', error);
Alert.alert('Error', 'An error occured while getting sessions. (server might be down)');
//dispatch(fetchDataRejected(error)) //dispatch(fetchDataRejected(error))
} }
} }

@ -1,5 +1,5 @@
import { Team } from "../../core/Team"; import { Team } from "../../core/Team";
import { FETCH_TEAMS, ADD_TEAM } from "../Constants"; import { FETCH_TEAMS, ADD_TEAM, server_link } from "../Constants";
export const setTeamsList = (teamsList: Team[]) => { export const setTeamsList = (teamsList: Team[]) => {
return { return {
@ -11,7 +11,7 @@ export const setTeamsList = (teamsList: Team[]) => {
export const addNewTeam = (newTeam: Team) => { export const addNewTeam = (newTeam: Team) => {
return async dispatch => { return async dispatch => {
try { try {
const response = await fetch('https://r-dash.azurewebsites.net/Ecuries?' + "Email=test@gmail.com" + "&password=test123" + "&pseudoPilote=test_PILOTE", { const response = await fetch(server_link + '/Ecuries?' + "Email=test@gmail.com" + "&password=test123" + "&pseudoPilote=test_PILOTE", {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -33,7 +33,7 @@ export const addNewTeam = (newTeam: Team) => {
export const getTeamsList = () => { export const getTeamsList = () => {
return async dispatch => { return async dispatch => {
try { try {
const teamsPromise = await fetch('https://r-dash.azurewebsites.net/Ecuries'); const teamsPromise = await fetch(server_link+'/Ecuries');
const teamsListJson = await teamsPromise.json(); const teamsListJson = await teamsPromise.json();
const teamsList: Team[] = teamsListJson.map(elt => new Team(elt["name"], elt["owner"], elt["users"], elt["logo"])); const teamsList: Team[] = teamsListJson.map(elt => new Team(elt["name"], elt["owner"], elt["users"], elt["logo"]));
dispatch(setTeamsList(teamsList)); dispatch(setTeamsList(teamsList));

@ -16,7 +16,7 @@ export const setUsersList = (usersList: User[]) => {
export const getUsersList = (team: Team) => { export const getUsersList = (team: Team) => {
return async dispatch => { return async dispatch => {
try { try {
const usersPromise = await fetch('https://codefirst.iut.uca.fr/containers/enzojolys-r-dash_container/Pilotes/'+team); const usersPromise = await fetch(server_link+'/Pilotes/'+team);
const usersListJson = await usersPromise.json(); const usersListJson = await usersPromise.json();
const dto: DtoUserEcurie = usersListJson.map(elt => new DtoUserEcurie(elt["owner"], elt["members"], elt["waitingMember"])); const dto: DtoUserEcurie = usersListJson.map(elt => new DtoUserEcurie(elt["owner"], elt["members"], elt["waitingMember"]));
const usersList: User[] = [] const usersList: User[] = []

@ -106,12 +106,12 @@ export default function Lap(props: { navigation: any, route : any}) {
<View style={styles.infoContainer}> <View style={styles.infoContainer}>
<Text style={styles.infoItem}>Average Speed:</Text> <Text style={styles.infoItem}>Average Speed:</Text>
<Text style={styles.infoValue}>{currentLap.getAverageSpeed()} km/h</Text> <Text style={styles.infoValue}>{currentLap.getAverageSpeed().toFixed()} km/h</Text>
</View> </View>
<View style={styles.infoContainer}> <View style={styles.infoContainer}>
<Text style={styles.infoItem}>Max Speed:</Text> <Text style={styles.infoItem}>Max Speed:</Text>
<Text style={styles.infoValue}>{currentLap.getMaxSpeed()} km/h</Text> <Text style={styles.infoValue}>{currentLap.getMaxSpeed().toFixed()} km/h</Text>
</View> </View>
</View> </View>
</BackgroundImage> </BackgroundImage>

@ -1,25 +1,144 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Pressable, StyleSheet, Text, View, Image, TouchableOpacity, TextInput } from 'react-native'; import { Pressable, StyleSheet, Text, View, Image, TouchableOpacity, TextInput } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
import * as DocumentPicker from 'expo-document-picker';
import TopBar from '../components/TopBar'; import TopBar from '../components/TopBar';
import { addXlsFile } from '../redux/actions/sessions';
import { useDispatch } from 'react-redux';
import * as DocumentPicker from 'expo-document-picker';
import { uploadFiles, DocumentDirectoryPath } from 'react-native-fs';
export default function NewTrack(props: { navigation: any }) { export default function NewTrack(props: { navigation: any }) {
const { navigation } = props; const { navigation } = props;
const dispatch = useDispatch();
const [pickedDocument, setPickedDocument] = useState<DocumentPicker.DocumentResult | null>(null); const [pickedDocument, setPickedDocument] = useState<DocumentPicker.DocumentResult | null>(null);
const [trackName, setTrackName] = useState('');
const [sessionName, setSessionName] = useState('');
const handlePickDocument = async () => { const handlePickDocument = async () => {
try { try {
const result = await DocumentPicker.getDocumentAsync({ type: 'excel/xls' }); const result = await DocumentPicker.getDocumentAsync({});
if (result.type === 'success') { if (result.type === 'success') {
setPickedDocument(result); setPickedDocument(result);
} }
else if(result.type === 'cancel'){
console.log("AAA");
setPickedDocument(null);
}
} catch (err) { } catch (err) {
console.log(err); console.log(err);
} }
}; };
// var files = [
// {
// name: "file",
// filename: "file.jpg",
// filepath: pickedDocument.uri,
// filetype: "image/jpeg",
// },
// ];
// const handleConfirm = async () => {
// if (!pickedDocument || !trackName || !sessionName) {
// return;
// }
// const formData = new FormData();
// formData.append('file', {
// uri: pickedDocument.uri,
// type: pickedDocument.type,
// name: pickedDocument.name,
// });
// try {
// await dispatch(addXlsFile(formData, 'test_PILOTE', 'test@gmail.com', 'test123', sessionName, trackName, 'Training'));
// navigation.goBack();
// } catch (error) {
// console.log('Error - POST FILE', error);
// }
// };
// const handleConfirm = async () => {
// if (!pickedDocument || !trackName || !sessionName) {
// return;
// }
// try {
// const file = new File([await pickedDocument.uri], pickedDocument.name, { type: pickedDocument.type });
// const url = 'https://r-dash.azurewebsites.net/File?pseudoPilote=test_PILOTE&nameSession=weekend&nameCircuit=test_CIRCUIT&typeSession=Training';
// const options = {
// method: 'POST',
// body: file,
// headers: {
// 'Content-Type': 'application/octet-stream',
// },
// };
// await fetch(url, options);
// navigation.goBack();
// } catch (error) {
// console.log('Error - POST FILE', error);
// }
// };
// const handleConfirm = async () => {
// if (!pickedDocument || !trackName || !sessionName) {
// return;
// }
// try {
// const file = new File([await pickedDocument.uri], pickedDocument.name, { type: pickedDocument.type });
// const url = 'https://r-dash.azurewebsites.net/File?pseudoPilote=test_PILOTE&nameSession=weekend&nameCircuit=test_CIRCUIT&typeSession=Training';
// const options = {
// method: 'POST',
// body: file,
// headers: {
// 'Content-Type': 'application/octet-stream',
// },
// };
// const response = await fetch(url, options);
// const responseData = await response.text(); // or response.text() or response.blob() depending on the expected response type
// navigation.goBack();
// console.log(responseData);
// } catch (error) {
// console.log('Error - POST FILE', error);
// }
// };
const handleConfirm = async () => {
if (!pickedDocument || !trackName || !sessionName) {
return;
}
try {
//const file = new File([await pickedDocument.uri], pickedDocument.name, { type: pickedDocument.type });
const url = 'https://r-dash.azurewebsites.net/File?pseudoPilote=test_PILOTE&nameSession=test%20import&nameCircuit=test_CIRCUIT&typeSession=Training';
const formData = new FormData();
console.log(pickedDocument.type);
console.log(pickedDocument.uri);
formData.append('file',
{
name: pickedDocument.name,
type: "application/vnd.ms-excel",
uri : pickedDocument.uri,
});
const response = await fetch(url, {
method: 'POST',
body: formData,
headers: {
'accept':'*/*',
'Content-Type': 'multipart/form-data',
},
});
const data = await response.json();
console.log('API response:', data);
if (!response.ok) {
throw new Error( JSON.stringify(response) + 'Failed to upload file');
}
navigation.goBack();
} catch (error) {
console.log('Error - POST FILE', error);
}
};
return ( return (
<SafeAreaView> <SafeAreaView>
<View style={styles.container}> <View style={styles.container}>
@ -33,7 +152,8 @@ export default function NewTrack(props: { navigation: any }) {
<Text style={{ paddingTop: 20 }}>Track name: </Text> <Text style={{ paddingTop: 20 }}>Track name: </Text>
<TextInput <TextInput
style={styles.textInput} style={styles.textInput}
secureTextEntry={true} onChangeText={setTrackName}
value={trackName}
placeholder="Track name" placeholder="Track name"
/> />
</View> </View>
@ -42,7 +162,8 @@ export default function NewTrack(props: { navigation: any }) {
<Text style={{ paddingTop: 20 }}>Session name: </Text> <Text style={{ paddingTop: 20 }}>Session name: </Text>
<TextInput <TextInput
style={styles.textInput} style={styles.textInput}
secureTextEntry={true} onChangeText={setSessionName}
value={sessionName}
placeholder="Session name" placeholder="Session name"
/> />
</View> </View>
@ -67,7 +188,7 @@ export default function NewTrack(props: { navigation: any }) {
source={require('../assets/images/return.png')} source={require('../assets/images/return.png')}
/> />
</Pressable> </Pressable>
<Pressable style={styles.button} onPress={() => navigation.goBack()}> <Pressable style={styles.button} onPress={handleConfirm}>
<Image <Image
style={styles.return} style={styles.return}
source={require('../assets/images/checked.png')} source={require('../assets/images/checked.png')}

@ -1,7 +1,7 @@
import { BackgroundImage } from '@rneui/base'; import { BackgroundImage } from '@rneui/base';
import { StyleSheet, Text, View, TouchableOpacity, ScrollView } from 'react-native'; import { StyleSheet, Text, View, TouchableOpacity, ScrollView } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
import MapView, { Marker } from 'react-native-maps'; import MapView, { MapCallout, Marker } from 'react-native-maps';
import React from 'react'; import React from 'react';
import TopBar from '../components/TopBar'; import TopBar from '../components/TopBar';
import { Point } from '../core/Point'; import { Point } from '../core/Point';
@ -20,6 +20,7 @@ export default function Lap(props: { navigation: any, route : any}) {
const goToPreviousPoint = () => { const goToPreviousPoint = () => {
if (currentPointIndex > 0) { if (currentPointIndex > 0) {
setCurrentPointIndex(currentPointIndex - 1); setCurrentPointIndex(currentPointIndex - 1);
} }
}; };
@ -29,11 +30,24 @@ export default function Lap(props: { navigation: any, route : any}) {
} }
}; };
const markers: { id: number; name: string; coordinate: { latitude: number; longitude: number } }[] = points.map((pt, index) => { const markers: { id: number; name: string; coordinate: { latitude: number; longitude: number }, image: HTMLImageElement }[] = points.map((pt, index) => {
var img;
const brake = pt.getPBreakF();
if(brake <= 0)
{
img = require("../assets/images/noBrake.png");
}else if(brake > 0 && brake <= 30){
img = require("../assets/images/startBrake.png");
}else if(brake > 0 && brake <= 100){
img = require("../assets/images/midBrake.png");
}else{
img = require("../assets/images/fullBrake.png");
}
return { return {
id: index, id: index,
name: pt.getDistance() + 'm', name: pt.getDistance() + 'm',
coordinate: { latitude: pt.getGeo().getGpsLat(), longitude: pt.getGeo().getGpsLong() }, coordinate: { latitude: pt.getGeo().getGpsLat(), longitude: pt.getGeo().getGpsLong() },
image: img,
}; };
}); });
@ -63,7 +77,7 @@ export default function Lap(props: { navigation: any, route : any}) {
</View> </View>
</TouchableOpacity> </TouchableOpacity>
<Text style={styles.text_title}>Point {currentPointIndex + 1 } / { points.length } </Text> <Text style={styles.text_title}>Point {currentPointIndex + 1 } </Text>
<TouchableOpacity style={[styles.LapBrowserButton, currentPointIndex === points.length - 1 ? styles.disabled : null]} onPress={goToNextPoint}> <TouchableOpacity style={[styles.LapBrowserButton, currentPointIndex === points.length - 1 ? styles.disabled : null]} onPress={goToNextPoint}>
<View> <View>
@ -84,8 +98,8 @@ export default function Lap(props: { navigation: any, route : any}) {
longitudeDelta: 0.015, longitudeDelta: 0.015,
}} }}
> >
{markers.map(({ id, name, coordinate }) => ( {markers.map(({ id, name, coordinate,image }) => (
<Marker key={id} title={name} coordinate={coordinate} onPress={() => handleMarker(id)} /> <Marker key={id} title={name} coordinate={coordinate} onPress={() => handleMarker(id)} icon={image} style={{ width: 1, height: 1 }} />
))} ))}
@ -116,7 +130,7 @@ export default function Lap(props: { navigation: any, route : any}) {
<View style={styles.infoContainer}> <View style={styles.infoContainer}>
<Text style={styles.infoItem}>nGear:</Text> <Text style={styles.infoItem}>nGear:</Text>
<Text style={styles.infoValue}>{currentPoint.getVCar()} gear</Text> <Text style={styles.infoValue}>{currentPoint.getNGear()} gear</Text>
</View> </View>
<View style={styles.infoContainer}> <View style={styles.infoContainer}>
@ -137,7 +151,7 @@ export default function Lap(props: { navigation: any, route : any}) {
</View> </View>
<View style={styles.infoContainer}> <View style={styles.infoContainer}>
<Text style={styles.infoItem}>gLat:</Text> <Text style={styles.infoItem}>gLat:</Text>
<Text style={styles.infoValue}>{currentPoint.getGLong()} g</Text> <Text style={styles.infoValue}>{currentPoint.getGLat()} g</Text>
</View> </View>
</View> </View>
</BackgroundImage> </BackgroundImage>

@ -6,6 +6,7 @@ import {
Text, Text,
View, View,
TouchableOpacity, TouchableOpacity,
ActivityIndicator,
} from "react-native"; } from "react-native";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import SessionListItem from "../components/SessionCmp"; import SessionListItem from "../components/SessionCmp";
@ -17,6 +18,7 @@ import { SESSIONS } from "../stub/stub";
export default function Session_browser(props: { navigation: any }) { export default function Session_browser(props: { navigation: any }) {
const { navigation } = props; const { navigation } = props;
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [loading, setLoading] = useState(false);
const handlePress = (item: Session) => { const handlePress = (item: Session) => {
setSearch(""); setSearch("");
@ -28,8 +30,10 @@ export default function Session_browser(props: { navigation: any }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
useEffect(() => { useEffect(() => {
setLoading(true);
const loadTeams = async () => { const loadTeams = async () => {
await dispatch(getSessionsList()); await dispatch(getSessionsList());
setLoading(false);
}; };
loadTeams(); loadTeams();
}, [dispatch]); }, [dispatch]);
@ -61,13 +65,17 @@ export default function Session_browser(props: { navigation: any }) {
value={search} value={search}
onChangeText={setSearch} onChangeText={setSearch}
/> />
<FlatList {loading ? (
data={filteredData} <ActivityIndicator size="large" color="#BF181F" />
renderItem={({ item }) => ( ) : (
<SessionListItem session={item} onPress={handlePress} /> <FlatList
)} data={filteredData}
keyExtractor={(Item) => Item.getName()} renderItem={({ item }) => (
/> <SessionListItem session={item} onPress={handlePress} />
)}
keyExtractor={(Item) => Item.getName()}
/>
)}
<TouchableOpacity <TouchableOpacity
style={styles.addContainerButton} style={styles.addContainerButton}

Loading…
Cancel
Save