Merge branch 'front_foundation' of https://gitea.piair.dev/piair/MyINPulse into front_foundation

This commit is contained in:
Mohamed Maoulainine Maoulainine 2025-03-24 12:43:04 +01:00
commit 7e0851bfef
3 changed files with 221 additions and 52 deletions

View File

@ -1,10 +1,63 @@
{ {
"entrepreneurs": [ "entrepreneurs": [
{ "id": 1, "name": "Alice", "email": "alice@example.com" }, { "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob", "email": "bob@example.com" }, { "id": 2, "name": "Bob", "email": "bob@example.com" },
{ "id": 3, "name": "Charlie", "email": "charlie@example.com" } { "id": 3, "name": "Charlie", "email": "charlie@example.com" }
], ],
"data": [ "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"
}
] ]
} }

View File

@ -1,21 +1,28 @@
<template> <template>
<div :class="['cell', { expanded }]" @click="handleClick"> <div :class="['cell', { expanded }]" @click="handleClick">
<h3>{{ title }}</h3> <h3>{{ title_text }}</h3>
<!-- Mode affichage --> <div v-for="(desc, index) in currentDescriptions" :key="index">
<template v-if="!isEditing"> <!-- Mode affichage -->
<p>{{ currentDescription }}</p> <template v-if="!isEditing[index]">
<button v-if="expanded" @click.stop="startEditing" class="edit-button">Éditer</button> <div class="description">
</template> <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> </div>
</template> </template>
@ -23,16 +30,22 @@
import { ref, defineProps } from "vue"; import { ref, defineProps } from "vue";
import axios from "axios"; import axios from "axios";
const props = defineProps<{ const IS_MOCK_MODE = true;
title: string;
const props = defineProps<{
projectId: number;
title: number;
title_text: string;
description: string; description: string;
}>(); }>();
const expanded = ref(false); const expanded = ref(false);
const isEditing = ref(false); const currentDescriptions = ref<string[]>([]);
const currentDescription = ref(props.description); const editedDescriptions = ref<string[]>([]);
const editedDescription = ref(props.description); const isEditing = ref<boolean[]>([]);
/*
const fetchData = async () => { const fetchData = async () => {
try { try {
const response = await axios.get("http://localhost:5000/data"); // Met à jour l'URL 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); 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 () => { const handleClick = async () => {
if (!expanded.value) { if (!expanded.value) {
await fetchData(); await fetchData(props.projectId, props.title, "NaN", IS_MOCK_MODE); // true pour activer le mock
} else if (!isEditing.value) { } else if (!isEditing.value.includes(true)) {
currentDescription.value = props.description; // Réinitialiser les descriptions si aucune édition n'est en cours
editedDescription.value = props.description; currentDescriptions.value = [props.description];
editedDescriptions.value = [props.description];
} }
if (!isEditing.value) { if (!isEditing.value.includes(true)) {
expanded.value = !expanded.value; expanded.value = !expanded.value;
} }
}; };
const startEditing = () => {
isEditing.value = true; const startEditing = (index: number) => {
isEditing.value[index] = true;
}; };
const saveEdit = () => { /*
currentDescription.value = editedDescription.value; const saveEdit = async (index: number) => {
isEditing.value = false; 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 = () => { // Utilisation de `mockSaveEdit` au lieu de `saveEdit` dans `handleClick` ou tout autre endroit
editedDescription.value = currentDescription.value; const saveEdit = async (index: number) => {
isEditing.value = false; 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> </script>
@ -109,6 +211,17 @@ const cancelEdit = () => {
color: #666; color: #666;
} }
.cell .description {
width: 800px;
height: 100px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 10px;
}
.expanded { .expanded {
position: fixed; position: fixed;
top: 0; top: 0;
@ -124,21 +237,21 @@ const cancelEdit = () => {
} }
.edit-input { .edit-input {
width: 80%; width: 800px;
height: 100px; height: 100px;
font-size: 16px; font-size: 16px;
padding: 10px; padding: 10px;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 5px; border-radius: 5px;
margin-top: 10px; margin-top: 10px;
box-sizing: border-box;
} }
.button-container { .button-container {
position: absolute;
bottom: 20px;
right: 20px;
display: flex; display: flex;
gap: 10px; gap: 10px;
margin-top: 10px;
} }
.edit-button, .save-button, .cancel-button { .edit-button, .save-button, .cancel-button {
@ -147,7 +260,8 @@ const cancelEdit = () => {
border-radius: 5px; border-radius: 5px;
cursor: pointer; cursor: pointer;
transition: background 0.3s ease; transition: background 0.3s ease;
font-size: 16px; font-size: 12px;
margin-right: 5px;
} }
.edit-button { .edit-button {
@ -177,5 +291,4 @@ const cancelEdit = () => {
background-color: #c82333; background-color: #c82333;
} }
</style> </style>

View File

@ -4,7 +4,9 @@
v-for="(item, index) in items" v-for="(item, index) in items"
:key="index" :key="index"
:title="item.title" :title="item.title"
:title_text="item.title_text"
:description="item.description" :description="item.description"
:projectId="item.projectId"
:class="item.class" :class="item.class"
/> />
</div> </div>
@ -15,16 +17,17 @@ import { ref } from "vue";
import CanvasItem from "@/components/canvas/CanvasItem.vue"; import CanvasItem from "@/components/canvas/CanvasItem.vue";
const items = ref([ const items = ref([
{ title: "1. Problème", description: "3 problèmes essentiels à résoudre pour le client", class: "Probleme" }, { projectId: 1, title: 1, title_text: "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" }, { projectId: 1, title: 2, title_text: "2. Segments", description: "Les segments de clientèle visés", class: "Segments" },
{ title: "3. Valeur", description: "La proposition de valeur", class: "Valeur" }, { projectId: 1, title: 3, title_text: "3. Valeur", description: "La proposition de valeur", class: "Valeur" },
{ title: "4. Solution", description: "Les solutions proposées", class: "Solution" }, { projectId: 1, title: 4, title_text: "4. Solution", description: "Les solutions proposées", class: "Solution" },
{ title: "5. Avantage", description: "Les avantages concurrentiels", class: "Avantage" }, { projectId: 1, title: 5, title_text: "5. Avantage", description: "Les avantages concurrentiels", class: "Avantage" },
{ title: "6. Canaux", description: "Les canaux de distribution", class: "Canaux" }, { projectId: 1, title: 6, title_text: "6. Canaux", description: "Les canaux de distribution", class: "Canaux" },
{ title: "7. Indicateurs", description: "Les indicateurs clés de performance", class: "Indicateurs" }, { projectId: 1, title: 7, title_text: "7. Indicateurs", description: "Les indicateurs clés de performance", class: "Indicateurs" },
{ title: "8. Coûts", description: "Les coûts associés", class: "Couts" }, { projectId: 1, title: 8, title_text: "8. Coûts", description: "Les coûts associés", class: "Couts" },
{ title: "9. Revenus", description: "Les sources de revenus", class: "Revenus" } { projectId: 1, title: 9, title_text: "9. Revenus", description: "Les sources de revenus", class: "Revenus" }
]); ]);
</script> </script>
<style scoped> <style scoped>