Rework to use marbas and authentik instead of poketbase #1

Merged
Sirttas merged 18 commits from rework-acquisition into main 2024-05-17 23:00:52 +02:00
10 changed files with 105 additions and 13 deletions
Showing only changes of commit 6d67e92749 - Show all commits

View File

@@ -1,14 +1,19 @@
<script setup lang="ts">
import { useAuthStore } from '@/auth';
import { RouterView } from 'vue-router';
import { computed } from 'vue';
import { RouterView, useRoute } from 'vue-router';
import { Sidebar } from './sidebar';
const route = useRoute();
const authStore = useAuthStore();
const hideSidebar = computed(() => {
return !authStore.isLoggedIn || route.name === 'callback' || route.name === 'about';
});
</script>
<template>
<template v-if="!authStore.isLoggedIn">
<template v-if="hideSidebar">
<RouterView />
</template>
<template v-else>

View File

@@ -18,6 +18,7 @@ export const useAuthStore = defineStore('auth', () => {
const isLoggedIn = computed(() => !!user.value);
const accessToken = computed(() => user.value?.access_token);
const username = computed(() => user.value?.profile.name ?? "");
const userId = computed(() => user.value?.profile.sub ?? "");
const redirect = async () => {
await userManager.signinRedirect();
@@ -42,5 +43,5 @@ export const useAuthStore = defineStore('auth', () => {
}
userManager.events.addUserLoaded(setUser);
userManager.getUser().then(setUser);
return { redirect, login, logout, isLoggedIn, accessToken, username };
return { redirect, login, logout, isLoggedIn, accessToken, username, userId };
});

View File

@@ -0,0 +1,46 @@
<script setup lang="ts">
import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/24/outline';
import { vOnClickOutside } from '@vueuse/components';
import { useEventListener } from '@vueuse/core';
import { ref } from 'vue';
const isOpen = ref(false);
useEventListener('keyup', e => {
if (e.key === 'Escape') {
isOpen.value = false;
}
});
</script>
<template>
<div class="dropdown" :class="{'dropdown-open': isOpen, 'dropdown-close': !isOpen}" v-on-click-outside="() => isOpen = false">
<button @click="isOpen = !isOpen">
<slot name="button" />
<ChevronDownIcon v-if="!isOpen" class="chevron" />
<ChevronUpIcon v-else class="chevron" />
</button>
<Transition name="fade">
<div v-if="isOpen" class="relative">
<div class="z-10 divide-y rounded-b-md absolute">
<slot />
</div>
</div>
</Transition>
</div>
</template>
<style scoped lang="postcss">
.chevron {
@apply w-4 h-4 ms-1;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 100ms ease-out;
}
</style>

View File

@@ -1,4 +1,5 @@
export { default as ClipboardButton } from './ClipboardButton.vue';
export { default as Dropdown } from './Dropdown.vue';
export { default as LoadingSpinner } from './LoadingSpinner.vue';
export { default as Modal } from './Modal.vue';
export { default as SliderCheckbox } from './SliderCheckbox.vue';

View File

@@ -36,7 +36,7 @@ defineEmits<Emits>();
const marketTaxStore = useMarketTaxStore();
const threshold = useStorage('market-aquisition-threshold', 10);
const threshold = useStorage('market-acquisition-threshold', 10);
const filter = ref("");
const { sortedArray, headerProps } = useSort<Result>(computed(() => props.items
.filter(r => r.type.name.toLowerCase().includes(filter.value.toLowerCase()))
@@ -107,7 +107,7 @@ const getLineColor = (result: Result) => {
<td class="text-right">{{ formatIsk(r.sell) }}</td>
<td class="text-right">{{ formatIsk(r.price) }}</td>
<td class="text-right">{{ r.count }}</td>
<td class="text-right">{{ percentFormater.format(r.precentProfit) }}</td>
<td class="text-right">{{ percentFormater.format(r.precentProfit) }}</td>
<td class="text-right">{{ formatIsk(r.iskProfit) }}</td>
<td class="text-right">
<button class="btn-icon me-1" @click="$emit('buy', r.type, r.price, r.buy, r.sell)"><PlusIcon /></button>

View File

@@ -1,3 +1,4 @@
import { useAuthStore } from "@/auth";
import { marbasAxiosInstance } from "@/service";
import { defineStore } from "pinia";
import { computed, onMounted, ref } from "vue";
@@ -17,6 +18,7 @@ const endpoint = '/api/acquisitions';
export const useAcquiredItemStore = defineStore('market-acquisition', () => {
const _acquiredItems = ref<AcquiredMarketItem[]>([]);
const authStore = useAuthStore();
const items = computed(() => _acquiredItems.value);
const addAcquiredItem = async (type: number, quantity: number, price: number) => {
@@ -27,7 +29,7 @@ export const useAcquiredItemStore = defineStore('market-acquisition', () => {
price: price,
date: new Date(),
source: 'bo',
user: 0 // TODO: get user id
user: authStore.userId,
})).data];
};
const removeAcquiredItem = async (type: number, quantity: number) => {

View File

@@ -96,7 +96,7 @@ watchEffect(async () => {
<template>
<div @click="() => isOpen = true" v-on-click-outside="() => isOpen = false">
<div class="fake-input">
<img v-if="value?.id" :src="`https://images.evetech.net/types/${value.id}/icon`" />
<img v-if="value?.id" :src="`https://images.evetech.net/types/${value.id}/icon`" alt="" />
<input type="text" v-model="name" @keyup.enter="submit" @keyup.down="moveDown" @keyup.up="moveUp" />
</div>
<div v-if="suggestions.length > 1" class="z-10 absolute w-96">

View File

@@ -11,5 +11,5 @@ export const routes: RouteRecordRaw[] = [
{ path: 'acquisitions', component: () => import('@/pages/market/Acquisitions.vue') },
] },
{ path: '/tools', component: () => import('@/pages/Tools.vue') },
{ path: '/about', component: () => import('@/pages/About.vue') },
{ path: '/about', name: 'about', component: () => import('@/pages/About.vue') },
];

View File

@@ -44,7 +44,13 @@ marbasAxiosInstance.interceptors.response.use(async r => {
return r;
})
marbasAxiosInstance.interceptors.request.use(r => {
const accessToken = useAuthStore().accessToken;
const authStore = useAuthStore();
if (!authStore.isLoggedIn) {
throw new Error("Not logged in");
}
const accessToken = authStore.accessToken;
if (accessToken) {
r.headers.Authorization = `Bearer ${accessToken}`;

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import { useAuthStore } from '@/auth';
import { Dropdown } from '@/components';
import { RouterLink } from 'vue-router';
const links = [
@@ -18,22 +19,52 @@ const logout = async () => {
<template>
<aside class="fixed top-0 left-0 w-64 h-screen transition-transform -translate-x-full sm:translate-x-0">
<div class="h-full px-3 py-4 overflow-y-auto bg-slate-700 flex flex-col">
<div class="mb-2 border-b-2 border-emerald-500">
<Dropdown class="mb-2 user-dropdown">
<template #button>
<span>{{ authStore.username }}</span>
</template>
<ul>
<li>
<RouterLink class="sidebar-button py-0.5 px-2" :to="{name: 'about'}">About EVE Online</RouterLink>
</li>
<li>
<a class="sidebar-button py-0.5 px-2 text-amber-700" @click="logout">Logout</a>
</li>
</ul>
</Dropdown>
</div>
<ul class="space-y-2 font-medium">
<li v-for="link in links" :key="link.name">
<RouterLink :to="link.path" class="flex items-center p-2 rounded-md hover:bg-slate-800">
<RouterLink :to="link.path" class="sidebar-button p-2">
<span>{{ link.name }}</span>
</RouterLink>
</li>
</ul>
<div class="mt-auto">
<button @click="logout">Logout</button>
</div>
</div>
</aside>
</template>
<style scoped lang="postcss">
.sidebar-button {
@apply flex items-center rounded-md hover:bg-slate-800 cursor-pointer;
}
.router-link-active {
@apply bg-emerald-500 hover:bg-emerald-700;
}
.user-dropdown {
@apply w-full;
:deep(>div) {
@apply w-full;
>div {
@apply w-full bg-slate-800;
}
}
:deep(>button) {
@apply bg-slate-700 hover:bg-slate-800 border-none flex items-center w-full;
}
&.dropdown-open:deep(>button) {
@apply bg-slate-800 rounded-b-none;
}
}
</style>