Compare commits
7 Commits
reservatio
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
677972626f | ||
|
|
b7eb0be157 | ||
|
|
41b2b58102 | ||
|
|
5271fe1f54 | ||
|
|
3296d301ee | ||
|
|
707ae1dc30 | ||
|
|
0de6462c31 |
11
README.md
11
README.md
@@ -27,7 +27,7 @@ npx expo start
|
|||||||
#### Présentation de l'application :
|
#### Présentation de l'application :
|
||||||
|
|
||||||
##### 5 écrans :
|
##### 5 écrans :
|
||||||
Accuil :
|
Accueil :
|
||||||
- Affiche le chantier sélectionné :
|
- Affiche le chantier sélectionné :
|
||||||
- Résumé du chantier
|
- Résumé du chantier
|
||||||
- état éditable par l'utilisateur
|
- état éditable par l'utilisateur
|
||||||
@@ -36,15 +36,20 @@ Accuil :
|
|||||||
|
|
||||||
Ressources :
|
Ressources :
|
||||||
|
|
||||||
Ouvriers :
|
Permet de voir les ressources enregistrées dans la base de données et leurs différentes données (Nom , Type, quantité totale et quantité disponible). On peut rechercher par le nom et un filtre est aussi disponible pour affiner la recherche.
|
||||||
|
|
||||||
|
Users :
|
||||||
|
Permet de voir les différents utilisateurs enregistrés dans la base de données, ainsi que leur rang (chef ou responsable).
|
||||||
|
|
||||||
MapScreen :
|
MapScreen :
|
||||||
|
|
||||||
|
Permet de voir les différents chantiers sur une carte avec leurs adresses et leur état.
|
||||||
|
|
||||||
Ajouter :
|
Ajouter :
|
||||||
Permet d'ajouter un chantier ou une ressource (ouvrier,véhicule,outil)
|
Permet d'ajouter un chantier ou une ressource (ouvrier,véhicule,outil)
|
||||||
##### Fonctionnalité manquante :
|
##### Fonctionnalité manquante :
|
||||||
|
|
||||||
Par manque de temps nous n'avons pas peu finnalité certaine fonctionnalité
|
Par manque de temps nous n'avons pas pu finaliser certaines fonctionnalités
|
||||||
|
|
||||||
- possibilité de modifier les ressources d'un chantier (ex : réajustement des besoins)
|
- possibilité de modifier les ressources d'un chantier (ex : réajustement des besoins)
|
||||||
- modifier la quantité totale d'une ressource (ex : restock de ressources)
|
- modifier la quantité totale d'une ressource (ex : restock de ressources)
|
||||||
|
|||||||
@@ -1,33 +1,27 @@
|
|||||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
|
||||||
import { } from 'expo-router';
|
|
||||||
import React from 'react';
|
|
||||||
import { HapticTab } from '@/components/expoExempleComponents/haptic-tab';
|
import { HapticTab } from '@/components/expoExempleComponents/haptic-tab';
|
||||||
import { IconSymbol } from '@/components/ui/icon-symbol';
|
import { IconSymbol } from '@/components/ui/icon-symbol';
|
||||||
import { Colors } from '@/constants/theme';
|
import { Colors } from '@/constants/theme';
|
||||||
import { useColorScheme } from '@/hooks/use-color-scheme';
|
import { useColorScheme } from '@/hooks/use-color-scheme';
|
||||||
import GestionOuvrier from './gestion_ouvrier';
|
|
||||||
import ListMateriel from './gestionnaire_ressource';
|
|
||||||
import Home from './home';
|
|
||||||
import MapScreen from './mapScreen';
|
|
||||||
import AntDesign from '@expo/vector-icons/AntDesign';
|
import AntDesign from '@expo/vector-icons/AntDesign';
|
||||||
import AddScreen from './addScreen';
|
import { Tabs } from 'expo-router';
|
||||||
|
import React from 'react';
|
||||||
const Tabs = createBottomTabNavigator();
|
import { useAuthHandler } from '../AuthHandler';
|
||||||
|
import { useUser } from '../ContextUser';
|
||||||
|
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
|
const { role } = useUser();
|
||||||
|
|
||||||
|
// Handle auth in tabs layout
|
||||||
|
useAuthHandler();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs.Navigator
|
<Tabs screenOptions={{tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint, headerShown: false, tabBarButton: HapticTab}}>
|
||||||
initialRouteName='explore'
|
<Tabs.Screen name="index" options={{ href: null}}/>
|
||||||
screenOptions={{
|
<Tabs.Screen name="explore" options={{ href: null }}/>
|
||||||
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
|
<Tabs.Screen name="templateSreen" options={{ href: null}}/>
|
||||||
headerShown: false,
|
|
||||||
tabBarButton: HapticTab,
|
|
||||||
}}>
|
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="home"
|
name="home"
|
||||||
component={Home}
|
|
||||||
options={{
|
options={{
|
||||||
title: 'Home',
|
title: 'Home',
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => (
|
||||||
@@ -37,7 +31,6 @@ export default function TabLayout() {
|
|||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="gestionnaire_ressource"
|
name="gestionnaire_ressource"
|
||||||
component={ListMateriel}
|
|
||||||
options={{
|
options={{
|
||||||
title: 'Ressources',
|
title: 'Ressources',
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => (
|
||||||
@@ -46,34 +39,29 @@ export default function TabLayout() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="GestionOuvrier"
|
name="gestion_user"
|
||||||
component={GestionOuvrier}
|
|
||||||
options={{
|
options={{
|
||||||
title: 'Ouvriers',
|
title: 'Users',
|
||||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name="person.fill" color={color} />,
|
tabBarIcon: ({ color }) => <IconSymbol size={28} name="person.fill" color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="explore"
|
name="mapScreen"
|
||||||
component={MapScreen}
|
|
||||||
options={{
|
options={{
|
||||||
title: 'MapScreen',
|
title: 'Map',
|
||||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
|
tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
</Tabs.Screen>
|
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="Ajouter"
|
name="addScreen"
|
||||||
component={AddScreen}
|
|
||||||
options={{
|
options={{
|
||||||
title: 'Ajouter',
|
title: 'Ajouter',
|
||||||
|
href: role === 'resp' ? '/(tabs)/addScreen' : null,
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => (
|
||||||
<AntDesign name="plus" size={24} color={color} />
|
<AntDesign name="plus" size={24} color={color} />
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
</Tabs.Navigator>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2,14 +2,11 @@ import { ThemedText } from "@/components/theme/themed-text";
|
|||||||
import { ThemedTextInput } from "@/components/theme/themed-textinput";
|
import { ThemedTextInput } from "@/components/theme/themed-textinput";
|
||||||
import { ThemedView } from "@/components/theme/themed-view";
|
import { ThemedView } from "@/components/theme/themed-view";
|
||||||
import Constants from "expo-constants"; //pour connaître la taille de la barre menu de l'OS en haut
|
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, { useEffect, useState } from "react";
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import { FlatList, StyleSheet, Text, View } from "react-native";
|
||||||
import { FlatList, Image, StyleSheet, Text, View } from "react-native";
|
|
||||||
import { getUsers } from "@/services/ressourcesService";
|
import { getUsers } from "@/services/ressourcesService";
|
||||||
import { useChantier } from "../ContextChantier";
|
|
||||||
import SelectChantier from "@/components/selectChantier";
|
import SelectChantier from "@/components/selectChantier";
|
||||||
import { Ressources } from "@/class/class";
|
import { User } from "@/class/class";
|
||||||
import { getRessources } from "@/services/ressourcesService";
|
|
||||||
|
|
||||||
type Concert = {
|
type Concert = {
|
||||||
group: string;
|
group: string;
|
||||||
@@ -22,19 +19,15 @@ type Concert = {
|
|||||||
favorite: boolean;
|
favorite: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function GestionOuvrier() {
|
export default function GestionUser() {
|
||||||
const router = useRouter();
|
|
||||||
const { nom, prenom } = useLocalSearchParams(); // Recup data ecran precedent
|
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const { chantier, setChantier } = useChantier();
|
const [users, setUsers] = useState<User[]>([]);
|
||||||
const [artisans, setRessources] = useState<Ressources[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
try {
|
try {
|
||||||
//Nous ne gardons que les Ouvriers, qui peuvent être assignés à un chantier
|
const data = (await getUsers());
|
||||||
const data = (await getRessources()).filter(u => u.type === "Ouvrier");
|
setUsers(data);
|
||||||
setRessources(data);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors du chargement :", error);
|
console.error("Erreur lors du chargement :", error);
|
||||||
}
|
}
|
||||||
@@ -42,17 +35,15 @@ export default function GestionOuvrier() {
|
|||||||
loadData();
|
loadData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const renderItem = ({ item, index }: { item?: Ressources; index: number }) => {
|
const renderItem = ({ item, index }: { item?: User; index: number }) => {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ThemedView lvl={1} shadow={true} style={styles.card}>
|
<ThemedView lvl={1} shadow={true} style={styles.card}>
|
||||||
<ThemedView lvl={1} style={styles.info}>
|
<ThemedView lvl={1} style={styles.info}>
|
||||||
<Image source={{ uri: item.Image }} style={styles.image} />
|
<ThemedText style={styles.group}>{item.name} {item.last_name}</ThemedText>
|
||||||
<ThemedText style={styles.group}>{item.name}</ThemedText>
|
<ThemedText>{item.role}</ThemedText>
|
||||||
<ThemedText>{item.quantity}</ThemedText>
|
|
||||||
<ThemedText>{item.type}</ThemedText>
|
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
);
|
);
|
||||||
@@ -67,7 +58,7 @@ export default function GestionOuvrier() {
|
|||||||
|
|
||||||
|
|
||||||
<FlatList
|
<FlatList
|
||||||
data={artisans}
|
data={users}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
keyExtractor={(_, index) => index.toString()}
|
keyExtractor={(_, index) => index.toString()}
|
||||||
contentContainerStyle={{ paddingBottom: 40 }}
|
contentContainerStyle={{ paddingBottom: 40 }}
|
||||||
@@ -8,19 +8,25 @@ import { useLocalSearchParams, useRouter } from "expo-router";
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { FlatList, Image, StyleSheet, Text, View } from "react-native";
|
import { FlatList, Image, StyleSheet, Text, View } from "react-native";
|
||||||
import { Ressources } from "../../class/class";
|
import { Ressources } from "../../class/class";
|
||||||
import { getRessources } from "../../services/ressourcesService";
|
import { getReservations, getRessources } from "../../services/ressourcesService";
|
||||||
import SelectChantier from "@/components/selectChantier";
|
import SelectChantier from "@/components/selectChantier";
|
||||||
import { useRessources } from "../ContextRessource";
|
import { useRessources } from "../ContextRessource";
|
||||||
|
import { useChantier } from "../ContextChantier";
|
||||||
|
import { getNbUseRessources, getNbUseRessourcesInChantier, isInChantier } from "@/class/utils";
|
||||||
|
import { useReservations } from "../ContextReservation";
|
||||||
|
|
||||||
export default function GestionnaireRessource() {
|
export default function GestionnaireRessource() {
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const {ressources, setRessources} = useRessources();
|
const {ressources, setRessources} = useRessources();
|
||||||
|
const {reservations, setReservations} = useReservations();
|
||||||
|
const {chantier, setChantier} = useChantier();
|
||||||
const [filterType, setFilterType] = useState("Tout");
|
const [filterType, setFilterType] = useState("Tout");
|
||||||
const [showFilterMenu, setShowFilterMenu] = useState(false);
|
const [showFilterMenu, setShowFilterMenu] = useState(false);
|
||||||
|
const [filterChantier, setFilterChantier] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function loadData() {
|
async function loadDataRessources() {
|
||||||
try {
|
try {
|
||||||
const data = await getRessources();
|
const data = await getRessources();
|
||||||
setRessources(data);
|
setRessources(data);
|
||||||
@@ -28,13 +34,23 @@ export default function GestionnaireRessource() {
|
|||||||
console.error("Erreur lors du chargement :", error);
|
console.error("Erreur lors du chargement :", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadData();
|
async function loadDataReservations() {
|
||||||
|
try {
|
||||||
|
const data = await getReservations();
|
||||||
|
setReservations(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors du chargement :", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadDataRessources();
|
||||||
|
loadDataReservations();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const filteredData = ressources.filter((r) => {
|
const filteredData = ressources.filter((r) => {
|
||||||
const matchName = r.name.toLowerCase().includes(search.toLowerCase());
|
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;
|
|
||||||
|
return matchName && matchType && (!filterChantier || (chantier && isInChantier(r,chantier,reservations)));
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderRessource = ({ item }: { item: Ressources }) => {
|
const renderRessource = ({ item }: { item: Ressources }) => {
|
||||||
@@ -43,11 +59,13 @@ export default function GestionnaireRessource() {
|
|||||||
<ThemedView lvl={1} shadow={true} style={styles.card}>
|
<ThemedView lvl={1} shadow={true} style={styles.card}>
|
||||||
<Image source={{ uri: item.Image }} style={styles.image} />
|
<Image source={{ uri: item.Image }} style={styles.image} />
|
||||||
<ThemedView lvl={1} style={styles.info}>
|
<ThemedView lvl={1} style={styles.info}>
|
||||||
<ThemedText>Id : {item.id}</ThemedText>
|
|
||||||
<ThemedText>Nom : {item.name}</ThemedText>
|
<ThemedText>Nom : {item.name}</ThemedText>
|
||||||
<ThemedText>Type : {item.type}</ThemedText>
|
<ThemedText>Type : {item.type}</ThemedText>
|
||||||
<ThemedText>Quantité totale : {item.quantity}</ThemedText>
|
<ThemedText>Quantité totale : {item.quantity}</ThemedText>
|
||||||
<ThemedText>Quantité disponible : {item.available_quantity}</ThemedText>
|
<ThemedText>Quantité disponible : {item.quantity-getNbUseRessources(item, reservations)}</ThemedText>
|
||||||
|
{filterChantier&&chantier &&
|
||||||
|
<ThemedText>Quantité utilisé dans le chantier : {getNbUseRessourcesInChantier(item,chantier, reservations)}</ThemedText>
|
||||||
|
}
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
);
|
);
|
||||||
@@ -84,6 +102,7 @@ export default function GestionnaireRessource() {
|
|||||||
>
|
>
|
||||||
<ThemedText style={{ textAlign: "center" }}>{t}</ThemedText>
|
<ThemedText style={{ textAlign: "center" }}>{t}</ThemedText>
|
||||||
</ThemedButton>
|
</ThemedButton>
|
||||||
|
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Bouton "Fermer" remplacé */}
|
{/* Bouton "Fermer" remplacé */}
|
||||||
@@ -117,14 +136,22 @@ export default function GestionnaireRessource() {
|
|||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|
||||||
{/* Bouton filtre en haut à droite */}
|
{/* Bouton filtre en haut à droite */}
|
||||||
|
<View style={{flexDirection: "row", gap:5}}>
|
||||||
<ThemedButton
|
<ThemedButton
|
||||||
lvl={1}
|
lvl={1}
|
||||||
shadow={true}
|
shadow={true}
|
||||||
style={{ padding: 10, borderRadius: 8, marginTop: 10 }}
|
style={styles.button}
|
||||||
onPress={() => setShowFilterMenu(true)}
|
onPress={() => setShowFilterMenu(true)}
|
||||||
>
|
>
|
||||||
<ThemedText>{`Filtre: ${filterType}`}</ThemedText>
|
<ThemedText>{`Filtre: ${filterType}`}</ThemedText>
|
||||||
</ThemedButton>
|
</ThemedButton>
|
||||||
|
<ThemedButton style={styles.button}>
|
||||||
|
<ThemedText onPress={() => setFilterChantier(!filterChantier)}>
|
||||||
|
{filterChantier?"chantier courant":"tous"}
|
||||||
|
</ThemedText>
|
||||||
|
</ThemedButton>
|
||||||
|
</View>
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
ListEmptyComponent={
|
ListEmptyComponent={
|
||||||
@@ -214,4 +241,9 @@ const styles = StyleSheet.create({
|
|||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
},
|
},
|
||||||
|
button:{
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 8,
|
||||||
|
marginTop: 10
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const region = {
|
|||||||
<Marker
|
<Marker
|
||||||
key = {chantier.id}
|
key = {chantier.id}
|
||||||
coordinate={{ latitude: chantier.latitude, longitude: chantier.longitude}}
|
coordinate={{ latitude: chantier.latitude, longitude: chantier.longitude}}
|
||||||
title={chantier.adresse}
|
title={chantier.name}
|
||||||
description={chantier.etat}
|
description={chantier.etat}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
45
app/AuthHandler.tsx
Normal file
45
app/AuthHandler.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { useRouter, useSegments } from "expo-router";
|
||||||
|
import { onAuthStateChanged } from "firebase/auth";
|
||||||
|
import { doc, getDoc } from "firebase/firestore";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { auth, db } from "../firebase_config";
|
||||||
|
import { useUser } from "./ContextUser";
|
||||||
|
|
||||||
|
export function useAuthHandler() {
|
||||||
|
const router = useRouter();
|
||||||
|
const segments = useSegments();
|
||||||
|
const { setUser, setRole } = useUser();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = onAuthStateChanged(auth, async (currentUser) => {
|
||||||
|
if (!currentUser) {
|
||||||
|
setUser(null);
|
||||||
|
setRole(null);
|
||||||
|
router.replace("/login/login");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userDocRef = doc(db, "user", currentUser.uid);
|
||||||
|
const userDoc = await getDoc(userDocRef);
|
||||||
|
|
||||||
|
if (!userDoc.exists()) {
|
||||||
|
setUser(null);
|
||||||
|
setRole(null);
|
||||||
|
router.replace("/login/login");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { role } = userDoc.data();
|
||||||
|
setUser(currentUser);
|
||||||
|
setRole(role);
|
||||||
|
|
||||||
|
// Only redirect if we're on login page
|
||||||
|
const inAuthGroup = segments[0] === 'login';
|
||||||
|
if (inAuthGroup) {
|
||||||
|
router.replace("/(tabs)/home");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
import { ThemedText } from "@/components/theme/themed-text";
|
import { ThemedText } from "@/components/theme/themed-text";
|
||||||
import { ThemedTextInput } from "@/components/theme/themed-textinput";
|
import { ThemedTextInput } from "@/components/theme/themed-textinput";
|
||||||
import { ThemedView } from "@/components/theme/themed-view";
|
import { ThemedView } from "@/components/theme/themed-view";
|
||||||
import { router } from "expo-router";
|
import { signInWithEmailAndPassword } from "firebase/auth";
|
||||||
import {
|
|
||||||
signInWithEmailAndPassword
|
|
||||||
} from "firebase/auth";
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Button, StyleSheet, View } from "react-native";
|
import { Button, StyleSheet, View } from "react-native";
|
||||||
import { auth } from "../../firebase_config";
|
import { auth } from "../../firebase_config";
|
||||||
|
|
||||||
const DEFAULT_ROLE = "resp";
|
|
||||||
|
|
||||||
const LoginScreen: React.FC = () => {
|
const LoginScreen: React.FC = () => {
|
||||||
const [email, setEmail] = useState<string>("");
|
const [email, setEmail] = useState<string>("");
|
||||||
const [password, setPassword] = useState<string>("");
|
const [password, setPassword] = useState<string>("");
|
||||||
@@ -18,21 +13,11 @@ const LoginScreen: React.FC = () => {
|
|||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
try {
|
try {
|
||||||
await signInWithEmailAndPassword(auth, email, password);
|
await signInWithEmailAndPassword(auth, email, password);
|
||||||
router.replace("/(tabs)");
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
alert(error.message);
|
alert(error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*const handleRegister = async () => {
|
|
||||||
try {
|
|
||||||
await createUserWithEmailAndPassword(auth, email, password);
|
|
||||||
router.replace("/(tabs)");
|
|
||||||
} catch (error: any) {
|
|
||||||
alert(error.message);
|
|
||||||
}
|
|
||||||
}; */
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemedView lvl={1} style={styles.container}>
|
<ThemedView lvl={1} style={styles.container}>
|
||||||
<ThemedText style={styles.title}>Se connecter</ThemedText>
|
<ThemedText style={styles.title}>Se connecter</ThemedText>
|
||||||
@@ -45,7 +30,6 @@ const LoginScreen: React.FC = () => {
|
|||||||
value={email}
|
value={email}
|
||||||
onChangeText={setEmail}
|
onChangeText={setEmail}
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<ThemedTextInput
|
<ThemedTextInput
|
||||||
lvl = {2}
|
lvl = {2}
|
||||||
@@ -59,7 +43,6 @@ const LoginScreen: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
<Button title="Se connecter" onPress={handleLogin} />
|
<Button title="Se connecter" onPress={handleLogin} />
|
||||||
<View style={{ height: 10 }} />
|
<View style={{ height: 10 }} />
|
||||||
{/* <Button title="S'inscrire" onPress={handleRegister} /> */}
|
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -76,7 +59,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
//borderColor: "#ccc",
|
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export type Ressources = {
|
|||||||
type: string; //"Machine","Outil","Ouvrier"
|
type: string; //"Machine","Outil","Ouvrier"
|
||||||
Image: string;
|
Image: string;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
available_quantity: number;
|
//available_quantity: number;
|
||||||
allocation: Reservation[];
|
//allocation: Reservation[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Reservation = {
|
export type Reservation = {
|
||||||
|
|||||||
@@ -29,3 +29,26 @@ export function getNbUseRessources(ressource:Ressources, allReservations:Reserva
|
|||||||
})
|
})
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNbUseRessourcesInChantier(ressource:Ressources,chantier: Chantier, allReservations:Reservation[]):number{
|
||||||
|
var res:number = 0;
|
||||||
|
getReservationOfRessource(ressource,allReservations).forEach(reserv => {
|
||||||
|
if(reserv.chantier.id === chantier.id && reserv.ressource.id===ressource.id){
|
||||||
|
res+=reserv.quantity;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isInChantier(ressource:Ressources, chantier: Chantier, allReservations:Reservation[]):boolean{
|
||||||
|
console.log(allReservations.length+ " --------------------------------");
|
||||||
|
const reservations:Reservation[] = getReservationOfRessource(ressource,allReservations);
|
||||||
|
var res=false;
|
||||||
|
reservations.forEach(reserv => {
|
||||||
|
console.log(reserv.chantier.id + " " + chantier.id)
|
||||||
|
if(reserv.chantier.id === chantier.id){
|
||||||
|
res=true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -1,24 +1,17 @@
|
|||||||
import ChantierSummary from '@/components/chantierSummary';
|
|
||||||
import SelectChantier from '@/components/selectChantier';
|
import SelectChantier from '@/components/selectChantier';
|
||||||
import SetStatus from '@/components/setStatus';
|
|
||||||
|
|
||||||
|
|
||||||
import { ThemedView } from '@/components/theme/themed-view';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { StyleSheet, ScrollView, Button, TextInput, Text, View, Modal } from 'react-native';
|
|
||||||
import { useChantier } from '@/app/ContextChantier';
|
|
||||||
import { useRessources } from '@/app/ContextRessource';
|
import { useRessources } from '@/app/ContextRessource';
|
||||||
import { useUser } from '@/app/ContextUser';
|
import { Ressources } from '@/class/class';
|
||||||
import { getRessources, getUsers, addChantier , addRessources} from '@/services/ressourcesService';
|
|
||||||
import { Chantier, Ressources, User } from '@/class/class';
|
|
||||||
import { ThemedText } from '@/components/theme/themed-text';
|
|
||||||
import { ThemedButton } from '@/components/theme/themed-button';
|
import { ThemedButton } from '@/components/theme/themed-button';
|
||||||
|
import { ThemedText } from '@/components/theme/themed-text';
|
||||||
import { ThemedTextInput } from '@/components/theme/themed-textinput';
|
import { ThemedTextInput } from '@/components/theme/themed-textinput';
|
||||||
import DateTimePicker, { DateTimePickerEvent } from '@react-native-community/datetimepicker';
|
import { ThemedView } from '@/components/theme/themed-view';
|
||||||
|
import { addRessources } from '@/services/ressourcesService';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Modal, ScrollView, StyleSheet, View } from 'react-native';
|
||||||
|
|
||||||
import Constants from 'expo-constants'; //pour connaître la taille de la barre menu de l'OS en haut
|
import Constants from 'expo-constants'; //pour connaître la taille de la barre menu de l'OS en haut
|
||||||
import SelectChafChantier from '@/components/add/select/selectChefChantier';
|
|
||||||
import SelectMachine from '@/components/selectMachine';
|
|
||||||
|
|
||||||
|
|
||||||
type Dictionary = {
|
type Dictionary = {
|
||||||
@@ -66,9 +59,9 @@ export default function AddRessource({ressourceType, ...otherProps }: Props) {
|
|||||||
name: nom,
|
name: nom,
|
||||||
type : ressourceType,
|
type : ressourceType,
|
||||||
quantity : parseInt(quantite),
|
quantity : parseInt(quantite),
|
||||||
available_quantity : parseInt(quantite),
|
//available_quantity : parseInt(quantite),
|
||||||
Image : "",
|
Image : "",
|
||||||
allocation : [],
|
//allocation : [],
|
||||||
};
|
};
|
||||||
const id = await addRessources(nouvelleRessource);
|
const id = await addRessources(nouvelleRessource);
|
||||||
|
|
||||||
|
|||||||
@@ -18,22 +18,21 @@ export default function ChantierSummary({data,style , ...otherProps }: Props) {
|
|||||||
{data.chantier ? (
|
{data.chantier ? (
|
||||||
<ThemedView lvl={4} style={styles.chantier}>
|
<ThemedView lvl={4} style={styles.chantier}>
|
||||||
<View>
|
<View>
|
||||||
<Image source={{ uri:"https://cdn.discordapp.com/attachments/1425108443571945644/1427207643180826757/raw.png?ex=693f1a72&is=693dc8f2&hm=86ffb97145fc8d3aec822b87d99be233c98477d4424c1ef58f80eb81b17c7c80&" /*chantier.urlImg*/ }} style={styles.image} />
|
<Image source={{ uri:"" /*chantier.urlImg*/ }} style={styles.image} />
|
||||||
</View>
|
</View>
|
||||||
<View style={{flex: 1}}>
|
<View style={{flex: 1}}>
|
||||||
<ThemedText selectable={true}>Id: {data.chantier.id}</ThemedText>
|
|
||||||
<ThemedText selectable={true}>Objet: {data.chantier.name}</ThemedText>
|
<ThemedText selectable={true}>Objet: {data.chantier.name}</ThemedText>
|
||||||
<ThemedText selectable={true}>Adresse: {data.chantier.adresse}</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}>Chef de chantier: {data.chantier.chef.last_name}{" "}{data.chantier.chef.name}</ThemedText>
|
||||||
<ThemedText selectable={true}>État: {data.chantier.etat}</ThemedText>
|
<ThemedText selectable={true}>État: {data.chantier.etat}</ThemedText>
|
||||||
<ThemedText selectable={true}>equipe:
|
<ThemedText selectable={true}>
|
||||||
{getNbItemReservation(data.chantier.equipe)} ({data.chantier.equipe.length} type{data.chantier.equipe.length>1&&"s"})
|
equipe: {getNbItemReservation(data.chantier.equipe)} ({data.chantier.equipe.length} type{data.chantier.equipe.length>1&&"s"})
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<ThemedText selectable={true}>materiel:
|
<ThemedText selectable={true}>
|
||||||
{getNbItemReservation(data.chantier.materiel)} ({data.chantier.materiel.length} type{data.chantier.materiel.length>1&&"s"})
|
materiel: {getNbItemReservation(data.chantier.materiel)} ({data.chantier.materiel.length} type{data.chantier.materiel.length>1&&"s"})
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<ThemedText selectable={true}>vehicules:
|
<ThemedText selectable={true}>
|
||||||
{getNbItemReservation(data.chantier.vehicules)} ({data.chantier.vehicules.length} type{data.chantier.vehicules.length>1&&"s"})
|
vehicules: {getNbItemReservation(data.chantier.vehicules)} ({data.chantier.vehicules.length} type{data.chantier.vehicules.length>1&&"s"})
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</View>
|
</View>
|
||||||
</ThemedView>
|
</ThemedView>
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export default function SelectChantier() {
|
|||||||
<Image source={{ uri:"https://cdn.discordapp.com/attachments/1425108443571945644/1427207643180826757/raw.png?ex=693f1a72&is=693dc8f2&hm=86ffb97145fc8d3aec822b87d99be233c98477d4424c1ef58f80eb81b17c7c80&" /*chantier.urlImg*/ }} style={styles.image} />
|
<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>
|
||||||
<View style={{flex: 1}}>
|
<View style={{flex: 1}}>
|
||||||
<ThemedText>Renovation: {item.name}</ThemedText>
|
<ThemedText>Objet: {item.name}</ThemedText>
|
||||||
<ThemedText>Adresse: {item.adresse}</ThemedText>
|
<ThemedText>Adresse: {item.adresse}</ThemedText>
|
||||||
<ThemedText>Chef de chantier: {item.chef.last_name}{" "}{item.chef.name}</ThemedText>
|
<ThemedText>Chef de chantier: {item.chef.last_name}{" "}{item.chef.name}</ThemedText>
|
||||||
<ThemedText>État: {item.etat}</ThemedText>
|
<ThemedText>État: {item.etat}</ThemedText>
|
||||||
@@ -138,7 +138,7 @@ export default function SelectChantier() {
|
|||||||
<ThemedView lvl={2} shadow={true} style={styles.window}>
|
<ThemedView lvl={2} shadow={true} style={styles.window}>
|
||||||
<AnimatedThemedButton style={animatedButtonStyle} lvl={isOpen ? 1 : 1} onPress={() => onPressOpen()}>
|
<AnimatedThemedButton style={animatedButtonStyle} lvl={isOpen ? 1 : 1} onPress={() => onPressOpen()}>
|
||||||
<ThemedText style={styles.buttonText}>
|
<ThemedText style={styles.buttonText}>
|
||||||
{isOpen ? "Fermer" : (chantier!=null ? chantier.adresse : "Chantier")}
|
{isOpen ? "Fermer" : (chantier!=null ? chantier.name : "Chantier")}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</AnimatedThemedButton>
|
</AnimatedThemedButton>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ const styles = StyleSheet.create({
|
|||||||
windowBox:{
|
windowBox:{
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
//backgroundColor: '#00FFFF40',
|
//backgroundColor: '#00FFFF40',
|
||||||
width:"30%",
|
width:"35%",
|
||||||
padding: 10,
|
padding: 10,
|
||||||
paddingLeft: 0,
|
paddingLeft: 0,
|
||||||
//overflow: 'hidden',
|
//overflow: 'hidden',
|
||||||
|
|||||||
32
package-lock.json
generated
32
package-lock.json
generated
@@ -90,6 +90,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
|
||||||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.3",
|
"@babel/generator": "^7.28.3",
|
||||||
@@ -1471,6 +1472,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
||||||
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
|
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -2329,6 +2331,7 @@
|
|||||||
"version": "0.14.6",
|
"version": "0.14.6",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.6.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.6.tgz",
|
||||||
"integrity": "sha512-4uyt8BOrBsSq6i4yiOV/gG6BnnrvTeyymlNcaN/dKvyU1GoolxAafvIvaNP1RCGPlNab3OuE4MKUQuv2lH+PLQ==",
|
"integrity": "sha512-4uyt8BOrBsSq6i4yiOV/gG6BnnrvTeyymlNcaN/dKvyU1GoolxAafvIvaNP1RCGPlNab3OuE4MKUQuv2lH+PLQ==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/component": "0.7.0",
|
"@firebase/component": "0.7.0",
|
||||||
"@firebase/logger": "0.5.0",
|
"@firebase/logger": "0.5.0",
|
||||||
@@ -2394,6 +2397,7 @@
|
|||||||
"version": "0.5.6",
|
"version": "0.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.6.tgz",
|
||||||
"integrity": "sha512-YYGARbutghQY4zZUWMYia0ib0Y/rb52y72/N0z3vglRHL7ii/AaK9SA7S/dzScVOlCdnbHXz+sc5Dq+r8fwFAg==",
|
"integrity": "sha512-YYGARbutghQY4zZUWMYia0ib0Y/rb52y72/N0z3vglRHL7ii/AaK9SA7S/dzScVOlCdnbHXz+sc5Dq+r8fwFAg==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/app": "0.14.6",
|
"@firebase/app": "0.14.6",
|
||||||
"@firebase/component": "0.7.0",
|
"@firebase/component": "0.7.0",
|
||||||
@@ -2409,7 +2413,8 @@
|
|||||||
"version": "0.9.3",
|
"version": "0.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz",
|
||||||
"integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==",
|
"integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/auth": {
|
"node_modules/@firebase/auth": {
|
||||||
"version": "1.11.1",
|
"version": "1.11.1",
|
||||||
@@ -2859,6 +2864,7 @@
|
|||||||
"integrity": "sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==",
|
"integrity": "sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -3894,6 +3900,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.25.tgz",
|
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.25.tgz",
|
||||||
"integrity": "sha512-zQeWK9txDePWbYfqTs0C6jeRdJTm/7VhQtW/1IbJNDi9/rFIRzZule8bdQPAnf8QWUsNujRmi1J9OG/hhfbalg==",
|
"integrity": "sha512-zQeWK9txDePWbYfqTs0C6jeRdJTm/7VhQtW/1IbJNDi9/rFIRzZule8bdQPAnf8QWUsNujRmi1J9OG/hhfbalg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^7.13.6",
|
"@react-navigation/core": "^7.13.6",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
@@ -4096,6 +4103,7 @@
|
|||||||
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
|
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
@@ -4167,6 +4175,7 @@
|
|||||||
"integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==",
|
"integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.46.0",
|
"@typescript-eslint/scope-manager": "8.46.0",
|
||||||
"@typescript-eslint/types": "8.46.0",
|
"@typescript-eslint/types": "8.46.0",
|
||||||
@@ -4729,6 +4738,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -5414,6 +5424,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.8.9",
|
"baseline-browser-mapping": "^2.8.9",
|
||||||
"caniuse-lite": "^1.0.30001746",
|
"caniuse-lite": "^1.0.30001746",
|
||||||
@@ -6553,6 +6564,7 @@
|
|||||||
"integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
|
"integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@@ -6750,6 +6762,7 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@@ -6988,6 +7001,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.13.tgz",
|
||||||
"integrity": "sha512-F1puKXzw8ESnsbvaKdXtcIiyYLQ2kUHqP8LuhgtJS1wm6w55VhtOPg8yl/0i8kPbTA0YfD+KYdXjSfhPXgUPxw==",
|
"integrity": "sha512-F1puKXzw8ESnsbvaKdXtcIiyYLQ2kUHqP8LuhgtJS1wm6w55VhtOPg8yl/0i8kPbTA0YfD+KYdXjSfhPXgUPxw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.0",
|
"@babel/runtime": "^7.20.0",
|
||||||
"@expo/cli": "54.0.11",
|
"@expo/cli": "54.0.11",
|
||||||
@@ -7055,6 +7069,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.9.tgz",
|
||||||
"integrity": "sha512-sqoXHAOGDcr+M9NlXzj1tGoZyd3zxYDy215W6E0Z0n8fgBaqce9FAYQE2bu5X4G629AYig5go7U6sQz7Pjcm8A==",
|
"integrity": "sha512-sqoXHAOGDcr+M9NlXzj1tGoZyd3zxYDy215W6E0Z0n8fgBaqce9FAYQE2bu5X4G629AYig5go7U6sQz7Pjcm8A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/config": "~12.0.9",
|
"@expo/config": "~12.0.9",
|
||||||
"@expo/env": "~2.0.7"
|
"@expo/env": "~2.0.7"
|
||||||
@@ -7079,6 +7094,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.9.tgz",
|
||||||
"integrity": "sha512-xCoQbR/36qqB6tew/LQ6GWICpaBmHLhg/Loix5Rku/0ZtNaXMJv08M9o1AcrdiGTn/Xf/BnLu6DgS45cWQEHZg==",
|
"integrity": "sha512-xCoQbR/36qqB6tew/LQ6GWICpaBmHLhg/Loix5Rku/0ZtNaXMJv08M9o1AcrdiGTn/Xf/BnLu6DgS45cWQEHZg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fontfaceobserver": "^2.1.0"
|
"fontfaceobserver": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -7150,6 +7166,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.8.tgz",
|
||||||
"integrity": "sha512-MyeMcbFDKhXh4sDD1EHwd0uxFQNAc6VCrwBkNvvvufUsTYFq3glTA9Y8a+x78CPpjNqwNAamu74yIaIz7IEJyg==",
|
"integrity": "sha512-MyeMcbFDKhXh4sDD1EHwd0uxFQNAc6VCrwBkNvvvufUsTYFq3glTA9Y8a+x78CPpjNqwNAamu74yIaIz7IEJyg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"expo-constants": "~18.0.8",
|
"expo-constants": "~18.0.8",
|
||||||
"invariant": "^2.2.4"
|
"invariant": "^2.2.4"
|
||||||
@@ -11394,6 +11411,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -11413,6 +11431,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.26.0"
|
"scheduler": "^0.26.0"
|
||||||
},
|
},
|
||||||
@@ -11449,6 +11468,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.4.tgz",
|
||||||
"integrity": "sha512-bt5bz3A/+Cv46KcjV0VQa+fo7MKxs17RCcpzjftINlen4ZDUl0I6Ut+brQ2FToa5oD0IB0xvQHfmsg2EDqsZdQ==",
|
"integrity": "sha512-bt5bz3A/+Cv46KcjV0VQa+fo7MKxs17RCcpzjftINlen4ZDUl0I6Ut+brQ2FToa5oD0IB0xvQHfmsg2EDqsZdQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jest/create-cache-key-function": "^29.7.0",
|
"@jest/create-cache-key-function": "^29.7.0",
|
||||||
"@react-native/assets-registry": "0.81.4",
|
"@react-native/assets-registry": "0.81.4",
|
||||||
@@ -11506,6 +11526,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz",
|
||||||
"integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==",
|
"integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@egjs/hammerjs": "^2.0.17",
|
"@egjs/hammerjs": "^2.0.17",
|
||||||
"hoist-non-react-statics": "^3.3.0",
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
@@ -11560,6 +11581,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.3.tgz",
|
||||||
"integrity": "sha512-GP8wsi1u3nqvC1fMab/m8gfFwFyldawElCcUSBJQgfrXeLmsPPUOpDw44lbLeCpcwUuLa05WTVePdTEwCLTUZg==",
|
"integrity": "sha512-GP8wsi1u3nqvC1fMab/m8gfFwFyldawElCcUSBJQgfrXeLmsPPUOpDw44lbLeCpcwUuLa05WTVePdTEwCLTUZg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-native-is-edge-to-edge": "^1.2.1",
|
"react-native-is-edge-to-edge": "^1.2.1",
|
||||||
"semver": "7.7.2"
|
"semver": "7.7.2"
|
||||||
@@ -11588,6 +11610,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
|
||||||
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
|
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
@@ -11598,6 +11621,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
|
||||||
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
|
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-freeze": "^1.0.0",
|
"react-freeze": "^1.0.0",
|
||||||
"react-native-is-edge-to-edge": "^1.2.1",
|
"react-native-is-edge-to-edge": "^1.2.1",
|
||||||
@@ -11613,6 +11637,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.1.tgz",
|
||||||
"integrity": "sha512-BeNsgwwe4AXUFPAoFU+DKjJ+CVQa3h54zYX77p7GVZrXiiNo3vl03WYDYVEy5R2J2HOPInXtQZB5gmj3vuzrKg==",
|
"integrity": "sha512-BeNsgwwe4AXUFPAoFU+DKjJ+CVQa3h54zYX77p7GVZrXiiNo3vl03WYDYVEy5R2J2HOPInXtQZB5gmj3vuzrKg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.18.6",
|
"@babel/runtime": "^7.18.6",
|
||||||
"@react-native/normalize-colors": "^0.74.1",
|
"@react-native/normalize-colors": "^0.74.1",
|
||||||
@@ -11645,6 +11670,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.5.1.tgz",
|
||||||
"integrity": "sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==",
|
"integrity": "sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/plugin-transform-arrow-functions": "^7.0.0-0",
|
"@babel/plugin-transform-arrow-functions": "^7.0.0-0",
|
||||||
"@babel/plugin-transform-class-properties": "^7.0.0-0",
|
"@babel/plugin-transform-class-properties": "^7.0.0-0",
|
||||||
@@ -11755,6 +11781,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||||
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
|
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -13177,6 +13204,7 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -13383,6 +13411,7 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -14358,6 +14387,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { addDoc, arrayUnion, collection, doc, Firestore, getDoc, getDocs, Timestamp, updateDoc, DocumentReference, query, where } from "firebase/firestore";
|
import { addDoc, arrayUnion, collection, doc, DocumentReference, getDoc, getDocs, query, Timestamp, updateDoc, where } from "firebase/firestore";
|
||||||
import { Chantier, Reservation, Ressources, User } from "../class/class";
|
import { Chantier, Reservation, Ressources, User } from "../class/class";
|
||||||
import { db } from "../firebase_config";
|
import { db } from "../firebase_config";
|
||||||
|
|
||||||
@@ -40,10 +40,15 @@ export async function getRessources(): Promise<Ressources[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//ADD RESSOURCES
|
//ADD RESSOURCES
|
||||||
export async function addRessources(ressourceData: Omit<Ressources, 'id'>): Promise<string | null> {
|
export async function addRessources(ressourceData: Ressources): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
const colRef = collection(db, "ressources");
|
const ressourcesRef = await addDoc(collection(db, "ressources"), {
|
||||||
const ressourcesRef = await addDoc(colRef, ressourceData);
|
name:ressourceData.name,
|
||||||
|
type:ressourceData.type,
|
||||||
|
Image: ressourceData.Image,
|
||||||
|
quantity: ressourceData.quantity,
|
||||||
|
});
|
||||||
|
|
||||||
console.log(`Ressource ajoutée avec ID: ${ressourcesRef.id}`);
|
console.log(`Ressource ajoutée avec ID: ${ressourcesRef.id}`);
|
||||||
return ressourcesRef.id;
|
return ressourcesRef.id;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -219,8 +224,14 @@ async function convertReservation(res: any): Promise<Reservation|null> {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
id: res.id,
|
id: res.id,
|
||||||
chantier: chantierSnap.data() as Chantier,
|
chantier: {
|
||||||
ressource: ressourceSnap.data() as Ressources,
|
id: chantierSnap.id,
|
||||||
|
...(chantierSnap.data() as Omit<Chantier, "id">),
|
||||||
|
},
|
||||||
|
ressource: {
|
||||||
|
id: ressourceSnap.id,
|
||||||
|
...(ressourceSnap.data() as Omit<Ressources, "id">),
|
||||||
|
},
|
||||||
quantity: data.quantity,
|
quantity: data.quantity,
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -254,6 +265,10 @@ export async function sendNewChantier(chantier:Chantier): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function sendNewReservation(list: Reservation[],chantierId:string): Promise<void> {
|
export async function sendNewReservation(list: Reservation[],chantierId:string): Promise<void> {
|
||||||
|
list.forEach(reservation => {
|
||||||
|
console.log("log: " + reservation.ressource.id);
|
||||||
|
});
|
||||||
|
|
||||||
const promises = list.map((reservation) =>
|
const promises = list.map((reservation) =>
|
||||||
addDoc(collection(db,"Reservation"),{
|
addDoc(collection(db,"Reservation"),{
|
||||||
chantier: doc(db, "chantier", chantierId),
|
chantier: doc(db, "chantier", chantierId),
|
||||||
|
|||||||
Reference in New Issue
Block a user