From e95bb3fd70dcf2edb43a71825b9da258ce617415 Mon Sep 17 00:00:00 2001 From: Rochas Date: Fri, 12 Dec 2025 21:57:09 +0100 Subject: [PATCH] addChanter, selectChefChantier, en cour + Update de themed-button pour prendre en charge le changement de theme pendant la pression --- README.md | 1 + app/(tabs)/addChantier.tsx | 198 +++++++++++++++++++++-------- components/selectChefChantier.tsx | 126 ++++++++++++++++++ components/theme/themed-button.tsx | 17 ++- package-lock.json | 27 +++- package.json | 1 + 6 files changed, 309 insertions(+), 61 deletions(-) create mode 100644 components/selectChefChantier.tsx diff --git a/README.md b/README.md index 01cee85..dedca44 100644 --- a/README.md +++ b/README.md @@ -15,5 +15,6 @@ Différentes commandes a effectuer pour lancer le projet: npx expo install react-native-maps@1.9.0 npm install react-native-maps @react-navigation/native @react-navigation/bottom-tabs react-native-safe-area-context react-native-screens firebase +npm install @react-native-community/datetimepicker npx expo start \ No newline at end of file diff --git a/app/(tabs)/addChantier.tsx b/app/(tabs)/addChantier.tsx index 6ae4ce1..b5aeb3c 100644 --- a/app/(tabs)/addChantier.tsx +++ b/app/(tabs)/addChantier.tsx @@ -2,9 +2,10 @@ import ChantierSummary from '@/components/chantierSummary'; 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 } from 'react-native'; +import { StyleSheet, ScrollView, Button, TextInput, Text, View, Modal } from 'react-native'; import { useChantier } from '../ContextChantier'; import { useRessources } from '../ContextRessource'; import { useUser } from '../ContextUser'; @@ -13,7 +14,10 @@ import { Chantier, Ressources } from '@/class/class'; import { ThemedText } from '@/components/theme/themed-text'; import { ThemedButton } from '@/components/theme/themed-button'; import { ThemedTextInput } from '@/components/theme/themed-textinput'; +import DateTimePicker, { DateTimePickerEvent } from '@react-native-community/datetimepicker'; + import Constants from 'expo-constants'; //pour connaître la taille de la barre menu de l'OS en haut +import SelectChafChantier from '@/components/selectChefChantier'; //Uniquement accessible par le RESPONSSABLE du chantier //Pour créer ou modifier un chantier @@ -26,23 +30,115 @@ export default function AddChantier() { const [loading, setLoading] = useState(false); const [objet, setObjet] = useState(''); - const [date, setDate] = useState(''); + const [date, setDate] = useState(new Date()); + const [morning, setMorning] = useState(true); const [chefChantier, setChefChantier] = useState(''); const [adresse, setAdresse] = useState(''); const [duree, setDuree] = useState(''); const [contact, setContact] = useState(''); + const [vehicule, setVehicule] = useState(''); + + const [showDateSelect,setSowDateSelect] = useState(false); + const [openConfirmation,setOpenConfirmation] = useState(false); + const [userSelect, setUserSelect] = useState([]); const [ressourcesSelect, setRessourcesSelect] = useState([]); async function handleAddChantier() { setLoading(true); + setOpenConfirmation(true); } - const renderInut = (name : string, preFill : string, value : string, setValue : ((text:string) => void)) => { + + const onSelectDate = (event: DateTimePickerEvent, selectedDate?: Date) => { + setSowDateSelect(false); + if (selectedDate) { + setDate(selectedDate); + } + }; + + async function onConfirm(): Promise { + //TODO + //await changeChantierStatus(chantier.id,tempStatus) + //Il faut changer le UX + //setChantier({...chantier,etat: tempStatus}) + if(isValidChantier()){ + setOpenConfirmation(false); + } + } + + function onCancel(): void { + setOpenConfirmation(false); + } + + function isValidChantier(): boolean { + return objet!=="" && duree!=='' && adresse!=='' && contact!=='' && chefChantier!==''; //TODO + } + + const renderValidationScreen = () => { + return( + + + + Créer le nouveau chantier suivant ? : + + Objet: {objet===''?"NONE":objet} + Date: {date.toLocaleDateString()} {morning ? "matin" : "après-midi"} + Durée: {duree===''?"0":duree} demi-journées + Adresse: {adresse===''?"NONE":adresse} + Contact client: {contact===''?"NONE":contact} + Chef de chantier: {chefChantier===''?"NONE":chefChantier} + + + + onConfirm()}> + Confirmer + + + + onCancel()}> + Annuler + + + + + + ) + } + + const renderInutDate = (name : string) => { return ( {name}: - + + + + setSowDateSelect(true)} style = {{borderRadius:10}}>{date.toLocaleDateString()} + + + + + setMorning(!morning)} style = {{borderRadius:10}}>{morning ? "matin" : "après-midi"} + + + {showDateSelect && ( + + )} + + + ); + }; + + const renderInut = (name : string, preFill : string, value : string, setValue : ((text:string) => void),numeric:boolean) => { + return ( + + {name}: + ); }; @@ -63,23 +159,31 @@ export default function AddChantier() { {editMode? "Edition d'un chantier" :"Ajouter un nouveau chantier"} - {renderInut("Objet","Renovation",objet,setObjet)} - {renderInut("Date de départ","TOTO : JOUR + Demi journé",date,setDate)} - {renderInut("Estimation de la durée (1/2 Journée)","14",duree,setDuree)} - {renderInut("Adresse","1 Rue de la Coutellerie, Paris",adresse,setAdresse)} - {renderInut("Contact client","07 01 02 03 04 05",contact,setContact)} - {renderInut("Vehicule","TODO pas un input bien sûre",adresse,setAdresse)} - {renderInut("Chef de chantier","TODO pas un input non plus",chefChantier,setChefChantier)} + {renderInut("Objet","Renovation",objet,setObjet,false)} + {//renderInut("Date de départ","TOTO : JOUR + Demi journé",date,setDate) + } + {renderInutDate("Date de départ")} + {renderInut("Estimation de la durée (en demi-journées)","14",duree,setDuree,false)} + {renderInut("Adresse","1 Rue de la Coutellerie, Paris",adresse,setAdresse,false)} + {renderInut("Contact client","07 01 02 03 04 05",contact,setContact,true)} + {renderInut("Vehicule","TODO Ouvrir un menu",vehicule,setVehicule,false)} + + Chef de chantier: + + + handleAddChantier()} > - + + Valider + + {openConfirmation && renderValidationScreen()} @@ -127,52 +231,34 @@ const styles = StyleSheet.create({ padding: 10, fontSize: 16, }, - card: { - flexDirection: "row", - marginHorizontal: 20, - marginBottom: 15, - borderRadius: 10, - padding: 10, + overlay:{ + backgroundColor:'#00000080', + padding:"5%", + paddingVertical:"20%", + width:"100%", + height:"100%", }, - image: { - width: 80, - height: 80, - borderRadius: 8, - marginRight: 10, - }, - info: { - flex: 1, - justifyContent: "center", - }, - footer: { + overlayView:{ + borderRadius: 20, padding: 20, - }, - empty: { - textAlign: "center", - marginTop: 30, - color: "#888", - }, - filterMenuOverlay: { - position: "absolute", - top: 0, - left: 0, - right: 0, - bottom: 0, - backgroundColor: "rgba(0,0,0,0.4)", - justifyContent: "center", alignItems: "center", - zIndex: 999, + width: "100%", + gap:5, + //backgroundColor:'#ff0000', }, - filterMenu: { - width: "80%", - borderRadius: 12, - padding: 20, - backgroundColor: "#fff", - }, - filterTitle: { - fontSize: 18, - fontWeight: "bold", - marginBottom: 20, - textAlign: "center", + buttonValid:{ + //borderWidth: 2, + width:'100%', + margin: 0, + borderRadius: 15, + padding: 10, + height:60, + alignItems: "center", + justifyContent: 'center', }, + summaryNewChantier:{ + width:'100%', + borderRadius: 15, + padding:10, + } }); diff --git a/components/selectChefChantier.tsx b/components/selectChefChantier.tsx new file mode 100644 index 0000000..f26f2f2 --- /dev/null +++ b/components/selectChefChantier.tsx @@ -0,0 +1,126 @@ +import { useChantier } from '@/app/ContextChantier'; +import { changeChantierStatus } from "@/services/ressourcesService"; +import { useState } from 'react'; +import { Dimensions, LayoutAnimation, Modal, Pressable, StyleProp, StyleSheet, View, ViewStyle } from 'react-native'; +import Animated, { LinearTransition } from 'react-native-reanimated'; +import { ThemedButton } from './theme/themed-button'; +import { ThemedText } from './theme/themed-text'; +import { ThemedView } from "./theme/themed-view"; +import { User } from '@/class/class'; + +const { width, height } = Dimensions.get("window"); + +type Props = { + + style?: StyleProp; +}; + +export default function SelectChafChantier({style , ...otherProps }: Props) { + + const { chantier, setChantier} = useChantier(); + const [chefDeChantier, setChefDeChantier] = useState(); + const [tempStatus, setTempStatus] = useState(""); + const [isOpen,setIsOpen] = useState(false); + const [openConfirmation,setOpenConfirmation] = useState(false); + + const AnimatedThemedView = Animated.createAnimatedComponent(ThemedView); + + const choices = ["En cours","Interrompu","Terminé","Non réalisé"] + + function onPressOpen(): void { + setIsOpen(!isOpen); + } + + + + + const chefChantierSearch = () => { + return( + + + + Rechercher un chef de chantier : + + + setIsOpen(false)}> + Annuler + + + + + + ) + } + + return( + onPressOpen()}> + {chefDeChantier?chefDeChantier.name+" "+chefDeChantier.last_name:"selectionner un chef de chantier"} + {isOpen && chefChantierSearch()} + + + + ) +} + +const styles = StyleSheet.create({ + + windowBox:{ + zIndex: 2, + //backgroundColor: '#00FFFF40', + width:"100%", + padding: 10, + paddingLeft: 0, + //overflow: 'hidden', + }, + window:{ + borderRadius:15, + //backgroundColor: '#00FF00', + overflow: 'hidden', + position: 'relative', + }, + autoClose: { + + position: 'absolute', + top: -height, + left: -width, + width:width*2, + height:height*2, + //backgroundColor: 'rgba(255, 0, 0, 0.5)', + }, + button:{ + width:'100%', + margin: 0, + borderRadius: 15, + padding: 10, + height:40, + justifyContent: 'center', + }, + centeredText:{ + textAlign: 'center', + }, + overlay:{ + backgroundColor:'#00000080', + padding:"5%", + paddingVertical:"20%", + width:"100%", + height:"100%", + }, + overlayView:{ + borderRadius: 20, + padding: 20, + alignItems: "center", + width: "100%", + //backgroundColor:'#ff0000', + }, + buttonValid:{ + //borderWidth: 2, + width:'100%', + margin: 0, + borderRadius: 15, + padding: 10, + height:60, + alignItems: "center", + justifyContent: 'center', + }, + +}); diff --git a/components/theme/themed-button.tsx b/components/theme/themed-button.tsx index 49f9e28..4644ee0 100644 --- a/components/theme/themed-button.tsx +++ b/components/theme/themed-button.tsx @@ -6,23 +6,32 @@ export type ThemedPressableProps = PressableProps & { lightColor?: string; darkColor?: string; lvl?:number; + lvlPressed?:number; border?:number; opacity?:string; shadow?: boolean; }; //nb : pour border ne pas oublier de mettre en plus "borderWidth" dans le style du composant /!\ -export function ThemedButton({ style, lightColor, darkColor,lvl=1,border=-1,opacity="FF",shadow=false, ...otherProps }: ThemedPressableProps) { +export function ThemedButton({ style, lightColor, darkColor,lvl=1,lvlPressed=1,border=-1,opacity="FF",shadow=false, ...otherProps }: ThemedPressableProps) { var lvlStr:string = "background"; + var lvlStrPressed:string = "background"; var borderColor =""; var borderWidth = 0; + if(lvl>=0 && lvl<6){ lvlStr+=lvl; } else lvlStr+='5'; + if((lvl+lvlPressed)>=0 && (lvl+lvlPressed)<6){ + lvlStrPressed+=(lvl+lvlPressed); + } + else lvlStrPressed+='0'; + const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor },lvlStr as 'background0'|'background1'|'background2'|'background3'|'background4'|'background5')+opacity; + const backgroundPressed = useThemeColor({ light: lightColor, dark: darkColor },lvlStrPressed as 'background0'|'background1'|'background2'|'background3'|'background4'|'background5')+opacity; if(border!=-1){ var borderStr = ""; @@ -46,5 +55,9 @@ export function ThemedButton({ style, lightColor, darkColor,lvl=1,border=-1,opac shadowRadius: 6, } - return [{ backgroundColor, borderColor, borderWidth }, shadow && shadowStyle, typeof style === 'function' ? style(state) : style,]} {...otherProps}/>; + return [{ + backgroundColor: state.pressed ? backgroundPressed: backgroundColor, + borderColor, + borderWidth + }, shadow && shadowStyle, typeof style === 'function' ? style(state) : style,]} {...otherProps}/>; } diff --git a/package-lock.json b/package-lock.json index 9ba6691..4b82fb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "dependencies": { "@expo/vector-icons": "^15.0.2", + "@react-native-community/datetimepicker": "^8.5.1", "@react-navigation/bottom-tabs": "^7.8.12", "@react-navigation/elements": "^2.6.3", "@react-navigation/native": "^7.1.25", @@ -1468,7 +1469,6 @@ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -3579,6 +3579,29 @@ } } }, + "node_modules/@react-native-community/datetimepicker": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-8.5.1.tgz", + "integrity": "sha512-TuwM1ORbxCjOp1GOtONj0QnpDpVfq0F4UlfKZYPxL/vmriaLHt2Kgvw63Bv0Bpep4eOkslVVSS1IRfRI6d392g==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4" + }, + "peerDependencies": { + "expo": ">=52.0.0", + "react": "*", + "react-native": "*", + "react-native-windows": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "react-native-windows": { + "optional": true + } + } + }, "node_modules/@react-native/assets-registry": { "version": "0.81.4", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.4.tgz", @@ -11514,7 +11537,6 @@ "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.3.tgz", "integrity": "sha512-GP8wsi1u3nqvC1fMab/m8gfFwFyldawElCcUSBJQgfrXeLmsPPUOpDw44lbLeCpcwUuLa05WTVePdTEwCLTUZg==", "license": "MIT", - "peer": true, "dependencies": { "react-native-is-edge-to-edge": "^1.2.1", "semver": "7.7.2" @@ -11603,7 +11625,6 @@ "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.5.1.tgz", "integrity": "sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==", "license": "MIT", - "peer": true, "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.0.0-0", "@babel/plugin-transform-class-properties": "^7.0.0-0", diff --git a/package.json b/package.json index 4938b7a..3c5eb63 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@expo/vector-icons": "^15.0.2", + "@react-native-community/datetimepicker": "^8.5.1", "@react-navigation/bottom-tabs": "^7.8.12", "@react-navigation/elements": "^2.6.3", "@react-navigation/native": "^7.1.25",