diff --git a/app/(tabs)/bonjourFL.tsx b/app/(tabs)/bonjourFL.tsx index a0581c3..956b65d 100644 --- a/app/(tabs)/bonjourFL.tsx +++ b/app/(tabs)/bonjourFL.tsx @@ -1,16 +1,15 @@ -import SelectChantier from '@/components/selectChantier'; -import { ThemedText } from '@/components/themed-text'; -import { ThemedTextInput } from '@/components/themed-textinpute'; -import { ThemedView } from '@/components/themed-view'; -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 Constants from 'expo-constants' //pour connaître la taille de la barre menu de l'OS en haut - -import Example from '@/components/example'; -import { useChantier } from '../Context'; +import SelectChantier from "@/components/selectChantier"; +import { ThemedText } from "@/components/themed-text"; +import { ThemedTextInput } from "@/components/themed-textinpute"; +import { ThemedView } from "@/components/themed-view"; +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 Constants from "expo-constants"; //pour connaître la taille de la barre menu de l'OS en haut +import Example from "@/components/example"; +import { useChantier } from "../Context"; type Concert = { group: string; @@ -24,14 +23,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[]) : []; @@ -41,32 +37,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} @@ -95,14 +88,17 @@ export default function BonjourScreen() { } /> - - - - + + - - ) + ); } const styles = StyleSheet.create({ @@ -114,21 +110,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, @@ -136,7 +132,7 @@ const styles = StyleSheet.create({ fontSize: 16, }, card: { - flexDirection: 'row', + flexDirection: "row", marginHorizontal: 20, marginBottom: 15, //borderWidth: 1, @@ -144,7 +140,6 @@ const styles = StyleSheet.create({ borderRadius: 10, padding: 10, //backgroundColor: '#fafafa', - }, image: { width: 80, @@ -154,10 +149,10 @@ const styles = StyleSheet.create({ }, info: { flex: 1, - justifyContent: 'center', + justifyContent: "center", }, group: { - fontWeight: 'bold', + fontWeight: "bold", fontSize: 16, marginBottom: 5, }, @@ -165,8 +160,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/Context.tsx b/app/Context.tsx index 4809d5c..7adfdc3 100644 --- a/app/Context.tsx +++ b/app/Context.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 24ff68a..8109be0 100644 --- a/class/class.tsx +++ b/class/class.tsx @@ -1,139 +1,126 @@ -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[]; +import { collection, getDocs, doc, updateDoc } from "firebase/firestore"; +import { db } from "../firebase_config"; +import { Timestamp } from "firebase/firestore"; - constructor( - id: number, - adresse: string, - etat: string, - contact: string, - chef: Chef, - equipe: Equipier[], - materiel: Materiel[], - dateDep: string, - tempsEst: number, - vehicules: Vehicule[], - anomalies: 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; - } +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, "chantiers"); + 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, "users"); + 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"]) diff --git a/components/selectChantier.tsx b/components/selectChantier.tsx index d486313..0dd5100 100644 --- a/components/selectChantier.tsx +++ b/components/selectChantier.tsx @@ -1,17 +1,30 @@ -import { useState } from 'react'; -import { Button, GestureResponderEvent, Pressable, ScrollView, StyleSheet, View, LayoutAnimation } from 'react-native'; -import { ThemedTextInput } from './themed-textinpute'; +import { useState, useEffect } from "react"; +import { + Button, + GestureResponderEvent, + Pressable, + ScrollView, + StyleSheet, + View, + LayoutAnimation, +} from "react-native"; +import { ThemedTextInput } from "./themed-textinpute"; import { ThemedView } from "./themed-view"; -import { ThemedText } from './themed-text'; -import { ThemedButton } from './themed-button'; -import { Chantier, Chef, exempleChantier } from '@/class/class'; +import { ThemedText } from "./themed-text"; +import { ThemedButton } from "./themed-button"; +import { Chantier, User } from "@/class/class"; import { Dimensions } from "react-native"; -import Animated, { Layout,LinearTransition,Easing,runOnJS } from 'react-native-reanimated'; -import { useChantier } from '@/app/Context'; +import Animated, { + Layout, + LinearTransition, + Easing, + runOnJS, +} from "react-native-reanimated"; +import { useChantier } from "@/app/Context"; +import { getChantiers } from "@/class/class"; const screenHeight = Dimensions.get("window").height; - /* @@ -21,156 +34,174 @@ 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 ( + + {chantiers + .filter((c) => c.adresse.toLowerCase().includes(search.toLowerCase())) + .map((chantier, index) => ( + selectChantier(chantier)}> + + Adresse: {chantier.adresse} + + Chef de chantier: {chantier.chef.last_name}{" "} + {chantier.chef.name} + + + Date de début: {chantier.dateDep.toLocaleDateString()} + + État: {chantier.etat} + + + ))} + + ); + }; - - 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 ? "Close" : "Open"} - - {isOpen && - - - - - - {chantiers.map((chantier, index) => ( - renderChantier(chantier, index) - )) - } - - - - } - - - ) - + style={isOpen ? styles.windowOpean : styles.windowClose} + > + + onPressOpen()} + > + + {isOpen ? "Close" : "Open"} + + + {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, - }, 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 = {