Added Notifications
Added Mentions in HistoryItems
This commit is contained in:
@@ -69,6 +69,10 @@ setup()
|
|||||||
|
|
||||||
const addHistoryItemData = ref({
|
const addHistoryItemData = ref({
|
||||||
text: "",
|
text: "",
|
||||||
|
config: {
|
||||||
|
type: type,
|
||||||
|
id: elementId
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const addHistoryItem = async () => {
|
const addHistoryItem = async () => {
|
||||||
@@ -120,6 +124,29 @@ const addHistoryItem = async () => {
|
|||||||
if(error) {
|
if(error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
} else {
|
} else {
|
||||||
|
if(addHistoryItemData.value.text.includes("@")){
|
||||||
|
let usernames = [...addHistoryItemData.value.text.matchAll(/@(\S*)/gm)]
|
||||||
|
|
||||||
|
const {data:profiles} = await supabase.from("profiles").select("id,username")
|
||||||
|
|
||||||
|
let notifications = usernames.map(i => {
|
||||||
|
let rawUsername = i[1]
|
||||||
|
|
||||||
|
return {
|
||||||
|
tenant: dataStore.currentTenant,
|
||||||
|
profile: profiles.find(x => x.username === rawUsername).id,
|
||||||
|
initiatingProfile: dataStore.activeProfile.id,
|
||||||
|
title: "Sie wurden im Logbuch erwähnt",
|
||||||
|
link: `/${type}s/show/${elementId}`,
|
||||||
|
message: addHistoryItemData.value.text
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(notifications)
|
||||||
|
|
||||||
|
const {error} = await supabase.from("notifications").insert(notifications)
|
||||||
|
}
|
||||||
|
|
||||||
addHistoryItemData.value = {}
|
addHistoryItemData.value = {}
|
||||||
toast.add({title: "Eintrag erfolgreich erstellt"})
|
toast.add({title: "Eintrag erfolgreich erstellt"})
|
||||||
showAddHistoryItemModal.value = false
|
showAddHistoryItemModal.value = false
|
||||||
@@ -188,7 +215,6 @@ const renderText = (text) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ITEM LIST -->
|
<!-- ITEM LIST -->
|
||||||
|
|
||||||
<div style="height: 90%; overflow-y: scroll">
|
<div style="height: 90%; overflow-y: scroll">
|
||||||
<div
|
<div
|
||||||
v-if="items.length > 0"
|
v-if="items.length > 0"
|
||||||
|
|||||||
@@ -1,29 +1,60 @@
|
|||||||
<script setup lang="ts">
|
<script setup>
|
||||||
import { formatTimeAgo } from '@vueuse/core'
|
import {formatTimeAgo} from '@vueuse/core'
|
||||||
import type { Notification } from '~/types'
|
|
||||||
|
const supabase = useSupabaseClient()
|
||||||
|
|
||||||
|
|
||||||
const { isNotificationsSlideoverOpen } = useDashboard()
|
const { isNotificationsSlideoverOpen } = useDashboard()
|
||||||
|
|
||||||
//const { data: notifications } = await useFetch<Notification[]>('/api/notifications')
|
watch(isNotificationsSlideoverOpen, async (newVal,oldVal) => {
|
||||||
|
if(newVal === true) {
|
||||||
|
await setup()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const notifications = ref([])
|
||||||
|
|
||||||
|
const setup = async () => {
|
||||||
|
notifications.value = (await supabase.from("notifications").select()).data
|
||||||
|
}
|
||||||
|
|
||||||
|
setup()
|
||||||
|
|
||||||
|
const setNotificationAsRead = async (notification) => {
|
||||||
|
console.log(notification)
|
||||||
|
|
||||||
|
const {data,error} = await supabase.from("notifications").update({read: true}).eq("id", notification.id)
|
||||||
|
|
||||||
|
console.log(error)
|
||||||
|
|
||||||
|
setup()
|
||||||
|
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UDashboardSlideover v-model="isNotificationsSlideoverOpen" title="Benachrichtigungen">
|
<UDashboardSlideover v-model="isNotificationsSlideoverOpen" title="Benachrichtigungen">
|
||||||
<!-- <NuxtLink v-for="notification in notifications" :key="notification.id" :to="`/inbox?id=${notification.id}`" class="p-3 rounded-md hover:bg-gray-50 dark:hover:bg-gray-800/50 cursor-pointer flex items-center gap-3 relative">
|
<NuxtLink
|
||||||
<UChip color="red" :show="!!notification.unread" inset>
|
v-for="notification in notifications"
|
||||||
<UAvatar v-bind="notification.sender.avatar" :alt="notification.sender.name" size="md" />
|
:key="notification.id"
|
||||||
|
:to="notification.link"
|
||||||
|
class="p-3 rounded-md hover:bg-gray-50 dark:hover:bg-gray-800/50 cursor-pointer flex items-center gap-3 relative"
|
||||||
|
@click="setNotificationAsRead(notification)"
|
||||||
|
>
|
||||||
|
<UChip color="primary" :show="!notification.read" inset>
|
||||||
|
<UAvatar alt="FEDEO" size="md" />
|
||||||
</UChip>
|
</UChip>
|
||||||
|
|
||||||
<div class="text-sm flex-1">
|
<div class="text-sm flex-1">
|
||||||
<p class="flex items-center justify-between">
|
<p class="flex items-center justify-between">
|
||||||
<span class="text-gray-900 dark:text-white font-medium">{{ notification.sender.name }}</span>
|
<span class="text-gray-900 dark:text-white font-medium">{{notification.title}}</span>
|
||||||
|
|
||||||
<time :datetime="notification.date" class="text-gray-500 dark:text-gray-400 text-xs" v-text="formatTimeAgo(new Date(notification.date))" />
|
<time :datetime="notification.date" class="text-gray-500 dark:text-gray-400 text-xs" v-text="formatTimeAgo(new Date(notification.created_at))" />
|
||||||
</p>
|
</p>
|
||||||
<p class="text-gray-500 dark:text-gray-400">
|
<p class="text-gray-500 dark:text-gray-400">
|
||||||
{{ notification.body }}
|
{{ notification.message }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</NuxtLink>-->
|
</NuxtLink>
|
||||||
</UDashboardSlideover>
|
</UDashboardSlideover>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
83
pages/communication/historyItems/index.vue
Normal file
83
pages/communication/historyItems/index.vue
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<script setup>
|
||||||
|
import dayjs from "dayjs"
|
||||||
|
|
||||||
|
const supabase = useSupabaseClient()
|
||||||
|
const dataStore = useDataStore()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
|
||||||
|
const items = ref([])
|
||||||
|
|
||||||
|
const setup = async () => {
|
||||||
|
|
||||||
|
items.value = (await supabase.from("historyitems").select().like('text',`%@${dataStore.activeProfile.username}%`)/*.textSearch("text", `'@${dataStore.activeProfile.username}'`)*/.order("created_at")).data
|
||||||
|
}
|
||||||
|
|
||||||
|
const navigateToHistoryItem = (item) => {
|
||||||
|
/*if(item.customer) {
|
||||||
|
router.push(`/customers/show/${item.customer}`)
|
||||||
|
} else if(item.vendor) {
|
||||||
|
router.push(`/vendors/show/${item.vendor}`)
|
||||||
|
} else if(item.project) {
|
||||||
|
router.push(`/projects/show/${item.project}`)
|
||||||
|
} else if(item.plant) {
|
||||||
|
router.push(`/plants/show/${item.plant}`)
|
||||||
|
} else if(item.incomingInvoice) {
|
||||||
|
router.push(`/incomingInvoices/show/${item.incomingInvoice}`)
|
||||||
|
}/!* else if(item.document) {
|
||||||
|
router.push(`/documents/show/${item.document}`)
|
||||||
|
}*!/ else if(item.contact) {
|
||||||
|
router.push(`/contacts/show/${item.contact}`)
|
||||||
|
} else if(item.inventoryitem) {
|
||||||
|
router.push(`/inventoryitems/show/${item.inventoryitem}`)
|
||||||
|
} else if(item.product) {
|
||||||
|
router.push(`/products/show/${item.product}`)
|
||||||
|
} else if(item.profile) {
|
||||||
|
router.push(`/profiles/show/${item.profile}`)
|
||||||
|
} else if(item.absenceRequest) {
|
||||||
|
router.push(`/absenceRequests/show/${item.absenceRequest}`)
|
||||||
|
} else if(item.event) {
|
||||||
|
router.push(`/events/show/${item.event}`)
|
||||||
|
} else if(item.task) {
|
||||||
|
router.push(`/tasks/show/${item.task}`)
|
||||||
|
} else if(item.vehicle) {
|
||||||
|
router.push(`/vehicle/show/${item.vehicle}`)
|
||||||
|
} else if(item.bankStatement) {
|
||||||
|
router.push(`/bankStatements/show/${item.bankStatement}`)
|
||||||
|
} else if(item.space) {
|
||||||
|
router.push(`/spaces/show/${item.space}`)
|
||||||
|
} else if(item.trackingtrip) {
|
||||||
|
router.push(`/trackingtrips/show/${item.trackingtrip}`)
|
||||||
|
}*/
|
||||||
|
if(item.config && item.config.type !== "document") {
|
||||||
|
router.push(`/${item.config.type}s/show/${item.config.id}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setup()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UDashboardNavbar title="Erwähnungen in Logbüchern" :badge="items.length">
|
||||||
|
|
||||||
|
</UDashboardNavbar>
|
||||||
|
<UTable
|
||||||
|
:rows="items"
|
||||||
|
@select="navigateToHistoryItem"
|
||||||
|
:columns="[{key:'created_at',label:'Datum'},{key:'config',label:'Typ'},{key:'text',label:'Text'}]"
|
||||||
|
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Erwähnungen anzuzeigen' }"
|
||||||
|
class="w-full"
|
||||||
|
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||||
|
>
|
||||||
|
<template #config-data="{row}">
|
||||||
|
<span v-if="row.config">{{dataStore.dataTypes[row.config.type + "s"].labelSingle}}</span>
|
||||||
|
</template>
|
||||||
|
<template #created_at-data="{row}">
|
||||||
|
{{dayjs(row.created_at).format("HH:mm DD.MM.YYYY")}}
|
||||||
|
</template>
|
||||||
|
</UTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<template #right>
|
<template #right>
|
||||||
<UTooltip text="Notifications" :shortcuts="['N']">
|
<UTooltip text="Notifications" :shortcuts="['N']">
|
||||||
<UButton color="gray" variant="ghost" square @click="isNotificationsSlideoverOpen = true">
|
<UButton color="gray" variant="ghost" square @click="isNotificationsSlideoverOpen = true">
|
||||||
<UChip :show="false" color="red" inset>
|
<UChip :show="unreadMessages" color="primary" inset>
|
||||||
<UIcon name="i-heroicons-bell" class="w-5 h-5" />
|
<UIcon name="i-heroicons-bell" class="w-5 h-5" />
|
||||||
</UChip>
|
</UChip>
|
||||||
</UButton>
|
</UButton>
|
||||||
@@ -88,6 +88,12 @@ const supabase = useSupabaseClient()
|
|||||||
|
|
||||||
const user = useSupabaseUser()
|
const user = useSupabaseUser()
|
||||||
|
|
||||||
|
const unreadMessages = ref(false)
|
||||||
|
const setup = async () => {
|
||||||
|
unreadMessages.value = (await supabase.from("notifications").select("id,read").eq("read",false)).data.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
setup()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ setupPage()
|
|||||||
<UCard class="w-1/2">
|
<UCard class="w-1/2">
|
||||||
<HistoryDisplay
|
<HistoryDisplay
|
||||||
type="plant"
|
type="plant"
|
||||||
v-if="itemInfo"
|
v-if="itemInfo.id"
|
||||||
:element-id="itemInfo.id"
|
:element-id="itemInfo.id"
|
||||||
render-headline
|
render-headline
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ const isLight = computed({
|
|||||||
v-model="itemInfo.employeeNumber"
|
v-model="itemInfo.employeeNumber"
|
||||||
/>
|
/>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
<UFormGroup
|
<UFormGroup
|
||||||
label="E-Mail"
|
label="E-Mail"
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
>
|
>
|
||||||
@@ -273,6 +273,14 @@ const isLight = computed({
|
|||||||
v-model="itemInfo.email"
|
v-model="itemInfo.email"
|
||||||
/>
|
/>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
|
<UFormGroup
|
||||||
|
label="Benutzername"
|
||||||
|
class="flex-auto"
|
||||||
|
>
|
||||||
|
<UInput
|
||||||
|
v-model="itemInfo.username"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
<InputGroup class="w-full">
|
<InputGroup class="w-full">
|
||||||
<UFormGroup
|
<UFormGroup
|
||||||
|
|||||||
Reference in New Issue
Block a user