Fix folder names. Adds missing files.
This commit is contained in:
167
src/views/profile/ProfilePage.vue
Normal file
167
src/views/profile/ProfilePage.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div class="flex flex-col md:flex-row">
|
||||
|
||||
<!-- Left Menu -->
|
||||
<div class="bg-[#f4f4f4] z-20 w-full md:max-w-xs fixed md:sticky md:top-0 md:flex md:flex-col top-0">
|
||||
<div class="sticky top-20 z-30 bg-[#f4f4f4]">
|
||||
<div class="flex flex-col items-center md:items-start md:pl-4 mt-16">
|
||||
<h1 class="text-2xl py-4 font-bold text-center md:text-left">Gérer votre compte Hutopy</h1>
|
||||
|
||||
<div class="relative flex items-center md:mt-0 w-full">
|
||||
<!-- Navigation buttons for small screens -->
|
||||
<button @click="scrollLeftFunc"
|
||||
class="rounded p-1 absolute left-2 z-10 md:hidden text-fuchsia-800 bg-[#f4f4f4] text-2xl ">
|
||||
<v-icon>mdi-chevron-left</v-icon>
|
||||
</button>
|
||||
|
||||
<div
|
||||
ref="scrollContainer"
|
||||
class="flex md:flex-col space-x-2 space-y-0 md:space-x-0 md:space-y-2 p-4 items-center md:items-start overflow-x-scroll md:overflow-x-visible mx-2 md:mx-0 custom-scroll min-w-[400px] px-1"
|
||||
@mousedown="mouseDown"
|
||||
@mouseleave="mouseLeave"
|
||||
@mouseup="mouseUp"
|
||||
@mousemove="mouseMove">
|
||||
|
||||
<v-btn variant="text" @click="currentComponent = 'CreatorPage'">
|
||||
<v-icon class="mr-2">mdi-file-edit-outline</v-icon>
|
||||
Créateur
|
||||
</v-btn>
|
||||
|
||||
<v-btn variant="text" @click="currentComponent = 'PersonnalInfo'">
|
||||
<v-icon class="mr-2">mdi-information</v-icon>
|
||||
Utilisateur
|
||||
</v-btn>
|
||||
|
||||
<v-btn variant="text" @click="currentComponent = 'ManageAccount'">
|
||||
<v-icon class="mr-2">mdi-account</v-icon>
|
||||
Gestion de Comptes
|
||||
</v-btn>
|
||||
|
||||
<v-btn variant="text" @click="currentComponent = 'AccountSecurity'">
|
||||
<v-icon class="mr-2">mdi-security</v-icon>
|
||||
Sécurité
|
||||
</v-btn>
|
||||
|
||||
</div>
|
||||
<button @click="scrollRightFunc"
|
||||
class="rounded p-1 absolute right-2 z-10 md:hidden text-fuchsia-800 bg-[#f4f4f4] text-2xl">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mid Content -->
|
||||
<div class="flex flex-col flex-1 align-center py-12 p-3 mt-28 md:mt-0">
|
||||
<template v-if="currentComponent === 'ManageAccount'">
|
||||
<manage-account></manage-account>
|
||||
</template>
|
||||
<template v-else-if="currentComponent === 'CreatorPage'">
|
||||
<creator-page></creator-page>
|
||||
</template>
|
||||
<template v-else-if="currentComponent === 'PersonnalInfo'">
|
||||
<personnal-info></personnal-info>
|
||||
</template>
|
||||
<template v-else-if="currentComponent === 'AccountSecurity'">
|
||||
<account-security></account-security>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, onMounted} from "vue";
|
||||
import ManageAccount from "@/views/profile/management/ManageAccount.vue";
|
||||
import CreatorPage from "@/views/profile/creators/CreatorPage.vue";
|
||||
import PersonnalInfo from "@/views/profile/account/PersonnalInfo.vue";
|
||||
import AccountSecurity from "@/views/profile/security/AccountSecurity.vue";
|
||||
|
||||
const currentComponent = ref('PersonnalInfo'); // Default component
|
||||
const isDown = ref(false);
|
||||
const startX = ref(0);
|
||||
const scrollLeft = ref(0);
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
const slider = document.querySelector('.custom-scroll');
|
||||
slider.addEventListener('mousedown', (e) => {
|
||||
isDown.value = true;
|
||||
slider.classList.add('active');
|
||||
startX.value = e.pageX - slider.offsetLeft;
|
||||
scrollLeft.value = slider.scrollLeft;
|
||||
});
|
||||
|
||||
slider.addEventListener('mouseleave', () => {
|
||||
isDown.value = false;
|
||||
slider.classList.remove('active');
|
||||
});
|
||||
|
||||
slider.addEventListener('mouseup', () => {
|
||||
isDown.value = false;
|
||||
slider.classList.remove('active');
|
||||
});
|
||||
|
||||
slider.addEventListener('mousemove', (e) => {
|
||||
if (!isDown.value) return;
|
||||
e.preventDefault();
|
||||
const x = e.pageX - slider.offsetLeft;
|
||||
const walk = (x - startX.value) * 3; // scroll-fast
|
||||
slider.scrollLeft = scrollLeft.value - walk;
|
||||
});
|
||||
});
|
||||
|
||||
const mouseDown = (e) => {
|
||||
const slider = document.querySelector('.custom-scroll');
|
||||
isDown.value = true;
|
||||
slider.classList.add('active');
|
||||
startX.value = e.pageX - slider.offsetLeft;
|
||||
scrollLeft.value = slider.scrollLeft;
|
||||
};
|
||||
|
||||
const mouseLeave = () => {
|
||||
isDown.value = false;
|
||||
const slider = document.querySelector('.custom-scroll');
|
||||
slider.classList.remove('active');
|
||||
};
|
||||
|
||||
const mouseUp = () => {
|
||||
isDown.value = false;
|
||||
const slider = document.querySelector('.custom-scroll');
|
||||
slider.classList.remove('active');
|
||||
};
|
||||
|
||||
const mouseMove = (e) => {
|
||||
if (!isDown.value) return;
|
||||
e.preventDefault();
|
||||
const slider = document.querySelector('.custom-scroll');
|
||||
const x = e.pageX - slider.offsetLeft;
|
||||
const walk = (x - startX.value) * 3; // scroll-fast
|
||||
slider.scrollLeft = scrollLeft.value - walk;
|
||||
};
|
||||
|
||||
const scrollLeftFunc = () => {
|
||||
const container = document.querySelector('.custom-scroll');
|
||||
container.scrollBy({left: -100, behavior: 'smooth'});
|
||||
};
|
||||
|
||||
const scrollRightFunc = () => {
|
||||
const container = document.querySelector('.custom-scroll');
|
||||
container.scrollBy({left: 100, behavior: 'smooth'});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.custom-scroll {
|
||||
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
.custom-scroll::-webkit-scrollbar {
|
||||
display: none; /* Safari and Chrome */
|
||||
}
|
||||
|
||||
</style>
|
||||
23
src/views/profile/account/AdressesHome.vue
Normal file
23
src/views/profile/account/AdressesHome.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Adresse à votre domicile</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="homeAddress"
|
||||
label="Votre adresse à votre domicile"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" >Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const homeAddress = ref('');
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
23
src/views/profile/account/AdressesWork.vue
Normal file
23
src/views/profile/account/AdressesWork.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Adresse au travail</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="homeAddress"
|
||||
label="Votre adresse au travail"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" >Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const homeAddress = ref('');
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
26
src/views/profile/account/Birthday.vue
Normal file
26
src/views/profile/account/Birthday.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Date de naissance</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="date"
|
||||
label="AAAA-MM-JJ"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain" color="black" >Annuler</v-btn>
|
||||
<v-btn color="#A6147D">Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
const date = ref('');
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
22
src/views/profile/account/Email.vue
Normal file
22
src/views/profile/account/Email.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Courriel</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="email"
|
||||
label="Votre courriel"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain" color="black">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" >Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const email = ref('');
|
||||
</script>
|
||||
|
||||
|
||||
33
src/views/profile/account/Gender.vue
Normal file
33
src/views/profile/account/Gender.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Genre</div>
|
||||
|
||||
<v-radio-group v-model="gender" row>
|
||||
<v-radio label="Homme" value="Homme"></v-radio>
|
||||
<v-radio label="Femme" value="Femme"></v-radio>
|
||||
<v-radio label="Autre" value="Autre"></v-radio>
|
||||
</v-radio-group>
|
||||
|
||||
<v-text-field
|
||||
v-if="gender === 'Autre'"
|
||||
v-model="otherGender"
|
||||
label="Veuillez spécifier"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain" color="black">Annuler</v-btn>
|
||||
<v-btn color="#A6147D">Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const gender = ref('');
|
||||
const otherGender = ref('');
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
50
src/views/profile/account/Name.vue
Normal file
50
src/views/profile/account/Name.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Nom</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="name"
|
||||
label="Name"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="lastName"
|
||||
label="Last Name"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="displayName"
|
||||
label="Display Name as"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain" color="black" @click="handleCancel">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" >Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const name = ref('');
|
||||
const lastName = ref('');
|
||||
const displayName = ref('');
|
||||
|
||||
|
||||
|
||||
const handleCancel = () => {
|
||||
// Logic for canceling the changes
|
||||
name.value = '';
|
||||
lastName.value = '';
|
||||
displayName.value = '';
|
||||
console.log('Cancelled');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
166
src/views/profile/account/PersonnalInfo.vue
Normal file
166
src/views/profile/account/PersonnalInfo.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center w-full">
|
||||
<h1 class="uppercase pb-5 text-2xl">
|
||||
<v-icon class="mr-2">mdi-information</v-icon> Informations personnelles
|
||||
</h1>
|
||||
|
||||
<div class="border rounded-2xl w-full max-w-[800px]">
|
||||
<div class="py-5 uppercase ml-4">Information de base</div>
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<button
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full"
|
||||
@click="openModal('Name')">
|
||||
<span class="min-w-40 text-left">Photo de profil</span>
|
||||
<span class="flex-auto pr-6 text-left">Une photo de profil aide à personnaliser votre compte</span>
|
||||
<span class="flex-none">
|
||||
<img
|
||||
:src="'/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
|
||||
alt="Profile Image"
|
||||
class="ml-2 rounded-full"
|
||||
style="width: 48px; height: 48px;">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full"
|
||||
@click="openModal('Name')">
|
||||
<span class="pa-2 min-w-40 text-left">Nom</span>
|
||||
<span class="flex-auto text-left pr-6">Pascal Marchesseault</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full"
|
||||
@click="openModal('Birthday')">
|
||||
<span class="flex-none pa-2 min-w-40 text-left">Date de naissance</span>
|
||||
<span class="flex-auto text-left pr-6">27 octobre 1988</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out rounded-b-2xl w-full"
|
||||
@click="openModal('Gender')">
|
||||
<span class="flex-none pa-2 min-w-40 text-left">Genre</span>
|
||||
<span class="flex-auto text-left pr-6">Homme</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phone & email -->
|
||||
<div class="flex flex-col items-center mt-10 w-full">
|
||||
<div class="border rounded-2xl w-full max-w-[800px]">
|
||||
<div class="py-5 uppercase ml-4">Coordonnées</div>
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<button
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full"
|
||||
@click="openModal('Email')">
|
||||
<span class="min-w-40 text-left">Courriel</span>
|
||||
<span class="flex-auto pr-6 text-left">marchesseault_pascal@hotmail.com</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full rounded-b-2xl"
|
||||
@click="openModal('Phone')">
|
||||
<span class="pa-2 min-w-40 text-left">Téléphone</span>
|
||||
<span class="flex-auto text-left pr-6">(581) 999-7540</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Address -->
|
||||
<div class="flex flex-col items-center mt-10 w-full">
|
||||
<div class="border rounded-2xl w-full max-w-[800px]">
|
||||
<div class="py-5 uppercase ml-4">Adresses</div>
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<button
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full"
|
||||
@click="openModal('AdressesHome')">
|
||||
<span class="min-w-40 text-left">Domicile</span>
|
||||
<span class="flex-auto pr-6 text-left">2127 Rue De Casson, Trois-Rivières, Qc</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full rounded-b-2xl"
|
||||
@click="openModal('AdressesWork')">
|
||||
<span class="pa-2 min-w-40 text-left">Travail</span>
|
||||
<span class="flex-auto pr-6 text-left">2127 Rue De Casson, Trois-Rivières, Qc</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<component :is="currentComponent"></component>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import Name from './Name.vue';
|
||||
import AdressesHome from './AdressesHome.vue';
|
||||
import AdressesWork from './AdressesWork.vue';
|
||||
import Birthday from './Birthday.vue';
|
||||
import Email from './Email.vue';
|
||||
import Gender from './Gender.vue';
|
||||
import Phone from './Phone.vue';
|
||||
|
||||
const dialog = ref(false);
|
||||
const currentComponent = ref('');
|
||||
|
||||
const componentsMap = {
|
||||
Name,
|
||||
AdressesHome,
|
||||
AdressesWork,
|
||||
Birthday,
|
||||
Email,
|
||||
Gender,
|
||||
Phone
|
||||
};
|
||||
|
||||
const openModal = (component) => {
|
||||
currentComponent.value = componentsMap[component];
|
||||
dialog.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.HoverBtn:hover {
|
||||
@apply bg-[#A6147D] text-white;
|
||||
@apply hover:opacity-90; /* Réduire l'opacité au survol */
|
||||
}
|
||||
</style>
|
||||
32
src/views/profile/account/Phone.vue
Normal file
32
src/views/profile/account/Phone.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Numéro de téléphone</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="cellNumber"
|
||||
label="Numéro de cellulaire"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="workNumber"
|
||||
label="Numéro au travail"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain" color="black">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" >Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const cellNumber = ref('');
|
||||
const workNumber = ref('');
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
67
src/views/profile/creators/About.vue
Normal file
67
src/views/profile/creators/About.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<script setup>
|
||||
import {ref} from 'vue'
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['closeRequested'])
|
||||
|
||||
const title = ref(props.creator.about.title)
|
||||
const description = ref(props.creator.about.description)
|
||||
|
||||
const client = useClient()
|
||||
const save = async () => {
|
||||
try {
|
||||
await client.post(
|
||||
`/api/creators/${props.creator.id}/about`,
|
||||
{
|
||||
"title": title.value || null,
|
||||
"description": description.value || null
|
||||
})
|
||||
|
||||
props.creator.about.title = title
|
||||
props.creator.about.description = description
|
||||
|
||||
emits('closeRequested')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
emits('closeRequested')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">About</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="title"
|
||||
label="Titre"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="description"
|
||||
label="Description"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn color="black" variant="text" @click="cancel">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" @click="save">Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
75
src/views/profile/creators/BannerPicker.vue
Normal file
75
src/views/profile/creators/BannerPicker.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<h2 class="text-2xl font-semibold mb-4 flex justify-center">
|
||||
Bannière
|
||||
</h2>
|
||||
|
||||
<img
|
||||
:src="fileUrl"
|
||||
class="mb-5 w-full transition duration-200 ease-in-out transform"
|
||||
alt="Aperçu de la bannière"
|
||||
>
|
||||
|
||||
<v-file-input
|
||||
v-model="selectedFile"
|
||||
variant="outlined"
|
||||
accept="image/*"
|
||||
label="Votre bannière"
|
||||
@change="onFileSelected"
|
||||
></v-file-input>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn color="black" variant="text" @click="cancel">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" @click="publish">Enregistrer</v-btn>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue'
|
||||
import {useClient} from '@/plugins/api.js'
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['closeRequested'])
|
||||
|
||||
const selectedFile = ref("")
|
||||
const fileUrl = ref(props.creator.images.banner)
|
||||
|
||||
const onFileSelected = () => {
|
||||
if (selectedFile.value) {
|
||||
const reader = new FileReader()
|
||||
reader.onload = (event) => {
|
||||
fileUrl.value = event.target.result
|
||||
}
|
||||
reader.readAsDataURL(selectedFile.value)
|
||||
} else {
|
||||
fileUrl.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const client = useClient()
|
||||
const publish = async () => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', selectedFile.value)
|
||||
|
||||
await client.post(
|
||||
`/api/creators/${props.creator.id}/banner`,
|
||||
formData)
|
||||
|
||||
props.creator.images.banner = fileUrl
|
||||
emits('closeRequested')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
emits('closeRequested')
|
||||
}
|
||||
|
||||
</script>
|
||||
161
src/views/profile/creators/ColorsPicker.vue
Normal file
161
src/views/profile/creators/ColorsPicker.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<script setup>
|
||||
import {ref, computed} from 'vue';
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
required: true
|
||||
},
|
||||
colorName: {
|
||||
type: String,
|
||||
default: 'bannerTop'
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(['closeRequested']);
|
||||
|
||||
const bannerTopColor = ref(props.creator.colors.bannerTop);
|
||||
const bannerBottomColor = ref(props.creator.colors.bannerBottom);
|
||||
const accentColor = ref(props.creator.colors.accent);
|
||||
const menuColor = ref(props.creator.colors.menu);
|
||||
|
||||
const selectedColorName = ref(props.colorName);
|
||||
const selectedColor = computed({
|
||||
get() {
|
||||
switch (selectedColorName.value) {
|
||||
case 'bannerTop':
|
||||
return bannerTopColor.value;
|
||||
case 'bannerBottom':
|
||||
return bannerBottomColor.value;
|
||||
case 'accent':
|
||||
return accentColor.value;
|
||||
case 'menu':
|
||||
return menuColor.value;
|
||||
default:
|
||||
return bannerTopColor.value;
|
||||
}
|
||||
},
|
||||
set(value) {
|
||||
switch (selectedColorName.value) {
|
||||
case 'bannerTop':
|
||||
bannerTopColor.value = value;
|
||||
break;
|
||||
case 'bannerBottom':
|
||||
bannerBottomColor.value = value;
|
||||
break;
|
||||
case 'accent':
|
||||
accentColor.value = value;
|
||||
break;
|
||||
case 'menu':
|
||||
menuColor.value = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const selectColor = (colorName) => {
|
||||
selectedColorName.value = colorName;
|
||||
};
|
||||
|
||||
const client = useClient();
|
||||
const save = async () => {
|
||||
try {
|
||||
await client.post(
|
||||
`/api/creators/${props.creator.id}/colors`,
|
||||
{
|
||||
"bannerTop": bannerTopColor.value || null,
|
||||
"bannerBottom": bannerBottomColor.value || null,
|
||||
"accent": accentColor.value || null,
|
||||
"menu": menuColor.value || null
|
||||
});
|
||||
|
||||
props.creator.colors.bannerTop = bannerTopColor.value;
|
||||
props.creator.colors.bannerBottom = bannerBottomColor.value;
|
||||
props.creator.colors.accent = accentColor.value;
|
||||
props.creator.colors.menu = menuColor.value;
|
||||
|
||||
emits('closeRequested');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
emits('closeRequested');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2 class="text-2xl font-semibold mb-4 flex justify-center">
|
||||
Palette de Couleurs
|
||||
</h2>
|
||||
|
||||
<div class="flex gap-6 justify-center items-start mt-5">
|
||||
|
||||
<div class="grid grid-cols-2 grid-rows-2 gap-4">
|
||||
<div
|
||||
class="color-square"
|
||||
:class="{ selected: selectedColorName === 'bannerTop' }"
|
||||
:style="{ backgroundColor: bannerTopColor }"
|
||||
@click="selectColor('bannerTop')"
|
||||
>
|
||||
<span class="color-name">Haut Banniere</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="color-square"
|
||||
:class="{ selected: selectedColorName === 'bannerBottom' }"
|
||||
:style="{ backgroundColor: bannerBottomColor }"
|
||||
@click="selectColor('bannerBottom')"
|
||||
>
|
||||
<span class="color-name">Bas Banniere</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="color-square"
|
||||
:class="{ selected: selectedColorName === 'accent' }"
|
||||
:style="{ backgroundColor: accentColor }"
|
||||
@click="selectColor('accent')"
|
||||
>
|
||||
<span class="color-name">Accent</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="color-square"
|
||||
:class="{ selected: selectedColorName === 'menu' }"
|
||||
:style="{ backgroundColor: menuColor }"
|
||||
@click="selectColor('menu')"
|
||||
>
|
||||
<span class="color-name">Menu</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-px bg-gray-300 h-full"></div>
|
||||
|
||||
<div class="flex-grow">
|
||||
<v-color-picker v-model="selectedColor"></v-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-4 mt-4">
|
||||
<v-btn color="black" variant="text" @click="cancel">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" @click="save">Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.color-square {
|
||||
@apply w-[150px] h-[150px];
|
||||
@apply flex rounded-md cursor-pointer relative;
|
||||
@apply items-center justify-center;
|
||||
@apply font-bold text-white;
|
||||
}
|
||||
|
||||
.color-square.selected {
|
||||
@apply border-4 border-solid border-[crimson];
|
||||
}
|
||||
|
||||
.color-name {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
71
src/views/profile/creators/CreateCreator.vue
Normal file
71
src/views/profile/creators/CreateCreator.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<script setup>
|
||||
import {ref} from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
creator: {type: Object, required: true},
|
||||
});
|
||||
|
||||
const isDialogActive = ref(false);
|
||||
|
||||
|
||||
const cancel = () => {
|
||||
closeDialog();
|
||||
};
|
||||
|
||||
const closeDialog = () => {
|
||||
isDialogActive.value = false;
|
||||
}
|
||||
|
||||
const CreateCreator = () => {
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="text-center">
|
||||
<div class="py-4 text-2xl font-bold border-b mb-2 flex flex-row items-center">
|
||||
<div class="flex-grow text-center">Informations pour votre</div>
|
||||
<v-btn icon @click="cancelPost" class="ml-auto" variant="text">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="Nom"
|
||||
label="Nom"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="Titre"
|
||||
label="Titre"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-textarea
|
||||
variant="outlined"
|
||||
v-model="Description"
|
||||
label="Description"
|
||||
outlined
|
||||
></v-textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn
|
||||
variant="outlined"
|
||||
@click="CreateCreator"
|
||||
class="w-full mb-5"
|
||||
:style="{ borderColor: 'rgb(159, 76, 173)', color: 'rgb(159, 76, 173)' }"
|
||||
>
|
||||
Créer
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
310
src/views/profile/creators/CreatorPage.vue
Normal file
310
src/views/profile/creators/CreatorPage.vue
Normal file
@@ -0,0 +1,310 @@
|
||||
<script setup>
|
||||
import {ref} from 'vue'
|
||||
import {useUserStore} from "@/stores/userStore.js"
|
||||
import Socials from './Socials.vue'
|
||||
import BannerPicker from './BannerPicker.vue'
|
||||
import ColorsPicker from './ColorsPicker.vue'
|
||||
import LogoPicker from "./LogoPicker.vue"
|
||||
import About from "./About.vue";
|
||||
import CreateCreator from "./CreateCreator.vue";
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const dialog = ref(false);
|
||||
const currentComponent = ref('')
|
||||
const colorToEdit = ref(null)
|
||||
|
||||
const componentsMap = {
|
||||
BannerPicker,
|
||||
LogoPicker,
|
||||
Socials,
|
||||
ColorsPicker,
|
||||
About,
|
||||
CreateCreator
|
||||
};
|
||||
|
||||
const openDialog = (component, colorName = null) => {
|
||||
currentComponent.value = componentsMap[component]
|
||||
colorToEdit.value = colorName
|
||||
dialog.value = true
|
||||
}
|
||||
|
||||
const closeDialog = () => {
|
||||
currentComponent.value = null
|
||||
dialog.value = false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<v-dialog v-model="dialog" max-width="800px">
|
||||
<v-card :style="{ borderRadius: '25px', border: '3px solid rgb(159, 76, 173)' }">
|
||||
<v-card-text>
|
||||
<component :is="currentComponent"
|
||||
:creator="userStore.creator"
|
||||
:colorName="colorToEdit"
|
||||
@closeRequested="closeDialog()
|
||||
"
|
||||
></component>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- Lorsque l'utilisateur n'a pas de creator name-->
|
||||
<div class="flex flex-col items-center w-full">
|
||||
<h1 class="uppercase pb-5 text-2xl">
|
||||
<v-icon class="mr-2">mdi-file-edit-outline</v-icon>
|
||||
Informations de votre page
|
||||
</h1>
|
||||
|
||||
<div v-if="userStore.creator.name == null">
|
||||
<div class="my-10 border rounded-2xl w-full max-w-[800px]">
|
||||
|
||||
<div class="py-5 uppercase ml-4 px-4">Informations pour pour votre page</div>
|
||||
<div class="flex flex-col w-full">
|
||||
<button
|
||||
@click="openDialog('CreateCreator')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left">Nom (Unique) </span>
|
||||
<span class="flex-auto text-left pr-6">Vous devez vous assurer de choisir un nom unique ou d'utiliser votre propre nom. Cela est important car c'est votre nom de marque, celui que vous allez présenter aux gens. Par exemple, notre projet s'appelle Hutopy, nous avons donc utilisé ce nom pour notre page officielle sur la plateforme.</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('CreateCreator')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left">Titre</span>
|
||||
<span class="flex-auto text-left pr-6">Le titre doit refléter ce que vous souhaitez mettre en avant sur la plateforme, ce que vous voulez présenter comme contenu ou la raison de votre présence sur la plateforme. Par exemple, des artistes pourraient écrire chanteur, danseur, peintre ou autre. Une entreprise pourrait indiquer son activité. Dans notre cas, pour Hutopy, c'est 'Créer un monde meilleur'. </span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('CreateCreator')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full rounded-b-2xl ">
|
||||
<span class="pa-2 min-w-32 text-left">Description</span>
|
||||
<span class="flex-auto text-left pr-6">Pour la description, c'est un espace où vous pouvez écrire ce que vous souhaitez : décrire votre page, le service que vous offrez, la raison de votre présence sur la plateforme, votre historique... Vous choisissez ! Dans notre cas, pour Hutopy, nous sommes ici afin de créer une plateforme sur laquelle les gens pourront s'exprimer et créer, tout en étant respectés et non exploités. </span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Si la personne a une creator name-->
|
||||
<div v-if="userStore.creator.name != null">
|
||||
<!-- Nom de la page créateur -->
|
||||
<div class="my-10 border rounded-2xl w-full max-w-[800px]">
|
||||
|
||||
<div class="py-5 uppercase ml-4">Informations</div>
|
||||
<div class="flex flex-col w-full">
|
||||
<button
|
||||
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left">Nom</span>
|
||||
<span class="flex-auto text-left pr-6 capitalize">{{ userStore.creator.name }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('About')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left">Titre</span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.about.title }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('About')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full rounded-b-2xl ">
|
||||
<span class="pa-2 min-w-32 text-left">Description</span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.about.description }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border rounded-2xl w-full max-w-[800px]">
|
||||
<div class="py-5 uppercase ml-4">Bannière et image de profil</div>
|
||||
<div class="flex flex-col w-full">
|
||||
|
||||
<button
|
||||
@click="openDialog('ColorsPicker', 'bannerTop')"
|
||||
class="flex justify-end h-10 align-center text-white px-5 hover:brightness-150"
|
||||
:style="{ backgroundColor: userStore.creator.colors.bannerTop }"
|
||||
>
|
||||
<v-icon>mdi-eyedropper-variant</v-icon>
|
||||
</button>
|
||||
|
||||
<button>
|
||||
<img
|
||||
@click="openDialog('BannerPicker')"
|
||||
:src="userStore.creator.images.banner"
|
||||
class="w-full transition duration-200 ease-in-out transform hover:brightness-125"
|
||||
alt="Tutorial Banner"
|
||||
>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('ColorsPicker', 'bannerBottom')"
|
||||
class="flex justify-end h-10 align-center text-white px-5 hover:brightness-150"
|
||||
:style="{ backgroundColor: userStore.creator.colors.bannerBottom }"
|
||||
>
|
||||
<v-icon>mdi-eyedropper-variant</v-icon>
|
||||
</button>
|
||||
|
||||
<button class="flex justify-center my-5">
|
||||
<img
|
||||
@click="openDialog('LogoPicker')"
|
||||
class="custom-border hover:brightness-125 active:bg-gray-600 shadow flex items-center transition duration-200 ease-in-out w-48 h-48 rounded-full"
|
||||
:style="{ borderColor: userStore.creator.colors.accent }"
|
||||
:src="userStore.creator.images.logo"
|
||||
alt="Profile Image"
|
||||
>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('ColorsPicker', 'accent')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="pa-2 min-w-32 text-left"><v-icon>mdi-circle-outline</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">Couleur du contour de la photo de profil.</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-eyedropper-variant</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('ColorsPicker', 'menu')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full rounded-b-2xl">
|
||||
<span class="flex-none pa-2 min-w-32 text-left"> <v-icon>mdi-menu</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">Couleur des entêtes de menus</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-eyedropper-variant</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Réseaux sociaux -->
|
||||
<div class="mt-10 border rounded-2xl w-full max-w-[800px]">
|
||||
|
||||
<div class="py-5 uppercase ml-4">Réseaux Sociaux</div>
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<button
|
||||
@click="openDialog('Socials')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="pa-2 min-w-32 text-left"><v-icon>mdi-facebook</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.socials.facebookUrl }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('Socials')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left"> <v-icon>mdi-instagram</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.socials.instagramUrl }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('Socials')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left"> <img src="/images/hutopymedia/icons/x.svg" width="23px"
|
||||
height="23px"></span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.socials.xUrl }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('Socials')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full ">
|
||||
<span class="pa-2 min-w-32 text-left"><v-icon>mdi-linkedin</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.socials.linkedInUrl }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('Socials')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full ">
|
||||
<span class="flex-none pa-2 min-w-32 text-left">
|
||||
<img src="/images/hutopymedia/icons/tiktok.svg" class="w-5 h-5">
|
||||
</span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.socials.tikTokUrl }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('Socials')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full ">
|
||||
<span class="pa-2 min-w-32 text-left"><v-icon>mdi-youtube</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.socials.youtubeUrl }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('Socials')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full ">
|
||||
<span class="pa-2 min-w-32 text-left"><v-icon>mdi-reddit</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.socials.redditUrl }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openDialog('Socials')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full rounded-b-2xl ">
|
||||
<span class="pa-2 min-w-32 text-left"><v-icon>mdi-web</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">{{ userStore.creator.socials.websiteUrl }}</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
||||
.HoverBtn:hover {
|
||||
@apply bg-[#A6147D] text-white;
|
||||
@apply hover:opacity-90;
|
||||
/* Réduire l'opacité au survol */
|
||||
}
|
||||
|
||||
.custom-border {
|
||||
border: 3px solid;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
79
src/views/profile/creators/LogoPicker.vue
Normal file
79
src/views/profile/creators/LogoPicker.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<h2 class="text-2xl font-semibold mb-4 flex justify-center">
|
||||
Logo
|
||||
</h2>
|
||||
|
||||
<div class="flex justify-center mb-5">
|
||||
<img
|
||||
:src="fileUrl"
|
||||
class="w-full transition duration-200 ease-in-out transform max-w-[400px]"
|
||||
alt="Aperçu de la bannière"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<v-file-input
|
||||
v-model="selectedFile"
|
||||
variant="outlined"
|
||||
accept="image/*"
|
||||
label="Votre logo"
|
||||
@change="onFileSelected"
|
||||
></v-file-input>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn color="black" variant="text" @click="cancel">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" @click="publish">Enregistrer</v-btn>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue'
|
||||
import {useClient} from '@/plugins/api.js'
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['closeRequested'])
|
||||
|
||||
const selectedFile = ref("")
|
||||
const fileUrl = ref(props.creator.images.logo)
|
||||
|
||||
const onFileSelected = () => {
|
||||
if (selectedFile.value) {
|
||||
const reader = new FileReader()
|
||||
reader.onload = (event) => {
|
||||
fileUrl.value = event.target.result
|
||||
}
|
||||
reader.readAsDataURL(selectedFile.value)
|
||||
} else {
|
||||
fileUrl.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const client = useClient()
|
||||
const publish = async () => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', selectedFile.value)
|
||||
|
||||
await client.post(
|
||||
`/api/creators/${props.creator.id}/logo`,
|
||||
formData)
|
||||
|
||||
props.creator.images.logoUrl = fileUrl
|
||||
emits('closeRequested')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
emits('closeRequested')
|
||||
}
|
||||
|
||||
</script>
|
||||
146
src/views/profile/creators/Socials.vue
Normal file
146
src/views/profile/creators/Socials.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<script setup>
|
||||
import {ref} from 'vue'
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['closeRequested'])
|
||||
|
||||
const facebookUrl = ref(props.creator.socials.facebookUrl)
|
||||
const instagramUrl = ref(props.creator.socials.instagramUrl)
|
||||
const linkedInUrl = ref(props.creator.socials.linkedInUrl)
|
||||
const redditUrl = ref(props.creator.socials.redditUrl)
|
||||
const tikTokUrl = ref(props.creator.socials.tikTokUrl)
|
||||
const websiteUrl = ref(props.creator.socials.websiteUrl)
|
||||
const xUrl = ref(props.creator.socials.xUrl)
|
||||
const youtubeUrl = ref(props.creator.socials.youtubeUrl)
|
||||
|
||||
const client = useClient()
|
||||
const save = async () => {
|
||||
try {
|
||||
await client.post(
|
||||
`/api/creators/${props.creator.id}/socials`,
|
||||
{
|
||||
"facebookUrl": facebookUrl.value || null,
|
||||
"instagramUrl": instagramUrl.value || null,
|
||||
"linkedInUrl": linkedInUrl.value || null,
|
||||
"redditUrl": redditUrl.value || null,
|
||||
"tikTokUrl": tikTokUrl.value || null,
|
||||
"websiteUrl": websiteUrl.value || null,
|
||||
"xUrl": xUrl.value || null,
|
||||
"youtubeUrl": youtubeUrl.value || null,
|
||||
})
|
||||
|
||||
props.creator.socials.facebookUrl = facebookUrl
|
||||
props.creator.socials.instagramUrl = instagramUrl
|
||||
props.creator.socials.linkedInUrl = linkedInUrl
|
||||
props.creator.socials.redditUrl = redditUrl
|
||||
props.creator.socials.tikTokUrl = tikTokUrl
|
||||
props.creator.socials.websiteUrl = websiteUrl
|
||||
props.creator.socials.xUrl = xUrl
|
||||
props.creator.socials.youtubeUrl = youtubeUrl
|
||||
|
||||
emits('closeRequested')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
emits('closeRequested')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Reseaux Sociaux</div>
|
||||
<div class="flex flex-row align-center">
|
||||
<v-icon class="mb-5 mr-2">mdi-facebook</v-icon>
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="facebookUrl"
|
||||
label="Lien Facebook"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-icon class="mb-5 mr-2">mdi-instagram</v-icon>
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="instagramUrl"
|
||||
label="Lien Instagram"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-icon class="mb-5 mr-2">mdi-linkedin</v-icon>
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="linkedInUrl"
|
||||
label="Lien LinkedIn"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-icon class="mb-5 mr-2">mdi-reddit</v-icon>
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="redditUrl"
|
||||
label="Lien Reddit"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<img src="/images/hutopymedia/icons/tiktok.svg" width="23px" height="23px" class="mb-5 mr-2">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="tikTokUrl"
|
||||
label="Lien TikTok"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-icon class="mb-5 mr-2">mdi-web</v-icon>
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="websiteUrl"
|
||||
label="Lien site web"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<img src="/images/hutopymedia/icons/x.svg" width="23px" height="23px" class="mb-5 mr-2">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="xUrl"
|
||||
label="Lien X"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row align-center">
|
||||
<v-icon class="mb-5 mr-2">mdi-youtube</v-icon>
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="youtubeUrl"
|
||||
label="Lien Youtube"
|
||||
outlined
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn color="black" variant="text" @click="cancel">Annuler</v-btn>
|
||||
<v-btn color="#A6147D" @click="save">Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
76
src/views/profile/management/ManageAccount.vue
Normal file
76
src/views/profile/management/ManageAccount.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center w-full">
|
||||
<h1 class="uppercase pb-5 text-2xl"> <v-icon class="mr-2 text">mdi-account</v-icon> Gestion des comptes</h1>
|
||||
|
||||
<div class="border rounded-2xl w-full max-w-[800px]">
|
||||
<div class="py-5 uppercase ml-4">Comptes</div>
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<button class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="min-w-32 text-left">Id de la page</span>
|
||||
<span class="flex-auto pr-6 text-left">Nom de la page / utilisateur </span>
|
||||
<span class="flex-none">
|
||||
<img
|
||||
:src="'/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
|
||||
alt="Profile Image"
|
||||
class="ml-2 rounded-full"
|
||||
width="48"
|
||||
height="48">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out rounded-b-2xl w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left">Ajouter un compte</span>
|
||||
|
||||
<span class="flex-none text-fuchsia-800">
|
||||
<v-icon>mdi-plus-circle</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border rounded-2xl w-full max-w-[800px] mt-10">
|
||||
<div class="py-5 uppercase ml-4">Autorisations accordées</div>
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<button class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="min-w-32 text-left">Id de la page</span>
|
||||
<span class="flex-auto pr-6 text-left">Nom de utilisateur </span>
|
||||
<span class="flex-none">
|
||||
<img
|
||||
:src="'/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
|
||||
alt="Profile Image"
|
||||
class="ml-2 rounded-full"
|
||||
width="48"
|
||||
height="48">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out rounded-b-2xl w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left">Ajouter un compte</span>
|
||||
|
||||
<span class="flex-none text-fuchsia-800">
|
||||
<v-icon>mdi-plus-circle</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.HoverBtn:hover {
|
||||
@apply bg-[#A6147D] text-white;
|
||||
@apply hover:opacity-90; /* Réduire l'opacité au survol */
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
93
src/views/profile/security/AccountSecurity.vue
Normal file
93
src/views/profile/security/AccountSecurity.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center w-full">
|
||||
<h1 class="uppercase pb-5 text-2xl"> <v-icon class="mr-2">mdi-security</v-icon> Sécurité</h1>
|
||||
|
||||
<div class="border rounded-2xl w-full max-w-[800px]">
|
||||
<div class="py-5 uppercase ml-4">Comment vous connecter à Hutopy</div>
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<button
|
||||
@click="openModal('ModalPassword')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="pa-2 min-w-32 text-left"><v-icon>mdi-onepassword</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">Mot de passe</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openModal('ModalRecoveryByEmailInfo')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full">
|
||||
<span class="flex-none pa-2 min-w-32 text-left"> <v-icon>mdi-email-outline</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">Récupération par E-mail</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="openModal('ModalRecoveryByPhoneInfo')"
|
||||
class="HoverBtn active:bg-gray-300 py-2 px-4 border-gray-400 shadow flex items-center transition duration-200 ease-in-out w-full rounded-b-2xl">
|
||||
<span class="flex-none pa-2 min-w-32 text-left"> <v-icon>mdi-cellphone</v-icon></span>
|
||||
<span class="flex-auto text-left pr-6">Récupération par mobile</span>
|
||||
<span class="flex-none">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<v-dialog v-model="dialog" max-width="600px">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<component :is="currentComponent"></component>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import ModalPassword from './ModalPassword.vue';
|
||||
import ModalRecoveryByEmailInfo from './ModalRecoveryByEmailInfo.vue';
|
||||
import ModalRecoveryByPhoneInfo from './ModalRecoveryByPhoneInfo.vue';
|
||||
|
||||
|
||||
const dialog = ref(false);
|
||||
const currentComponent = ref('');
|
||||
|
||||
const componentsMap = {
|
||||
ModalPassword,
|
||||
ModalRecoveryByEmailInfo,
|
||||
ModalRecoveryByPhoneInfo,
|
||||
|
||||
};
|
||||
|
||||
const openModal = (component) => {
|
||||
currentComponent.value = componentsMap[component];
|
||||
dialog.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.HoverBtn:hover {
|
||||
@apply bg-[#A6147D] text-white;
|
||||
@apply hover:opacity-90; /* Réduire l'opacité au survol */
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
44
src/views/profile/security/ModalPassword.vue
Normal file
44
src/views/profile/security/ModalPassword.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Changer le mot de passe</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="currentPassword"
|
||||
label="Mot de passe courant"
|
||||
type="password"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="newPassword"
|
||||
label="Nouveau mot de passe"
|
||||
type="password"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="confirmPassword"
|
||||
label="Confirmer le mot de passe"
|
||||
type="password"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain" >Annuler</v-btn>
|
||||
<v-btn color="#A6147D" >Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const currentPassword = ref('');
|
||||
const newPassword = ref('');
|
||||
const confirmPassword = ref('');
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
31
src/views/profile/security/ModalRecoveryByEmailInfo.vue
Normal file
31
src/views/profile/security/ModalRecoveryByEmailInfo.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Récupération par E-mail</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="currentPassword"
|
||||
label="Mot de passe"
|
||||
type="password"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="newEmail"
|
||||
label="Nouveau E-mail"
|
||||
type="password"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain" >Annuler</v-btn>
|
||||
<v-btn color="#A6147D" >Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const currentPassword = ref('');
|
||||
const newEmail = ref('');
|
||||
</script>
|
||||
|
||||
31
src/views/profile/security/ModalRecoveryByPhoneInfo.vue
Normal file
31
src/views/profile/security/ModalRecoveryByPhoneInfo.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div class="pb-5 text-2xl">Récupération par mobile</div>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="currentPassword"
|
||||
label="Mot de passe"
|
||||
type="password"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="newEmail"
|
||||
label="Nouveau numéro"
|
||||
type="password"
|
||||
outlined
|
||||
></v-text-field>
|
||||
|
||||
<div class="flex justify-end space-x-4">
|
||||
<v-btn variant="plain" >Annuler</v-btn>
|
||||
<v-btn color="#A6147D" >Enregistrer</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const currentPassword = ref('');
|
||||
const newEmail = ref('');
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user