Remodel of Profile System

Added isCompany to Customers
changes in workingtimes.vue
This commit is contained in:
2024-03-17 11:01:19 +01:00
parent 874ff01551
commit aef8cce755
16 changed files with 349 additions and 168 deletions

View File

@@ -0,0 +1,29 @@
<script setup>
const dataStore = useDataStore()
const supabase = useSupabaseClient()
//const tenants = ref(dataStore.getOwnProfile ? dataStore.getOwnProfile.tenants : [])
//const tenant = ref(dataStore.currentTenant)
const selectedProfile = ref(dataStore.activeProfile.id)
console.log(dataStore.ownProfiles)
</script>
<template>
<USelectMenu
:options="dataStore.ownProfiles"
value-attribute="id"
class="w-40"
@change="dataStore.changeProfile(selectedProfile)"
v-model="selectedProfile"
>
<UButton color="gray" variant="ghost" :class="[open && 'bg-gray-50 dark:bg-gray-800']" class="w-full">
<UAvatar :alt="dataStore.tenants.find(i => dataStore.getProfileById(selectedProfile).tenant === i.id).name" size="md" />
<span class="truncate text-gray-900 dark:text-white font-semibold">{{dataStore.tenants.find(i => dataStore.getProfileById(selectedProfile).tenant === i.id).name}}</span>
</UButton>
<template #option="{option}">
{{dataStore.tenants.find(i => i.id === option.tenant).name}}
</template>
</USelectMenu>
</template>

View File

@@ -1,25 +0,0 @@
<script setup>
const dataStore = useDataStore()
const tenants = ref(dataStore.getOwnProfile ? dataStore.getOwnProfile.tenants : [])
const tenant = ref(dataStore.currentTenant)
</script>
<template>
<USelectMenu
:options="tenants"
value-attribute="id"
option-attribute="name"
class="w-40"
@change="dataStore.changeTenant"
v-model="dataStore.currentTenant"
>
<UButton color="gray" variant="ghost" :class="[open && 'bg-gray-50 dark:bg-gray-800']" class="w-full">
<UAvatar :alt="tenants.find(i => i.id === dataStore.currentTenant).name" size="md" />
<span class="truncate text-gray-900 dark:text-white font-semibold">{{ tenants.find(i => i.id === dataStore.currentTenant).name }}</span>
</UButton>
</USelectMenu>
</template>

View File

@@ -59,9 +59,9 @@ const items = computed(() => [
<template>
<UDropdown mode="hover" :items="items" :ui="{ width: 'w-full', item: { disabled: 'cursor-text select-text' } }" :popper="{ strategy: 'absolute', placement: 'top' }" class="w-full">
<template #default="{ open }">
<UButton color="gray" variant="ghost" class="w-full" :label="dataStore.getProfileById(user.id).fullName" :class="[open && 'bg-gray-50 dark:bg-gray-800']">
<UButton color="gray" variant="ghost" class="w-full" :label="dataStore.activeProfile.fullName" :class="[open && 'bg-gray-50 dark:bg-gray-800']">
<template #leading>
<UAvatar :alt="dataStore.getProfileById(user.id) ? dataStore.getProfileById(user.id).fullName : ''" size="xs" />
<UAvatar :alt="dataStore.activeProfile ? dataStore.activeProfile.fullName : ''" size="xs" />
</template>
<template #trailing>
@@ -76,7 +76,7 @@ const items = computed(() => [
Angemeldet als
</p>
<p class="truncate font-medium text-gray-900 dark:text-white">
{{dataStore.getProfileById(user.id).email}}
{{dataStore.activeProfile.email}}
</p>
</div>
</template>

View File

@@ -0,0 +1,31 @@
export const useSearch = (searchString,items) => {
const dataStore = useDataStore()
if(!searchString) {
return items
}
items = items.map(item => {
return {
...item,
customer: dataStore.getCustomerById(item.customer)
}
})
console.log(items)
return items.filter(i => JSON.stringify(i).includes(searchString))
/*return items.filter(item => {
return Object.values(item).some((value) => {
return String(value).toLowerCase().includes(searchString.toLowerCase())
})
})*/
}

View File

@@ -1,6 +1,6 @@
<script setup>
import TenantDropdown from "~/components/TenantDropdown.vue";
import TenantDropdown from "~/components/ProfileDropdown.vue";
const dataStore = useDataStore()
const colorMode = useColorMode()
@@ -435,7 +435,7 @@ const footerLinks = [/*{
<UDashboardPanel :width="250" :resizable="{ min: 200, max: 300 }" collapsible>
<UDashboardNavbar class="!border-transparent" :ui="{ left: 'flex-1' }">
<template #left>
<TenantDropdown class="w-full" />
<ProfileDropdown class="w-full" />
</template>
</UDashboardNavbar>

View File

@@ -9,6 +9,19 @@ const itemInfo = ref({
resources: []
})
const mapResources = () => {
itemInfo.value.resources.map(resource => {
return {
id: resource.id,
type: resource.type
}
})
}
const setupPage = () => {
if(route.query.start) itemInfo.value.start = route.query.start.replace(" ", "+")
@@ -47,17 +60,18 @@ setupPage()
>
<USelectMenu
v-model="itemInfo.resources"
:options="dataStore.getResources"
:options="dataStore.getResourcesList"
option-attribute="title"
value-attribute="id"
multiple
@change=""
onChange="mapResources"
>
<template #label>
<span v-if="itemInfo.resources.length == 0">Keine Ressourcen ausgewählt</span>
<span v-else >{{ itemInfo.resources.length }} ausgewählt</span>
</template>
</USelectMenu>
{{dataStore.getResourcesList}}
</UFormGroup>
<UFormGroup
label="Titel:"

View File

@@ -59,6 +59,8 @@
<script setup>
import {useSearch} from "~/composables/useSearch.js";
definePageMeta({
middleware: "auth"
})
@@ -124,7 +126,7 @@ const columns = computed(() => templateColumns.filter((column) => selectedColumn
const searchString = ref('')
const filteredRows = computed(() => {
/*const filteredRows = computed(() => {
if(!searchString.value) {
return dataStore.contacts
}
@@ -134,7 +136,12 @@ const filteredRows = computed(() => {
return String(value).toLowerCase().includes(searchString.value.toLowerCase())
})
})
})*/
const filteredRows = computed(() => {
return useSearch(searchString.value, dataStore.contacts)
})
</script>
<style scoped>

View File

@@ -54,7 +54,7 @@ const tabItems = computed(() => {
},
{
label: "Vorschau",
disabled: !itemInfo.value.customer && !itemInfo.value.contact
disabled: !itemInfo.value.customer
}
]
})
@@ -259,7 +259,10 @@ const getDocumentData = () => {
//Compile Start & EndText
const templateStartText = Handlebars.compile(itemInfo.value.startText);
const templateEndText = Handlebars.compile(itemInfo.value.endText);
console.log(templateStartText({vorname: contactData.firstName, nachname: contactData.lastName}))
console.log(templateStartText({
vorname: contactData ? contactData.firstName : "",
nachname: contactData ? contactData.lastName : ""
}))
console.log(templateEndText({zahlungsziel_in_tagen: 14}))
@@ -289,7 +292,10 @@ const getDocumentData = () => {
title: itemInfo.value.title,
description: itemInfo.value.description,
endText: templateEndText({zahlungsziel_in_tagen: itemInfo.value.paymentDays}),
startText: templateStartText({vorname: contactData.firstName, nachname: contactData.lastName}),
startText: templateStartText({
vorname: contactData ? contactData.firstName : "",
nachname: contactData ? contactData.lastName : ""
}),
rows: rows,
total: documentTotal.value
}
@@ -504,9 +510,11 @@ setupPage()
class="flex-auto"
>
<UButton
:color="itemInfo.contact ? 'primary' : 'rose'"
color="none"
variant="outline"
class="flex-1 justify-between">
class="flex-1 justify-between"
:disabled="!itemInfo.customer"
>
{{dataStore.getContactById(itemInfo.contact) ? dataStore.getContactById(itemInfo.contact).fullName : "Kein Kontakt ausgewählt"}}
<UIcon name="i-heroicons-chevron-right-20-solid" class="w-5 h-5 transition-transform text-gray-400 dark:text-gray-500" :class="['transform rotate-90']" />

View File

@@ -20,7 +20,8 @@ const itemInfo = ref({
infoData: {
country: "Deutschland"
},
active: true
active: true,
isCompany: true
})
//Functions
@@ -225,6 +226,13 @@ setupPage()
/>
</UFormGroup>
</UTooltip>
<UFormGroup
label="Firmenkunde:"
>
<UCheckbox
v-model="itemInfo.isCompany"
/>
</UFormGroup>
<UFormGroup
label="Notizen:"
>

View File

@@ -2,7 +2,7 @@
<UDashboardNavbar title="Kunden" :badge="filteredRows.length">
<template #right>
<UInput
ref="searchinput"
id="searchinput"
v-model="searchString"
icon="i-heroicons-funnel"
autocomplete="off"
@@ -45,6 +45,10 @@
@select="(i) => router.push(`/customers/show/${i.id}`) "
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Kunden anzuzeigen' }"
>
<template #isCompany-data="{row}">
<span v-if="row.isCompany">Firmenkunden</span>
<span v-else>Privatkunde</span>
</template>
<template #active-data="{row}">
<span v-if="row.active" class="text-primary-500">Aktiv</span>
<span v-else class="text-rose-500">Gesperrt</span>
@@ -85,6 +89,11 @@ const templateColumns = [
label: "Name",
sortable: true
},
{
key: "isCompany",
label: "Typ",
sortable: true
},
{
key: "notes",
label: "Notizen",

View File

@@ -81,8 +81,12 @@ setupPage()
<div
v-if="item.label === 'Informationen'"
>
<div class="truncate">
<p v-if="currentItem.sellingPrice">Verkaufspreis: {{String(Number(currentItem.sellingPrice).toFixed(2)).replace(".",",")}} </p>
<p>Beschreibung:</p>
<pre>{{currentItem.description}}</pre>
</div>
<span v-if="currentItem.sellingPrice">Verkaufspreis: {{String(Number(currentItem.sellingPrice).toFixed(2)).replace(".",",")}} <br></span>
</div>
<div

View File

@@ -2,7 +2,7 @@
<UDashboardNavbar title="Lieferanten" :badge="filteredRows.length">
<template #right>
<UInput
ref="searchinput"
id="searchinput"
v-model="searchString"
icon="i-heroicons-funnel"
autocomplete="off"

View File

@@ -445,10 +445,10 @@ const setState = async (newState) => {
</template>
<template #start-data="{row}">
{{dayjs(row.start, "HH:mm:ssZ").format("HH:mm")}} Uhr
{{dayjs(row.start, "HH:mm:ss").format("HH:mm")}} Uhr
</template>
<template #end-data="{row}">
{{dayjs(row.end, "HH:mm:ssZ").format("HH:mm")}} Uhr
{{dayjs(row.end, "HH:mm:ss").format("HH:mm")}} Uhr
</template>
<template #duration-data="{row}">
{{getDuration(row).composed}}

View File

@@ -143,6 +143,9 @@ export const useDataStore = defineStore('data', () => {
const profiles = ref([])
const ownProfiles = ref([])
const activeProfile = ref([])
const tenants = ref([])
const currentTenant = ref(null)
const events = ref([])
const customers = ref([])
@@ -180,6 +183,7 @@ export const useDataStore = defineStore('data', () => {
const texttemplates =ref([])
const services =ref([])
const serviceCategories =ref([])
const resources =ref([])
const rights = ref({
@@ -241,26 +245,54 @@ export const useDataStore = defineStore('data', () => {
])
async function initializeData (userId) {
let profile = (await supabase.from("profiles").select().eq("user",userId).single()).data
currentTenant.value = profile.tenant
let profileconnections = (await supabase.from("profileconnections").select()).data
let profiles = (await supabase.from("profiles").select()).data
let profileId = profileconnections.find(i => i.active).profile_id
activeProfile.value = profiles.find(i => i.id === profileId)
currentTenant.value = activeProfile.value.tenant
await fetchData()
}
async function changeTenant() {
async function changeProfile(newActiveProfileId) {
loaded.value = false
await clearStore()
await fetchData()
router.push("/")
loaded.value = true
let profileconnections = (await supabase.from("profileconnections").select()).data
let oldActiveProfileId = profileconnections.find(i => i.active).profile_id
const {error} = await supabase.from("profileconnections").update({active: true}).eq("profile_id", newActiveProfileId)
if(error) {
console.log(error)
} else {
const {error} = await supabase.from("profileconnections").update({active: false}).eq("profile_id", oldActiveProfileId)
if(error) {
} else {
reloadNuxtApp({
path:"/",
ttl: 10000
})
}
/*await clearStore()
await fetchData()
router.push("/")
loaded.value = true*/
}
}
async function fetchData () {
await fetchOwnProfiles()
await fetchProfiles()
await fetchDocuments()
await fetchTenants()
await fetchOwnTenant()
await fetchEvents()
await fetchTasks()
@@ -297,6 +329,7 @@ export const useDataStore = defineStore('data', () => {
await fetchTextTemplates()
await fetchServices()
await fetchServiceCategories()
await fetchResources()
loaded.value = true
}
@@ -305,6 +338,8 @@ export const useDataStore = defineStore('data', () => {
loaded.value = false
ownTenant.value = {}
profiles.value = []
ownProfiles.value = []
tenants.value = []
events.value= []
customers.value= []
tasks.value= []
@@ -341,6 +376,7 @@ export const useDataStore = defineStore('data', () => {
texttemplates.value = []
services.value = []
serviceCategories.value = []
resources.value = []
}
function hasRight (right) {
@@ -395,7 +431,7 @@ export const useDataStore = defineStore('data', () => {
if(dataTypes[dataType].numberRangeHolder) {
const numberRange = useNumberRange(dataType)
if(!dataTypes[dataType].numberRangeHolder) {
if(!data[dataTypes[dataType].numberRangeHolder]) {
data[dataTypes[dataType].numberRangeHolder] = await numberRange.useNextNumber()
}
@@ -517,12 +553,25 @@ export const useDataStore = defineStore('data', () => {
}
async function fetchOwnTenant () {
ownTenant.value = (await supabase.from("tenants").select().eq('id', currentTenant.value)).data[0]
ownTenant.value = (await supabase.from("tenants").select().eq('id', currentTenant.value).single()).data
}
async function fetchProfiles () {
profiles.value = (await supabase.from("profiles").select('* , tenants (id, name)').eq("tenant", currentTenant.value).order("fullName")).data
profiles.value = (await supabase.from("profiles").select().eq("tenant",currentTenant.value).order("fullName")).data
}
async function fetchOwnProfiles () {
let profiles = (await supabase.from("profiles").select().order("fullName")).data
let conns = (await supabase.from("profileconnections").select()).data.map(i => i.profile_id)
console.log(conns)
console.log(profiles.filter(i => conns.includes(i.id)))
ownProfiles.value = profiles.filter(i => conns.includes(i.id))
}
async function fetchTenants () {
tenants.value = (await supabase.from("tenants").select()).data
}
async function fetchBankAccounts () {
bankAccounts.value = (await supabase.from("bankaccounts").select().eq('tenant', currentTenant.value)).data
}
@@ -636,6 +685,10 @@ export const useDataStore = defineStore('data', () => {
serviceCategories.value = (await supabase.from("serviceCategories").select().eq('tenant', currentTenant.value)).data
}
async function fetchResources() {
resources.value = (await supabase.from("resources").select().eq('tenant', currentTenant.value)).data
}
async function fetchDocuments () {
let tempDocuments = (await supabase.from("documents").select().eq('tenant', currentTenant.value)).data
@@ -844,6 +897,32 @@ export const useDataStore = defineStore('data', () => {
]
})
const getResourcesList = computed(() => {
return [
...profiles.value.filter(i => i.tenant === currentTenant.value).map(profile => {
return {
type: 'Mitarbeiter',
title: profile.fullName,
id: profile.id
}
}),
...vehicles.value.map(vehicle => {
return {
type: 'Fahrzeug',
title: vehicle.licensePlate,
id: vehicle.id
}
}),
...inventoryitems.value.filter(i=> i.usePlanning).map(item => {
return {
type: 'Inventar',
title: item.name,
id: item.id
}
})
]
})
const getEvents = computed(() => {
return [
...events.value.map(event => {
@@ -880,6 +959,7 @@ export const useDataStore = defineStore('data', () => {
const getEventsByResource = computed(() => {
let tempEvents = []
events.value.forEach(event => {
console.log(event)
event.resources.forEach(resource => {
let eventColor = ownTenant.value.calendarConfig.eventTypes.find(type => type.label === event.type).color
@@ -894,8 +974,8 @@ export const useDataStore = defineStore('data', () => {
tempEvents.push({
...event,
resourceId: resource.type !== 'Mitarbeiter' ? `${resource.type[0]}-${resource.id}`: resource.id,
resourceType: resource.type,
resourceId: /*resource.type !== 'Mitarbeiter' ? `${resource.type[0]}-${resource.id}`:*/ resource.id,
resourceType: "Mitarbeiter",
title: title,
borderColor: eventColor,
textColor: eventColor,
@@ -1049,12 +1129,15 @@ export const useDataStore = defineStore('data', () => {
loaded,
ownTenant,
initializeData,
changeTenant,
changeProfile,
uploadFiles,
hasRight,
//Data
profiles,
ownProfiles,
activeProfile,
tenants,
events,
customers,
tasks,
@@ -1100,6 +1183,7 @@ export const useDataStore = defineStore('data', () => {
clearStore,
fetchOwnTenant,
fetchProfiles,
fetchOwnProfiles,
fetchBankAccounts,
fetchBankStatements,
fetchEvents,
@@ -1161,6 +1245,7 @@ export const useDataStore = defineStore('data', () => {
getDocumentTags,
getMeasures,
getResources,
getResourcesList,
getEvents,
getEventsByResource,
getCostCentresComposed,