fix : merged the main with the front branch and fixed all possible issues

This commit is contained in:
Mohamed Maoulainine Maoulainine 2025-03-21 01:16:49 +01:00
commit fad52644d2
20 changed files with 1802 additions and 281 deletions

View File

@ -0,0 +1,24 @@
name: CI
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install everything
working-directory: ./front/MyINPulse-front
run: npm i
- name: Run ESLint
working-directory: ./front/MyINPulse-front
run: npx eslint
- name: Run prettier
working-directory: ./front/MyINPulse-front
run: npx prettier src --check
- name: Build frontend
working-directory: ./front/MyINPulse-front
run: npm run build

View File

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

View File

@ -0,0 +1,7 @@
{
"useTabs":false,
"semi":true,
"trailingComma":"es5",
"arrowParens":"always",
"tabWidth":4
}

View File

@ -0,0 +1,29 @@
import eslint from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier";
import eslintPluginVue from "eslint-plugin-vue";
import globals from "globals";
import typescriptEslint from "typescript-eslint";
export default typescriptEslint.config(
{ ignores: ["*.d.ts", "**/coverage", "**/dist"] },
{
extends: [
eslint.configs.recommended,
...typescriptEslint.configs.recommended,
...eslintPluginVue.configs["flat/recommended"],
],
files: ["**/*.{ts,vue}"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: globals.browser,
parserOptions: {
parser: typescriptEslint.parser,
},
},
rules: {
// your rules
},
},
eslintConfigPrettier
);

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

View File

@ -15,6 +15,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineProps } from "vue"; import { defineProps } from "vue";
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'

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,22 +1,25 @@
<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%;
//background-color: blue; //background-color: blue;
height: 100%; height: 100%;
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>

View File

@ -0,0 +1,79 @@
<script lang="ts" setup>
import { store } from "../main.ts";
import { callApi } from "@/services/api.ts";
</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>
</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>