refactor(login): change to Setup store instead of Options store, fix auth frontend flow

This commit is contained in:
Nicolas Drolet 2025-08-06 17:09:30 -04:00
parent 6006c3fb42
commit 7399232ed8
9 changed files with 109 additions and 348 deletions

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { RouterView } from 'vue-router';
import HeaderBar from 'src/modules/shared/components/navigation/header-bars/header-bar.vue';
import FooterBar from 'src/modules/shared/components/navigation/footer-bars/footer-bar.vue';
import HeaderBar from 'src/modules/shared/components/navigation/header-bar.vue';
import FooterBar from 'src/modules/shared/components/navigation/footer-bar.vue';
</script>
<template>

View File

@ -1,59 +1,48 @@
/* eslint-disable */
import { defineStore } from "pinia";
import { api } from "src/boot/axios";
import { User } from "src/modules/users/types/user-interface";
import { AuthState } from "./types/auth-interface";
import { AuthService } from "./services/services-auth";
import { computed, ref } from "vue";
export const useAuthStore = defineStore('auth', {
state: (): AuthState => ({
token: "",
user: {
firstName: 'Unknown',
lastName: 'Unknown',
email: 'guest@guest.com',
role: 'guest'
} as User,
loading: false,
error: "",
}),
export const useAuthStore = defineStore('auth', () => {
const user = ref ({
firstName: 'Unknown',
lastName: 'Unknown',
email: 'guest@guest.com',
role: 'guest'
} as User);
const error = ref("");
const isAuthorizedUser = computed( () => user.value.role !== 'guest');
getters: {
hasAuthToken: (state) => !!state.token,
},
const login = () => {
//TODO: manage customer login process
};
actions: {
login() {
const authPopup = window.open('http://localhost:3000/auth/v1/login', 'authPopup', 'width=600,height=800');
window.addEventListener('message', (event) => {
if (event.data.type === 'authSuccess') {
console.log('Logged in successfully!');
}
})
},
async oidcLogin() {
return "openIDConnect login";
},
async logout() {
return "logout";
},
setAuthToken(token: string) {
return "setting auth token";
},
setUser(user: Record<string, any>) {
return "setting user info";
},
isAuthorizedUser(): boolean {
return this.$state.user.role.toLowerCase() != 'guest';
},
async forgotPassword(email: string) {
return "resetting password";
const oidcLogin = () => {
const oidcPopup = AuthService.oidcLogin();
if (!oidcPopup) {
error.value = "You have popups blocked on this website!";
}
},
};
const logout = () => {
return "logout";
};
const setUser = (currentUser: User, isBypass: boolean = false, bypassRole?: string) => {
if (isBypass) {
user.value = {
firstName: "Testing",
lastName: "Tester",
email: "testingT@targointernet.com",
role: bypassRole || "guest"} as User;
} else {
user.value = currentUser;
}
};
return { login, oidcLogin, logout, setUser };
});

View File

@ -1,8 +1,9 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
import { useAuthApi } from '../composables/use-auth-api';
import { useAuthStore } from '../auth-store';
const { login } = useAuthApi();
const authStore = useAuthStore();
const email = ref('');
const isShowingEmployeeLoginButton = ref(false);
const isRemembered = ref(false);
@ -13,55 +14,77 @@
</script>
<template>
<q-layout view="hHh lpR fFf" class="flex flex-center bg-dark">
<q-img src="src/assets/village.png" fit="cover" position="50% 100%" class="absolute-full" />
<q-page-container>
<transition appear enter-active-class="animated zoomIn" leave-active-class="animated zoomOut">
<q-card class="rounded-20">
<q-card-section class="text-center bg-primary q-pa-lg">
<q-img src="/src/assets/logo-targo-white.svg" ratio="4.6" fit="contain" />
</q-card-section>
<div class="q-pt-sm q-px-xl q-pb-lg">
<q-card-section class="text-center">
<div class="text-h6 text-grey-9 text-weight-bold">
{{ $t('loginPage.title') }}
</div>
<q-layout view="hHh lpR fFf">
<q-page-container class="bg-dark">
<q-img src="src/assets/village.png" fit="cover" position="50% 100%" class="absolute-full" />
<q-page class="flex flex-center">
<transition appear slow enter-active-class="animated zoomIn" leave-active-class="animated zoomOut">
<q-card class="rounded-20">
<q-card-section class="text-center bg-primary q-pa-lg">
<q-img src="/src/assets/logo-targo-white.svg" ratio="4.6" fit="contain" />
</q-card-section>
<q-form class="q-gutter-sm" @submit="login">
<q-input dense outlined label-color="primary" v-model="email" :label="$t('loginPage.email')" />
<q-card-section class="q-ma-none q-pa-none">
<q-toggle v-model="isRemembered" :label="$t('loginPage.rememberMe')" color="primary" />
<div class="q-pt-sm q-px-xl q-pb-lg">
<q-card-section class="text-center">
<div class="text-h6 text-grey-9 text-weight-bold">
{{ $t('loginPage.title') }}
</div>
</q-card-section>
<q-card-actions>
<q-btn disabled rounded push :label="$t('loginPage.submit')" type="submit" color="primary" class="full-width" />
</q-card-actions>
<!-- A implémenter plus tard sans doute, pour les clients. A revoir avec Authentik API pour création de users -->
<!-- <q-card-section class="text-center q-pa-none q-mt-none">
<RouterLink disabled class="text-primary" to="/signup">{{ $t('loginPage.signUp') }}</RouterLink>
</q-card-section> -->
</q-form>
<q-card-section class="row q-pt-sm">
<q-separator color="primary" class="col self-center"/>
<span class="col text-primary text-weight-bolder text-center vertical-align self-center">{{$t('loginPage.loginOrSeparator')}}</span>
<q-separator color="primary" class="col self-center"/>
</q-card-section>
<q-form class="q-gutter-sm" @submit="authStore.login">
<q-input dense outlined label-color="primary" v-model="email" :label="$t('loginPage.email')" />
<q-card-section class="q-ma-none q-pa-none">
<q-toggle v-model="isRemembered" :label="$t('loginPage.rememberMe')" color="primary" />
</q-card-section>
<q-card-actions>
<q-btn disabled rounded push :label="$t('loginPage.submit')" type="submit" color="primary" class="full-width" />
</q-card-actions>
<!-- A implémenter plus tard sans doute, pour les clients. A revoir avec Authentik API pour création de users -->
<!-- <q-card-section class="text-center q-pa-none q-mt-none">
<RouterLink disabled class="text-primary" to="/signup">{{ $t('loginPage.signUp') }}</RouterLink>
</q-card-section> -->
</q-form>
<q-card-section class="column q-px-sm q-pt-none">
<q-btn disabled rounded push :label="$t('loginPage.facebookLoginButton')" color="fb-blue" class="full-width row q-mb-sm" icon="img:src/assets/Facebook-f_Logo-White-Logo.wine.svg">
<q-tooltip anchor="top middle" class="bg-primary">{{$t('loginPage.tooltipComingSoon')}}</q-tooltip>
</q-btn>
<transition appear enter-active-class="animated zoomIn" leave-active-class="animated zoomOut">
<q-btn rounded push color="primary" v-if="isShowingEmployeeLoginButton" @click="login" :label="$t('loginPage.employeeLoginButton')" class="full-width row" icon="img:src/assets/logo-targo-simple.svg" />
</transition>
</q-card-section>
</div>
</q-card>
</transition>
<q-card-section class="row q-pt-sm">
<q-separator color="primary" class="col self-center"/>
<span class="col text-primary text-weight-bolder text-center vertical-align self-center">{{$t('loginPage.loginOrSeparator')}}</span>
<q-separator color="primary" class="col self-center"/>
</q-card-section>
<q-card-section class="column q-px-sm q-pt-none">
<q-btn disabled rounded push :label="$t('loginPage.facebookLoginButton')" color="fb-blue" class="full-width row q-mb-sm" icon="img:src/assets/Facebook-f_Logo-White-Logo.wine.svg">
<q-tooltip anchor="top middle" class="bg-primary">{{$t('loginPage.tooltipComingSoon')}}</q-tooltip>
</q-btn>
<q-slide-transition>
<div v-if="isShowingEmployeeLoginButton">
<transition slow enter-active-class="animated zoomIn" leave-active-class="animated zoomOut">
<q-btn rounded push color="primary" @click="authStore.oidcLogin" :label="$t('loginPage.employeeLoginButton')" class="full-width row" icon="img:src/assets/logo-targo-simple.svg" />
</transition>
</div>
</q-slide-transition>
</q-card-section>
</div>
</q-card>
</transition>
<!-- DEV TOOLS -->
<q-card class="absolute-bottom-right q-ma-sm">
<q-card-section class="q-pa-sm text-primary"> BYPASS LOGIN WITH: </q-card-section>
<q-separator color="primary" />
<q-card-section>
<q-btn-group push rounded>
<q-btn push color="primary" text-color="white" label="ACCOUNTING" icon="attach_money" />
<q-btn push color="primary" text-color="white" label="SUPERVISOR" icon="supervisor_account"/>
<q-btn push color="primary" text-color="white" label="HR" icon="diversity_3"/>
<q-btn push color="primary" text-color="white" label="EMPLOYEE" icon="support_agent"/>
</q-btn-group>
</q-card-section>
</q-card>
</q-page>
</q-page-container>
</q-layout>
</template>

View File

@ -1,66 +0,0 @@
<script lang="ts" setup>
/* eslint-disable */
import { ref } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useAuthStore } from 'src/modules/auth/auth-store';
const route = useRoute();
const router = useRouter();
const authStore = useAuthStore();
const userConnected = authStore.user;
const userRole: string = userConnected.role;
const leftDrawerOpen = ref(false);
function toggleLeftDrawer() {
leftDrawerOpen.value = !leftDrawerOpen.value;
}
const goToUsers = () => {
router.replace('/users');
};
const goToShiftsValidations = () => {
router.replace('/time_sheet_validations');
};
const goToHome = () => {
router.replace('/');
};
// const goToHelp = () => {
// router.replace('/help');
// };
</script>
<template>
<q-footer bordered class="bg-white">
<q-tabs no-caps active-color="primary" indicator-color="transparent" class="text-grey-8">
<q-tab name="home" icon="home" @click="goToHome" />
<!-- <q-tab name="help" icon="help" @click="goToHelp" /> -->
<q-tab name="menu" icon="menu" @click="toggleLeftDrawer" />
<q-drawer v-model="leftDrawerOpen" side="right">
<q-scroll-area style="border-right: 1px solid #ddd;">
<q-list padding>
<q-item clickable v-ripple :active="route.path === '/users'" active-class="bg-primary text-white" @click="goToUsers" >
<q-item-section avatar>
<q-icon name="list" />
</q-item-section>
<q-item-section> {{ $t('navBar.navItem_1') }} </q-item-section>
</q-item>
<q-item clickable v-ripple :active="route.path === '/time_sheet_validations'" active-class="bg-primary text-white" @click="goToShiftsValidations" v-if="userRole === 'admin'">
<q-item-section avatar>
<q-icon name="supervisor_account" />
</q-item-section>
<q-item-section>{{ $t('navBar.navItem_2') }} </q-item-section>
</q-item>
</q-list>
</q-scroll-area>
<q-img class="absolute-top" src="https://cdn.quasar.dev/img/material.png" height="150px" />
</q-drawer>
</q-tabs>
</q-footer>
</template>

View File

@ -1,5 +0,0 @@
<template>
<q-toolbar>
<div class="text-right ">© 2025 Targo Communications inc.</div>
</q-toolbar>
</template>

View File

@ -1,12 +0,0 @@
<script setup lang="ts">
// import FooterBarMobile from './footer-bar-mobile.vue';
import FooterBarWeb from './footer-bar-web.vue';
</script>
<template>
<q-footer elevated class="bg-primary text-white">
<FooterBarWeb />
<!-- <FooterBarMobile class="lt-md" /> -->
</q-footer>
</template>

View File

@ -1,47 +0,0 @@
<script lang="ts" setup>
/* eslint-disable */
import { useRoute } from 'vue-router';
import { computed } from 'vue';
import { useAuthStore } from 'src/modules/auth/auth-store';
// import dialogs from 'src/components/dialogs';
// const authStore = useAuthStore();
// const user = authStore.user;
// const { NotificationsDialog, AccountDialog } = dialogs;
const route = useRoute();
const backRoutes = [
'newUser',
'userById',
'timeSheet',
'timeSheetValidationsId',
];
const isBackRoute = computed(
() => backRoutes.indexOf(route.name as string) !== -1,
);
</script>
<template>
<q-toolbar v-if="!isBackRoute">
<q-toolbar-title>
<!-- {{ $t('navBar.mobileIndexTitle') }} {{ user.first_name }} -->
</q-toolbar-title>
<NotificationsDialog />
<AccountDialog />
</q-toolbar>
<q-toolbar v-else>
<q-toolbar-title>
<q-btn
icon="chevron_left"
flat
round
dense
color="white"
@click="$router.go(-1)"
/>
</q-toolbar-title>
<div class="text-h6 text-white">
{{ $t(`pagesTitles.${route.meta.title}`) }}
</div>
<q-space />
</q-toolbar>
</template>

View File

@ -1,109 +0,0 @@
<script lang="ts" setup>
/* eslint-disable */
import { useRouter } from 'vue-router';
import { useQuasar } from 'quasar';
// import { getInitials } from 'src/helpers/object';
import { useAuthStore } from 'src/modules/auth/auth-store';
import LanguageSwitch from 'src/modules/shared/components/language-switch.vue';
// import dialogs from 'src/components/dialogs';
// import authenticationApi from 'src/composables/useAuthentication';
// const { logout } = authenticationApi.useAuthUser();
// const { NotificationsDialog } = dialogs;
const authStore = useAuthStore();
const router = useRouter();
const $q = useQuasar();
const userConnected = authStore.user;
const userRole = userConnected.role;
// const userType = userConnected.type;
const goToProfile = () => {
router.replace('/profile');
};
const goToHelp = () => {
router.replace('/help');
};
const goToCalender = () => {
const pdfUrl = '/calendrier_annuel.pdf';
window.open(pdfUrl, '_blank');
};
const goToTimeSheet = () => {
router.replace('/time_sheet');
};
const handleLogout = async () => {
// const response = await logout();
// const { type, message } = response;
// $q.notify({ type, message });
};
</script>
<template>
<q-toolbar>
<q-btn flat color="white" icon="img:src/assets/logo-targo-white.svg">
</q-btn>
<q-space />
<q-btn flat class="q-mr-xs" to="/users" color="white" :label="$t('navBar.navItem_1')" />
<q-btn flat class="q-mr-xs" to="/time_sheet_validations" color="white" :label="$t('navBar.navItem_2')" />
<LanguageSwitch class="q-mr-xs text-white"/>
<q-btn round color="white">
<q-avatar color="white" text-color="primary" />
<q-menu fit transition-show="flip-right" transition-hide="flip-left">
<q-list>
<q-item>
<div class="text-subtitle1 q-mb-xs text-no-wrap text-center">
ND
</div>
</q-item>
<q-separator />
<q-item v-ripple clickable @click="goToProfile">
<q-item-section avatar
><q-icon name="mdi-account" color="primary" size="2em"
/></q-item-section>
<q-item-section>{{ $t('navBar.menuItem_1') }}</q-item-section>
</q-item>
<!-- <q-item
v-if="userType === 'employee'"
v-ripple
clickable
@click="goToTimeSheet"
>
<q-item-section avatar>
<q-icon name="work_history" color="primary" size="2em" />
</q-item-section>
<q-item-section>{{ $t('navBar.menuItem_4') }}</q-item-section>
</q-item>
<q-item
v-if="userType === 'employee'"
v-ripple
clickable
@click="goToCalender"
>
<q-item-section avatar>
<q-icon name="calendar_month" color="primary" size="2em" />
</q-item-section>
<q-item-section>{{ $t('navBar.menuItem_5') }}</q-item-section>
</q-item> -->
<q-item v-ripple clickable @click="goToHelp">
<q-item-section avatar>
<q-icon name="help" color="primary" size="2em" />
</q-item-section>
<q-item-section>{{ $t('navBar.menuItem_2') }}</q-item-section>
</q-item>
<q-separator />
<q-item v-ripple clickable @click="handleLogout">
<q-item-section avatar>
<q-icon name="logout" color="primary" size="2em" />
</q-item-section>
<q-item-section>{{ $t('navBar.menuItem_3') }}</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</q-toolbar>
</template>

View File

@ -1,12 +0,0 @@
<script lang="ts" setup>
// import HeaderBarMobile from './header-bar-mobile.vue';
import HeaderBarWeb from './header-bar-web.vue';
</script>
<template>
<q-header elevated>
<!-- <HeaderBarMobile /> -->
<HeaderBarWeb />
</q-header>
</template>