front_foundation #5

Open
mohamed_maoulainine wants to merge 73 commits from front_foundation into main
17 changed files with 1761 additions and 413 deletions
Showing only changes of commit 14a2a59786 - Show all commits

View File

@ -36,4 +36,4 @@ playwright-report/
# Custom # Custom
.installed .installed
package-lock.json ./package-lock.json

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,15 @@
"@types/node": "^22.10.7", "@types/node": "^22.10.7",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"@vue/tsconfig": "^0.7.0", "@vue/tsconfig": "^0.7.0",
"eslint": "^9.20.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-vue": "^9.32.0",
"globals": "^15.14.0",
"jiti": "^2.4.2",
"npm-run-all2": "^7.0.2", "npm-run-all2": "^7.0.2",
"prettier": "3.5.0",
"typescript": "~5.7.3", "typescript": "~5.7.3",
"typescript-eslint": "^8.23.0",
"vite": "^6.0.11", "vite": "^6.0.11",
"vite-plugin-vue-devtools": "^7.7.0", "vite-plugin-vue-devtools": "^7.7.0",
"vue-tsc": "^2.2.0" "vue-tsc": "^2.2.0"

View File

@ -1,26 +0,0 @@
<template>
<header>
<img src="./icons/logo inpulse.png" alt="INPulse" />
</header>
</template>
<script lang="ts">
export default {
name: 'Header',
};
</script>
<style scoped>
header img {
width: 100px;
}
header{
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background-color: #fff;
border-bottom: 2px solid #ddd;
}
</style>

View File

@ -1,129 +0,0 @@
<template>
<div @click="goToLink" class="project">
<div class="project-header">
<h2 >{{ projectName }}</h2>
<div class="project-buttons">
<button class="contact-btn">Contact</button>
</div>
</div>
<div class="project-body">
<ul>
<li v-for="(name, index) in listName" :key="index">{{ name }}</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
import { defineProps } from "vue";
import { useRouter } from 'vue-router'
const props = defineProps<{
projectName: string;
listName: string[];
projectLink: string;
}>();
const router = useRouter();
const goToLink = () => {
if (props.projectLink) {
router.push(props.projectLink);
}
};
</script>
<style scoped>
.project {
background: linear-gradient(to right, #f4f4f4, #ffffff);
border: 1px solid #ddd;
border-radius: 10px;
padding: 20px;
margin: 20px 0;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
font-family: Arial, sans-serif;
}
/* Header Styling */
.project-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.project-header h2 {
font-size: 20px;
color: #333;
margin: 0;
}
/* Button Container */
.project-buttons {
display: flex;
gap: 10px;
}
.info-btn {
background-color: #4CAF50;
color: #fff;
}
.info-btn:hover {
background-color: #45a049;
transform: scale(1.05);
}
.contact-btn {
background-color: #007BFF;
color: #fff;
}
.contact-btn:hover {
background-color: #0056b3;
transform: scale(1.05);
}
.project-body {
margin-top: 15px;
}
.project-body p {
font-size: 16px;
color: #555;
margin-bottom: 10px;
}
.project-body ul {
list-style-type: disc;
margin: 0;
padding-left: 20px;
}
.project-body ul li {
font-size: 14px;
color: #666;
line-height: 1.6;
}
button {
padding: 10px 15px;
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
border-radius: 5px;
}
button:hover {
background-color: #0056b3;
}
</style>

View File

@ -0,0 +1,120 @@
<template>
<header>
<img src="../icons/logo inpulse.png" alt="INPulse Logo">
<div class="header-buttons">
<div class="menu">
<button class="contact-button" @click="toggleDropdown">Contact</button>
<div class="contact-dropdown" v-bind:class="{ 'dropdown-visible': isDropdownOpen }">
<button @click="contactAll">Contact All</button>
<button v-for="(email, index) in entrepreneurEmails" :key="index">
{{ email }}
</button>
</div>
<button class="return-button">
mohamed_maoulainine marked this conversation as resolved Outdated
Outdated
Review

plutôt utiliser des routerLink au lieu de href
https://stackoverflow.com/questions/52675885/when-to-use-router-link-vs-a

plutôt utiliser des routerLink au lieu de href https://stackoverflow.com/questions/52675885/when-to-use-router-link-vs-a
<RouterLink to="/">Return to list project</RouterLink>
</button>
</div>
</div>
</header>
</template>
mohamed_maoulainine marked this conversation as resolved Outdated
Outdated
Review

Ce n'est pas de la composition API, a changer

Ce n'est pas de la composition API, a changer

où exactement?

où exactement?
Outdated
Review

Il faut se servir de axiosInstance, voir https://gitea.piair.dev/piair/MyINPulse/src/branch/main/front/MyINPulse-front/src/services/api.ts.
Cela permet de préconfigurer l'authentification et le host du backend.

Il faut se servir de `axiosInstance`, voir https://gitea.piair.dev/piair/MyINPulse/src/branch/main/front/MyINPulse-front/src/services/api.ts. Cela permet de préconfigurer l'authentification et le host du backend.
<script setup lang="ts">
import { ref, onMounted } from "vue";
import axios from "axios";
const isDropdownOpen = ref(false);
const entrepreneurEmails = ref([]);
mohamed_maoulainine marked this conversation as resolved Outdated
Outdated
Review

Vérifier que le type de données renvoyé par le backend correspond bien à ca (ce n'est pas le cas).

Vérifier que le type de données renvoyé par le backend correspond bien à ca (ce n'est pas le cas).
const toggleDropdown = () => {
isDropdownOpen.value = !isDropdownOpen.value;
console.log("Dropdown toggled:", isDropdownOpen.value); // for debug purposes
};
const fetchEntrepreneurs = async () => {
try {
const response = await axios.get("http://localhost:5000/entrepreneurs");
entrepreneurEmails.value = response.data.map((e: { email: string }) => e.email);
mohamed_maoulainine marked this conversation as resolved Outdated
Outdated
Review

il faut pas Hardcoder une addresse, elle est dans le fichier .env. Dans tout les cas, cette adresse ne devrait pas être là.

il faut pas Hardcoder une addresse, elle est dans le fichier .env. Dans tout les cas, cette adresse ne devrait pas être là.
Outdated
Review

je viens de voir le message de commit, c'est en effet logique d'utiliser cette donnée. Par contre je suis pas sur que ce soit la bonne méthode pour faire des tests, c'est a discuter.

Il serait bien d'appeler mock-data au lieu de fake-data

je viens de voir le message de commit, c'est en effet logique d'utiliser cette donnée. Par contre je suis pas sur que ce soit la bonne méthode pour faire des tests, c'est a discuter. Il serait bien d'appeler mock-data au lieu de fake-data
} catch (error) {
console.error("Erreur lors de la récupération des entrepreneurs:", error);
}
};
const contactAll = () => {
alert("Contacter tous les entrepreneurs : " + entrepreneurEmails.value.join(", "));
};
onMounted(fetchEntrepreneurs);
</script>
<style scoped>
@import "@/components/canvas/style-project.css";
header {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 10px;
}
.header-buttons {
display: flex;
align-items: flex-start;
}
.menu {
display: flex;
flex-direction: column;
gap: 10px;
}
.contact-button, .return-button {
background-color: #000;
color: white;
border: none;
padding: 10px;
cursor: pointer;
font-size: 14px;
text-align: center;
}
.return-button a {
color: white;
text-decoration: none;
}
.contact-dropdown {
display: none;
position: absolute;
background-color: white;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
border-radius: 8px;
padding: 10px;
margin-top: 5px;
z-index: 1000;
}
.contact-dropdown button {
display: block;
width: 100%;
padding: 5px;
text-align: left;
border: none;
background: none;
cursor: pointer;
}
.contact-dropdown button:hover {
background-color: #f0f0f0;
}
.dropdown-visible {
display: block;
}
header img {
width: 100px;
height: auto;
}
</style>

View File

@ -1,17 +1,43 @@
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps(['data']); import { color } from "@/services/popupDisplayer.ts";
import type { PropType } from "vue";
defineProps({
errorMessage: {
type: Object as PropType<string>,
required: true,
},
errorColor: {
type: Object as PropType<color>,
default: color.Red,
},
});
</script> </script>
<template> <template>
<div :class='["red", "yellow", "blue", "green"][data.type]' class="error-modal"> <div
<p>{{["Erreur :(", "Warning :|", "Info :)", "Succes ;)"][data.type]}}</p> :class="['red', 'yellow', 'blue', 'green'][errorColor]"
<p>{{data.errorMessage}}</p> class="error-modal"
<div class="loading" :class='["red-loader", "yellow-loader", "blue-loader", "green-loader"][data.type]'></div> >
</div> <p>
{{
["Erreur :(", "Warning :|", "Info :)", "Succes ;)"][errorColor]
}}
</p>
<p>{{ errorMessage }}</p>
<div
class="loading"
:class="
['red-loader', 'yellow-loader', 'blue-loader', 'green-loader'][
errorColor
]
"
></div>
</div>
</template> </template>
<style scoped> <style scoped>
.error-modal{ .error-modal {
margin-bottom: 1em; margin-bottom: 1em;
padding: 1em; padding: 1em;
border-radius: 1em; border-radius: 1em;
@ -19,41 +45,45 @@ const props = defineProps(['data']);
overflow: hidden; overflow: hidden;
position: relative; position: relative;
animation: disappear 5s linear forwards; animation: disappear 5s linear forwards;
} }
.red{ .red {
background-color: #ee6055; background-color: #ee6055;
color: white; color: white;
} }
.red-loader {
.red-loader {
background-color: #fa8383; background-color: #fa8383;
} }
.yellow{ .yellow {
background-color: #FF9D23; background-color: #ff9d23;
color: white; color: white;
} }
.yellow-loader{
.yellow-loader {
background-color: #ffbf81; background-color: #ffbf81;
} }
.blue { .blue {
background-color: #809bce; background-color: #809bce;
color: white; color: white;
} }
.blue-loader{
background-color: #95b8d1;
}
.green { .blue-loader {
background-color: #95b8d1;
}
.green {
background-color: green; background-color: green;
color: white; color: white;
} }
.green-loader {
background-color: darkgreen;
}
.loading { .green-loader {
background-color: darkgreen;
}
.loading {
box-sizing: border-box; box-sizing: border-box;
position: absolute; position: absolute;
padding: 0; padding: 0;
@ -62,33 +92,33 @@ const props = defineProps(['data']);
height: 1em; height: 1em;
width: 0; width: 0;
animation: loading 4s linear forwards; animation: loading 4s linear forwards;
} }
/* Animation for the loading bar */ /* Animation for the loading bar */
@keyframes loading { @keyframes loading {
0% { 0% {
width: 100%; width: 100%;
} }
100% { 100% {
width: 0; width: 0;
} }
} }
@keyframes disappear { @keyframes disappear {
0% { 0% {
height: 100px; height: 100px;
padding: 1em; padding: 1em;
margin: 1em; margin: 1em;
} }
80% { 80% {
height: 100px; height: 100px;
padding: 1em; padding: 1em;
margin: 1em; margin: 1em;
} }
100% { 100% {
height: 0; height: 0;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
} }
</style> </style>

View File

@ -1,30 +1,30 @@
import { createApp } from 'vue' import { createApp } from "vue";
import App from './App.vue' import App from "./App.vue";
import router from './router/router.ts' import router from "./router/router.ts";
import {createPinia} from "pinia"; import { createPinia } from "pinia";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
import AuthStorePlugin from './plugins/authStore'; import keycloakService from "./services/keycloak";
import keycloakService from './services/keycloak'; import { type AuthStore, useAuthStore } from "@/stores/authStore.ts";
import {useAuthStore} from "@/stores/authStore.ts";
let store: any; let store: AuthStore;
keycloakService.CallInit(() => { keycloakService.CallInit(() => {
try { try {
const app = createApp(App) const app = createApp(App);
// Setup pinia store, allowing user to keep logged in status after refresh // Setup pinia store, allowing user to keep logged in status after refresh
const pinia = createPinia(); const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); pinia.use(piniaPluginPersistedstate);
app.use(pinia); app.use(pinia);
app.use(AuthStorePlugin, { pinia });
store = useAuthStore(); store = useAuthStore();
app.use(router) keycloakService.CallInitStore(store);
app.use(router);
app.mount('#app'); app.mount("#app");
} catch (e) { } catch (e) {
console.error("Error while initiating Keycloak.") console.error("Error while initiating Keycloak.");
console.error(e) console.error(e);
createApp(App).mount('#app'); createApp(App).mount("#app");
} }
}) })
@ -74,4 +74,4 @@ app.use(VueKeyCloak,{
export {store}; export { store };

View File

@ -1,4 +1,4 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from "vue-router";
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
@ -9,7 +9,7 @@ const router = createRouter({
// route level code-splitting // route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route // this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited. // which is lazy-loaded when the route is visited.
component: () => import('../views/test.vue'), component: () => import('../views/testComponent.vue'),
}, },
{ {
@ -27,4 +27,4 @@ const router = createRouter({
], ],
}) })
export default router export default router;

View File

@ -1,31 +1,36 @@
import axios from "axios"; import axios, { type AxiosError, type AxiosResponse } from "axios";
import {store} from "@/main.ts"; import { store } from "@/main.ts";
import {addNewMessage, color} from "@/services/popupDisplayer.ts"; import { addNewMessage, color } from "@/services/popupDisplayer.ts";
const axiosInstance = axios.create({ const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_BACKEND_URL, baseURL: import.meta.env.VITE_BACKEND_URL,
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
}, },
}); });
axiosInstance.interceptors.response.use( axiosInstance.interceptors.response.use(
response => response, // Directly return successful responses. (response) => response, // Directly return successful responses.
async error => { async (error) => {
const originalRequest = error.config; const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry && store.authenticated) { if (
error.response.status === 401 &&
!originalRequest._retry &&
store.authenticated
) {
originalRequest._retry = true; // Mark the request as retried to avoid infinite loops. originalRequest._retry = true; // Mark the request as retried to avoid infinite loops.
try { try {
await store.refreshUserToken(); await store.refreshUserToken();
// Update the authorization header with the new access token. // Update the authorization header with the new access token.
axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${store.user.token}`; axiosInstance.defaults.headers.common["Authorization"] =
`Bearer ${store.user.token}`;
return axiosInstance(originalRequest); // Retry the original request with the new access token. return axiosInstance(originalRequest); // Retry the original request with the new access token.
} catch (refreshError) { } catch (refreshError) {
// Handle refresh token errors by clearing stored tokens and redirecting to the login page. // Handle refresh token errors by clearing stored tokens and redirecting to the login page.
console.error('Token refresh failed:', refreshError); console.error("Token refresh failed:", refreshError);
localStorage.removeItem('accessToken'); localStorage.removeItem("accessToken");
localStorage.removeItem('refreshToken'); localStorage.removeItem("refreshToken");
window.location.href = '/login'; window.location.href = "/login";
return Promise.reject(refreshError); return Promise.reject(refreshError);
} }
} }
@ -34,23 +39,29 @@ axiosInstance.interceptors.response.use(
); );
// TODO: spawn a error modal // TODO: spawn a error modal
function defaultApiErrorHandler(err: string){ function defaultApiErrorHandler(err: AxiosError) {
addNewMessage(err, color.Red); addNewMessage(err.message, color.Red);
} }
function defaultApiSuccessHandler(response: any){ function defaultApiSuccessHandler(response: AxiosResponse) {
addNewMessage(response.data, color.green) addNewMessage(response.data, color.Green);
}
function callApi(endpoint: string, onSuccessHandler?: any, onErrorHandler?: any): void {
axiosInstance.get(endpoint).then(
onSuccessHandler == null ? defaultApiSuccessHandler : onSuccessHandler
).catch(
(err) => {
onErrorHandler == null ? defaultApiErrorHandler(err): onErrorHandler(err);
throw err;
}
)
} }
function callApi(
endpoint: string,
onSuccessHandler?: (response: AxiosResponse) => void,
onErrorHandler?: (error: AxiosError) => void
): void {
axiosInstance
.get(endpoint)
.then(
onSuccessHandler == null
? defaultApiSuccessHandler
: onSuccessHandler
)
.catch(
onErrorHandler == null ? defaultApiErrorHandler : onErrorHandler
);
}
export {callApi} export { callApi };

View File

@ -1,33 +1,31 @@
import Keycloak from 'keycloak-js'; import Keycloak from "keycloak-js";
import type { AuthStore } from "@/stores/authStore.ts";
const options = { const options = {
url: import.meta.env.VITE_KEYCLOAK_URL, url: import.meta.env.VITE_KEYCLOAK_URL,
clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID, clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID,
realm: import.meta.env.VITE_KEYCLOAK_REALM realm: import.meta.env.VITE_KEYCLOAK_REALM,
} };
const keycloak = new Keycloak(options); const keycloak = new Keycloak(options);
let authenticated: boolean | undefined; let authenticated: boolean | undefined;
let store = null; let store = null;
async function login(){ async function login() {
try { try {
await keycloak.login() // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login await keycloak.login(); // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
return keycloak; return keycloak;
} catch (error) { } catch (error) {
console.log(error) console.log(error);
} }
} }
async function signup(){ async function signup() {
try { try {
await keycloak.login( await keycloak.login({ action: "register" }); // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
{action: "register"}
) // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
return keycloak; return keycloak;
} catch (error) { } catch (error) {
console.log(error) console.log(error);
} }
} }
@ -42,31 +40,33 @@ async function init(onInitCallback: () => void) {
onLoad: "check-sso", onLoad: "check-sso",
silentCheckSsoRedirectUri: `${location.origin}/silent-check-sso.htm`, silentCheckSsoRedirectUri: `${location.origin}/silent-check-sso.htm`,
responseMode: "query", responseMode: "query",
}) });
onInitCallback() onInitCallback();
} catch (error) { } catch (error) {
console.error("Keycloak init failed") console.error("Keycloak init failed");
console.error(error) console.error(error);
} }
}; }
/** /**
* Initializes store with Keycloak user data * Initializes store with Keycloak user data
* *
*/ */
async function initStore(storeInstance: any) { async function initStore(storeInstance: AuthStore) {
try { try {
store = storeInstance store = storeInstance;
console.log(keycloak) console.log(keycloak);
await store.initOauth(keycloak) await store.initOauth(keycloak);
// Show alert if user is not authenticated // Show alert if user is not authenticated
if (!authenticated) { console.warn("not authenticated") } if (!authenticated) {
console.warn("not authenticated");
}
} catch (error) { } catch (error) {
console.error("Keycloak init failed") console.error("Keycloak init failed");
console.error(error) console.error(error);
} }
}; }
/** /**
* Logout user * Logout user
@ -83,7 +83,7 @@ async function refreshToken() {
await keycloak.updateToken(480); await keycloak.updateToken(480);
return keycloak; return keycloak;
} catch (error) { } catch (error) {
console.error('Failed to refresh token'); console.error("Failed to refresh token");
console.error(error); console.error(error);
} }
} }
@ -97,4 +97,4 @@ const KeycloakService = {
callSignup: signup, callSignup: signup,
}; };
export default KeycloakService; export default KeycloakService;

View File

@ -1,19 +1,43 @@
import {ref} from "vue"; import { ref, type Ref } from "vue";
enum color {Red, Yellow, Blue, green}
function addNewMessage(errorMessage: string, type?: color, timeout?: number){ enum color {
if (timeout == null){ Red,
Yellow,
Blue,
Green,
}
type ErrorMessageContent = {
message: string;
color: color;
id: number;
timeout: number;
};
let id: number = 0;
const getId = () => {
id = id + 1;
return id;
};
function addNewMessage(errorMessage: string, type?: color, timeout?: number) {
if (timeout == null) {
timeout = 5000; timeout = 5000;
} }
if (type == null){ if (type == null) {
type = color.Red; type = color.Red;
} }
const data = {errorMessage: errorMessage, timeout: timeout, type: type, uid: Math.random()*100000}; const data: ErrorMessageContent = {
errorList.value.push(data) message: errorMessage,
setTimeout(() => errorList.value.slice(0, 1), timeout) timeout: timeout,
color: type,
id: getId(),
};
errorList.value.push(data);
setTimeout(() => errorList.value.slice(0, 1), timeout);
} }
const errorList: any= ref([]) const errorList: Ref<ErrorMessageContent[]> = ref([]);
export {addNewMessage, errorList, color} export { addNewMessage, errorList, color, type ErrorMessageContent };

View File

@ -1,54 +1,61 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import keycloakService from '@/services/keycloak'; import keycloakService from "@/services/keycloak";
import type Keycloak from "keycloak-js"; import type Keycloak from "keycloak-js";
export const useAuthStore = defineStore("storeAuth", {
const useAuthStore = defineStore("storeAuth", {
state: () => { state: () => {
return { return {
testv: true,
authenticated: false, authenticated: false,
user: { user: {
token: "", token: "",
refreshToken: "", refreshToken: "",
username: "", username: "",
}, },
} };
}, },
persist: true, persist: true,
getters: {}, getters: {},
actions: { actions: {
// Initialize Keycloak OAuth // Initialize Keycloak OAuth
async initOauth(keycloak: Keycloak, clearData = true) { async initOauth(keycloak: Keycloak, clearData = true) {
if(clearData) { await this.clearUserData(); } if (clearData) {
await this.clearUserData();
}
this.authenticated = !!keycloak.authenticated; // the !! removes undefined this.authenticated = !!keycloak.authenticated; // the !! removes undefined
if (this.authenticated && keycloak.token && keycloak.idTokenParsed && keycloak.refreshToken){ if (
this.authenticated &&
keycloak.token &&
keycloak.idTokenParsed &&
keycloak.refreshToken
) {
this.user.username = keycloak.idTokenParsed.given_name; this.user.username = keycloak.idTokenParsed.given_name;
this.user.token = keycloak.token; this.user.token = keycloak.token;
this.user.refreshToken = keycloak.refreshToken; this.user.refreshToken = keycloak.refreshToken;
} }
}, },
async login(){ async login() {
try { try {
const keycloak = await keycloakService.callLogin(); const keycloak = await keycloakService.callLogin();
if (keycloak) if (keycloak) await this.initOauth(keycloak);
await this.initOauth(keycloak);
} catch (error) { } catch (error) {
console.log(error) console.log(error);
} }
}, },
async signup() { async signup() {
try { try {
const keycloak = await keycloakService.callSignup(); const keycloak = await keycloakService.callSignup();
if (keycloak) if (keycloak) await this.initOauth(keycloak);
await this.initOauth(keycloak);
} catch (error) { } catch (error) {
console.log(error) console.log(error);
} }
}, },
// Logout user // Logout user
async logout() { async logout() {
try { try {
await keycloakService.CallLogout(import.meta.env.VITE_APP_URL + "/test"); await keycloakService.CallLogout(
import.meta.env.VITE_APP_URL + "/test"
);
await this.clearUserData(); await this.clearUserData();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -58,23 +65,23 @@ export const useAuthStore = defineStore("storeAuth", {
async refreshUserToken() { async refreshUserToken() {
try { try {
const keycloak = await keycloakService.CallTokenRefresh(); const keycloak = await keycloakService.CallTokenRefresh();
if (keycloak) if (keycloak) await this.initOauth(keycloak, false);
await this.initOauth(keycloak, false);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
}, },
test() {
this.testv = !this.testv;
},
// Clear user's store data // Clear user's store data
clearUserData() { clearUserData() {
this.authenticated = false; this.authenticated = false;
this.user = { this.user = {
token: "", token: "",
refreshToken: "", refreshToken: "",
username: "", username: "",
}; };
} },
} },
}); });
type AuthStore = ReturnType<typeof useAuthStore>;
export { useAuthStore, type AuthStore };

View File

@ -1,15 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
}
</style>

View File

@ -18,9 +18,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Header from '../components/Header.vue'; import Header from '../components/HeaderComponent.vue';
import Agenda from "../components/Agenda.vue" import Agenda from "../components/Agenda.vue"
import ProjectComp from '../components/Project-comp.vue'; import ProjectComp from '../components/ProjectComponent.vue';
import { ref } from "vue"; import { ref } from "vue";

View File

@ -1,16 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { errorList } from "@/services/popupDisplayer.ts";
import {errorList} from "@/services/popupDisplayer.ts";
import ErrorModal from "@/components/errorModal.vue"; import ErrorModal from "@/components/errorModal.vue";
</script> </script>
<template> <template>
<div class="error-wrapper"> <div class="error-wrapper">
<error-modal v-for="elm in errorList" :data=elm></error-modal> <error-modal
</div> v-for="elm in errorList"
:key="elm.id"
:error-message="elm.message"
:error-color="elm.color"
/>
</div>
</template> </template>
<style scoped> <style scoped>
.error-wrapper{ .error-wrapper{
position: absolute; position: absolute;
left: 70%; left: 70%;
@ -19,4 +24,4 @@ import ErrorModal from "@/components/errorModal.vue";
width: 30%; width: 30%;
} }
</style> </style>

View File

@ -1,75 +0,0 @@
<script setup lang="ts">
import {store} from "../main.ts";
import {callApi} from "@/services/api.ts";
import ErrorModal from "@/components/errorModal.vue";
import {errorList} from "@/services/popupDisplayer.ts";
//import TempModal from "@/components/temp-modal.vue";
import ErrorWrapper from "@/App.vue";
function addResToTable(id: any){
return (req: any) => {
console.log(req)
}
}
</script>
<template>
<h1>Test page</h1>
<table class="test" style="width:100%">
<tbody>
<tr>
<td>Is Currently Authenticated ? </td>
<td>{{store.authenticated}}</td>
<td><button @click="store.login">Login</button></td>
<td><button @click="store.logout">Logout</button></td>
<td><button @click="store.signup">Signup</button></td>
</tr>
<tr>
<td>current token</td>
<td>{{store.user.token}}</td>
<td><button @click="store.refreshUserToken">Refresh</button></td>
</tr>
<tr>
<td>Current refresh token</td>
<td>{{store.user.refreshToken}}</td>
</tr>
<tr>
<td>Entrepreneur API call</td>
<td><button @click="callApi('random')">call</button></td>
<td>res</td>
<td></td>
</tr>
<tr>
<td>Admin API call</td>
<td><button @click="callApi('random2')">call</button></td>
<td>res</td>
<td></td>
</tr>
<tr>
<td>Unauth API call</td>
<td><button @click="callApi('random3')">call</button></td>
<td>res</td>
<td id="3"></td>
</tr>
</tbody>
</table>
<temp-modal></temp-modal>
</template>
<style scoped>
table {
width: 100px;
table-layout: fixed
}
tr {
width: 100%;
height: 100%;
}
td {
border: solid 1px black;
width: 20%;
height: 100%;
overflow: hidden;
}
</style>