Merge branch 'front_foundation' of https://gitea.piair.dev/piair/MyINPulse into front_foundation
This commit is contained in:
		| @@ -1,10 +1,63 @@ | ||||
| { | ||||
|   "entrepreneurs": [ | ||||
|       { "id": 1, "name": "Alice", "email": "alice@example.com" }, | ||||
|       { "id": 2, "name": "Bob", "email": "bob@example.com" }, | ||||
|       { "id": 3, "name": "Charlie", "email": "charlie@example.com" } | ||||
|     { "id": 1, "name": "Alice", "email": "alice@example.com" }, | ||||
|     { "id": 2, "name": "Bob", "email": "bob@example.com" }, | ||||
|     { "id": 3, "name": "Charlie", "email": "charlie@example.com" } | ||||
|   ], | ||||
|   "data": [ | ||||
|       { "canva_data": "this is a fake data to test api" } | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 1, | ||||
|       "title_text": "1. Problème", | ||||
|       "description": "3 problèmes essentiels à résoudre pour le client" | ||||
|     }, | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 2, | ||||
|       "title_text": "2. Segments", | ||||
|       "description": "Les segments de clientèle visés" | ||||
|     }, | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 3, | ||||
|       "title_text": "3. Valeur", | ||||
|       "description": "La proposition de valeur" | ||||
|     }, | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 4, | ||||
|       "title_text": "4. Solution", | ||||
|       "description": "Les solutions proposées" | ||||
|     }, | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 5, | ||||
|       "title_text": "5. Avantage", | ||||
|       "description": "Les avantages concurrentiels" | ||||
|     }, | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 6, | ||||
|       "title_text": "6. Canaux", | ||||
|       "description": "Les canaux de distribution" | ||||
|     }, | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 7, | ||||
|       "title_text": "7. Indicateurs", | ||||
|       "description": "Les indicateurs clés de performance" | ||||
|     }, | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 8, | ||||
|       "title_text": "8. Coûts", | ||||
|       "description": "Les coûts associés" | ||||
|     }, | ||||
|     { | ||||
|       "projectId": 1, | ||||
|       "title": 9, | ||||
|       "title_text": "9. Revenus", | ||||
|       "description": "Les sources de revenus" | ||||
|     } | ||||
|   ] | ||||
| } | ||||
|   | ||||
							
								
								
									
										191
									
								
								front/MyINPulse-front/src/components/canvas/CanvasItem.vue
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										191
									
								
								front/MyINPulse-front/src/components/canvas/CanvasItem.vue
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,21 +1,28 @@ | ||||
| <template> | ||||
|   <div :class="['cell', { expanded }]" @click="handleClick"> | ||||
|     <h3>{{ title }}</h3> | ||||
|     <h3>{{ title_text }}</h3> | ||||
|  | ||||
|     <!-- Mode affichage --> | ||||
|     <template v-if="!isEditing"> | ||||
|       <p>{{ currentDescription }}</p> | ||||
|       <button v-if="expanded" @click.stop="startEditing" class="edit-button">Éditer</button> | ||||
|     </template> | ||||
|     <div v-for="(desc, index) in currentDescriptions" :key="index"> | ||||
|       <!-- Mode affichage --> | ||||
|       <template v-if="!isEditing[index]"> | ||||
|         <div class="description"> | ||||
|           <p>{{ desc }}</p> | ||||
|         </div> | ||||
|         <div class="button-container"> | ||||
|           <button v-if="expanded" @click.stop="startEditing(index)" class="edit-button">Éditer</button> | ||||
|         </div> | ||||
|       </template> | ||||
|  | ||||
|       <!-- Mode édition --> | ||||
|       <template v-else> | ||||
|         <textarea v-model="editedDescriptions[index]" class="edit-input"></textarea> | ||||
|         <div class="button-container"> | ||||
|           <button @click.stop="saveEdit(index)" class="save-button">Enregistrer</button> | ||||
|           <button @click.stop="cancelEdit(index)" class="cancel-button">Annuler</button> | ||||
|         </div> | ||||
|       </template> | ||||
| </div> | ||||
|  | ||||
|     <!-- Mode édition --> | ||||
|     <template v-else> | ||||
|       <textarea v-model="editedDescription" class="edit-input"></textarea> | ||||
|       <div class="button-container"> | ||||
|         <button @click.stop="saveEdit" class="save-button">Enregistrer</button> | ||||
|         <button @click.stop="cancelEdit" class="cancel-button">Annuler</button> | ||||
|       </div> | ||||
|     </template> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| @@ -23,16 +30,22 @@ | ||||
| import { ref, defineProps } from "vue"; | ||||
| import axios from "axios"; | ||||
|  | ||||
| const props = defineProps<{   | ||||
|   title: string; | ||||
| const IS_MOCK_MODE = true;  | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   projectId: number; | ||||
|   title: number; | ||||
|   title_text: string; | ||||
|   description: string; | ||||
| }>(); | ||||
|  | ||||
| const expanded = ref(false); | ||||
| const isEditing = ref(false); | ||||
| const currentDescription = ref(props.description); | ||||
| const editedDescription = ref(props.description); | ||||
| const currentDescriptions = ref<string[]>([]); | ||||
| const editedDescriptions = ref<string[]>([]); | ||||
| const isEditing = ref<boolean[]>([]); | ||||
|  | ||||
|  | ||||
| /* | ||||
| const fetchData = async () => { | ||||
|   try { | ||||
|     const response = await axios.get("http://localhost:5000/data"); // Met à jour l'URL | ||||
| @@ -46,32 +59,121 @@ const fetchData = async () => { | ||||
|     console.error("Erreur lors de la récupération des données :", error); | ||||
|   } | ||||
| }; | ||||
| */ | ||||
|  | ||||
| // Fonction de simulation de l'API | ||||
| const mockFetch = async (projectId: number, title: number, date: string) => { | ||||
|   console.log(`Mock fetch pour projectId: ${projectId}, title: ${title}, date: ${date}`); | ||||
|  | ||||
|   return new Promise<{ txt: string }[]>((resolve) => { | ||||
|     setTimeout(() => { | ||||
|       resolve([ | ||||
|         { txt: "Ceci est une description 1 pour tester the damn front, Why are u still reading dumbass this is just some nonsense sentence XD" }, | ||||
|         { txt: "Ceci est une description 1 pour tester the damn front, Bruh are u still here?" }, | ||||
|         { txt: "Ceci est une description 1 pour tester the damn front, .-. BRUH" } | ||||
|       ]); | ||||
|     }, 500); // Simule un délai réseau de 500ms | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| // Fonction fetchData avec possibilité d'utiliser le mock | ||||
| const fetchData = async (projectId: number, title: number, date: string, useMock = false) => { | ||||
|   try { | ||||
|     const responseData = useMock | ||||
|       ? await mockFetch(projectId, title, date) | ||||
|       : (await axios.get<{ txt: string }[]>( | ||||
|           `http://localhost:5000/shared/projects/lcsection/${projectId}/${title}/${date}` | ||||
|         )).data; | ||||
|  | ||||
|     if (responseData.length > 0) { | ||||
|       currentDescriptions.value = responseData.map((item) => item.txt); | ||||
|       editedDescriptions.value = [...currentDescriptions.value]; // Copie initiale | ||||
|       isEditing.value = Array(responseData.length).fill(false); | ||||
|     } else { | ||||
|       console.warn("Aucune donnée reçue."); | ||||
|     } | ||||
|   } catch (error) { | ||||
|     console.error("Erreur lors de la récupération des données :", error); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // Utilisation du mock dans handleClick pour tester sans serveur | ||||
| const handleClick = async () => { | ||||
|   if (!expanded.value) { | ||||
|     await fetchData(); | ||||
|   } else if (!isEditing.value) { | ||||
|     currentDescription.value = props.description; | ||||
|     editedDescription.value = props.description; | ||||
|     await fetchData(props.projectId, props.title, "NaN", IS_MOCK_MODE); // true pour activer le mock | ||||
|   } else if (!isEditing.value.includes(true)) { | ||||
|     // Réinitialiser les descriptions si aucune édition n'est en cours | ||||
|     currentDescriptions.value = [props.description]; | ||||
|     editedDescriptions.value = [props.description]; | ||||
|   } | ||||
|  | ||||
|   if (!isEditing.value) { | ||||
|   if (!isEditing.value.includes(true)) { | ||||
|     expanded.value = !expanded.value; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const startEditing = () => { | ||||
|   isEditing.value = true; | ||||
|  | ||||
| const startEditing = (index: number) => { | ||||
|   isEditing.value[index] = true; | ||||
| }; | ||||
|  | ||||
| const saveEdit = () => { | ||||
|   currentDescription.value = editedDescription.value; | ||||
|   isEditing.value = false; | ||||
| /* | ||||
| const saveEdit = async (index: number) => { | ||||
|   try { | ||||
|     const id = index + 1; // À adapter selon l'ID réel des données | ||||
|     await axios.put(`http://localhost:5000/data/${id}`, { | ||||
|       canva_data: editedDescriptions.value[index] | ||||
|     }); | ||||
|  | ||||
|     // Mettre à jour l'affichage local après la mise à jour réussie | ||||
|     currentDescriptions.value[index] = editedDescriptions.value[index]; | ||||
|     isEditing.value[index] = false; | ||||
|   } catch (error) { | ||||
|     console.error("Erreur lors de la mise à jour des données :", error); | ||||
|   } | ||||
| }; | ||||
| */ | ||||
|  | ||||
| // Fonction de mock pour l'enregistrement | ||||
| const mockSaveEdit = async (index: number) => { | ||||
|   try { | ||||
|     const id = index + 1; // À adapter selon l'ID réel des données | ||||
|     console.log(`Mock save pour l'ID ${id} avec la description : ${editedDescriptions.value[index]}`); | ||||
|  | ||||
|     // Simuler un délai d'enregistrement comme une requête réseau | ||||
|     await new Promise((resolve) => setTimeout(resolve, 500)); // Simulation de délai réseau | ||||
|  | ||||
|     // Mettre à jour l'affichage local après la mise à jour réussie | ||||
|     currentDescriptions.value[index] = editedDescriptions.value[index]; | ||||
|     isEditing.value[index] = false; | ||||
|   } catch (error) { | ||||
|     console.error("Erreur lors de la mise à jour des données mockées :", error); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const cancelEdit = () => { | ||||
|   editedDescription.value = currentDescription.value; | ||||
|   isEditing.value = false; | ||||
| // Utilisation de `mockSaveEdit` au lieu de `saveEdit` dans `handleClick` ou tout autre endroit | ||||
| const saveEdit = async (index: number) => { | ||||
|   if (IS_MOCK_MODE) { | ||||
|     await mockSaveEdit(index); | ||||
|   } else { | ||||
|     try { | ||||
|       const id = index + 1; | ||||
|       await axios.put(`http://localhost:5000/data/${id}`, { | ||||
|         canva_data: editedDescriptions.value[index] | ||||
|       }); | ||||
|  | ||||
|       // Mettre à jour l'affichage local après la mise à jour réussie | ||||
|       currentDescriptions.value[index] = editedDescriptions.value[index]; | ||||
|       isEditing.value[index] = false; | ||||
|     } catch (error) { | ||||
|       console.error("Erreur lors de la mise à jour des données :", error); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const cancelEdit = (index: number) => { | ||||
|   editedDescriptions.value[index] = currentDescriptions.value[index]; | ||||
|   isEditing.value[index] = false; | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| @@ -109,6 +211,17 @@ const cancelEdit = () => { | ||||
|   color: #666; | ||||
| } | ||||
|  | ||||
| .cell .description { | ||||
|   width: 800px; | ||||
|   height: 100px; | ||||
|   overflow: hidden; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   text-align: center; | ||||
|   padding: 10px; | ||||
| } | ||||
|  | ||||
| .expanded { | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
| @@ -124,21 +237,21 @@ const cancelEdit = () => { | ||||
| } | ||||
|  | ||||
| .edit-input { | ||||
|   width: 80%; | ||||
|   width: 800px; | ||||
|   height: 100px; | ||||
|   font-size: 16px; | ||||
|   padding: 10px; | ||||
|   border: 1px solid #ccc; | ||||
|   border-radius: 5px; | ||||
|   margin-top: 10px; | ||||
|   box-sizing: border-box; | ||||
| } | ||||
|  | ||||
|  | ||||
| .button-container { | ||||
|   position: absolute; | ||||
|   bottom: 20px; | ||||
|   right: 20px; | ||||
|   display: flex; | ||||
|   gap: 10px; | ||||
|   margin-top: 10px; | ||||
| } | ||||
|  | ||||
| .edit-button, .save-button, .cancel-button { | ||||
| @@ -147,7 +260,8 @@ const cancelEdit = () => { | ||||
|   border-radius: 5px; | ||||
|   cursor: pointer; | ||||
|   transition: background 0.3s ease; | ||||
|   font-size: 16px; | ||||
|   font-size: 12px; | ||||
|   margin-right: 5px; | ||||
| } | ||||
|  | ||||
| .edit-button { | ||||
| @@ -177,5 +291,4 @@ const cancelEdit = () => { | ||||
|   background-color: #c82333; | ||||
| } | ||||
|  | ||||
| </style> | ||||
|    | ||||
| </style> | ||||
| @@ -4,7 +4,9 @@ | ||||
|       v-for="(item, index) in items" | ||||
|       :key="index" | ||||
|       :title="item.title" | ||||
|       :title_text="item.title_text" | ||||
|       :description="item.description" | ||||
|       :projectId="item.projectId" | ||||
|       :class="item.class" | ||||
|     /> | ||||
|   </div> | ||||
| @@ -15,16 +17,17 @@ import { ref } from "vue"; | ||||
| import CanvasItem from "@/components/canvas/CanvasItem.vue"; | ||||
|  | ||||
| const items = ref([ | ||||
|   { title: "1. Problème", description: "3 problèmes essentiels à résoudre pour le client", class: "Probleme" }, | ||||
|   { title: "2. Segments", description: "Les segments de clientèle visés", class: "Segments" }, | ||||
|   { title: "3. Valeur", description: "La proposition de valeur", class: "Valeur" }, | ||||
|   { title: "4. Solution", description: "Les solutions proposées", class: "Solution" }, | ||||
|   { title: "5. Avantage", description: "Les avantages concurrentiels", class: "Avantage" }, | ||||
|   { title: "6. Canaux", description: "Les canaux de distribution", class: "Canaux" }, | ||||
|   { title: "7. Indicateurs", description: "Les indicateurs clés de performance", class: "Indicateurs" }, | ||||
|   { title: "8. Coûts", description: "Les coûts associés", class: "Couts" }, | ||||
|   { title: "9. Revenus", description: "Les sources de revenus", class: "Revenus" } | ||||
|   { projectId: 1, title: 1, title_text: "1. Problème", description: "3 problèmes essentiels à résoudre pour le client", class: "Probleme" }, | ||||
|   { projectId: 1, title: 2, title_text: "2. Segments", description: "Les segments de clientèle visés", class: "Segments" }, | ||||
|   { projectId: 1, title: 3, title_text: "3. Valeur", description: "La proposition de valeur", class: "Valeur" }, | ||||
|   { projectId: 1, title: 4, title_text: "4. Solution", description: "Les solutions proposées", class: "Solution" }, | ||||
|   { projectId: 1, title: 5, title_text: "5. Avantage", description: "Les avantages concurrentiels", class: "Avantage" }, | ||||
|   { projectId: 1, title: 6, title_text: "6. Canaux", description: "Les canaux de distribution", class: "Canaux" }, | ||||
|   { projectId: 1, title: 7, title_text: "7. Indicateurs", description: "Les indicateurs clés de performance", class: "Indicateurs" }, | ||||
|   { projectId: 1, title: 8, title_text: "8. Coûts", description: "Les coûts associés", class: "Couts" }, | ||||
|   { projectId: 1, title: 9, title_text: "9. Revenus", description: "Les sources de revenus", class: "Revenus" } | ||||
| ]); | ||||
|  | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user