diff --git a/app/(tabs)/bonjourFL.tsx b/app/(tabs)/bonjourFL.tsx
index 4acb71a..21ef451 100644
--- a/app/(tabs)/bonjourFL.tsx
+++ b/app/(tabs)/bonjourFL.tsx
@@ -1,15 +1,14 @@
-import SelectChantier from '@/components/selectChantier';
-import { ThemedText } from '@/components/themed-text';
-import { ThemedTextInput } from '@/components/themed-textinput';
-import { ThemedView } from '@/components/themed-view';
-import Constants from 'expo-constants'; //pour connaître la taille de la barre menu de l'OS en haut
-import { useLocalSearchParams, useRouter } from 'expo-router';
-import React, { useMemo, useState } from 'react';
-import { Button, FlatList, Image, StyleSheet, Text } from 'react-native';
-import rawConcerts from '../../data/concerts.json';
-
-import { useChantier } from '../ContextChantier';
+import SelectChantier from "@/components/selectChantier";
+import { ThemedText } from "@/components/themed-text";
+import { ThemedTextInput } from "@/components/themed-textinput";
+import { ThemedView } from "@/components/themed-view";
+import Constants from "expo-constants"; //pour connaître la taille de la barre menu de l'OS en haut
+import { useLocalSearchParams, useRouter } from "expo-router";
+import React, { useMemo, useState } from "react";
+import { FlatList, Image, StyleSheet, Text } from "react-native";
+import rawConcerts from "../../data/concerts.json";
+import { useChantier } from "../ContextChantier";
type Concert = {
group: string;
@@ -23,14 +22,11 @@ type Concert = {
};
export default function BonjourScreen() {
-
const router = useRouter();
const { nom, prenom } = useLocalSearchParams(); // Recup data ecran precedent
- const [search, setSearch] = useState('');
+ const [search, setSearch] = useState("");
const { chantier, setChantier } = useChantier();
-
-
const concertsData: Concert[] = Array.isArray(rawConcerts)
? (rawConcerts as Concert[])
: [];
@@ -40,32 +36,29 @@ export default function BonjourScreen() {
const q = search.trim().toLowerCase();
if (!q) return concertsData;
return concertsData.filter(
- (item) => !!item && (item.group ?? '').toLowerCase().includes(q)
+ (item) => !!item && (item.group ?? "").toLowerCase().includes(q)
);
}, [concertsData, search]);
-
- const renderItem = ({ item, index }: { item?: Concert; index: number }) => {
+ const renderItem = ({ item, index }: { item?: Concert; index: number }) => {
if (!item) {
return null;
}
- return(
-
-
-
- {item.group}
- {item.date}
- {item.location}
- Prix : {item.price} €
- Places restantes : {item.ticketsLeft}
+ return (
+
+
+
+ {item.group}
+ {item.date}
+ {item.location}
+ Prix : {item.price} €
+ Places restantes : {item.ticketsLeft}
+
- );
+ );
};
-
-
-
- return(
+ return (
- Bonjour {prenom} {nom} {chantier&&chantier.chef.nom}
+ Bonjour {prenom} {nom} {chantier && chantier.chef.name}
@@ -94,14 +87,17 @@ export default function BonjourScreen() {
}
/>
-
-
-
-
+
+
-
- )
+ );
}
const styles = StyleSheet.create({
@@ -113,21 +109,21 @@ const styles = StyleSheet.create({
header: {
marginTop: 60,
marginBottom: 20,
- alignItems: 'center',
+ alignItems: "center",
paddingHorizontal: 20,
},
text: {
fontSize: 22,
- fontWeight: 'bold',
+ fontWeight: "bold",
marginBottom: 10,
},
- inputBack:{
- width:"100%",
- borderRadius:10,
- backgroundColor:'transparent'
+ inputBack: {
+ width: "100%",
+ borderRadius: 10,
+ backgroundColor: "transparent",
},
input: {
- width: '100%',
+ width: "100%",
//borderWidth: 1,
//borderColor: '#ccc',
borderRadius: 10,
@@ -135,7 +131,7 @@ const styles = StyleSheet.create({
fontSize: 16,
},
card: {
- flexDirection: 'row',
+ flexDirection: "row",
marginHorizontal: 20,
marginBottom: 15,
//borderWidth: 1,
@@ -143,7 +139,6 @@ const styles = StyleSheet.create({
borderRadius: 10,
padding: 10,
//backgroundColor: '#fafafa',
-
},
image: {
width: 80,
@@ -153,10 +148,10 @@ const styles = StyleSheet.create({
},
info: {
flex: 1,
- justifyContent: 'center',
+ justifyContent: "center",
},
group: {
- fontWeight: 'bold',
+ fontWeight: "bold",
fontSize: 16,
marginBottom: 5,
},
@@ -164,8 +159,8 @@ const styles = StyleSheet.create({
padding: 20,
},
empty: {
- textAlign: 'center',
+ textAlign: "center",
marginTop: 30,
- color: '#888',
+ color: "#888",
},
-});
\ No newline at end of file
+});
diff --git a/app/(tabs)/gestionnaire_ressource.tsx b/app/(tabs)/gestionnaire_ressource.tsx
index deffbd7..ce31b48 100644
--- a/app/(tabs)/gestionnaire_ressource.tsx
+++ b/app/(tabs)/gestionnaire_ressource.tsx
@@ -1,22 +1,24 @@
-import { useRouter, useLocalSearchParams } from "expo-router";
-import { navigate } from "expo-router/build/global-state/routing";
+import { ThemedText } from "@/components/themed-text";
+import { ThemedTextInput } from '@/components/themed-textinput';
+import { ThemedView } from "@/components/themed-view";
+import { useLocalSearchParams, useRouter } from "expo-router";
+
import React, { useEffect, useState } from "react";
import {
Button,
FlatList,
Image,
- Text,
- TextInput,
- View,
StyleSheet,
+ Text
} from "react-native";
import { getRessources, Ressource } from "../../services/ressourcesService";
export default function GestionnaireRessource() {
- const { nom, prenom } = useLocalSearchParams(); // Recup data ecran precedent
+ const { nom, prenom } = useLocalSearchParams();
const [search, setSearch] = useState("");
const [ressource, setRessources] = useState([]);
const [loading, setLoading] = useState(true);
+
const router = useRouter();
useEffect(() => {
@@ -25,12 +27,11 @@ export default function GestionnaireRessource() {
const data = await getRessources();
setRessources(data);
} catch (error) {
- console.error("Erreur lors du chargement des ressources :", error);
+ console.error("Erreur lors du chargement :", error);
} finally {
setLoading(false);
}
}
-
loadData();
}, []);
@@ -38,73 +39,66 @@ export default function GestionnaireRessource() {
r.name.toLowerCase().includes(search.toLowerCase())
);
- const renderRessource = ({
- item,
- index,
- }: {
- item?: Ressource;
- index: number;
- }) => {
- if (!item) {
- // optionnel : afficher un placeholder pour debug
- // return Item manquant;
- return null;
- }
+ const renderRessource = ({ item }: { item: Ressource }) => {
+ if (!item) return null;
+
return (
-
-
-
+
+
+
{item.id}
{item.name}
{item.type}
{item.quantity}
{item.available_quantity}
-
-
+
+
);
};
return (
-
+
index.toString()}
contentContainerStyle={{ paddingBottom: 40 }}
ListHeaderComponent={
-
+
Bonjour {prenom} {nom}
- {/* 🔍 Champ de recherche */}
-
-
+ {/* Input background */}
+
+
+
+
}
ListEmptyComponent={
- Aucun résultat trouvé 😕
+ Aucun résultat trouvé 😕
}
/>
-
+
-
+
+
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
- backgroundColor: "#fff",
},
header: {
marginTop: 60,
@@ -117,10 +111,12 @@ const styles = StyleSheet.create({
fontWeight: "bold",
marginBottom: 10,
},
+ inputBack: {
+ width: "100%",
+ borderRadius: 10,
+ },
input: {
width: "100%",
- borderWidth: 1,
- borderColor: "#ccc",
borderRadius: 10,
padding: 10,
fontSize: 16,
@@ -129,11 +125,8 @@ const styles = StyleSheet.create({
flexDirection: "row",
marginHorizontal: 20,
marginBottom: 15,
- borderWidth: 1,
- borderColor: "#ddd",
borderRadius: 10,
padding: 10,
- backgroundColor: "#fafafa",
},
image: {
width: 80,
@@ -145,11 +138,6 @@ const styles = StyleSheet.create({
flex: 1,
justifyContent: "center",
},
- group: {
- fontWeight: "bold",
- fontSize: 16,
- marginBottom: 5,
- },
footer: {
padding: 20,
},
diff --git a/app/ContextChantier.tsx b/app/ContextChantier.tsx
index 4809d5c..7adfdc3 100644
--- a/app/ContextChantier.tsx
+++ b/app/ContextChantier.tsx
@@ -1,5 +1,5 @@
-import { Chantier, Chef, exempleChantier } from '@/class/class';
-import { createContext, ReactNode, useContext, useMemo, useState } from 'react';
+import { Chantier } from "@/class/class";
+import { createContext, ReactNode, useContext, useMemo, useState } from "react";
type ChantierContextType = {
chantier: Chantier | null;
@@ -15,10 +15,7 @@ type ChantierProviderProps = {
export const ChantierProvider = ({ children }: ChantierProviderProps) => {
const [chantier, setChantier] = useState(null);
- const value = useMemo(
- () => ({ chantier, setChantier }),
- [chantier]
- );
+ const value = useMemo(() => ({ chantier, setChantier }), [chantier]);
return (
@@ -30,7 +27,7 @@ export const ChantierProvider = ({ children }: ChantierProviderProps) => {
export const useChantier = () => {
const context = useContext(ChantierContext);
if (!context) {
- throw new Error('useChantier doit être utilisé dans ');
+ throw new Error("useChantier doit être utilisé dans ");
}
return context;
-};
\ No newline at end of file
+};
diff --git a/class/class.tsx b/class/class.tsx
index 98c3e8b..c9b589f 100644
--- a/class/class.tsx
+++ b/class/class.tsx
@@ -1,155 +1,125 @@
-export class Chantier{
- id: number;
- adresse: string;
- etat: string;
- contact: string;
- chef: Chef;
- equipe : Equipier[];
- materiel : Materiel[];
- dateDep : string;
- tempsEst : number;
- vehicules : Vehicule[];
- anomalies : string[];
- urlImg : string;
+import { collection, getDocs, Timestamp } from "firebase/firestore";
+import { db } from "../firebase_config";
- constructor(
- id: number,
- adresse: string,
- etat: string,
- contact: string,
- chef: Chef,
- equipe: Equipier[],
- materiel: Materiel[],
- dateDep: string,
- tempsEst: number,
- vehicules: Vehicule[],
- anomalies: string[],
- urlImg: string
- ) {
- this.id = id;
- this.adresse = adresse;
- this.etat = etat;
- this.contact = contact;
- this.chef = chef;
- this.equipe = equipe;
- this.materiel = materiel;
- this.dateDep = dateDep;
- this.tempsEst = tempsEst;
- this.vehicules = vehicules;
- this.anomalies = anomalies;
- this.urlImg = urlImg;
- }
+export type Chantier = {
+ id: number;
+ adresse: string;
+ etat: string;
+ contact: string;
+ chef: User;
+ equipe: User[];
+ materiel: Ressources[];
+ dateDep: Date;
+ tempsEst: number;
+ vehicules: Ressources[];
+ anomalies: string[];
+};
+
+export async function getChantiers(): Promise {
+ try {
+ const colRef = collection(db, "chantier");
+ const snapshot = await getDocs(colRef);
+ return snapshot.docs.map((doc) => {
+ const data = doc.data() as any;
+ return {
+ ...data,
+ chef: {
+ ...data.chef,
+ allocation: data.chef?.allocation?.map(convertReservation) || [],
+ },
+ equipe:
+ data.equipe?.map((u: any) => ({
+ ...u,
+ allocation: u.allocation?.map(convertReservation) || [],
+ })) || [],
+ materiel:
+ data.materiel?.map((m: any) => ({
+ ...m,
+ allocation: m.allocation?.map(convertReservation) || [],
+ })) || [],
+ vehicules:
+ data.vehicules?.map((v: any) => ({
+ ...v,
+ allocation: v.allocation?.map(convertReservation) || [],
+ })) || [],
+ anomalies: data.anomalies || [],
+ } as Chantier;
+ });
+ } catch (err) {
+ console.error("Firestore Chantiers Error:", err);
+ return [];
+ }
}
-export abstract class Equipier{
- id: number;
- nom: string;
- prenom: string;
- allocation: Reservation[];
+export type User = {
+ id: string;
+ name: string;
+ last_name: string;
+ allocation: Reservation[];
+ role: string;
+ qualifications: string;
+};
- constructor(id: number, nom:string, prenom:string, allocation: Reservation[]){
- this.id = id;
- this.nom = nom;
- this.prenom = prenom;
- this.allocation = allocation;
- }
+export async function getUsers(): Promise {
+ try {
+ const colRef = collection(db, "user");
+ const snapshot = await getDocs(colRef);
+ return snapshot.docs.map((doc) => {
+ const data = doc.data();
+ return {
+ ...data,
+ allocation: data.allocation?.map(convertReservation) || [],
+ } as User;
+ });
+ } catch (err) {
+ console.error("Firestore Users Error:", err);
+ return [];
+ }
}
-export class Chef extends Equipier{
- constructor(id: number, nom:string, prenom:string, allocation: Reservation[]){
- super(id,nom,prenom,allocation);
- }
+export type Ressources = {
+ id: number;
+ name: string;
+ type: string;
+ Image: string;
+ quantity: number;
+ available_quantity: number;
+ allocation: Reservation[];
+};
+
+export async function getRessources(): Promise {
+ try {
+ const colRef = collection(db, "ressources");
+ const snapshot = await getDocs(colRef);
+ return snapshot.docs.map((doc) => {
+ const data = doc.data();
+ return {
+ ...data,
+ allocation: data.allocation?.map(convertReservation) || [],
+ } as Ressources;
+ });
+ } catch (err) {
+ console.error("Firestore Ressources Error:", err);
+ return [];
+ }
}
-export class Ouvrier extends Equipier{
- qualification : string;
+export type Reservation = {
+ id: string;
+ dateChantier: Date;
+ dateFin: Date;
+};
- constructor(id: number, nom:string, prenom:string, allocation: Reservation[], qualification: string){
- super(id,nom,prenom,allocation);
- this.qualification=qualification;
- }
+function convertReservation(res: any): Reservation {
+ 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),
+ };
}
-
-export class ResponsableChantier extends Equipier{
- constructor(id: number, nom:string, prenom:string, allocation: Reservation[]){
- super(id,nom,prenom,allocation);
- }
-}
-
-export class Materiel {
- id: number;
- nom: string;
- prenom: string;
- type: string;
- allocation: Reservation[];
-
- constructor(
- id: number,
- nom: string,
- prenom: string,
- type: string,
- allocation: Reservation[]
- ) {
- this.id = id;
- this.nom = nom;
- this.prenom = prenom;
- this.type = type;
- this.allocation = allocation;
- }
-}
-
-
-export class Reservation {
- id: string;
- dateChantier: Date;
- dateFin: Date;
- duree: number;
-
- constructor(
- id: string,
- dateChantier: Date,
- dateFin: Date,
- duree: number
- ) {
- this.id = id;
- this.dateChantier = dateChantier;
- this.dateFin = dateFin;
- this.duree = duree;
- }
-}
-
-
-export class Vehicule {
- id: number;
- nom: string;
- type: string;
- allocation: Reservation[];
-
- constructor(
- id: number,
- nom: string,
- type: string,
- allocation: Reservation[]
- ) {
- this.id = id;
- this.nom = nom;
- this.type = type;
- this.allocation = allocation;
- }
-}
-
-
-export const exempleChantier = new Chantier(
- 1,
- "Rennes",
- "en cours",
- "contact",
- new Chef(1,"Chyeef","YEE",[]),
- [],
- [],
- "01/01/25",
- 10,
- [],
- ["YEE"],
- "https://cdn.discordapp.com/attachments/1425108443571945644/1427207643180826757/raw.png?ex=69392bb2&is=6937da32&hm=dcc09e76d3dca89d2418947b46efbd38673b9dc559027724b2e51d493b173bc9&"
-)
diff --git a/components/selectChantier.tsx b/components/selectChantier.tsx
index 24de27b..521f5d4 100644
--- a/components/selectChantier.tsx
+++ b/components/selectChantier.tsx
@@ -1,16 +1,25 @@
-import { useChantier } from '@/app/ContextChantier';
-import { Chantier, exempleChantier } from '@/class/class';
-import { useState } from 'react';
-import { Dimensions, Image, LayoutAnimation, Pressable, ScrollView, StyleSheet, View } from 'react-native';
-import Animated, { LinearTransition } from 'react-native-reanimated';
-import { ThemedButton } from './themed-button';
-import { ThemedText } from './themed-text';
-import { ThemedTextInput } from './themed-textinput';
+import { useChantier } from "@/app/ContextChantier";
+import { Chantier, getChantiers } from "@/class/class";
+import { useEffect, useState } from "react";
+import {
+ Dimensions,
+ Image,
+ LayoutAnimation,
+ Pressable,
+ ScrollView,
+ StyleSheet,
+ View
+} from "react-native";
+import Animated, {
+ LinearTransition
+} from "react-native-reanimated";
+import { ThemedButton } from "./themed-button";
+import { ThemedText } from "./themed-text";
+import { ThemedTextInput } from "./themed-textinput";
import { ThemedView } from "./themed-view";
const screenHeight = Dimensions.get("window").height;
-
/*
@@ -20,136 +29,123 @@ const screenHeight = Dimensions.get("window").height;
*/
export default function SelectChantier() {
+ const { chantier, setChantier } = useChantier();
+ const [search, setSearch] = useState("");
+ const [isOpen, setIsOpen] = useState(false);
+ const [chantiers, setChantiers] = useState([]);
- const { chantier, setChantier } = useChantier();
- const [search, setSearch] = useState('');
- const [isOpen,setIsOpen] = useState(false);
- const [chantiers,setChantiers] = useState([exempleChantier,exempleChantier,exempleChantier,exempleChantier,exempleChantier,exempleChantier]);
-
- const AnimatedThemedView = Animated.createAnimatedComponent(ThemedView);
- const AnimatedThemedText = Animated.createAnimatedComponent(ThemedText);
- const AnimatedThemedButton = Animated.createAnimatedComponent(ThemedButton);
- const AnimatedThemedTextInput = Animated.createAnimatedComponent(ThemedTextInput);
+ const AnimatedThemedView = Animated.createAnimatedComponent(ThemedView);
+ const AnimatedThemedText = Animated.createAnimatedComponent(ThemedText);
+ const AnimatedThemedButton = Animated.createAnimatedComponent(ThemedButton);
+ const AnimatedThemedTextInput =
+ Animated.createAnimatedComponent(ThemedTextInput);
function onPressOpen(): void {
- LayoutAnimation.configureNext(
- LayoutAnimation.Presets.easeInEaseOut
- );
+ LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setIsOpen(!isOpen);
}
+ useEffect(() => {
+ async function loadChantiers() {
+ const list = await getChantiers();
+ setChantiers(list);
+ }
+
+ loadChantiers();
+ }, []);
+
function selectChantier(chantier: Chantier): void {
setChantier(chantier);
setIsOpen(false);
}
-
-
- const renderChantier = (chantier:Chantier, index: number) => {
- return(
- selectChantier(chantier)}>
-
-
-
-
-
-
- Adresse: {chantier.adresse}
- Chef de chantier: {chantier.chef.prenom} {chantier.chef.nom}
- Date de début: {chantier.dateDep}
- Etat: {chantier.etat}
-
-
-
- );
-
- };
-
-
- return(
-
-
-
- onPressOpen()}>
- {isOpen ? "Fermer" : "Chantiers"}
-
- {isOpen &&
-
-
-
-
-
- {chantiers.map((chantier, index) => (
- renderChantier(chantier, index)
- ))
- }
-
-
+ const renderChantier = (chantier: Chantier, index: number) => {
+ return (
+ selectChantier(chantier)}>
+
+
+
- }
-
-
- )
-
+
+ Adresse: {chantier.adresse}
+ Chef de chantier: {chantier.chef.last_name}{" "}{chantier.chef.name}
+ État: {chantier.etat}
+
+
+
+ );
+ };
+
+ return (
+
+
+ onPressOpen()}>
+
+ {isOpen ? "Fermer" : "Chantier"}
+
+
+ {isOpen && (
+
+
+
+
+ {chantiers.map((chantier, index) =>
+ renderChantier(chantier, index)
+ )}
+
+
+
+ )}
+
+
+ );
}
const styles = StyleSheet.create({
-
- windowClose:{
+ windowClose: {
//backgroundColor: '#00FFFF',
//borderRadius:10,
padding: 10,
- width:"50%",
- height:60,
- overflow: 'hidden',
+ width: "50%",
+ height: 60,
+ overflow: "hidden",
},
- windowOpean:{
+ windowOpean: {
//backgroundColor: '#00FFFF',
//borderRadius:10,
- width:"100%",
- height: screenHeight/2,
+ width: "100%",
+ height: screenHeight / 2,
padding: 10,
},
- window:{
- borderRadius:15,
+ window: {
+ borderRadius: 15,
height: "100%",
//backgroundColor: '#00FF00',
- overflow: 'hidden',
+ overflow: "hidden",
},
- menu:{
- padding:5,
- flex: 1,
+ menu: {
+ padding: 5,
+ flex: 1,
minHeight: 0,
//backgroundColor:'#FF00FF',
},
- list:{
+ list: {
flex: 1,
- overflow: 'hidden',
- borderRadius:10,
-
+ overflow: "hidden",
+ borderRadius: 10,
},
- chantiersList:{
+ chantiersList: {
//padding:5,
//backgroundColor:'0000FF',
//flexDirection: 'row',
//alignItems: 'center',
gap: 8,
-
},
- chantier:{
- padding:5,
+ chantier: {
+ padding: 5,
//marginTop:5,
//margin:5,
- borderRadius:10,
+ borderRadius: 10,
//borderWidth: 1,
flexDirection: 'row',
height: 100,
@@ -162,28 +158,28 @@ const styles = StyleSheet.create({
marginRight: 10,
},
input: {
- width: '100%',
+ width: "100%",
borderWidth: 1,
borderRadius: 10,
padding: 10,
fontSize: 16,
- marginBottom:10,
+ marginBottom: 10,
},
- buttonClose:{
- width:'100%',
+ buttonClose: {
+ width: "100%",
margin: 0,
borderRadius: 15,
padding: 10,
- height:40,
+ height: 40,
},
- buttonOpen:{
- width:'50%',
+ buttonOpen: {
+ width: "50%",
margin: 5,
borderRadius: 10,
padding: 10,
- height:40,
+ height: 40,
+ },
+ buttonText: {
+ textAlign: "center",
},
- buttonText:{
- textAlign: 'center',
- }
});
diff --git a/services/ressourcesService.ts b/services/ressourcesService.ts
index a102e79..a47406c 100644
--- a/services/ressourcesService.ts
+++ b/services/ressourcesService.ts
@@ -1,4 +1,4 @@
-import { collection, getDocs } from "firebase/firestore";
+import { collection, getDocs, doc, updateDoc } from "firebase/firestore";
import { db } from "../firebase_config";
export type Ressource = {