test reservation todo corriger getChantier avec la nouvelelle structure

This commit is contained in:
Rochas
2025-12-14 03:04:12 +01:00
parent 1f698076df
commit 27d13ace9d
10 changed files with 190 additions and 100 deletions

View File

@@ -9,7 +9,11 @@ import { ThemedView } from "@/components/theme/themed-view";
export default function AddScreen() {
const [typeAdd, setTypeAdd] = useState('');
const [editMode, setEditMode] = useState(false);
function onPressSwitchMode(){
setEditMode(!editMode);
}
return(
<ThemedView lvl={3} style={styles.back}>

View File

@@ -5,7 +5,6 @@ import Constants from "expo-constants"; //pour connaître la taille de la barre
import { useLocalSearchParams, useRouter } from "expo-router";
import React, { useEffect, useMemo, useState } from "react";
import { FlatList, Image, StyleSheet, Text, View } from "react-native";
import rawConcerts from "../../data/concerts.json";
import { getUsers } from "@/services/ressourcesService";
import { useChantier } from "../ContextChantier";
import SelectChantier from "@/components/selectChantier";
@@ -34,7 +33,7 @@ export default function GestionOuvrier() {
async function loadData() {
try {
//Nous ne gardons que les Ouvriers, qui peuvent être assignés à un chantier
const data = (await getRessources()).filter(u => u.type === "ouvrier");
const data = (await getRessources()).filter(u => u.type === "Ouvrier");
setRessources(data);
} catch (error) {
console.error("Erreur lors du chargement :", error);
@@ -43,19 +42,6 @@ export default function GestionOuvrier() {
loadData();
}, []);
const concertsData: Concert[] = Array.isArray(rawConcerts)
? (rawConcerts as Concert[])
: [];
const filteredData = useMemo(() => {
if (!Array.isArray(concertsData)) return [];
const q = search.trim().toLowerCase();
if (!q) return concertsData;
return concertsData.filter(
(item) => !!item && (item.group ?? "").toLowerCase().includes(q)
);
}, [concertsData, search]);
const renderItem = ({ item, index }: { item?: Ressources; index: number }) => {
if (!item) {
return null;

View File

@@ -15,7 +15,7 @@ import { useRessources } from "../ContextRessource";
export default function GestionnaireRessource() {
const [search, setSearch] = useState("");
const {ressources, setRessources} = useRessources();
const [filterType, setFilterType] = useState("tout");
const [filterType, setFilterType] = useState("Tout");
const [showFilterMenu, setShowFilterMenu] = useState(false);
const router = useRouter();
@@ -33,7 +33,7 @@ export default function GestionnaireRessource() {
const filteredData = ressources.filter((r) => {
const matchName = r.name.toLowerCase().includes(search.toLowerCase());
const matchType = filterType === "tout" || r.type === filterType;
const matchType = filterType === "Tout" || r.type === filterType;
return matchName && matchType;
});
@@ -43,6 +43,7 @@ export default function GestionnaireRessource() {
<ThemedView lvl={1} shadow={true} style={styles.card}>
<Image source={{ uri: item.Image }} style={styles.image} />
<ThemedView lvl={1} style={styles.info}>
<ThemedText>Id : {item.id}</ThemedText>
<ThemedText>Nom : {item.name}</ThemedText>
<ThemedText>Type : {item.type}</ThemedText>
<ThemedText>Quantité totale : {item.quantity}</ThemedText>
@@ -68,7 +69,7 @@ export default function GestionnaireRessource() {
<ThemedView lvl={2} style={styles.filterMenuOverlay}>
<ThemedView lvl={5} style={styles.filterMenu}>
<ThemedText style={styles.filterTitle}>Filtrer par type</ThemedText>
{["tout", "Outil", "Machine"].map((t) => (
{["Tout", "Outil", "Machine","Ouvrier"].map((t) => (
<ThemedButton
key={t}
lvl={1}

View File

@@ -5,11 +5,11 @@ export type Chantier = {
etat: string;
contact: string;
chef: User;
equipe: User[];
materiel: Ressources[];
equipe: Reservation[];
materiel: Reservation[];
vehicules: Reservation[];
dateDep: Date;
tempsEst: number;
vehicules: Ressources[];
anomalies: string[];
latitude: number;
longitude: number;
@@ -36,6 +36,7 @@ export type Ressources = {
export type Reservation = {
id: string;
dateChantier: Date;
dateFin: Date;
chantier: Chantier;
ressource: Ressources;
quantity: number;
};

View File

@@ -7,8 +7,8 @@ import { StyleSheet, ScrollView, Button, TextInput, Text, View, Modal } from 're
import { useChantier } from '../../app/ContextChantier';
import { useRessources } from '../../app/ContextRessource';
import { useUser } from '../../app/ContextUser';
import { getRessources, getUsers, addChantier } from '@/services/ressourcesService';
import { Chantier, Ressources, User } from '@/class/class';
import { getRessources, getUsers, addChantier, sendNewChantier } from '@/services/ressourcesService';
import { Chantier, Ressources, User, Reservation } from '@/class/class';
import { ThemedText } from '@/components/theme/themed-text';
import { ThemedButton } from '@/components/theme/themed-button';
import { ThemedTextInput } from '@/components/theme/themed-textinput';
@@ -34,7 +34,6 @@ export default function AddChantier() {
const [editMode,setEditMode] = useState(false);
const [loading, setLoading] = useState(false);
const [objet, setObjet] = useState('');
const [date, setDate] = useState(new Date());
const [morning, setMorning] = useState(true);
@@ -44,6 +43,7 @@ export default function AddChantier() {
const [contact, setContact] = useState('');
const [machines, setMachines] = useState<RessourcesQte[]>();
const [ouvriers, setOuviers] = useState<RessourcesQte[]>();
const [outils, setOutils] = useState<RessourcesQte[]>();
const [showDateSelect,setSowDateSelect] = useState(false);
const [openConfirmation,setOpenConfirmation] = useState(false);
@@ -52,7 +52,6 @@ export default function AddChantier() {
const [ressourcesSelect, setRessourcesSelect] = useState<string[]>([]);
async function handleAddChantier() {
setLoading(true);
setOpenConfirmation(true);
}
@@ -64,15 +63,89 @@ export default function AddChantier() {
}
};
async function onConfirm(): Promise<void> {
if (!isValidChantier() || !chefChantier) return;
try {
setLoading(true);
if (!isValidChantier() || !chefChantier){
alert("Choisir un chef de Chantier");
return;
}
setOpenConfirmation(false);
var latitude=0;
var longitude=0;
try { //verification de l'adresse
const coords = await geocodeAddress(adresse);
if (coords) {
latitude=coords.latitude;
longitude=coords.longitude;
}
else{
console.error("Impossible de géocoder l'adresse");
alert("Adresse introuvable. Veuillez vérifier l'adresse.");
}
} catch (error) {
console.error("Erreur lors de la création du chantier:", error);
alert("Erreur lors de la création du chantier");
}
var chantier: Chantier = {
id:"0",
name: objet,
adresse: adresse,
etat: 'En cours',
contact: contact,
chef: chefChantier,
dateDep: date,
tempsEst: Number(duree),
anomalies: [],
latitude: latitude,
longitude: longitude,
equipe: [],
materiel: [],
vehicules: []
}
if(machines){
machines.forEach(item => {
chantier.vehicules.push({
id:"0",
chantier: chantier,
ressource: item[0],
quantity: item[1],
})
});
}
if(ouvriers){
ouvriers.forEach(item => {
chantier.equipe.push({
id:"0",
chantier: chantier,
ressource: item[0],
quantity: item[1],
})
});
}
if(outils){
outils.forEach(item => {
chantier.materiel.push({
id:"0",
chantier: chantier,
ressource: item[0],
quantity: item[1],
})
});
}
sendNewChantier(chantier);
/*try {
const coords = await geocodeAddress(adresse);
if (!coords) {
console.error("Impossible de géocoder l'adresse");
alert("Adresse introuvable. Veuillez vérifier l'adresse.");
setLoading(false);
return;
}
const chantierDate = new Date(date);
@@ -85,17 +158,17 @@ export default function AddChantier() {
contact,
chef: doc(db, "user", chefChantier.id),
equipe: [],
/*materiel: materiels
? [doc(db, "ressources", String(materiels.id))]
: [],*/
//materiel: materiels
// ? [doc(db, "ressources", String(materiels.id))]
// : [],
vehicules: machines?.map(e =>
doc(db, "ressources", String(e[0].id))
) || [],
anomalies: [],
dateDep: chantierDate,
tempsEst: parseInt(duree) || 1,
latitude: coords.latitude, //TODO
longitude: coords.longitude, //TODO
latitude: coords.latitude,
longitude: coords.longitude,
};
const id = await addChantier(chantierFirestore as any);
if (id) {
@@ -113,9 +186,7 @@ export default function AddChantier() {
} catch (error) {
console.error("Erreur lors de la création du chantier:", error);
alert("Erreur lors de la création du chantier");
} finally {
setLoading(false);
}
}*/
}
function onCancel(): void {
@@ -231,7 +302,7 @@ export default function AddChantier() {
</View>
<View style = {styles.inputLine}>
<ThemedText style = {styles.inputName}>Outils:</ThemedText>
<SelectRessource style={styles.input} sendRessources={setOuviers} ressourceType="Outil"/>
<SelectRessource style={styles.input} sendRessources={setOutils} ressourceType="Outil"/>
</View>

View File

@@ -53,6 +53,7 @@ export default function SelectChafChantier({style,sendChefChantier , ...otherPro
return(
<View style={{padding:10,width:"100%"}}>
<ThemedButton lvl={2} style={{padding:10,width:"100%",borderRadius:10}} onPress={() => {onPressUser(item)}}>
<ThemedText>{item.id}</ThemedText>
<ThemedText>{item.name}</ThemedText>
<ThemedText>{item.last_name}</ThemedText>
<ThemedText>{item.role}</ThemedText>

View File

@@ -20,9 +20,9 @@ export default function ChantierSummary({data,style , ...otherProps }: Props) {
<Image source={{ uri:"https://cdn.discordapp.com/attachments/1425108443571945644/1427207643180826757/raw.png?ex=693f1a72&is=693dc8f2&hm=86ffb97145fc8d3aec822b87d99be233c98477d4424c1ef58f80eb81b17c7c80&" /*chantier.urlImg*/ }} style={styles.image} />
</View>
<View style={{flex: 1}}>
<ThemedText>Adresse: {data.chantier.adresse}</ThemedText>
<ThemedText>Chef de chantier: {data.chantier.chef.last_name}{" "}{data.chantier.chef.name}</ThemedText>
<ThemedText>État: {data.chantier.etat}</ThemedText>
<ThemedText selectable={true}>Adresse: {data.chantier.adresse}</ThemedText>
<ThemedText selectable={true}>Chef de chantier: {data.chantier.chef.last_name}{" "}{data.chantier.chef.name}</ThemedText>
<ThemedText selectable={true}>État: {data.chantier.etat}</ThemedText>
</View>
</ThemedView>
) :

View File

@@ -78,7 +78,7 @@ export default function SelectChantier() {
var keyWords:string[] = search.toLowerCase().split(" ") ;
var containsAllKeyWord:boolean = true;
keyWords.forEach(keyWord => {
containsAllKeyWord = containsAllKeyWord && (chantier.adresse.toLowerCase().includes(keyWord))
containsAllKeyWord = containsAllKeyWord && (chantier.adresse.toLowerCase().includes(keyWord) || chantier.name.toLowerCase().includes(keyWord))
});
return containsAllKeyWord
});

View File

@@ -1,45 +0,0 @@
[
{
"group": "Bernard DupYEEd",
"date":"Rennes",
"nationality": "French",
"location": "PlombYEEr",
"price": 20,
"ticketsLeft": 36,
"Image": "https://media.discordapp.net/attachments/1415267028201246812/1424825038657425518/a06e3304-86ca-4b4f-8016-c4ae9844b0df.png?ex=68e9f879&is=68e8a6f9&hm=b6ff1f540d5c382930b56bd6f90565f517ee179347d6ee6aebd5254b10cf4c88&=&format=webp&quality=lossless&width=579&height=579",
"favorite": false
},
{
"group": "MYEEchel Câble",
"date":"Nantes",
"nationality": "French",
"location": "ElectrYEEcien",
"price": 22,
"ticketsLeft": 400,
"Image": "https://media.discordapp.net/attachments/1415267028201246812/1424826240090509332/7fdbfe06-8300-441e-81ac-87851d004dc3.png?ex=68e9f997&is=68e8a817&hm=cc71621c3e7c3c1aaeda5555e9dd4204d43414cd0332c2b116b10d009b68df3c&=&format=webp&quality=lossless&width=579&height=579",
"favorite": false
},
{
"group": "PYEErre soulever",
"date":"Redon",
"nationality": "French",
"location": "GrutYEEr",
"price": 32,
"ticketsLeft": 0,
"Image": "https://media.discordapp.net/attachments/1425108443571945644/1427207643180826757/raw.png?ex=68ee0632&is=68ecb4b2&hm=1efc51065c6abfb1af75b8382f9924c2eb177c7d7672f7ed9837e96ef3076d16&=&format=webp&quality=lossless&width=233&height=350",
"favorite": false
},
{
"group": "Greg NegatYEEf",
"date":"Pacé",
"nationality": "French",
"location": "ElectrYEEcien",
"price": 20,
"ticketsLeft": 36,
"Image": "https://media.discordapp.net/attachments/1415267028201246812/1424826240090509332/7fdbfe06-8300-441e-81ac-87851d004dc3.png?ex=68e9f997&is=68e8a817&hm=cc71621c3e7c3c1aaeda5555e9dd4204d43414cd0332c2b116b10d009b68df3c&=&format=webp&quality=lossless&width=579&height=579",
"favorite": true
}
]

View File

@@ -1,4 +1,4 @@
import { addDoc, arrayUnion, collection, doc, getDoc, getDocs, Timestamp, updateDoc } from "firebase/firestore";
import { addDoc, arrayUnion, collection, doc, Firestore, getDoc, getDocs, Timestamp, updateDoc, DocumentReference } from "firebase/firestore";
import { Chantier, Reservation, Ressources, User } from "../class/class";
import { db } from "../firebase_config";
@@ -28,6 +28,7 @@ export async function getRessources(): Promise<Ressources[]> {
return snapshot.docs.map((doc) => {
const data = doc.data();
return {
id: doc.id,
...data,
allocation: data.allocation?.map(convertReservation) || [],
} as Ressources;
@@ -66,22 +67,46 @@ export async function getChantiers(): Promise<Chantier[]> {
chef = chefSnap.data() as User;
}
}
let equipe: User[] = [];
let equipe: Reservation[] = [];
if (Array.isArray(data.equipe)) {
equipe = await Promise.all(
data.equipe.map(async (ref: any) => {
const snap = await getDoc(ref);
return snap.exists() ? (snap.data() as User) : null;
return snap.exists() ? (snap.data() as Reservation) : null;
})
).then(list => list.filter(x => x !== null)) as User[];
).then(list => list.filter(x => x !== null)) as Reservation[];
}
let vehicules: Reservation[] = [];
if (Array.isArray(data.vehicules)) {
vehicules = await Promise.all(
data.vehicules.map(async (ref: any) => {
const snap = await getDoc(ref);
return snap.exists() ? (snap.data() as Reservation) : null;
})
).then(list => list.filter(x => x !== null)) as Reservation[];
}
let materiel: Reservation[] = [];
if (Array.isArray(data.materiel)) {
materiel = await Promise.all(
data.materiel.map(async (ref: any) => {
const snap = await getDoc(ref);
return snap.exists() ? (snap.data() as Reservation) : null;
})
).then(list => list.filter(x => x !== null)) as Reservation[];
}
chantiers.push({
...data,
id: docSnap.id,
dateDep,
chef,
equipe
equipe,
vehicules,
materiel,
} as Chantier);
}
return chantiers;
@@ -144,12 +169,58 @@ export async function deleteAnomalie(chantierId: string, anomalie_String: string
}
}
function convertReservation(res: any): Reservation {
type ReservationFirestore = {
chantier: DocumentReference;
ressource: DocumentReference;
quantity: number;
};
async function convertReservation(res: any): Promise<Reservation> {
const data = res.data() as ReservationFirestore;
const chantierSnap = await getDoc(data.chantier as DocumentReference);
const ressourceSnap = await getDoc(data.ressource as DocumentReference);
return {
id: res.id,
dateChantier:
res.dateChantier instanceof Timestamp ? res.dateChantier.toDate() : new Date(res.dateChantier),
dateFin:
res.dateFin instanceof Timestamp ? res.dateFin.toDate() : new Date(res.dateFin),
chantier: chantierSnap.data() as Chantier,
ressource: ressourceSnap.data() as Ressources,
quantity: data.quantity,
};
}
//ENVOYER CHANTIER
export async function sendNewChantier(chantier:Chantier): Promise<void> {
const chantierRef = await addDoc(collection(db, "chantier"), {
name:chantier.name,
adresse:chantier.adresse,
etat:chantier.etat,
contact:chantier.contact,
chef: doc(db, "users", chantier.chef.id), //un objet déjà dans la base de donné
date: Timestamp.fromDate(chantier.dateDep),
tempsEst: chantier.tempsEst,
anomalies: chantier.anomalies ?? [], //strings[]
latitude: chantier.latitude,
longitude: chantier.longitude,
})
await Promise.all([
sendNewReservation(chantier.equipe, chantierRef.id),
sendNewReservation(chantier.materiel, chantierRef.id),
sendNewReservation(chantier.vehicules, chantierRef.id),
]);
}
export async function sendNewReservation(list: Reservation[],chantierId:string): Promise<void> {
const promises = list.map((reservation) =>
addDoc(collection(db,"Reservation"),{
chantier: doc(db, "chantier", chantierId),
ressource: doc(db, "ressources", reservation.ressource.id),
quantity: reservation.quantity,
})
);
await Promise.all(promises);
}