Fixed auth, NAV, projecttypes,numberranges,tenant,textemplates

This commit is contained in:
2025-09-07 19:26:46 +02:00
parent 34c5764472
commit 949b094490
7 changed files with 129 additions and 125 deletions

View File

@@ -289,19 +289,14 @@ const links = computed(() => {
icon: "i-heroicons-cog-8-tooth", icon: "i-heroicons-cog-8-tooth",
children: [ children: [
{ {
label: "Abrechnung",
to: "https://billing.stripe.com/p/login/cN29Eb32Vdx0gOk288",
icon: "i-heroicons-document-currency-euro",
target: "_blank"
},{
label: "Nummernkreise", label: "Nummernkreise",
to: "/settings/numberRanges", to: "/settings/numberRanges",
icon: "i-heroicons-clipboard-document-list" icon: "i-heroicons-clipboard-document-list"
},{ },/*{
label: "Rollen", label: "Rollen",
to: "/roles", to: "/roles",
icon: "i-heroicons-key" icon: "i-heroicons-key"
},{ },*/{
label: "E-Mail Konten", label: "E-Mail Konten",
to: "/settings/emailAccounts", to: "/settings/emailAccounts",
icon: "i-heroicons-envelope", icon: "i-heroicons-envelope",

View File

@@ -21,8 +21,6 @@ defineShortcuts({
}) })
const openTab = ref(0) const openTab = ref(0)
const dataStore = useDataStore()
const supabase = useSupabaseClient()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const toast = useToast() const toast = useToast()
@@ -53,9 +51,9 @@ const setKeys = () => {
const setupPage = async() => { const setupPage = async() => {
if(mode.value === "show" ){ if(mode.value === "show" ){
itemInfo.value = await useSupabaseSelectSingle("projecttypes",route.params.id,"*") itemInfo.value = await useEntities("projecttypes").selectSingle(route.params.id,"*")
} else if (mode.value === "edit") { } else if (mode.value === "edit") {
itemInfo.value = await useSupabaseSelectSingle("projecttypes",route.params.id,"*") itemInfo.value = await useEntities("projecttypes").selectSingle(route.params.id,"*")
} }
if(mode.value === "create") { if(mode.value === "create") {
@@ -74,7 +72,7 @@ setupPage()
const addPhase = () => { const addPhase = () => {
itemInfo.value.initialPhases.push({label: '', icon: ''}), itemInfo.value.initialPhases.push({label: '', icon: ''}),
setKeys setKeys
} }
</script> </script>
@@ -99,13 +97,13 @@ const addPhase = () => {
<template #right> <template #right>
<UButton <UButton
v-if="mode === 'edit'" v-if="mode === 'edit'"
@click="dataStore.updateItem('projecttypes',itemInfo,oldItemInfo)" @click="useEntities('projecttypes').update(itemInfo.id, itemInfo)"
> >
Speichern Speichern
</UButton> </UButton>
<UButton <UButton
v-else-if="mode === 'create'" v-else-if="mode === 'create'"
@click="dataStore.createNewItem('projecttypes', itemInfo)" @click="useEntities('projecttypes').create( itemInfo)"
> >
Erstellen Erstellen
</UButton> </UButton>
@@ -158,7 +156,7 @@ const addPhase = () => {
variant="outline" variant="outline"
class="mb-5" class="mb-5"
v-if="mode === 'edit'" v-if="mode === 'edit'"
description="Achtung Änderungen an diesem Projekttypen betreffen nur Projekte die damit neu erstellt werden. Bestehende Projekte bleiben unverändert." description="Achtung Änderungen an diesem Projekttypen betreffen nur Projekte die damit neu erstellt werden. Bestehende Projekte bleiben unverändert."
/> />
<UFormGroup <UFormGroup
@@ -242,9 +240,9 @@ const addPhase = () => {
selectedKeyForQuickAction = phase.key" selectedKeyForQuickAction = phase.key"
>+ Schnellaktion</UButton> >+ Schnellaktion</UButton>
<UButton <UButton
@click="phase.quickactions = phase.quickactions.filter(i => i.label !== button.label)" @click="phase.quickactions = phase.quickactions.filter(i => i.label !== button.label)"
v-for="button in phase.quickactions" v-for="button in phase.quickactions"
class="ml-1" class="ml-1"
> >
{{ button.label }} {{ button.label }}
</UButton> </UButton>

View File

@@ -17,14 +17,14 @@ defineShortcuts({
} }
}, },
'arrowdown': () => { 'arrowdown': () => {
if(selectedItem.value < filteredRows.value.length - 1) { if (selectedItem.value < filteredRows.value.length - 1) {
selectedItem.value += 1 selectedItem.value += 1
} else { } else {
selectedItem.value = 0 selectedItem.value = 0
} }
}, },
'arrowup': () => { 'arrowup': () => {
if(selectedItem.value === 0) { if (selectedItem.value === 0) {
selectedItem.value = filteredRows.value.length - 1 selectedItem.value = filteredRows.value.length - 1
} else { } else {
selectedItem.value -= 1 selectedItem.value -= 1
@@ -34,14 +34,14 @@ defineShortcuts({
const router = useRouter() const router = useRouter()
const tempStore = useTempStore()
const items = ref([]) const items = ref([])
const selectedItem = ref(0) const selectedItem = ref(0)
const setup = async () => { const setup = async () => {
items.value = await useSupabaseSelect("projecttypes","*") items.value = await useEntities("projecttypes").select()
} }
setup() setup()
@@ -56,7 +56,7 @@ const templateColumns = [
const selectedColumns = ref(templateColumns) const selectedColumns = ref(templateColumns)
const columns = computed(() => templateColumns.filter((column) => selectedColumns.value.includes(column))) const columns = computed(() => templateColumns.filter((column) => selectedColumns.value.includes(column)))
const searchString = ref("") const searchString = ref(tempStore.searchStrings["projecttypes"] || '')
const filteredRows = computed(() => { const filteredRows = computed(() => {
return useListFilter(searchString.value, items.value) return useListFilter(searchString.value, items.value)
@@ -75,9 +75,10 @@ const filteredRows = computed(() => {
placeholder="Suche..." placeholder="Suche..."
class="hidden lg:block" class="hidden lg:block"
@keydown.esc="$event.target.blur()" @keydown.esc="$event.target.blur()"
@change="tempStore.modifySearchString('projecttypes',searchString)"
> >
<template #trailing> <template #trailing>
<UKbd value="/" /> <UKbd value="/"/>
</template> </template>
</UInput> </UInput>
@@ -94,8 +95,8 @@ const filteredRows = computed(() => {
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Projekttypen anzuzeigen' }" :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Projekttypen anzuzeigen' }"
> >
<template #name-data="{row}"> <template #name-data="{row}">
<span class="text-primary-500 font-bold" v-if="row === filteredRows[selectedItem]">{{row.name}}</span> <span class="text-primary-500 font-bold" v-if="row === filteredRows[selectedItem]">{{ row.name }}</span>
<span v-else>{{row.name}}</span> <span v-else>{{ row.name }}</span>
</template> </template>
</UTable> </UTable>

View File

@@ -1,11 +1,5 @@
<script setup> <script setup>
const auth = useAuthStore()
const supabase = useSupabaseClient()
const dataStore = useDataStore()
const profileStore = useProfileStore()
const resources = { const resources = {
customers: { customers: {
@@ -43,16 +37,19 @@ const resources = {
} }
} }
const numberRanges = ref(profileStore.ownTenant.numberRanges) const numberRanges = ref(auth.activeTenantData.numberRanges)
const updateNumberRanges = async (range) => { const updateNumberRanges = async (range) => {
const {data,error} = await supabase const res = await useNuxtApp().$api(`/api/tenant/numberrange/${range}`,{
.from("tenants") method: "PUT",
.update({numberRanges: numberRanges.value}) body: {
.eq('id',profileStore.currentTenant) numberRange: numberRanges.value[range]
}
})
console.log(res)
await profileStore.fetchOwnTenant()
} }
@@ -60,7 +57,7 @@ const updateNumberRanges = async (range) => {
<template> <template>
<UDashboardNavbar <UDashboardNavbar
title="Nummernkreise bearbeiten" title="Nummernkreise bearbeiten"
> >
</UDashboardNavbar> </UDashboardNavbar>
@@ -74,7 +71,7 @@ const updateNumberRanges = async (range) => {
</UDashboardToolbar> </UDashboardToolbar>
<table <table
class="m-3" class="m-3"
> >
<tr class="text-left"> <tr class="text-left">
<th>Typ</th> <th>Typ</th>
@@ -83,19 +80,19 @@ const updateNumberRanges = async (range) => {
<th>Suffix</th> <th>Suffix</th>
</tr> </tr>
<tr <tr
v-for="key in Object.keys(resources)" v-for="key in Object.keys(resources)"
> >
<td>{{resources[key].label}}</td> <td>{{resources[key].label}}</td>
<td> <td>
<UInput <UInput
v-model="numberRanges[key].prefix" v-model="numberRanges[key].prefix"
@change="updateNumberRanges" @change="updateNumberRanges(key)"
/> />
</td> </td>
<td> <td>
<UInput <UInput
v-model="numberRanges[key].nextNumber" v-model="numberRanges[key].nextNumber"
@change="updateNumberRanges" @change="updateNumberRanges(key)"
type="number" type="number"
step="1" step="1"
/> />
@@ -103,7 +100,7 @@ const updateNumberRanges = async (range) => {
<td> <td>
<UInput <UInput
v-model="numberRanges[key].suffix" v-model="numberRanges[key].suffix"
@change="updateNumberRanges" @change="updateNumberRanges(key)"
/> />
</td> </td>
</tr> </tr>
@@ -112,4 +109,4 @@ const updateNumberRanges = async (range) => {
<style scoped> <style scoped>
</style> </style>

View File

@@ -1,8 +1,6 @@
<script setup> <script setup>
const dataStore = useDataStore() const auth = useAuthStore()
const profileStore = useProfileStore()
const supabase = useSupabaseClient()
const itemInfo = ref({ const itemInfo = ref({
features: {}, features: {},
@@ -11,20 +9,21 @@ const itemInfo = ref({
}) })
const setupPage = async () => { const setupPage = async () => {
itemInfo.value = (await supabase.from("tenants").select().eq("id",profileStore.currentTenant).single()).data itemInfo.value = auth.activeTenantData
console.log(itemInfo.value) console.log(itemInfo.value)
} }
const features = ref(profileStore.ownTenant.features) const features = ref(auth.activeTenantData.features)
const businessInfo = ref(profileStore.ownTenant.businessInfo) const businessInfo = ref(auth.activeTenantData.businessInfo)
const updateTenant = async (newData) => { const updateTenant = async (newData) => {
const {data,error} = await supabase.from("tenants")
.update(newData)
.eq("id",profileStore.currentTenant)
.select()
if (error) console.log(error) const res = await useNuxtApp().$api(`/api/tenant/other/${auth.activeTenant}`, {
method: "PUT",
body: {
data: newData,
}
})
} }
setupPage() setupPage()
@@ -36,7 +35,7 @@ setupPage()
</UDashboardNavbar> </UDashboardNavbar>
<UTabs <UTabs
class="p-5" class="p-5"
:items="[ :items="[
{ {
label: 'Dokubox' label: 'Dokubox'
},{ },{
@@ -167,4 +166,4 @@ setupPage()
<style scoped> <style scoped>
</style> </style>

View File

@@ -1,41 +1,43 @@
<script setup> <script setup>
const dataStore = useDataStore() const dataStore = useDataStore()
defineShortcuts({ defineShortcuts({
'+': () => { '+': () => {
editTemplateModalOpen.value = true editTemplateModalOpen.value = true
}
})
const editTemplateModalOpen = ref(false)
const itemInfo = ref({})
const texttemplates = ref([])
const setup = async () => {
texttemplates.value = (await useSupabaseSelect("texttemplates")).filter(i => !i.archived)
} }
})
setup() const editTemplateModalOpen = ref(false)
const itemInfo = ref({})
const texttemplates = ref([])
const loading = ref(true)
const expand = ref({ const setup = async () => {
openedRows: [], texttemplates.value = (await useEntities("texttemplates").select()).filter(i => !i.archived)
row: {} loading.value = false
}) }
setup()
const expand = ref({
openedRows: [],
row: {}
})
</script> </script>
<template> <template>
<UDashboardNavbar <UDashboardNavbar
title="Text Vorlagen" title="Text Vorlagen"
> >
<template #right> <template #right>
<UButton <UButton
@click="editTemplateModalOpen = true, itemInfo = {}" @click="editTemplateModalOpen = true, itemInfo = {}"
> >
+ Erstellen + Erstellen
</UButton> </UButton>
</template> </template>
</UDashboardNavbar> </UDashboardNavbar>
<UDashboardPanelContent> <UDashboardPanelContent>
<UCard class="mx-5"> <UCard class="mx-5">
@@ -77,9 +79,11 @@
<UTable <UTable
class="mt-3" class="mt-3"
:rows="texttemplates" :rows="texttemplates"
v-model:expand="expand" :loading-state="{ icon: 'i-heroicons-arrow-path-20-solid', label: 'Loading...' }"
:columns="[{key:'name',label:'Name'},{key:'documentType',label:'Dokumententyp'},{key:'default',label:'Standard'},{key:'pos',label:'Position'}]" :loading="loading"
v-model:expand="expand" :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Textvorlagen anzuzeigen' }"
:columns="[{key:'name',label:'Name'},{key:'documentType',label:'Dokumententyp'},{key:'default',label:'Standard'},{key:'pos',label:'Position'}]"
> >
<template #documentType-data="{row}"> <template #documentType-data="{row}">
{{dataStore.documentTypesForCreation[row.documentType].label}} {{dataStore.documentTypesForCreation[row.documentType].label}}
@@ -121,26 +125,26 @@
</UTable> </UTable>
<!-- <div class="w-3/4 mx-auto mt-5"> <!-- <div class="w-3/4 mx-auto mt-5">
<UCard <UCard
v-for="template in dataStore.texttemplates" v-for="template in dataStore.texttemplates"
class="mb-3" class="mb-3"
> >
<p class="text-2xl">{{dataStore.documentTypesForCreation[template.documentType].label}}</p> <p class="text-2xl">{{dataStore.documentTypesForCreation[template.documentType].label}}</p>
<p class="text-xl">{{template.pos === 'startText' ? 'Einleitung' : 'Ende'}}</p> <p class="text-xl">{{template.pos === 'startText' ? 'Einleitung' : 'Ende'}}</p>
<p class="text-justify">{{template.text}}</p> <p class="text-justify">{{template.text}}</p>
<UButton <UButton
@click="itemInfo = template; @click="itemInfo = template;
editTemplateModalOpen = true" editTemplateModalOpen = true"
icon="i-heroicons-pencil-solid" icon="i-heroicons-pencil-solid"
variant="outline" variant="outline"
/> />
</UCard> </UCard>
</div>--> </div>-->
</UDashboardPanelContent> </UDashboardPanelContent>
<UModal <UModal
v-model="editTemplateModalOpen" v-model="editTemplateModalOpen"
> >
<UCard class="h-full"> <UCard class="h-full">
<template #header> <template #header>
@@ -157,51 +161,51 @@
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="Dokumententyp:" label="Dokumententyp:"
> >
<USelectMenu <USelectMenu
:options="Object.keys(dataStore.documentTypesForCreation).filter(i => i !== 'serialInvoices').map(i => { :options="Object.keys(dataStore.documentTypesForCreation).filter(i => i !== 'serialInvoices').map(i => {
return { return {
label: dataStore.documentTypesForCreation[i].label, label: dataStore.documentTypesForCreation[i].label,
key: i key: i
} }
})" })"
option-attribute="label" option-attribute="label"
value-attribute="key" value-attribute="key"
v-model="itemInfo.documentType" v-model="itemInfo.documentType"
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="Position:" label="Position:"
> >
<USelectMenu <USelectMenu
:options="[{label:'Einleitung',key: 'startText'},{label:'Ende',key: 'endText'}]" :options="[{label:'Einleitung',key: 'startText'},{label:'Ende',key: 'endText'}]"
option-attribute="label" option-attribute="label"
value-attribute="key" value-attribute="key"
v-model="itemInfo.pos" v-model="itemInfo.pos"
/> />
</UFormGroup> </UFormGroup>
<UFormGroup <UFormGroup
label="Text:" label="Text:"
> >
<UTextarea <UTextarea
v-model="itemInfo.text" v-model="itemInfo.text"
/> />
</UFormGroup> </UFormGroup>
</UForm> </UForm>
<!-- TODO: Update und Create -->
<template #footer> <template #footer>
<UButton <UButton
@click="dataStore.createNewItem('texttemplates',itemInfo); @click="dataStore.createNewItem('texttemplates',itemInfo);
editTemplateModalOpen = false" editTemplateModalOpen = false"
v-if="!itemInfo.id" v-if="!itemInfo.id"
>Erstellen</UButton> >Erstellen</UButton>
<UButton <UButton
@click="dataStore.updateItem('texttemplates',itemInfo); @click="dataStore.updateItem('texttemplates',itemInfo);
editTemplateModalOpen = false" editTemplateModalOpen = false"
v-if="itemInfo.id" v-if="itemInfo.id"
>Speichern</UButton> >Speichern</UButton>
</template> </template>
</UCard> </UCard>

View File

@@ -1,4 +1,5 @@
import { defineStore } from "pinia" import { defineStore } from "pinia"
import router from "#app/plugins/router";
export const useAuthStore = defineStore("auth", { export const useAuthStore = defineStore("auth", {
state: () => ({ state: () => ({
@@ -7,6 +8,7 @@ export const useAuthStore = defineStore("auth", {
tenants: [] as { tenant_id: string; role: string; tenants: { id: string; name: string } }[], tenants: [] as { tenant_id: string; role: string; tenants: { id: string; name: string } }[],
permissions: [] as string[], permissions: [] as string[],
activeTenant: null as any, activeTenant: null as any,
activeTenantData: null as any,
loading: true as boolean, loading: true as boolean,
}), }),
@@ -43,18 +45,25 @@ export const useAuthStore = defineStore("auth", {
try { try {
const me = await useNuxtApp().$api("/api/me", { const me = await useNuxtApp().$api("/api/me", {
headers: { Authorization: `Bearer ${jwt}`, headers: { Authorization: `Bearer ${jwt}`,
context: { context: {
jwt jwt
}} }}
}) })
console.log(me) console.log(me)
this.user = me.user this.user = me.user
this.permissions = me.permissions this.permissions = me.permissions
this.tenants = me.tenants this.tenants = me.tenants
this.tenants.sort(function (a, b) {
if (a.id < b.id) return -1
if (a.id > b.id) return 1
})
this.profile = me.profile this.profile = me.profile
if(me.activeTenant) { if(me.activeTenant) {
this.activeTenant = me.activeTenant this.activeTenant = me.activeTenant
this.activeTenantData = me.tenants.find(i => i.id === me.activeTenant)
this.loading = false this.loading = false
} else { } else {
@@ -75,6 +84,7 @@ export const useAuthStore = defineStore("auth", {
}) })
useCookie("token").value = token useCookie("token").value = token
await this.init(token) await this.init(token)
navigateTo("/")
}, },
hasPermission(key: string) { hasPermission(key: string) {