front_foundation #9
@ -67,6 +67,16 @@ class Project {
|
|||||||
) {
|
) {
|
||||||
this._status = value;
|
this._status = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toObject() {
|
||||||
|
return {
|
||||||
|
idProject: this.idProject,
|
||||||
|
projectName: this.projectName,
|
||||||
|
creationDate: this.creationDate,
|
||||||
|
logo: this.logo,
|
||||||
|
status: this.status,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Project;
|
export default Project;
|
||||||
|
@ -44,7 +44,7 @@ class SectionCell {
|
|||||||
this._modificationDate = value;
|
this._modificationDate = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
toPlainObject() {
|
toObject() {
|
||||||
return {
|
return {
|
||||||
idSectionCell: this._idSectionCell,
|
idSectionCell: this._idSectionCell,
|
||||||
sectionId: this._sectionId,
|
sectionId: this._sectionId,
|
||||||
|
@ -3,18 +3,20 @@
|
|||||||
<div class="project-header">
|
<div class="project-header">
|
||||||
<h2 @click="goToLink">{{ projectName }}</h2>
|
<h2 @click="goToLink">{{ projectName }}</h2>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<div class="dropdown-wrapper">
|
<div ref="dropdownRef" class="dropdown-wrapper">
|
||||||
<!-- Empêche la propagation du clic vers le parent -->
|
|
||||||
<button class="contact-button" @click.stop="toggleDropdown">
|
<button class="contact-button" @click.stop="toggleDropdown">
|
||||||
Contact
|
Contact
|
||||||
</button>
|
</button>
|
||||||
|
<div
|
||||||
<div v-if="isDropdownOpen" class="dropdown-menu">
|
v-if="entrepreneurEmails.length > 0"
|
||||||
<button @click.stop="contactAll">Contacter tous</button>
|
class="contact-dropdown"
|
||||||
|
:class="{ 'dropdown-visible': isDropdownOpen }"
|
||||||
|
>
|
||||||
|
<button @click="contactAll">Contacter tous</button>
|
||||||
<button
|
<button
|
||||||
v-for="(email, index) in entrepreneurEmails"
|
v-for="(email, index) in entrepreneurEmails"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click.stop="contactSingle(email)"
|
@click="contactSingle(email)"
|
||||||
>
|
>
|
||||||
{{ email }}
|
{{ email }}
|
||||||
</button>
|
</button>
|
||||||
@ -37,9 +39,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, ref, onMounted, onBeforeUnmount } from "vue";
|
import { defineProps, ref, onMounted, onBeforeUnmount } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import axios from "axios";
|
import { getProjectEntrepreneurs } from "@/services/Apis/Shared.ts";
|
||||||
adnane marked this conversation as resolved
Outdated
|
|||||||
|
import UserEntrepreneur from "@/ApiClasses/UserEntrepreneur.ts";
|
||||||
|
|
||||||
const IS_MOCK_MODE = true;
|
const IS_MOCK_MODE = false;
|
||||||
|
const dropdownRef = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
projectName: string;
|
projectName: string;
|
||||||
@ -52,11 +56,97 @@ const router = useRouter();
|
|||||||
|
|
||||||
const isDropdownOpen = ref(false);
|
const isDropdownOpen = ref(false);
|
||||||
const entrepreneurEmails = ref<string[]>([]);
|
const entrepreneurEmails = ref<string[]>([]);
|
||||||
|
const entrepreneurs = ref<UserEntrepreneur[]>([]);
|
||||||
|
|
||||||
|
const goToLink = () => {
|
||||||
|
if (props.projectLink) {
|
||||||
|
router.push(props.projectLink);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleDropdown = () => {
|
||||||
|
isDropdownOpen.value = !isDropdownOpen.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchMockEntrepreneurs = () => {
|
||||||
|
const mockData = [
|
||||||
|
{
|
||||||
|
userName: "Doe",
|
||||||
|
userSurname: "John",
|
||||||
|
primaryMail: "john.doe@example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userName: "Smith",
|
||||||
|
userSurname: "Anna",
|
||||||
|
primaryMail: "anna.smith@example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userName: "Mock",
|
||||||
|
userSurname: "User",
|
||||||
|
primaryMail: undefined,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
entrepreneurs.value = mockData.map((item) => new UserEntrepreneur(item));
|
||||||
|
entrepreneurEmails.value = entrepreneurs.value
|
||||||
adnane marked this conversation as resolved
Outdated
piair
commented
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.
|
|||||||
|
.map((e) => e.primaryMail)
|
||||||
|
.filter((mail): mail is string => !!mail);
|
||||||
|
|
||||||
|
console.log("Mock entrepreneurs chargés :", entrepreneurs.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchEntrepreneurs = (projectId: number, useMock = false) => {
|
||||||
|
if (useMock) {
|
||||||
|
fetchMockEntrepreneurs();
|
||||||
|
} else {
|
||||||
|
getProjectEntrepreneurs(
|
||||||
|
projectId,
|
||||||
|
(response) => {
|
||||||
|
const rawData = response.data as Partial<UserEntrepreneur>[];
|
||||||
|
entrepreneurs.value = rawData.map(
|
||||||
|
(item) => new UserEntrepreneur(item)
|
||||||
|
);
|
||||||
|
entrepreneurEmails.value = entrepreneurs.value
|
||||||
|
.map((e) => e.primaryMail)
|
||||||
|
.filter((mail): mail is string => !!mail);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error(
|
||||||
|
"Erreur lors de la récupération des entrepreneurs :",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
adnane marked this conversation as resolved
Outdated
piair
commented
I don't love the fact that the mock tests are in the code here, it should be better to have a server. It's not a big probleme though I don't love the fact that the mock tests are in the code here, it should be better to have a server. It's not a big probleme though
|
|||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const contactAll = () => {
|
||||||
|
const allEmails = entrepreneurEmails.value.join(", ");
|
||||||
|
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) => console.error("Erreur lors de la copie :", err));
|
||||||
|
};
|
||||||
|
|
||||||
|
const contactSingle = (email: string) => {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(email)
|
||||||
|
.then(() => {
|
||||||
|
alert(`Adresse copiée : ${email}`);
|
||||||
|
window.open("https://partage.bordeaux-inp.fr/", "_blank");
|
||||||
|
})
|
||||||
|
.catch((err) => console.error("Erreur lors de la copie :", err));
|
||||||
|
};
|
||||||
|
|
||||||
// Pour fermer le dropdown si on clique ailleurs
|
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
const dropdown = document.querySelector(".dropdown-wrapper");
|
if (
|
||||||
if (dropdown && !dropdown.contains(event.target as Node)) {
|
isDropdownOpen.value &&
|
||||||
|
dropdownRef.value &&
|
||||||
|
!dropdownRef.value.contains(event.target as Node)
|
||||||
|
) {
|
||||||
isDropdownOpen.value = false;
|
isDropdownOpen.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -69,98 +159,6 @@ onMounted(() => {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
document.removeEventListener("click", handleClickOutside);
|
document.removeEventListener("click", handleClickOutside);
|
||||||
});
|
});
|
||||||
|
|
||||||
const toggleDropdown = () => {
|
|
||||||
isDropdownOpen.value = !isDropdownOpen.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const goToLink = () => {
|
|
||||||
if (props.projectLink) {
|
|
||||||
router.push(props.projectLink);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
entrepreneurEmails.value = responseData.map(
|
|
||||||
(item: Entrepreneur) => item.primaryMail
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(
|
|
||||||
"Erreur lors de la récupération des entrepreneurs :",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
type Entrepreneur = {
|
|
||||||
idUser: number;
|
|
||||||
userSurname: string;
|
|
||||||
userName: string;
|
|
||||||
primaryMail: string;
|
|
||||||
secondaryMail: string;
|
|
||||||
phoneNumber: string;
|
|
||||||
school: string;
|
|
||||||
course: string;
|
|
||||||
sneeStatus: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockFetchEntrepreneurs = async (/*projectId: number*/) => {
|
|
||||||
return new Promise<Entrepreneur[]>((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 allEmails = entrepreneurEmails.value.join(", ");
|
|
||||||
navigator.clipboard.writeText(allEmails).then(() => {
|
|
||||||
alert("Tous les emails copiés dans le presse-papiers !");
|
|
||||||
window.open("https://partage.bordeaux-inp.fr/", "_blank");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const contactSingle = (email: string) => {
|
|
||||||
navigator.clipboard.writeText(email).then(() => {
|
|
||||||
alert(`Adresse copiée : ${email}`);
|
|
||||||
window.open("https://partage.bordeaux-inp.fr/", "_blank");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -233,48 +231,78 @@ const contactSingle = (email: string) => {
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 10px 15px;
|
.header {
|
||||||
background-color: #007bff;
|
display: flex;
|
||||||
adnane marked this conversation as resolved
Outdated
piair
commented
generic style once again generic style once again
|
|||||||
color: white;
|
justify-content: space-between;
|
||||||
border: none;
|
align-items: center;
|
||||||
cursor: pointer;
|
padding: 15px 30px;
|
||||||
border-radius: 5px;
|
background-color: #f9f9f9;
|
||||||
}
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
button:hover {
|
|
||||||
background-color: #0056b3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-wrapper {
|
.logo {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu {
|
.contact-button,
|
||||||
position: absolute;
|
.return-button {
|
||||||
top: 100%; /* juste en dessous du bouton */
|
background-color: #009cde;
|
||||||
right: 0;
|
color: white;
|
||||||
background-color: white;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
padding: 0.5rem;
|
|
||||||
z-index: 1000;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
min-width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-menu button {
|
|
||||||
text-align: left;
|
|
||||||
padding: 0.3rem 0.5rem;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
border: none;
|
||||||
|
padding: 10px 15px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s;
|
font-size: 14px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu button:hover {
|
.return-button:hover,
|
||||||
background-color: #f0f0f0;
|
.contact-button:hover {
|
||||||
|
background-color: #007bad;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
.contact-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
background-color: #000;
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0px 4px 8px rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
z-index: 1000;
|
||||||
|
min-width: 200px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-dropdown button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 5px;
|
||||||
|
text-align: left;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-dropdown button:hover {
|
||||||
|
background-color: #009cde;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-dropdown.dropdown-visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -35,8 +35,8 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<RouterLink to="/" class="return-button">Retour</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
<RouterLink to="/" class="return-button">Retour</RouterLink>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
@ -9,12 +9,12 @@ import {
|
|||||||
|
|
||||||
// Entrepreneurs API
|
// Entrepreneurs API
|
||||||
function requestProjectCreation(
|
function requestProjectCreation(
|
||||||
projectDetails: Project, // Replace 'any' with a proper type for project details if available
|
projectDetails: Project,
|
||||||
onSuccessHandler?: (response: AxiosResponse) => void,
|
onSuccessHandler?: (response: AxiosResponse) => void,
|
||||||
onErrorHandler?: (error: AxiosError) => void
|
onErrorHandler?: (error: AxiosError) => void
|
||||||
): void {
|
): void {
|
||||||
axiosInstance
|
axiosInstance
|
||||||
.post("/entrepreneur/projects/request", projectDetails)
|
.post("/entrepreneur/projects/request", projectDetails.toObject())
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (onSuccessHandler) {
|
if (onSuccessHandler) {
|
||||||
onSuccessHandler(response);
|
onSuccessHandler(response);
|
||||||
@ -32,12 +32,12 @@ function requestProjectCreation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addSectionCell(
|
function addSectionCell(
|
||||||
sectionCellDetails: SectionCell, // Replace 'any' with a proper type for section cell details if available
|
sectionCellDetails: SectionCell,
|
||||||
onSuccessHandler?: (response: AxiosResponse) => void,
|
onSuccessHandler?: (response: AxiosResponse) => void,
|
||||||
onErrorHandler?: (error: AxiosError) => void
|
onErrorHandler?: (error: AxiosError) => void
|
||||||
): void {
|
): void {
|
||||||
axiosInstance
|
axiosInstance
|
||||||
.post("/entrepreneur/sectionCells", sectionCellDetails.toPlainObject())
|
.post("/entrepreneur/sectionCells", sectionCellDetails.toObject())
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (onSuccessHandler) {
|
if (onSuccessHandler) {
|
||||||
onSuccessHandler(response);
|
onSuccessHandler(response);
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
import Header from "../components/HeaderComponent.vue";
|
import Header from "../components/HeaderComponent.vue";
|
||||||
|
//import Agenda from "../components/AdminAppointments.vue";
|
||||||
import Agenda from "../components/AgendaComponent.vue";
|
import Agenda from "../components/AgendaComponent.vue";
|
||||||
import ProjectComp from "../components/ProjectComponent.vue";
|
import ProjectComp from "../components/ProjectComponent.vue";
|
||||||
import PendingProjectComponent from "@/components/PendingProjectComponent.vue";
|
import PendingProjectComponent from "@/components/PendingProjectComponent.vue";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<header>
|
<header>
|
||||||
<HeaderCanvas :project-id="1" :is-admin="isAdmin_" />
|
<HeaderCanvas :project-id="101" :is-admin="isAdmin_" />
|
||||||
</header>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
Cliquez sur un champ du tableau pour afficher son contenu en détail
|
Cliquez sur un champ du tableau pour afficher son contenu en détail
|
||||||
ci-dessous.
|
ci-dessous.
|
||||||
</p>
|
</p>
|
||||||
<LeanCanvas :project-id="1" :is-admin="isAdmin_" />
|
<LeanCanvas :project-id="101" :is-admin="isAdmin_" />
|
||||||
<div class="info-box">
|
<div class="info-box">
|
||||||
<p v-if="admin">
|
<p v-if="admin">
|
||||||
Responsable :
|
Responsable :
|
||||||
@ -90,7 +90,7 @@ const fetchAdminData = (projectId: number, useMock = IS_MOCK_MODE) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const projectId = 1;
|
const projectId = 101;
|
||||||
fetchAdminData(projectId);
|
fetchAdminData(projectId);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import Project from "@/ApiClasses/Project";
|
||||||
|
import { requestProjectCreation } from "@/services/Apis/Entrepreneurs.ts";
|
||||||
|
|
||||||
const choix = ref<string | null>(null);
|
const choix = ref<string | null>(null);
|
||||||
const nomProjet = ref("");
|
const nomProjet = ref("");
|
||||||
@ -53,8 +55,36 @@ const validerCreation = () => {
|
|||||||
alert("Veuillez entrer un nom de projet.");
|
alert("Veuillez entrer un nom de projet.");
|
||||||
return;
|
return;
|
||||||
adnane marked this conversation as resolved
piair
commented
Just do it! Just do it!
|
|||||||
}
|
}
|
||||||
alert(`Projet "${nomProjet.value}" créé avec succès !`);
|
|
||||||
|
// Obtenir la date actuelle au format YYYY-MM-DD
|
||||||
|
const today = new Date();
|
||||||
|
const yyyy = today.getFullYear();
|
||||||
|
const mm = String(today.getMonth() + 1).padStart(2, "0");
|
||||||
|
const dd = String(today.getDate()).padStart(2, "0");
|
||||||
|
const formattedDate = `${yyyy}-${mm}-${dd}`;
|
||||||
|
|
||||||
|
// Créer une instance de Project
|
||||||
|
const nouveauProjet = new Project({
|
||||||
|
projectName: nomProjet.value.trim(),
|
||||||
|
creationDate: formattedDate,
|
||||||
|
status: "PENDING",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Appeler l’API
|
||||||
|
requestProjectCreation(
|
||||||
|
nouveauProjet,
|
||||||
|
(response) => {
|
||||||
|
console.log("Projet créé :", response.data);
|
||||||
|
alert(`Projet "${nomProjet.value}" créé avec succès !`);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error("Erreur lors de la création du projet :", error);
|
||||||
|
alert("Une erreur est survenue lors de la création du projet.");
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user
It would be better to use an ENV variable