Merge remote-tracking branch 'origin/jo-wip' into jo-wip
This commit is contained in:
@@ -1,114 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="hidden sm:block" style="height: 40px"></div>
|
<div class="hidden sm:block" style="height: 40px"></div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="flex flex-col lg:flex-row items-center justify-center">
|
<div class="flex flex-col lg:flex-row items-center justify-center">
|
||||||
<div class="max-w-[700px] min-w-[300px]">
|
<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"
|
<img class="rounded-none sm:rounded-2xl sm:w-full mr-8" src="/images/hutopymedia/loginpage/loginhutopy.png" alt="hutopy login">
|
||||||
alt="hutopy login">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col items-center min-w-[300px] m-12">
|
<div class="flex flex-col items-center min-w-[300px] m-12">
|
||||||
<h1 class="text-center text-2xl font-bold mb-5">Connexion</h1>
|
<LoginForm :onSuccess="handleSuccess"></LoginForm>
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<selected-footer></selected-footer>
|
<selected-footer></selected-footer>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
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";
|
import SelectedFooter from "@/views/main/SelectedFooter.vue";
|
||||||
|
import LoginForm from "@/views/main/LoginForm.vue";
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const email = ref("");
|
const handleSuccess = () => {
|
||||||
const password = ref("");
|
router.push('/');
|
||||||
|
|
||||||
const errorSnackBar = ref(false);
|
|
||||||
const showEmailForm = ref(false);
|
|
||||||
const showPassword = ref(false);
|
|
||||||
|
|
||||||
async function login() {
|
|
||||||
const result = await authStore.login(email.value, password.value);
|
|
||||||
if (result === true) {
|
|
||||||
await router.push('/')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const googleCallback = async (response) => {
|
|
||||||
await authStore.loginGoogle(response["access_token"]);
|
|
||||||
await router.push("/");
|
|
||||||
};
|
|
||||||
|
|
||||||
// const facebookAppId = import.meta.env.VITE_FACEBOOK_APP_ID;
|
|
||||||
// const facebookCallback = (response) => {
|
|
||||||
// console.log("User Successfully Logged In", response);
|
|
||||||
// };
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
67
src/views/main/LoginForm.vue
Normal file
67
src/views/main/LoginForm.vue
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex flex-col items-center min-w-[300px] m-4">
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref} from 'vue';
|
||||||
|
import {useRouter} from 'vue-router';
|
||||||
|
import {useAuthStore} from '@/stores/authStore.js';
|
||||||
|
import {GoogleLogin} from "vue3-google-login";
|
||||||
|
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const email = ref("");
|
||||||
|
const password = ref("");
|
||||||
|
const errorSnackBar = ref(false);
|
||||||
|
const showEmailForm = ref(false);
|
||||||
|
const showPassword = ref(false);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
onSuccess: {
|
||||||
|
type: Function,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
onFailure: {
|
||||||
|
type: Function,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function login() {
|
||||||
|
const result = await authStore.login(email.value, password.value);
|
||||||
|
if (result === true) {
|
||||||
|
props.onSuccess();
|
||||||
|
} else {
|
||||||
|
if (props.onFailure) {
|
||||||
|
props.onFailure();
|
||||||
|
}
|
||||||
|
errorSnackBar.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -59,6 +59,8 @@
|
|||||||
|
|
||||||
import {time_ago} from "@/internal_time_ago.js";
|
import {time_ago} from "@/internal_time_ago.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
message: {
|
message: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -1,46 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="flex flex-column">
|
<div class="flex flex-column">
|
||||||
|
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
|
|
||||||
<div class="mx-2 content-center">
|
<div class="mx-2 content-center">
|
||||||
|
<img :src="userStore.portraitUrl" alt="Profile Image" class="rounded-full" width="32px" height="32px">
|
||||||
<img :src="userStore.portraitUrl"
|
|
||||||
alt="Profile Image"
|
|
||||||
class="rounded-full"
|
|
||||||
width="32px"
|
|
||||||
height="32px">
|
|
||||||
</div>
|
</div>
|
||||||
|
<v-text-field v-model="value" density="compact" variant="solo-inverted" placeholder="Votre commentaire..." hide-details clearable></v-text-field>
|
||||||
<v-text-field
|
|
||||||
v-model="value"
|
|
||||||
density="compact"
|
|
||||||
variant="solo-inverted"
|
|
||||||
placeholder="Votre commentaire..."
|
|
||||||
hide-details
|
|
||||||
clearable>
|
|
||||||
</v-text-field>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-row gap-2 mt-2 justify-end">
|
<div class="flex flex-row gap-2 mt-2 justify-end">
|
||||||
<v-btn variant="plain">Annuler</v-btn>
|
<v-btn variant="plain">Annuler</v-btn>
|
||||||
<v-btn variant="tonal" @click="publish">Commenter</v-btn>
|
<v-btn variant="tonal" @click="publish">Commenter</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<v-dialog v-model="loginModal" max-width="400">
|
||||||
|
<v-card>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<v-img src="/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png" class="w-50"></v-img>
|
||||||
|
<LoginForm :onSuccess="handleSuccess" :onFailure="handleFailure"></LoginForm>
|
||||||
|
<v-card-text>Vous devez être connecté pour poster un commentaire.</v-card-text>
|
||||||
|
</div>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-btn color="primary" text @click="closeModal">Fermer</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
import {ref} from 'vue';
|
import {ref} from 'vue';
|
||||||
import {v7} from 'uuid'
|
import {v7} from 'uuid';
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import {useClient} from '@/plugins/api.js';
|
import {useClient} from '@/plugins/api.js';
|
||||||
import {useUserStore} from "@/stores/userStore.js";
|
import {useUserStore} from "@/stores/userStore.js";
|
||||||
import {useAuthStore} from "@/stores/authStore.js";
|
import {useAuthStore} from "@/stores/authStore.js";
|
||||||
|
import LoginForm from "@/views/main/LoginForm.vue";
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
loginModal.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
subjectId: {
|
subjectId: {
|
||||||
@@ -51,6 +47,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['message-posted'])
|
const emit = defineEmits(['message-posted'])
|
||||||
|
|
||||||
|
const loginModal = ref(false);
|
||||||
const client = useClient()
|
const client = useClient()
|
||||||
const value = ref("")
|
const value = ref("")
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -58,37 +55,38 @@ const userStore = useUserStore()
|
|||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
const publish = async () => {
|
const publish = async () => {
|
||||||
|
|
||||||
if (!authStore.isAuthenticated) {
|
if (!authStore.isAuthenticated) {
|
||||||
await router.push('/login')
|
loginModal.value = true;
|
||||||
}
|
} else {
|
||||||
|
try {
|
||||||
try {
|
const messageId = v7()
|
||||||
const messageId = v7()
|
await client.post(`/api/messages/`, {
|
||||||
|
"id": messageId,
|
||||||
await client.post(`/api/messages/`,
|
"subjectId": props.subjectId,
|
||||||
{
|
"message": value.value
|
||||||
"id": messageId,
|
})
|
||||||
"subjectId": props.subjectId,
|
emit('message-posted', {
|
||||||
"message": value.value
|
"id": messageId,
|
||||||
})
|
"subjectId": props.subjectId,
|
||||||
|
"createdBy": userStore.user.id,
|
||||||
emit('message-posted',
|
"createdByName": userStore.alias,
|
||||||
{
|
"createdByPortraitUrl": userStore.portraitUrl,
|
||||||
"id": messageId,
|
"createdAt": new Date(Date.now()).toISOString(),
|
||||||
"subjectId": props.subjectId,
|
"value": value.value,
|
||||||
"createdBy": userStore.user.id,
|
"parentId": null
|
||||||
"createdByName": userStore.alias,
|
})
|
||||||
"createdByPortraitUrl": userStore.portraitUrl,
|
value.value = ''
|
||||||
"createdAt": new Date(Date.now()).toISOString(),
|
} catch (error) {
|
||||||
"value": value.value,
|
console.error(`post api/message : ${error}`)
|
||||||
"parentId": null
|
}
|
||||||
})
|
|
||||||
|
|
||||||
value.value = ''
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`post api/message : ${error}`)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSuccess = () => {
|
||||||
|
loginModal.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFailure = () => {
|
||||||
|
console.error('Login failed');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user