front_foundation #5

Open
mohamed_maoulainine wants to merge 73 commits from front_foundation into main
3 changed files with 133 additions and 58 deletions
Showing only changes of commit 647812576e - Show all commits

View File

@ -7,8 +7,8 @@ import ErrorWrapper from "@/views/errorWrapper.vue";
<Header /> <Header />
<ErrorWrapper /> <ErrorWrapper />
<RouterLink to="/">Home</RouterLink> | <!--<RouterLink to="/">Home</RouterLink> | -->
<RouterLink to="/canvas">Canvas</RouterLink> <!--<RouterLink to="/canvas">Canvas</RouterLink> -->
<RouterView /> <RouterView />
</template> </template>

View File

@ -35,9 +35,12 @@
</template> </template>
</template> </template>
</div> </div>
<!----------------------------------------------------------------------------------------------------> <!---------------------------------------------------------------------------------------------------->
<template v-if="expanded">
<div class="canvas-exit-hint">
Cliquez n'importe pour quitter le canvas
</div>
</template>
</div> </div>
</template> </template>
@ -107,9 +110,9 @@ const mockFetch = async (projectId: number, title: number, date: string) => {
return new Promise<{ txt: string }[]>((resolve) => { return new Promise<{ txt: string }[]>((resolve) => {
setTimeout(() => { setTimeout(() => {
resolve([ 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 le front. Franchement, si tu es encore en train de lire, cest probablement que tu veux t'assurer que tout saffiche bien même avec un texte bien long. Allez, encore quelques mots inutiles pour bien remplir la ligne et tester les retours à la ligne. Bravo champion."},
{ txt: "Ceci est une description 1 pour tester the damn front, Bruh are u still here?" }, {txt: "Deuxième description : elle est là pour taider à tester le comportement du composant avec du texte plus dense. Peut-être même avec quelques caractères spéciaux, tiens : éèàçù$#@! Et si on faisait semblant davoir du contenu sérieux ? Non, toujours pas."},
{ txt: "Ceci est une description 1 pour tester the damn front, .-. BRUH" } {txt: "Troisième description, probablement inutile mais bon, on continue pour la forme. À ce stade, tu testes sûrement si le champ de texte peut supporter un pavé sans exploser. Spoiler alert : si t'as tout bien codé, ça devrait aller. Sinon, bah... débogue. Courage."}
]); ]);
}, 500); // Simule un délai réseau de 500ms }, 500); // Simule un délai réseau de 500ms
}); });
@ -118,7 +121,7 @@ const mockFetch = async (projectId: number, title: number, date: string) => {
// Utilisation du mock dans handleClick pour tester sans serveur // Utilisation du mock dans handleClick pour tester sans serveur
const handleClick = async () => { const handleClick = async () => {
if (!expanded.value) { if (!expanded.value) {
await fetchData(props.projectId, props.title, "NaN", IS_MOCK_MODE); // true pour activer le mock await fetchData(props.projectId, props.title, "NaN", IS_MOCK_MODE);
} else if (!isEditing.value.includes(true)) { } else if (!isEditing.value.includes(true)) {
// Réinitialiser les descriptions si aucune édition n'est en cours // Réinitialiser les descriptions si aucune édition n'est en cours
currentDescriptions.value = [props.description]; currentDescriptions.value = [props.description];
@ -152,7 +155,6 @@ const saveEdit = async (index: number) => {
}; };
*/ */
// Utilisation de `mockSaveEdit` au lieu de `saveEdit` dans `handleClick` ou tout autre endroit
const saveEdit = async (index: number) => { const saveEdit = async (index: number) => {
if (IS_MOCK_MODE) { if (IS_MOCK_MODE) {
await mockSaveEdit(index); await mockSaveEdit(index);
@ -175,10 +177,9 @@ const saveEdit = async (index: number) => {
// Fonction de mock pour l'enregistrement // Fonction de mock pour l'enregistrement
const mockSaveEdit = async (index: number) => { const mockSaveEdit = async (index: number) => {
try { try {
const id = index + 1; // À adapter selon l'ID réel des données const id = index + 1;
console.log(`Mock save pour l'ID ${id} avec la description : ${editedDescriptions.value[index]}`); 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 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 // Mettre à jour l'affichage local après la mise à jour réussie
@ -198,6 +199,9 @@ const cancelEdit = (index: number) => {
<style scoped> <style scoped>
@import "@/components/canvas/style-project.css"; @import "@/components/canvas/style-project.css";
#marque {
}
.cell { .cell {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -221,7 +225,6 @@ const cancelEdit = (index: number) => {
.cell h3 { .cell h3 {
font-size: 20px; font-size: 20px;
font-weight: 500; font-weight: 500;
/*margin-bottom: 10px;*/
} }
.cell p { .cell p {
@ -247,9 +250,9 @@ const cancelEdit = (index: number) => {
.description { .description {
display: flex; display: flex;
align-items: center; /* Centre verticalement */ align-items: center;
justify-content: center; /* Centre horizontalement */ justify-content: center;
text-align: center; /* Centre le texte à l'intérieur */ text-align: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size: 16px; font-size: 16px;
@ -344,4 +347,15 @@ const cancelEdit = (index: number) => {
background-color: #c82333; background-color: #c82333;
} }
.canvas-exit-hint {
font-size: 0.75rem;
color: #666;
position: fixed;
bottom: 10px;
left: 0;
width: 100%;
text-align: center;
z-index: 1000;
}
</style> </style>

View File

@ -1,19 +1,19 @@
<template> <template>
<header> <header class="header">
<img src="../icons/logo inpulse.png" alt="INPulse Logo"> <img src="../icons/logo inpulse.png" alt="INPulse Logo" class="logo" />
<div class="header-buttons">
<div class="menu"> <div class="header-actions">
<div class="dropdown-wrapper">
<button class="contact-button" @click="toggleDropdown">Contact</button> <button class="contact-button" @click="toggleDropdown">Contact</button>
<div class="contact-dropdown" v-bind:class="{ 'dropdown-visible': isDropdownOpen }"> <div class="contact-dropdown" :class="{ 'dropdown-visible': isDropdownOpen }">
<button @click="contactAll">Contact All</button> <button @click="contactAll">Contacter tous</button>
<button v-for="(email, index) in entrepreneurEmails" :key="index"> <button v-for="(email, index) in entrepreneurEmails" :key="index">
{{ email }} {{ email }}
</button> </button>
</div> </div>
<button class="return-button">
<RouterLink to="/">Return to list project</RouterLink>
</button>
</div> </div>
<RouterLink to="/" class="return-button">Retour</RouterLink>
</div> </div>
</header> </header>
</template> </template>
@ -23,76 +23,138 @@
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import axios from "axios"; import axios from "axios";
const IS_MOCK_MODE = true;
const props = defineProps<{
projectId: number;
}>();
type Entrepreneur = {
id: number;
name: string;
primaryMail: string;
};
const isDropdownOpen = ref(false); const isDropdownOpen = ref(false);
const entrepreneurEmails = ref([]); const entrepreneurEmails = ref([]);
const toggleDropdown = () => { const toggleDropdown = () => {
isDropdownOpen.value = !isDropdownOpen.value; isDropdownOpen.value = !isDropdownOpen.value;
console.log("Dropdown toggled:", isDropdownOpen.value); // for debug purposes console.log("Dropdown toggled:", isDropdownOpen.value);
}; };
const fetchEntrepreneurs = async () => {
const fetchEntrepreneurs = async (projectId :number, useMock = IS_MOCK_MODE) => {
try { try {
const response = await axios.get("http://localhost:5000/entrepreneurs"); const responseData = useMock
entrepreneurEmails.value = response.data.map((e: { email: string }) => e.email); ? await mockFetchEntrepreneurs(projectId)
} catch (error) { : (await axios.get(`http://localhost:5000/shared/projects/entrepreneurs/${projectId}`)).data;
console.error("Erreur lors de la récupération des entrepreneurs:", error);
if (responseData.length > 0) {
entrepreneurEmails.value = responseData.map((item) => item.primaryMail);
} else {
console.warn("Aucun entrepreneur trouvé.");
} }
} catch (error) {
console.error("Erreur lors de la récupération des entrepreneurs :", error);
}
};
// Fonction de simulation de l'API
const mockFetchEntrepreneurs = async (projectId :number) => {
console.log(`Mock fetch pour projectId: ${projectId}`);
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{
idUser: 1,
userSurname: "Doe",
userName: "John",
primaryMail: "john.doe@example.com",
secondaryMail: "johndoe@backup.com",
phoneNumber: "612345678",
school: "ENSEIRB",
course: "Info",
sneeStatus: false
},
{
idUser: 2,
userSurname: "Smith",
userName: "Jane",
primaryMail: "jane.smith@example.com",
secondaryMail: "janesmith@backup.com",
phoneNumber: "698765432",
school: "ENSEIRB",
course: "Info",
sneeStatus: true
}
]);
}, 500);
});
}; };
const contactAll = () => { const contactAll = () => {
alert("Contacter tous les entrepreneurs : " + entrepreneurEmails.value.join(", ")); alert("Contacter tous les entrepreneurs : " + entrepreneurEmails.value.join(", "));
}; };
onMounted(fetchEntrepreneurs); onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
</script> </script>
<style scoped> <style scoped>
@import "@/components/canvas/style-project.css"; @import "@/components/canvas/style-project.css";
header { .header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: flex-start; align-items: center;
padding: 10px; padding: 15px 30px;
background-color: #f9f9f9;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
} }
.header-buttons { .logo {
height: 50px;
}
.header-actions {
display: flex; display: flex;
align-items: flex-start; align-items: center;
gap: 20px;
position: relative;
} }
.menu { .contact-button,
display: flex; .return-button {
flex-direction: column; background-color: #009CDE;
gap: 10px;
}
.contact-button, .return-button {
background-color: #000;
color: white; color: white;
border: none; border: none;
padding: 10px; padding: 10px 15px;
cursor: pointer; cursor: pointer;
font-size: 14px; font-size: 14px;
text-align: center; border-radius: 5px;
text-decoration: none;
transition: background-color 0.2s ease;
} }
.return-button a { .return-button:hover,
color: white; .contact-button:hover {
text-decoration: none; background-color: #007bad;
} }
.contact-dropdown { .contact-dropdown {
display: none;
position: absolute; position: absolute;
background-color: white; top: 100%;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2); left: 0;
background-color: #000;
color: white;
box-shadow: 0px 4px 8px rgba(255, 255, 255, 0.2);
border-radius: 8px; border-radius: 8px;
padding: 10px; padding: 10px;
margin-top: 5px; margin-top: 5px;
z-index: 1000; z-index: 1000;
min-width: 200px;
display: none;
} }
.contact-dropdown button { .contact-dropdown button {
@ -103,18 +165,17 @@ header {
border: none; border: none;
background: none; background: none;
cursor: pointer; cursor: pointer;
color: white;
} }
.contact-dropdown button:hover { .contact-dropdown button:hover {
background-color: #f0f0f0; background-color: #009CDE;
} }
.dropdown-visible { .contact-dropdown.dropdown-visible {
display: block; display: block;
} }
header img {
width: 100px;
height: auto;
}
</style> </style>