Many fix and improvements

This commit is contained in:
Jonathan Bourdon
2024-08-03 04:15:55 -04:00
parent 0d94d79c77
commit 78ead7e387
37 changed files with 669 additions and 735 deletions

View File

@@ -2,107 +2,107 @@
<div class="hidden sm:block" style="height: 40px"></div>
<div>
<div class="flex flex-col lg:flex-row items-center justify-center">
<div class="max-w-[700px] min-w-[300px]">
<img class="rounded-none sm:rounded-2xl sm:w-full mr-8" src="/images/hutopymedia/loginpage/loginhutopy.png" alt="hutopy login">
</div>
<div class="flex flex-col lg:flex-row items-center justify-center">
<div class="max-w-[700px] min-w-[300px]">
<img class="rounded-none sm:rounded-2xl sm:w-full mr-8" src="/images/hutopymedia/loginpage/loginhutopy.png"
alt="hutopy login">
</div>
<div class="flex flex-col items-center min-w-[300px] m-12">
<h1 class="text-center text-2xl font-bold mb-5">Connexion</h1>
<google-login class="w-full" :callback="googleCallback" popup-type="TOKEN">
<template #default>
<v-btn density="comfortable" class="mb-2 w-full">
<v-icon left>mdi-google</v-icon>
Google
<div class="flex flex-col items-center min-w-[300px] m-12">
<h1 class="text-center text-2xl font-bold mb-5">Connexion</h1>
<google-login class="w-full" :callback="googleCallback" popup-type="TOKEN">
<template #default>
<v-btn density="comfortable" class="mb-2 w-full">
<v-icon left>mdi-google</v-icon>
Google
</v-btn>
</template>
</google-login>
<!-- <v-btn density="comfortable" class="mb-2 w-full">-->
<!-- <v-icon left>mdi-facebook</v-icon>-->
<!-- Facebook-->
<!-- </v-btn>-->
<div class="w-full h-0.5 mt-4 mb-4" :style="{ backgroundColor: '#A30E79' }"></div>
<v-btn density="comfortable" class="mb-2 w-full" @click="showEmailForm = !showEmailForm">
<v-icon left>mdi-account</v-icon>
Utilisateur
</v-btn>
<div v-if="showEmailForm" class="w-full mt-2">
<v-text-field v-model="email"
label="Courriel"
variant="outlined"
dense
prepend-inner-icon="mdi-email"
color="transparent"
class="text-black"
></v-text-field>
<v-text-field v-model="password"
label="Mot de passe"
:type="showPassword ? 'text' : 'password'"
variant="outlined"
dense
prepend-inner-icon="mdi-lock"
append-inner-icon="mdi-eye"
@click:append-inner="showPassword = !showPassword"
color="transparent"
class="text-black"
></v-text-field>
<v-btn class="w-full text-center text-white" :style="{ backgroundColor: '#A30E79' }" @click="login">
Connecter
</v-btn>
</template>
</google-login>
<!-- <v-btn density="comfortable" class="mb-2 w-full">-->
<!-- <v-icon left>mdi-facebook</v-icon>-->
<!-- Facebook-->
<!-- </v-btn>-->
<div class="w-full h-0.5 mt-4 mb-4" :style="{ backgroundColor: '#A30E79' }"></div>
<p class="mt-4 text-sm text-center">
Si vous n'avez pas de compte, <a href="/register" class="text-blue-500">cliquez ici</a> pour en créer un.
</p>
<v-btn density="comfortable" class="mb-2 w-full" @click="showEmailForm = !showEmailForm">
<v-icon left>mdi-account</v-icon>
Utilisateur
</v-btn>
<div v-if="showEmailForm" class="w-full mt-2">
<v-text-field v-model="user.email"
label="Courriel"
variant="outlined"
dense
prepend-inner-icon="mdi-email"
color="transparent"
class="text-black"
></v-text-field>
<v-text-field v-model="user.password"
label="Mot de passe"
:type="showPassword ? 'text' : 'password'"
variant="outlined"
dense
prepend-inner-icon="mdi-lock"
append-inner-icon="mdi-eye"
@click:append-inner="showPassword = !showPassword"
color="transparent"
class="text-black"
></v-text-field>
<v-btn class="w-full text-center text-white" :style="{ backgroundColor: '#A30E79' }" @click="login">Connecter</v-btn>
<p class="mt-4 text-sm text-center">
Si vous n'avez pas de compte, <a href="/register" class="text-blue-500">cliquez ici</a> pour en créer un.
</p>
<div v-if="errorSnackBar" class="mb-4 text-red-600">
Nom d'utilisateur ou mot de passe invalide.
<button class="text-red-600 ml-4" @click="errorSnackBar = false">Fermer</button>
<div v-if="errorSnackBar" class="mb-4 text-red-600">
Nom d'utilisateur ou mot de passe invalide.
<button class="text-red-600 ml-4" @click="errorSnackBar = false">Fermer</button>
</div>
</div>
</div>
</div>
</div>
</div>
<selected-footer></selected-footer>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { useClient } from "@/plugins/api.js";
import { auth } from '@/stores/auth.js';
import { GoogleLogin } from "vue3-google-login";
import {ref} from 'vue';
import {useRouter} from 'vue-router';
import {useAuthStore} from '@/stores/authStore.js';
import {GoogleLogin} from "vue3-google-login";
// import { FacebookAuth } from '@xtiannyeto/vue-auth-social';
import SelectedFooter from "@/views/main/SelectedFooter.vue";
const api = useClient();
const store = auth();
const authStore = useAuthStore();
const router = useRouter();
const user = ref({});
const email = ref("");
const password = ref("");
const errorSnackBar = ref(false);
const showEmailForm = ref(false);
const showPassword = ref(false);
async function login() {
try {
await store.login(api, user.value.email, user.value.password);
await router.push('/');
window.location.reload();
} catch (error) {
errorSnackBar.value = true;
const result = await authStore.login(email.value, password.value);
if (result === true) {
await router.push('/')
}
}
const googleCallback = async (response) => {
await store.loginGoogle(api, response["access_token"]);
await authStore.loginGoogle(response["access_token"]);
await router.push("/");
};
@@ -110,4 +110,5 @@ const googleCallback = async (response) => {
// const facebookCallback = (response) => {
// console.log("User Successfully Logged In", response);
// };
</script>

View File

@@ -106,7 +106,7 @@
<button
@click="openModal('ModalTikTok')"
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/black/tiktokblack.png" class="w-5 h-5" ></span>
<span class="flex-none pa-2 min-w-32 text-left"> <img src="/images/externals/tiktok-black.png" class="w-5 h-5" ></span>
<span class="flex-auto text-left pr-6">TikTok</span>
<span class="flex-none">
<v-icon>mdi-chevron-right</v-icon>

View File

@@ -1,45 +1,86 @@
<template>
<script setup>
import {computed, reactive, onMounted} from 'vue';
import {time_ago} from "@/internal_time_ago.js";
import MessageList from "@/views/messages/MessageList.vue";
import PostMessage from "@/views/messages/PostMessage.vue";
import YoutubePlayer from './YoutubePlayer.vue';
import ImageViewer from './ImageViewer.vue';
// import VimeoPlayer from '@/components/VimeoPlayer.vue';
// import AudioPlayer from '@/components/AudioPlayer.vue';
// import BlogViewer from '@/components/BlogViewer.vue';
const props = defineProps({
content: {
type: Object,
required: true,
}
});
const hasUrls = computed(() => !!props.content.urls && props.content.urls.length > 0);
const messages = reactive([]);
function addMessage(newMessage) {
messages.unshift(newMessage)
}
function getComponent(url) {
if (url.includes('youtube.com') || url.includes('youtu.be')) {
return YoutubePlayer;
// } else if (url.includes('vimeo.com')) {
// return VimeoPlayer;
} else if (url.match(/\.(jpeg|jpg|gif|png)$/)) {
return ImageViewer;
// } else if (url.match(/\.(mp3|wav|ogg)$/)) {
// return 'AudioPlayer';
// } else {
// return 'BlogViewer';
}
}
</script>
<template>
<div class="shadow-md rounded-lg bg-gray-50">
<div class="text-lg font-bold">
{{ props.content.title }}
<span class="text-md-caption">
{{ time_ago(props.content.createdAt) }}
<v-card
outlined
tile
>
<v-card-title>
{{ props.content.title }}
<span class="text-subtitle-2">
{{ time_ago(props.content.createdAt) }}
</span>
</div>
</v-card-title>
<div v-if="props.content.url !== null || props.content.uri !== null"
class="h-48 object-cover bg-gray-300 rounded-md">
<v-carousel v-if="hasUrls">
<v-img :src="props.content.url"
v-if="!isHttpUrl">
</v-img>
<v-carousel-item
v-for="url in props.content.urls"
:key="url"
>
<component :is="getComponent(url)"
:src="url"
></component>
</v-carousel-item>
<iframe v-if="isHttpUrl"
:src="props?.content?.uri"
title="YouTube video player"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen>
</iframe>
</v-carousel>
</div>
<v-card-text>
{{ props.content.description }}
</v-card-text>
<div class="flex flex-row">
<div>
<div class="text-sm text-gray-500">{{ props.content.description }}</div>
</div>
<div>
<router-link :to="'content/' + props?.content?.id">
<v-card-actions>
<router-link :to="'content/' + content.id">
<div class="bg-blue-500 rounded-lg py-1 px-2">Plus ...</div>
</router-link>
</div>
</v-card-actions>
</div>
</v-card>
<div>
@@ -58,28 +99,4 @@
</div>
</template>
<script setup>
import {computed, reactive} from 'vue';
import {time_ago} from "@/internal_time_ago.js";
import MessageList from "@/views/messages/MessageList.vue";
import PostMessage from "@/views/messages/PostMessage.vue";
const isHttpUrl = computed(() => props.content?.uri?.startsWith('http'))
const props = defineProps({
content: {
type: Object,
required: true,
}
});
const messages = reactive([]);
function addMessage(newMessage) {
messages.unshift(newMessage)
}
</script>
</template>

View File

@@ -48,7 +48,6 @@ async function load({done}) {
let uri = `/api/contents/user/${props.creatorId}?page_size=${page_size}`
if (last_id !== null) uri = uri + `&last_id=${last_id}`
console.log(`Fetching content at: ${uri}`)
const response = await client.get(uri)
if (response.status >= 200 && response.status < 300) {

View File

@@ -1,72 +1,8 @@
<template>
<div v-if="creator.id === userStore.getCurrentUser().id">
<button
class="flex items-center text-white transform transition-transform duration-200 hover:text-gray-300 hover:scale-125 px-4"
@click="isDialogActive = true">
<v-icon style="font-size: 35px; height: 35px; width: 55px;">mdi-text-box-plus-outline</v-icon>
</button>
<v-dialog v-model="isDialogActive" max-width="500">
<v-card class="text-center rounded-xl">
<v-card-title class="text-white p-4 rounded-t"
:style="{backgroundColor: creator.profileColors.menu || '#A30E79'}">
Quicky
</v-card-title>
<v-card-text>
<v-text-field v-model="title"
class="p-2"
label="Titre"
density="comfortable"
variant="outlined"
hide-details
clearable>
</v-text-field>
<v-textarea v-model="message"
label="Écrivez votre message ici..."
class="p-2"
density="comfortable"
variant="outlined"
hide-details
clearable
outlined>
</v-textarea>
<v-file-input v-model="files"
label="Ajoutez des fichiers"
class="p-2"
outlined
multiple
dropzone
placeholder="Glissez et déposez des fichiers ici ou cliquez pour sélectionner des fichiers"
></v-file-input>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn color="secondary" @click="cancelPost">Annuler</v-btn>
<v-btn color="primary" @click="publishPost">Publier</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script setup>
<script setup>
import {useClient} from '@/plugins/api.js';
import {ref} from 'vue';
import {useUserStore} from '@/stores/user.js';
import {useUserStore} from '@/stores/userStore.js';
import {v7} from 'uuid'
const props = defineProps({
creator: {type: Object, required: true},
@@ -75,22 +11,34 @@ const props = defineProps({
const userStore = useUserStore();
const isDialogActive = ref(false);
const title = ref('');
const message = ref('');
const files = ref([]);
const client = useClient();
const title = ref('');
const message = ref('');
const files = ref([])
const publishPost = async () => {
async function publishPost() {
const formData = new FormData();
formData.append('id', v7());
formData.append('creatorId', userStore.user.id);
formData.append('title', title.value);
formData.append('description', message.value);
files.value.forEach(file => {
formData.append('files', file);
});
try {
await client.post(
const response = await client.post(
`/api/contents/`,
formData,
{
"title": title.value,
"description": message.value
headers: {
'Content-Type': 'multipart/form-data',
}
})
console.log('Files uploaded successfully:', response.data);
closeDialog()
} catch (error) {
console.error(error)
@@ -110,3 +58,69 @@ const closeDialog = () => {
</script>
<template>
<button
v-if="creator.id === userStore.user.id"
class="flex items-center text-white transform transition-transform duration-200 hover:text-gray-300 hover:scale-125 px-4"
@click="isDialogActive = true">
<v-icon style="font-size: 35px; height: 35px; width: 55px;">mdi-text-box-plus-outline</v-icon>
</button>
<v-dialog v-model="isDialogActive"
max-width="500">
<v-form>
<v-card class="text-center rounded-xl">
<v-card-title class="text-white p-4 rounded-t"
:style="{backgroundColor: creator.profileColors.menu || '#A30E79'}">
Quicky
</v-card-title>
<v-card-text>
<v-text-field v-model="title"
class="p-2"
label="Titre"
density="comfortable"
variant="outlined"
hide-details
clearable
></v-text-field>
<v-textarea v-model="message"
label="Écrivez votre message ici..."
class="p-2"
density="comfortable"
variant="outlined"
hide-details
clearable
outlined
></v-textarea>
<v-file-input v-model="files"
label="Ajoutez des fichiers"
class="p-2"
outlined
multiple
dropzone
placeholder="Glissez et déposez des fichiers ici ou cliquez pour sélectionner des fichiers"
></v-file-input>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn color="secondary" @click="cancelPost">Annuler</v-btn>
<v-btn color="primary" @click="publishPost">Publier</v-btn>
</v-card-actions>
</v-card>
</v-form>
</v-dialog>
</template>

View File

@@ -0,0 +1,31 @@
<template>
<div class="image-container">
<img :src="src" alt="Image" class="image" />
</div>
</template>
<script setup>
const props = defineProps({
src: {
type: String,
required: true,
},
});
</script>
<style scoped>
.image-container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
overflow: hidden;
}
.image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
</style>

View File

@@ -0,0 +1,26 @@
<template>
<iframe
:src="src"
title="YouTube video player"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen
></iframe>
</template>
<script setup>
const props = defineProps({
src: {
type: String,
required: true,
},
});
</script>
<style scoped>
iframe {
width: 100%;
height: 100%;
border: 0;
}
</style>

View File

@@ -86,10 +86,9 @@
</template>
<script setup>
import MyUserModel from "@/models/myUserModel.js";
const props = defineProps({
user: {type: MyUserModel},
user
});
const dateRule = value => {

View File

@@ -15,7 +15,8 @@
class="text-white text-2xl transform transition-transform duration-200 hover:scale-125 hover:text-blue-500">
<v-icon v-if="socialNetwork.icon.includes('mdi')">{{ socialNetwork.icon }}</v-icon>
<img v-if="socialNetwork.icon.includes('tiktok')" :src="socialNetwork.icon" class="w-9 h-9" alt="Tiktok">
<img v-if="socialNetwork.icon.includes('websiteIcon')" :src="socialNetwork.icon" class="w-9 h-9" alt="Website">
<img v-if="socialNetwork.icon.includes('websiteIcon')" :src="socialNetwork.icon" class="w-9 h-9"
alt="Website">
</a>
</div>
</div>
@@ -91,29 +92,29 @@ const props = defineProps({
function GetActiveSocialNetworkUrls() {
const socialNetworks = [];
const userSocialNetworks = props.creator.socialNetworks;
if (userSocialNetworks.facebookUrl !== '') {
if (userSocialNetworks.facebookUrl !== null) {
socialNetworks.push({icon: "mdi-facebook", url: props.creator.socialNetworks.facebookUrl})
}
if (userSocialNetworks.facebookUrl !== '') {
if (userSocialNetworks.xUrl !== null) {
socialNetworks.push({icon: "mdi-twitter", url: props.creator.socialNetworks.xUrl})
}
if (userSocialNetworks.instagramUrl !== '') {
if (userSocialNetworks.instagramUrl !== null) {
socialNetworks.push({icon: "mdi-instagram", url: props.creator.socialNetworks.instagramUrl})
}
if (userSocialNetworks.tiktokUrl !== '') {
if (userSocialNetworks.tikTokUrl !== null) {
socialNetworks.push({
icon: "/images/hutopymedia/icons/white/tiktokwhite.png",
icon: '/images/externals/tiktok-white.png',
url: props.creator.socialNetworks.tikTokUrl
})
}
if (userSocialNetworks.youtubeUrl !== '') {
socialNetworks.push({icon: "mdi-youtube", url: props.creator.socialNetworks.youtubeUrl})
if (userSocialNetworks.youtubeUrl !== null) {
socialNetworks.push({icon: 'mdi-youtube', url: props.creator.socialNetworks.youtubeUrl})
}
if (userSocialNetworks.yourWebsiteUrl !== ''){
const websiteIconWithBackup = props.creator.storedDataUrls.websiteIconUrl === '' ? "mdi-web" : props.creator.storedDataUrls.websiteIconUrl;
socialNetworks.push({icon: websiteIconWithBackup, url: props.creator.socialNetworks.yourWebsiteUrl})
if (userSocialNetworks.websiteUrl !== null) {
socialNetworks.push({icon: 'mdi-web', url: props.creator.socialNetworks.websiteUrl})
}
return socialNetworks;

View File

@@ -1,50 +0,0 @@
<template>
<div class="mt-28">
<div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-4xl mb-4">
<div class="md:flex">
<div class="md:flex-shrink-0">
<img class="h-48 w-full object-cover md:h-full md:w-48" src="/images/usersmedia/HutopyProfile/banners/banner01.png" alt="Image">
</div>
<div class="p-8">
<div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">Nom du réseau social</div>
<p class="mt-2 text-gray-500">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam.</p>
<p class="mt-2 text-gray-500">Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.</p>
</div>
</div>
</div>
<div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-4xl mb-4">
<div class="md:flex">
<div class="md:flex-shrink-0">
<img class="h-48 w-full object-cover md:h-full md:w-48" src="/images/usersmedia/HutopyProfile/banners/banner01.png" alt="Image">
</div>
<div class="p-8">
<div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">Nom du réseau social</div>
<p class="mt-2 text-gray-500">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam.</p>
<p class="mt-2 text-gray-500">Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.</p>
</div>
</div>
</div>
<div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-4xl mb-4">
<div class="md:flex">
<div class="md:flex-shrink-0">
<img class="h-48 w-full object-cover md:h-full md:w-48" src="/images/usersmedia/HutopyProfile/banners/banner01.png" alt="Image">
</div>
<div class="p-8">
<div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">Nom du réseau social</div>
<p class="mt-2 text-gray-500">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam.</p>
<p class="mt-2 text-gray-500">Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.</p>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
</script>

View File

@@ -4,7 +4,7 @@
@click.stop
>
<div class="flex items-center">
<v-app-bar-nav-icon @click.stop="toggleSidebar">
<v-app-bar-nav-icon @click.stop="sideBarStore.toggle()">
</v-app-bar-nav-icon>
<RouterLink to="/" class="hidden md:block">
@@ -53,51 +53,52 @@
<div class="text-center">
<v-menu open-on-hover>
<template v-slot:activator="{ props }">
<v-btn variant="plain" v-bind="props" class="d-flex align-center text-capital-none">
<span class="normal-case max-w-xs hidden md:block">
{{ currentUser.userName }}
</span>
<div v-bind="props" class="flex align-center font-sans py-1 px-4 rounded-lg hover:bg-gray-100">
<span class="max-w-xs hidden md:block">
{{ userStore.alias }}
</span>
<img
:src="currentUser.storedDataUrls.profilePictureUrl ?? '/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
:src="userStore.portraitUrl"
alt="Profile Image"
class="ml-2 rounded-full" style="width: 32px; height: 32px;">
</v-btn>
class="ml-2 rounded-full"
width="32"
height="32">
</div>
</template>
<v-list min-width="200px" class=" align-center mt-3 left-3">
<div v-if="currentUser.userName === 'Anonyme'">
<template v-if="!authStore.isAuthenticated">
<v-list-item class="nav-button">
<v-list-item-title>
<v-btn to="/login" class="w-100 " variant="plain">Connexion</v-btn>
</v-list-item-title>
</v-list-item>
</div>
</template>
<div v-if="currentUser.userName !== 'Anonyme'">
<v-list-item v-if="currentUser.creatorAlias !== null" class="nav-button">
<router-link :to="`/@${currentUser.creatorAlias}`">
<v-btn class="w-100 " variant="plain">@{{ currentUser.creatorAlias }}</v-btn>
<template v-else>
<v-list-item v-if="userStore.creator" class="nav-button">
<router-link :to="`/@${userStore.creator.name}`">
<v-btn class="w-100 " variant="plain">@{{ userStore.creator.name }}</v-btn>
</router-link>
</v-list-item>
<v-list-item class="nav-button">
<v-list-item-title>
<v-btn to="/profile" class="w-100 " variant="plain">Mon profil</v-btn>
<v-btn to="/profile" class="w-100" variant="plain">Mon profil</v-btn>
</v-list-item-title>
</v-list-item>
<v-list-item class="nav-button">
<v-list-item-title>
<v-btn to="/wallet" class="w-100 " variant="plain"> Portefeuille</v-btn>
<v-btn to="/wallet" class="w-100" variant="plain">Portefeuille</v-btn>
</v-list-item-title>
</v-list-item>
<v-list-item class="nav-button">
<v-list-item-title>
<v-btn @click="logout" to="/wallet" class="w-100 " variant="plain"> Déconnexion</v-btn>
<v-btn @click="authStore.logout" class="w-100" variant="plain">Déconnexion</v-btn>
</v-list-item-title>
</v-list-item>
</div>
</template>
</v-list>
</v-menu>
</div>
@@ -108,21 +109,19 @@
</template>
<script setup>
import {ref, onBeforeUnmount, onBeforeMount, watch, reactive} from "vue";
import {eventBus} from '@/eventBus.js';
import {ref, onBeforeUnmount, onBeforeMount, watch} from "vue";
import {useRouter} from 'vue-router';
import {useUserStore} from "@/stores/user.js";
import MyUserModel from "@/models/myUserModel.js";
import {useSideBarStore} from '@/stores/sideBarStore.js';
import {useUserStore} from "@/stores/userStore.js";
import {useAuthStore} from "@/stores/authStore.js";
const authStore = useAuthStore()
const userStore = useUserStore()
const sideBarStore = useSideBarStore()
const router = useRouter();
const searchQuery = ref("");
const showSearch = ref(false);
let currentUser = reactive(MyUserModel.getDefaultUser());
const userStore = useUserStore();
const toggleSidebar = () => {
eventBus.value.toggleSidebar();
};
const onSearch = () => {
const query = searchQuery.value.trim();
@@ -148,33 +147,14 @@ const handleClickOutside = (event) => {
}
};
const navigateToMessages = () => {
router.push('/messages');
};
const logout = () => {
localStorage.removeItem('jwt');
window.location.reload();
};
onBeforeMount(() => {
currentUser = userStore.getCurrentUser();
document.addEventListener('click', handleClickOutside);
document.addEventListener('click', handleClickOutside)
});
// Watch the user state to get it again if needed.
watch(
() => userStore.hasChanged,
() => {
currentUser = userStore.getCurrentUser();
const timestamp = new Date().getTime();
currentUser.storedDataUrls.profilePictureUrl = `${currentUser.storedDataUrls.profilePictureUrl}?t=${timestamp}`;
}
);
onBeforeUnmount(() => {
document.removeEventListener('click', handleClickOutside);
});
</script>

View File

@@ -68,9 +68,8 @@
</template>
<script setup>
import {ref, onBeforeMount, onMounted} from "vue";
import {useUserStore} from "@/stores/user.js";
import {useClient} from "@/plugins/api.js";
import {ref, onMounted} from "vue";
import {useUserStore} from "@/stores/userStore.js";
import SizeIndicator from "@/views/tools/SizeIndicator.vue";
import ManageAccount from "@/views/Profile/ManageAccount.vue";
import PageInformations from "@/views/Profile/PageInformations.vue";
@@ -78,21 +77,12 @@ import PersonnalInfo from "@/views/Profile/PersonnalInfo.vue";
import AccountSecurity from "@/views/Profile/AccountSecurity.vue";
const userStore = useUserStore();
const client = useClient();
const currentUser = ref(null);
const currentComponent = ref('PageInformations'); // Default component
const isDown = ref(false);
const startX = ref(0);
const scrollLeft = ref(0);
onBeforeMount(() => {
try {
currentUser.value = userStore.getCurrentUser();
} catch (error) {
console.log("User not logged")
}
});
onMounted(() => {
const slider = document.querySelector('.custom-scroll');
@@ -163,9 +153,6 @@ const scrollRightFunc = () => {
</script>
<style scoped>
.save-btn {
z-index: 10;
}
.custom-scroll {
-ms-overflow-style: none; /* Internet Explorer 10+ */
@@ -176,8 +163,4 @@ const scrollRightFunc = () => {
display: none; /* Safari and Chrome */
}
.active {
cursor: grabbing;
cursor: -webkit-grabbing;
}
</style>

View File

@@ -86,14 +86,13 @@
<script setup>
import {ref} from 'vue';
import MyUserModel from "@/models/myUserModel.js";
const emit = defineEmits(["updateProfilePicture", "updateBannerPicture"]);
const fallbackProfilePictureUrl = '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png';
const fallbackBannerPictureUrl = '/images/usersmedia/HutopyProfile/banners/banner01.png';
const props = defineProps({
user: {type: MyUserModel},
user: {}
});
const bannerImageUrl = ref(props.user.storedDataUrls.bannerPictureUrl);

View File

@@ -1,87 +0,0 @@
<template>
<div ref="container">
<div class="text-center text-2xl py-4 border-t-4">Liens des réseaux sociaux et de votre site</div>
<div class="px-5 py-2 flex flex-col space-y-4">
<div class="flex justify-between items-center mb-2">
<label class="text-lg">Instagram</label>
</div>
<v-text-field v-model="props.user.socialNetworks.instagramUrl" label="Instagram"
variant="outlined"></v-text-field>
<div class="flex justify-between items-center mb-2">
<label class="text-lg">TikTok</label>
</div>
<v-text-field v-model="props.user.socialNetworks.tikTokUrl" label="TikTok" variant="outlined"></v-text-field>
<div class="flex justify-between items-center mb-2">
<label class="text-lg">Facebook</label>
</div>
<v-text-field v-model="props.user.socialNetworks.facebookUrl" label="Facebook" variant="outlined"></v-text-field>
<div class="flex justify-between items-center mb-2">
<label class="text-lg">X</label>
</div>
<v-text-field v-model="props.user.socialNetworks.xUrl" label="X" variant="outlined"></v-text-field>
<div class="flex justify-between items-center mb-2">
<label class="text-lg">LinkedIn</label>
</div>
<v-text-field v-model="props.user.socialNetworks.linkedInUrl" label="LinkedIn" variant="outlined"></v-text-field>
<div class="flex justify-between items-center mb-2">
<label class="text-lg">Site Web</label>
</div>
<v-text-field v-model="props.user.socialNetworks.yourWebsiteUrl" label="Site Web"
variant="outlined"></v-text-field>
<div class="flex flex-col space-y-4">
<div class="flex items-center mb-2">
<label class="text-lg mr-4">Icône pour votre site web *svg</label>
<v-file-input
v-model="iconFile"
accept=".png, .jpeg, .jpg"
hint="png, jpeg or jpg"
label="Téléverser une icône"
@change="onFileChange">
</v-file-input>
</div>
<div v-if="iconUrl" class="flex justify-center">
<img :src="iconUrl" alt="Icon" class="icon-preview">
</div>
</div>
</div>
</div>
</template>
<script setup>
import {ref} from 'vue';
import MyUserModel from "@/models/myUserModel.js";
const props = defineProps({
user: {type: MyUserModel},
});
const emit = defineEmits(["updateWebsiteIcon"]);
const iconUrl = ref(props.user.storedDataUrls.websiteIconUrl);
const iconFile = ref(null);
const onFileChange = (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
iconUrl.value = e.target.result;
};
reader.readAsDataURL(file);
emit("updateWebsiteIcon", file)
}
};
</script>
<style scoped>
.icon-preview {
max-width: 250px;
max-height: 250px;
}
</style>

View File

@@ -47,7 +47,7 @@
<script async setup>
import { onBeforeMount, ref, computed } from 'vue';
import { useRouter } from 'vue-router';
import {useUserStore} from "@/stores/user.js";
import {useUserStore} from "@/stores/userStore.js";
const userStore = useUserStore();
const router = useRouter();
@@ -75,10 +75,8 @@ const transactionCount = computed(() => userTransactions.value.length);
onBeforeMount( () => {
try {
const myUser = userStore.getCurrentUser();
userTransactions.value = myUser.userTransactions;
totalBalance.value = myUser.totalBalance;
userTransactions.value = userStore.user.userTransactions;
totalBalance.value = userStore.user.totalBalance;
} catch (error) {
navigateToHome();
}

View File

@@ -45,7 +45,7 @@
</a>
<a href="https://www.tiktok.com/@guillaumeaime">
<img class="socialicons invert-color" src="/images/hutopymedia/icons/white/tiktokwhite.png"
<img class="socialicons invert-color" src="/images/externals/tiktok-white.png"
alt="Description image 2">
</a>
</v-row>

View File

@@ -2,7 +2,7 @@
<div class="flex flex-column">
<div class="flex flex-row p-1 items-center">
<div class="px-2 content-center">
<img :src="message.profileImageUrl ?? '/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
<img :src="message.createdByPortraitUrl ?? '/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
alt="Profile Image"
class="rounded-full"
width="32px"

View File

@@ -59,7 +59,6 @@ onBeforeMount(async () => {
await load({
page_size: 2,
done: function (status) {
console.log(`Loading status: ${status}`)
}
})
})
@@ -71,8 +70,7 @@ async function load({done, page_size}) {
try {
let uri = `/api/messages/${props.subjectId}?page_size=${page_size}`
if (last_id !== null) uri = uri + `&last_id=${last_id}`
console.log(`Fetching messages at: ${uri}`)
const response = await client.get(uri)
if (response.status >= 200 && response.status < 300) {

View File

@@ -6,7 +6,7 @@
<div class="mx-2 content-center">
<img :src="profileUrl"
<img :src="userStore.portraitUrl"
alt="Profile Image"
class="rounded-full"
width="32px"
@@ -35,10 +35,12 @@
<script setup>
import {useClient} from '@/plugins/api.js';
import {ref} from 'vue';
import {useUserStore} from "@/stores/user.js";
import {v7} from 'uuid'
import {useRouter} from "vue-router";
import {useClient} from '@/plugins/api.js';
import {useUserStore} from "@/stores/userStore.js";
import {useAuthStore} from "@/stores/authStore.js";
const props = defineProps({
subjectId: {
@@ -51,13 +53,19 @@ const emit = defineEmits(['message-posted'])
const client = useClient()
const value = ref("")
const user = useUserStore()
const profileUrl = ref(user.getCurrentUser().storedDataUrls.profilePictureUrl ?? '/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png')
const router = useRouter()
const userStore = useUserStore()
const authStore = useAuthStore()
const publish = async () => {
if (!authStore.isAuthenticated) {
await router.push('/login')
}
try {
const messageId = v7()
await client.post(`/api/messages/`,
{
"id": messageId,
@@ -65,17 +73,16 @@ const publish = async () => {
"message": value.value
})
const currentUser = user.getCurrentUser()
emit('message-posted',
{
"id": messageId,
"subjectId": props.subjectId,
"createdBy": currentUser.id,
"createdByName": currentUser.alias ?? `${currentUser.firstName} ${currentUser.lastName}`,
"createdByPortraitUrl": currentUser.storedDataUrls.profilePictureUrl,
"createdBy": userStore.user.id,
"createdByName": userStore.alias,
"createdByPortraitUrl": userStore.portraitUrl,
"createdAt": new Date(Date.now()).toISOString(),
"value": value.value,
parentId: null,
"parentId": null
})
value.value = ''