front_foundation #9

Closed
mohamed_maoulainine wants to merge 181 commits from front_foundation into main
17 changed files with 1414 additions and 1286 deletions
Showing only changes of commit c60fb8945b - Show all commits

View File

@ -1,16 +1,12 @@
<script setup lang="ts">
import { /*RouterLink,*/ RouterView } from 'vue-router'
import { /*RouterLink,*/ RouterView } from "vue-router";
Review

I don't like the comments in the middle of the line, it would be better to delete this part.

I don't like the comments in the middle of the line, it would be better to delete this part.
import ErrorWrapper from "@/views/errorWrapper.vue";
</script>
<template>
<Header />
<ErrorWrapper />
Review

same, I don't think it's really important to keep comments

same, I don't think it's really important to keep comments
<!--<RouterLink to="/">Home</RouterLink> | -->
<!--<RouterLink to="/canvas">Canvas</RouterLink> -->
<RouterView />
</template>

View File

@ -53,7 +53,6 @@
</script>
<style scoped>
h2 {
Outdated
Review

The h2 from this file is the same as the h3 from the next (AgendaComponent). It would be better to have a single css file for this part.

The h2 from this file is the same as the h3 from the next (AgendaComponent). It would be better to have a single css file for this part.
font-size: 1.5rem;
color: #333;
@ -107,4 +106,3 @@
background-color: #45a049;
}
</style>

View File

@ -17,7 +17,6 @@
</tr>
</tbody>
</table>
</div>
</template>
@ -25,19 +24,17 @@
import { defineProps } from "vue";
interface rendezVous {
projectName: string,
date: string,
lieu: string,
projectName: string;
date: string;
lieu: string;
}
defineProps<{
projectRDV: rendezVous[]
projectRDV: rendezVous[];
Review

où est-ce que les RDV sont récupérés ?

où est-ce que les RDV sont récupérés ?
}>();
</script>
<style scoped>
h3 {
Review

same comment as before, most of the style here is not for this part only, so it should not be here

same comment as before, most of the style here is not for this part only, so it should not be here
font-size: 1.5rem;
color: #333;
@ -53,7 +50,6 @@
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
/* Table Styling */
table {
width: 100%;
@ -71,7 +67,6 @@
color: #333;
}
/* Table Body Rows */
tbody tr {
border-bottom: 1px solid #ddd;
@ -95,5 +90,4 @@
text-align: center;
width: 50px; /* Adjust width as needed */
}
</style>

View File

@ -13,7 +13,7 @@ type TokenPayload = {
};
};
const customRequest = ref('');
const customRequest = ref("");
onMounted(() => {
if (store.authenticated && store.user.token) {
@ -40,19 +40,24 @@ const callApiWithLoading = async (path: string) => {
loading.value = false;
};
*/
</script>
<template>
<error-wrapper></error-wrapper>
<div class="auth-container">
<div class="auth-card">
<h1>Bienvenue</h1>
<div class="status" :class="store.authenticated ? 'success' : 'error'">
<div
class="status"
:class="store.authenticated ? 'success' : 'error'"
>
<p>
{{ store.authenticated ? '✅ Authenticated' : '❌ Not Authenticated' }}
{{
store.authenticated
? "✅ Authenticated"
: "❌ Not Authenticated"
}}
</p>
</div>
@ -74,12 +79,17 @@ const callApiWithLoading = async (path: string) => {
Review

same, it should be hidden

same, it should be hidden
<div class="api-calls">
<h2>Test API Calls</h2>
<button @click="callApi('random')">Call Entrepreneur API</button>
<button @click="callApi('random')">
Call Entrepreneur API
</button>
<button @click="callApi('random2')">Call Admin API</button>
<button @click="callApi('unauth/dev')">Call Unauth API</button>
<div class="custom-call">
<input v-model="customRequest" placeholder="Custom endpoint" />
<input
v-model="customRequest"
placeholder="Custom endpoint"
/>
<button @click="callApi(customRequest)">Call</button>
</div>
</div>
@ -193,6 +203,4 @@ h1 {
background-color: #ffe2e2;
color: #c62828;
}
</style>

View File

@ -11,11 +11,8 @@
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { defineProps } from "vue";
import { postApi } from "@/services/api";
@ -52,8 +49,6 @@ const acceptProject = () => sendDecision("true");
const refuseProject = () => sendDecision("false");
</script>
<style scoped>
.project {
background: linear-gradient(to right, #f8f9fb, #ffffff);
@ -109,11 +104,13 @@ button {
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s ease, transform 0.2s ease;
transition:
background-color 0.2s ease,
transform 0.2s ease;
}
#accept {
background-color: #4CAF50;
background-color: #4caf50;
}
#accept:hover {
@ -129,5 +126,4 @@ button {
background-color: #c0392b;
transform: translateY(-2px);
}
</style>

View File

@ -4,8 +4,13 @@
<h2>{{ projectName }}</h2>
<div class="header-actions">
<div class="dropdown-wrapper">
<button class="contact-button" @click="toggleDropdown">Contact</button>
<div class="contact-dropdown" :class="{ 'dropdown-visible': isDropdownOpen }">
<button class="contact-button" @click="toggleDropdown">
Contact
</button>
<div
class="contact-dropdown"
:class="{ 'dropdown-visible': isDropdownOpen }"
>
<button @click="contactAll">Contacter tous</button>
<button
v-for="(email, index) in entrepreneurEmails"
@ -17,21 +22,20 @@
</div>
</div>
</div>
</div>
<div class="project-body">
<ul>
<li v-for="(name, index) in listName" :key="index">{{ name }}</li>
<li v-for="(name, index) in listName" :key="index">
{{ name }}
</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
import { defineProps } from "vue";
import { useRouter } from 'vue-router'
import { useRouter } from "vue-router";
import { ref, onMounted } from "vue";
import axios from "axios";
const IS_MOCK_MODE = true;
@ -49,7 +53,6 @@ const goToLink = () => {
if (props.projectLink) {
router.push(props.projectLink);
}
};
type Entrepreneur = {
@ -72,19 +75,31 @@ const toggleDropdown = () => {
console.log("Dropdown toggled:", isDropdownOpen.value);
};
const fetchEntrepreneurs = async (projectId: number, useMock = IS_MOCK_MODE) => {
const fetchEntrepreneurs = async (
projectId: number,
useMock = IS_MOCK_MODE
) => {
try {
const responseData: Entrepreneur[] = useMock
? await mockFetchEntrepreneurs(projectId)
: (await axios.get(`http://localhost:5000/shared/projects/entrepreneurs/${projectId}`)).data;
: (
await axios.get(
`http://localhost:5000/shared/projects/entrepreneurs/${projectId}`
)
).data;
if (responseData.length > 0) {
adnane marked this conversation as resolved Outdated
Outdated
Review

We should not use axios.get EVER, it does not send the authentication token.

We should not use axios.get EVER, it does not send the authentication token.
entrepreneurEmails.value = responseData.map((item: Entrepreneur) => item.primaryMail);
entrepreneurEmails.value = responseData.map(
(item: Entrepreneur) => item.primaryMail
);
} else {
console.warn("Aucun entrepreneur trouvé.");
}
} catch (error) {
console.error("Erreur lors de la récupération des entrepreneurs :", error);
console.error(
"Erreur lors de la récupération des entrepreneurs :",
error
);
}
};
@ -104,7 +119,7 @@ const mockFetchEntrepreneurs = async (projectId :number) => {
phoneNumber: "612345678",
school: "ENSEIRB",
course: "Info",
sneeStatus: false
sneeStatus: false,
},
{
idUser: 2,
@ -115,8 +130,8 @@ const mockFetchEntrepreneurs = async (projectId :number) => {
phoneNumber: "698765432",
school: "ENSEIRB",
course: "Info",
sneeStatus: true
}
sneeStatus: true,
},
]);
}, 500);
});
@ -124,23 +139,25 @@ const mockFetchEntrepreneurs = async (projectId :number) => {
const contactAll = () => {
const allEmails = entrepreneurEmails.value.join(", ");
navigator.clipboard.writeText(allEmails)
navigator.clipboard
.writeText(allEmails)
.then(() => {
alert("Tous les emails copiés dans le presse-papiers !");
window.open("https://partage.bordeaux-inp.fr/", "_blank");
})
.catch(err => {
.catch((err) => {
console.error("Erreur lors de la copie :", err);
});
};
const contactSingle = (email: string) => {
adnane marked this conversation as resolved Outdated
Outdated
Review

I personally hate that, can't we use an error mesage in green ?

I personally hate that, can't we use an error mesage in green ?

ok

ok
navigator.clipboard.writeText(email)
navigator.clipboard
.writeText(email)
.then(() => {
alert(`Adresse copiée : ${email}`);
window.open("https://partage.bordeaux-inp.fr/", "_blank");
})
.catch(err => {
.catch((err) => {
console.error("Erreur lors de la copie :", err);
});
};
@ -148,7 +165,6 @@ const contactSingle = (email: string) => {
onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
</script>
<style scoped>
.project {
background: linear-gradient(to right, #f8f9fb, #ffffff);
@ -193,7 +209,9 @@ onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
border-radius: 8px;
font-size: 0.9rem;
font-weight: 500;
transition: background-color 0.2s ease, transform 0.2s ease;
transition:
background-color 0.2s ease,
transform 0.2s ease;
}
.contact-btn:hover {
@ -217,7 +235,6 @@ onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
line-height: 1.6;
}
adnane marked this conversation as resolved Outdated
Outdated
Review

generic style once again

generic style once again
button {
padding: 10px 15px;
background-color: #007bff;
@ -229,5 +246,4 @@ onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
button:hover {
background-color: #0056b3;
}
</style>

View File

@ -2,8 +2,11 @@
<div :class="['cell', { expanded }]" @click="handleClick">
<h3 class="fs-5 fw-medium">{{ titleText }}</h3>
<div v-for="(desc, index) in currentDescriptions" :key="index" class="section-bloc">
<div
v-for="(desc, index) in currentDescriptions"
:key="index"
class="section-bloc"
>
<!-- ADMIN -------------------------------------------------------------------------------------------->
<template v-if="IS_ADMIN">
@ -21,16 +24,35 @@
<p class="m-0">{{ desc }}</p>
</div>
<div class="button-container">
<button v-if="expanded" class="edit-button" @click.stop="startEditing(index)">Éditer</button>
<button
v-if="expanded"
class="edit-button"
@click.stop="startEditing(index)"
>
Éditer
</button>
</div>
</template>
<!-- Mode édition -->
<template v-else>
<textarea v-model="editedDescriptions[index]" class="edit-input"></textarea>
<textarea
v-model="editedDescriptions[index]"
class="edit-input"
></textarea>
<div class="button-container">
<button class="save-button" @click.stop="saveEdit(index)">Enregistrer</button>
<button class="cancel-button" @click.stop="cancelEdit(index)">Annuler</button>
<button
class="save-button"
@click.stop="saveEdit(index)"
>
Enregistrer
</button>
<button
class="cancel-button"
@click.stop="cancelEdit(index)"
>
Annuler
</button>
</div>
</template>
</template>
@ -71,7 +93,6 @@ onMounted(() => {
fetchData(props.projectId, props.title, "NaN", IS_MOCK_MODE);
});
/* FOR LOCAL DATABASE
const fetchData = async () => {
try {
@ -111,13 +132,20 @@ const fetchData = async (projectId: number, title: number, date: string, useMock
*/
// Fonction fetchData avec possibilité d'utiliser le mock
const fetchData = async (projectId: number, title: number, date: string, useMock = false) => {
const fetchData = async (
projectId: number,
title: number,
date: string,
useMock = false
) => {
try {
const responseData = useMock
? await mockFetch(projectId, title, date)
: (await axiosInstance.get<{ txt: string }[]>(
: (
await axiosInstance.get<{ txt: string }[]>(
adnane marked this conversation as resolved Outdated
Outdated
Review

be careful with axiosInstance, but i may be fine

be careful with axiosInstance, but i may be fine
`/shared/projects/lcsection/${projectId}/${title}/${date}`
)).data;
)
).data;
if (responseData.length > 0) {
currentDescriptions.value = responseData.map((item) => item.txt);
@ -133,14 +161,16 @@ const fetchData = async (projectId: number, title: number, date: string, useMock
// 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}`);
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 le front." },
{ txt: "Deuxième description." },
{txt: "Troisième description."}
{ txt: "Troisième description." },
]);
}, 500); // Simule un délai réseau de 500ms
});
@ -161,7 +191,6 @@ const handleClick = async () => {
}
};
const startEditing = (index: number) => {
isEditing.value[index] = true;
};
@ -190,7 +219,7 @@ const saveEdit = async (index: number) => {
try {
const id = index + 1;
await axios.put(`http://localhost:5000/data/${id}`, {
adnane marked this conversation as resolved Outdated
Outdated
Review

same

same
canva_data: editedDescriptions.value[index]
canva_data: editedDescriptions.value[index],
});
// Mettre à jour l'affichage local après la mise à jour réussie
@ -206,7 +235,9 @@ const saveEdit = async (index: number) => {
const mockSaveEdit = async (index: number) => {
try {
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]}`
);
await new Promise((resolve) => setTimeout(resolve, 500)); // Simulation de délai réseau
@ -214,7 +245,10 @@ const mockSaveEdit = async (index: number) => {
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);
console.error(
"Erreur lors de la mise à jour des données mockées :",
error
);
}
};
@ -227,7 +261,6 @@ const cancelEdit = (index: number) => {
<style scoped>
@import "@/components/canvas/style-project.css";
.cell {
display: flex;
flex-direction: column;
@ -239,7 +272,6 @@ const cancelEdit = (index: number) => {
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.1);
}
.expanded-content {
justify-content: flex-start !important;
}
@ -252,13 +284,13 @@ const cancelEdit = (index: number) => {
.cell h3 {
font-size: 15px;
font-weight: 500;
font-family: 'Arial', sans-serif;
font-family: "Arial", sans-serif;
}
.p {
font-size: 10px;
color: #666;
font-family: 'Arial', sans-serif;
font-family: "Arial", sans-serif;
}
.expanded {
@ -276,7 +308,6 @@ const cancelEdit = (index: number) => {
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}
.description {
display: flex;
align-items: center;
@ -296,8 +327,6 @@ const cancelEdit = (index: number) => {
text-align: center;
}
.edit-input {
width: 100%;
height: 100%;
@ -309,7 +338,6 @@ const cancelEdit = (index: number) => {
margin-left: 2%;
}
.button-container {
display: block;
margin-top: 20px;
@ -319,8 +347,8 @@ const cancelEdit = (index: number) => {
padding-right: 1%;
}
.section-bloc ,.editing-section-bloc {
.section-bloc,
.editing-section-bloc {
width: 100%;
justify-content: center;
align-items: center;
@ -329,10 +357,6 @@ const cancelEdit = (index: number) => {
margin: 10px;
}
.edit-button {
width: 100px;
height: 40px;
@ -344,7 +368,8 @@ const cancelEdit = (index: number) => {
margin-right: 20px;
}
.save-button, .cancel-button {
.save-button,
.cancel-button {
width: 100px;
height: 40px;
border: none;
@ -392,5 +417,4 @@ const cancelEdit = (index: number) => {
text-align: center;
z-index: 1000;
}
</style>

View File

@ -4,8 +4,13 @@
<div class="header-actions">
<div class="dropdown-wrapper">
<button class="contact-button" @click="toggleDropdown">Contact</button>
<div class="contact-dropdown" :class="{ 'dropdown-visible': isDropdownOpen }">
<button class="contact-button" @click="toggleDropdown">
Contact
</button>
<div
class="contact-dropdown"
:class="{ 'dropdown-visible': isDropdownOpen }"
>
<button @click="contactAll">Contacter tous</button>
<button
v-for="(email, index) in entrepreneurEmails"
@ -21,7 +26,6 @@
</header>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import axios from "axios";
adnane marked this conversation as resolved Outdated
Outdated
Review

I won't talk again about axios

I won't talk again about axios
@ -52,19 +56,31 @@ const toggleDropdown = () => {
console.log("Dropdown toggled:", isDropdownOpen.value);
};
const fetchEntrepreneurs = async (projectId: number, useMock = IS_MOCK_MODE) => {
const fetchEntrepreneurs = async (
projectId: number,
useMock = IS_MOCK_MODE
) => {
try {
const responseData: Entrepreneur[] = useMock
? await mockFetchEntrepreneurs(projectId)
: (await axios.get(`http://localhost:5000/shared/projects/entrepreneurs/${projectId}`)).data;
: (
await axios.get(
`http://localhost:5000/shared/projects/entrepreneurs/${projectId}`
)
).data;
if (responseData.length > 0) {
entrepreneurEmails.value = responseData.map((item: Entrepreneur) => item.primaryMail);
entrepreneurEmails.value = responseData.map(
(item: Entrepreneur) => item.primaryMail
);
} else {
console.warn("Aucun entrepreneur trouvé.");
}
} catch (error) {
console.error("Erreur lors de la récupération des entrepreneurs :", error);
console.error(
"Erreur lors de la récupération des entrepreneurs :",
error
);
}
};
@ -84,7 +100,7 @@ const mockFetchEntrepreneurs = async (projectId :number) => {
phoneNumber: "612345678",
school: "ENSEIRB",
course: "Info",
sneeStatus: false
sneeStatus: false,
},
{
idUser: 2,
@ -95,8 +111,8 @@ const mockFetchEntrepreneurs = async (projectId :number) => {
phoneNumber: "698765432",
school: "ENSEIRB",
course: "Info",
sneeStatus: true
}
sneeStatus: true,
},
]);
}, 500);
});
@ -104,23 +120,25 @@ const mockFetchEntrepreneurs = async (projectId :number) => {
const contactAll = () => {
const allEmails = entrepreneurEmails.value.join(", ");
navigator.clipboard.writeText(allEmails)
navigator.clipboard
.writeText(allEmails)
.then(() => {
alert("Tous les emails copiés dans le presse-papiers !");
window.open("https://partage.bordeaux-inp.fr/", "_blank");
})
.catch(err => {
.catch((err) => {
console.error("Erreur lors de la copie :", err);
});
};
const contactSingle = (email: string) => {
navigator.clipboard.writeText(email)
navigator.clipboard
.writeText(email)
.then(() => {
alert(`Adresse copiée : ${email}`);
window.open("https://partage.bordeaux-inp.fr/", "_blank");
})
.catch(err => {
.catch((err) => {
console.error("Erreur lors de la copie :", err);
});
};
@ -163,7 +181,7 @@ onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
.contact-button,
.return-button {
background-color: #009CDE;
background-color: #009cde;
color: white;
border: none;
padding: 10px 15px;
@ -180,7 +198,6 @@ onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
background-color: #007bad;
}
.contact-dropdown {
position: absolute;
top: 100%;
@ -208,12 +225,10 @@ onMounted(() => fetchEntrepreneurs(props.projectId, IS_MOCK_MODE));
}
.contact-dropdown button:hover {
background-color: #009CDE;
background-color: #009cde;
}
.contact-dropdown.dropdown-visible {
display: block;
}
</style>

View File

@ -8,7 +8,7 @@
:description="item.description"
:project-id="item.projectId"
:class="['canvas-item', item.class, 'card', 'shadow', 'p-3']"
:is-admin= props.isAdmin
:is-admin="props.isAdmin"
/>
</div>
</template>
@ -22,31 +22,89 @@ const props = defineProps<{
}>();
const items = ref([
{ 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" }
{
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",
},
]);
onMounted(() => {
const bootstrapCss = document.createElement('link')
bootstrapCss.rel = 'stylesheet'
bootstrapCss.href = 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css'
bootstrapCss.integrity = 'sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+Fpc+NC'
bootstrapCss.crossOrigin = 'anonymous'
document.head.appendChild(bootstrapCss)
const bootstrapCss = document.createElement("link");
bootstrapCss.rel = "stylesheet";
bootstrapCss.href =
"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css";
adnane marked this conversation as resolved Outdated
Outdated
Review

Why is bootstrap imported here ?

Why is bootstrap imported here ?
bootstrapCss.integrity =
"sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+Fpc+NC";
bootstrapCss.crossOrigin = "anonymous";
document.head.appendChild(bootstrapCss);
const bootstrapJs = document.createElement('script')
bootstrapJs.src = 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js'
bootstrapJs.integrity = 'sha384-mQ93S0EhrF4Z1nM+fTflmYf0DyzsY5j7F5H3WlClDD6H3WUJh6kxBkF3GDW8n1j6'
bootstrapJs.crossOrigin = 'anonymous'
document.body.appendChild(bootstrapJs)
})
const bootstrapJs = document.createElement("script");
bootstrapJs.src =
"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js";
bootstrapJs.integrity =
"sha384-mQ93S0EhrF4Z1nM+fTflmYf0DyzsY5j7F5H3WlClDD6H3WUJh6kxBkF3GDW8n1j6";
bootstrapJs.crossOrigin = "anonymous";
document.body.appendChild(bootstrapJs);
});
</script>
<style scoped>
@ -64,15 +122,42 @@ onMounted(() => {
overflow: auto;
}
.Probleme { grid-column: 1 / 3; grid-row: 1 / 5; }
.Segments { grid-column: 9 / 11; grid-row: 1 / 5; }
.Valeur { grid-column: 5 / 7; grid-row: 1 / 5; }
.Solution { grid-column: 3 / 5; grid-row: 1 / 3; }
.Avantage { grid-column: 7 / 9; grid-row: 1 / 3; }
.Canaux { grid-column: 7 / 9; grid-row: 3 / 5; }
.Indicateurs { grid-column: 3 / 5; grid-row: 3 / 5; }
.Couts { grid-column: 1 / 6; grid-row: 5 / 7; }
.Revenus { grid-column: 6 / 11; grid-row: 5 / 7; }
.Probleme {
grid-column: 1 / 3;
grid-row: 1 / 5;
}
.Segments {
grid-column: 9 / 11;
grid-row: 1 / 5;
}
.Valeur {
grid-column: 5 / 7;
grid-row: 1 / 5;
}
.Solution {
grid-column: 3 / 5;
grid-row: 1 / 3;
}
.Avantage {
grid-column: 7 / 9;
grid-row: 1 / 3;
}
.Canaux {
grid-column: 7 / 9;
grid-row: 3 / 5;
}
.Indicateurs {
grid-column: 3 / 5;
grid-row: 3 / 5;
}
.Couts {
grid-column: 1 / 6;
grid-row: 5 / 7;
}
.Revenus {
grid-column: 6 / 11;
grid-row: 5 / 7;
}
.canvas-item {
/*background-color: white;*/

View File

@ -39,7 +39,6 @@ body {
font-size: 14px;
}
body {
font-family: Arial, sans-serif;
margin: 0;
@ -94,7 +93,8 @@ body {
position: relative;
}
.contact-button, .return {
.contact-button,
.return {
padding: 10px 15px;
border: none;
border-radius: 4px;
@ -103,7 +103,8 @@ body {
cursor: pointer;
}
.contact-button:hover, .return:hover {
.contact-button:hover,
.return:hover {
background-color: #1976d2;
}
@ -150,7 +151,6 @@ body {
gap: 15px;
}
a {
color: white;
}

View File

@ -26,8 +26,7 @@ keycloakService.CallInit(() => {
console.error(e);
createApp(App).mount("#app");
}
})
});
// this shit made by me so i can run the canva vue app
adnane marked this conversation as resolved Outdated
Outdated
Review

We can't let this kind of comments

We can't let this kind of comments
//createApp(App).use(router).mount('#app');
@ -71,7 +70,4 @@ app.use(VueKeyCloak,{
} );
*/
export { store };

View File

@ -4,43 +4,43 @@ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/test',
name: 'test',
path: "/test",
name: "test",
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/testComponent.vue'),
component: () => import("../views/testComponent.vue"),
},
{
path: '/login',
name: 'login',
component: () => import('../components/LoginComponent.vue'),
path: "/login",
name: "login",
component: () => import("../components/LoginComponent.vue"),
},
{
path: '/',
name: 'Admin-main',
component: () => import('../views/AdminMain.vue'),
path: "/",
name: "Admin-main",
component: () => import("../views/AdminMain.vue"),
},
// route pour les canvas (made by adnane), in fact the two vue apps are separated for now
{
path: '/canvas',
name: 'canvas',
component: () => import('../views/CanvasView.vue'),
path: "/canvas",
name: "canvas",
component: () => import("../views/CanvasView.vue"),
},
{
path: '/signup',
name: 'signup',
component: () => import('../views/EntrepSignUp.vue'),
path: "/signup",
name: "signup",
component: () => import("../views/EntrepSignUp.vue"),
},
{
path: '/JorCproject',
name: 'JorCproject',
component: () => import('../views/JoinOrCreatProjectForEntrep.vue'),
path: "/JorCproject",
adnane marked this conversation as resolved
Review

Can we find a better name ?

Can we find a better name ?
Review

ok

ok
name: "JorCproject",
component: () => import("../views/JoinOrCreatProjectForEntrep.vue"),
},
],
})
});
export default router;

View File

@ -88,5 +88,4 @@ function deleteApi(
.catch(onErrorHandler ?? defaultApiErrorHandler);
}
export { axiosInstance, callApi, postApi, deleteApi };

View File

@ -29,7 +29,6 @@
<Agenda :project-r-d-v="rendezVous" />
</div>
</template>
<script setup lang="ts">
@ -89,7 +88,6 @@ import AddProjectForm from "@/components/AddProjectForm.vue";
onMounted(fetchProjects);
*/
Outdated
Review

what is that for ?

what is that for ?
const projects = ref([
{
name: "Projet Alpha",
@ -103,21 +101,18 @@ const projects = ref([
},
]);
const pendingProjects = ref([
{ name: "l'eau", creationDate: "26-02-2024" },
{ name: "l'air", creationDate: "09-03-2023" },
])
]);
const rendezVous = ref([
{ projectName: "Projet Alpha", date: "2025-03-10", lieu: "P106" },
{ projectName: "Projet Beta", date: "2025-04-15", lieu: "Td10" },
]);
</script>
<style scoped>
#container {
Outdated
Review

same comment for CSS

same comment for CSS
display: grid;
grid-template-columns: 3fr 1fr;
@ -162,6 +157,4 @@ button:hover {
#main > * + * {
margin-top: 2rem;
}
</style>

View File

@ -8,24 +8,32 @@
<h1 class="page-title">PAGE CANVAS</h1>
<p class="canvas-help-text">
Cliquez sur un champ du tableau pour afficher son contenu en détail ci-dessous.
Cliquez sur un champ du tableau pour afficher son contenu en détail
ci-dessous.
</p>
<LeanCanvas :is-admin=isAdmin />
<LeanCanvas :is-admin="isAdmin" />
<div class="info-box">
<p>
Responsable : <strong>{{ admin.userName }} {{ admin.userSurname }}</strong><br />
Contact : <a href="mailto:{{ admin.primaryMail }}">{{ admin.primaryMail }}</a> |
<a href="tel:{{ admin.phoneNumber }}">{{ admin.phoneNumber }}</a>
Responsable :
<strong>{{ admin.userName }} {{ admin.userSurname }}</strong
><br />
Contact :
<a href="mailto:{{ admin.primaryMail }}">{{
admin.primaryMail
}}</a>
|
<a href="tel:{{ admin.phoneNumber }}">{{
admin.phoneNumber
}}</a>
</p>
</div>
</div>
</template>
<script setup lang="ts">
import HeaderCanvas from "../components/canvas/HeaderCanvas.vue";
import LeanCanvas from '../components/canvas/LeanCanvas.vue';
import LeanCanvas from "../components/canvas/LeanCanvas.vue";
import { ref, onMounted /*, defineProps*/ } from "vue";
import { axiosInstance } from "@/services/api.ts";
@ -41,7 +49,7 @@ const props = defineProps<{
is_admin = token.includes("MyINPulse-admin")
*/
const isAdmin = 0
const isAdmin = 0;
// Variables pour les informations de l'administrateur
const admin = ref({
@ -50,7 +58,7 @@ const admin = ref({
userName: "",
primaryMail: "",
secondaryMail: "",
phoneNumber: ""
phoneNumber: "",
});
const mockAdminData = {
@ -59,22 +67,29 @@ const mockAdminData = {
userName: "Adnane",
primaryMail: "mock.admin@example.com",
secondaryMail: "admin.backup@example.com",
phoneNumber: "0600000000"
phoneNumber: "0600000000",
};
// Fonction pour récupérer les données de l'administrateur
const fetchAdminData = async (projectId: number, useMock = IS_MOCK_MODE) => {
try {
if (useMock) {
console.log("Utilisation des données mockées pour l'administrateur");
console.log(
"Utilisation des données mockées pour l'administrateur"
);
admin.value = mockAdminData;
return;
}
const response = await axiosInstance.get(`/shared/projects/admin/${projectId}`);
const response = await axiosInstance.get(
adnane marked this conversation as resolved Outdated
Outdated
Review

weird to use axiosInstance.

weird to use axiosInstance.
`/shared/projects/admin/${projectId}`
);
admin.value = response.data;
} catch (error) {
console.error("Erreur lors de la récupération des données de l'administrateur :", error);
console.error(
"Erreur lors de la récupération des données de l'administrateur :",
error
);
}
};

View File

@ -4,12 +4,7 @@
<div class="form-group">
<label for="name">Nom du projet</label>
<input
id="name"
v-model="form.name"
type="text"
required
/>
<input id="name" v-model="form.name" type="text" required />
</div>
<h3>Entrepreneur</h3>
@ -94,17 +89,17 @@
import { postApi } from "@/services/api";
const form = ref({
name: '',
name: "",
founder: {
userSurname: '',
userName: '',
primaryMail: '',
secondaryMail: '',
phoneNumber: '',
school: '',
course: '',
sneeStatus: false
}
userSurname: "",
userName: "",
primaryMail: "",
secondaryMail: "",
phoneNumber: "",
school: "",
course: "",
sneeStatus: false,
},
});
function submitForm() {
@ -113,10 +108,10 @@
</script>
<style scoped>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap");
adnane marked this conversation as resolved
Review

this should be in a specific css file.

this should be in a specific css file.
.add-project-form {
font-family: 'Inter', sans-serif;
font-family: "Inter", sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
@ -184,7 +179,7 @@
input[type="text"]:focus,
input[type="email"]:focus,
input[type="tel"]:focus {
border-color: #4CAF50;
border-color: #4caf50;
outline: none;
}
</style>

View File

@ -15,13 +15,11 @@ import ErrorModal from "@/components/errorModal.vue";
</template>
<style scoped>
.error-wrapper {
position: absolute;
left: 70%;
/*background-color: blue;*/
Review

why ?

why ?
height: 100%;
width: 30%;
}
</style>