feat: notifications
This commit is contained in:
@@ -44,9 +44,21 @@ import SidebarLink from '@/components/SidebarLink.vue'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { ref } from 'vue'
|
||||
import { getSidebarLinks } from '../utils'
|
||||
import { sessionStore } from '@/stores/session'
|
||||
import { Bell } from 'lucide-vue-next'
|
||||
|
||||
const { user } = sessionStore()
|
||||
const links = getSidebarLinks()
|
||||
|
||||
if (user) {
|
||||
links.push({
|
||||
label: 'Notifications',
|
||||
icon: Bell,
|
||||
to: 'Notifications',
|
||||
activeFor: ['Notifications'],
|
||||
})
|
||||
}
|
||||
|
||||
const getSidebarFromStorage = () => {
|
||||
return useStorage('sidebar_is_collapsed', false)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<div
|
||||
class="relative block min-h-0 flex-shrink-0 overflow-hidden hover:overflow-auto"
|
||||
>
|
||||
<slot name="sidebar" />
|
||||
<AppSidebar />
|
||||
</div>
|
||||
<div class="w-full overflow-auto" id="scrollContainer">
|
||||
|
||||
@@ -69,9 +69,11 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TextEditor
|
||||
class="mt-5"
|
||||
:content="newReply"
|
||||
:mentions="mentionUsers"
|
||||
@change="(val) => (newReply = val)"
|
||||
placeholder="Type your reply here..."
|
||||
:fixedMenu="true"
|
||||
@@ -92,13 +94,14 @@ import { createResource, TextEditor, Button, Dropdown } from 'frappe-ui'
|
||||
import { timeAgo } from '../utils'
|
||||
import UserAvatar from '@/components/UserAvatar.vue'
|
||||
import { ChevronLeft, MoreHorizontal } from 'lucide-vue-next'
|
||||
import { ref, inject, onMounted } from 'vue'
|
||||
import { ref, inject, onMounted, computed } from 'vue'
|
||||
import { createToast } from '../utils'
|
||||
|
||||
const showTopics = defineModel('showTopics')
|
||||
const newReply = ref('')
|
||||
const socket = inject('$socket')
|
||||
const user = inject('$user')
|
||||
const allUsers = inject('$allUsers')
|
||||
|
||||
const props = defineProps({
|
||||
topic: {
|
||||
@@ -147,6 +150,16 @@ const newReplyResource = createResource({
|
||||
},
|
||||
})
|
||||
|
||||
const mentionUsers = computed(() => {
|
||||
return allUsers.data /* [{
|
||||
label: "jannat",
|
||||
value: "jannat"
|
||||
}, {
|
||||
label: "samreen",
|
||||
value: "samreen"
|
||||
}] */
|
||||
})
|
||||
|
||||
const postReply = () => {
|
||||
newReplyResource.submit(
|
||||
{},
|
||||
|
||||
@@ -42,14 +42,14 @@
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="flex items-center justify-center border mt-5 p-5 rounded-md"
|
||||
class="flex flex-col items-center justify-center border-2 border-dashed mt-5 py-8 rounded-md"
|
||||
>
|
||||
<MessageSquareIcon class="w-5 h-5 stroke-1.5 mr-2" />
|
||||
<div>
|
||||
<MessageSquareText class="w-7 h-7 text-gray-500 stroke-1.5 mr-2" />
|
||||
<div class="">
|
||||
<div v-if="emptyStateTitle" class="font-medium mb-2">
|
||||
{{ __(emptyStateTitle) }}
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="text-gray-600">
|
||||
{{ __(emptyStateText) }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,7 +69,7 @@ import { timeAgo } from '../utils'
|
||||
import { ref, onMounted, inject } from 'vue'
|
||||
import DiscussionReplies from '@/components/DiscussionReplies.vue'
|
||||
import DiscussionModal from '@/components/Modals/DiscussionModal.vue'
|
||||
import { MessageSquareIcon } from 'lucide-vue-next'
|
||||
import { MessageSquareText } from 'lucide-vue-next'
|
||||
|
||||
const showTopics = ref(true)
|
||||
const currentTopic = ref(null)
|
||||
@@ -96,7 +96,7 @@ const props = defineProps({
|
||||
},
|
||||
emptyStateText: {
|
||||
type: String,
|
||||
default: 'Be the first to start a discussion',
|
||||
default: 'Start a discussion',
|
||||
},
|
||||
singleThread: {
|
||||
type: Boolean,
|
||||
|
||||
@@ -34,7 +34,7 @@ import { sessionStore } from '@/stores/session'
|
||||
import { usersStore } from '@/stores/user'
|
||||
import { LogOut, LogIn, UserRound } from 'lucide-vue-next'
|
||||
|
||||
const { logout, user, username } = sessionStore()
|
||||
const { logout, user } = sessionStore()
|
||||
let { isLoggedIn } = sessionStore()
|
||||
const router = useRouter()
|
||||
let { userResource } = usersStore()
|
||||
|
||||
@@ -30,8 +30,9 @@ app.provide('$dayjs', dayjs)
|
||||
app.provide('$socket', initSocket())
|
||||
app.mount('#app')
|
||||
|
||||
const { userResource } = usersStore()
|
||||
const { userResource, allUsers } = usersStore()
|
||||
let { isLoggedIn } = sessionStore()
|
||||
|
||||
app.provide('$user', userResource)
|
||||
app.provide('$allUsers', allUsers)
|
||||
app.config.globalProperties.$user = userResource
|
||||
|
||||
69
frontend/src/pages/Notifications.vue
Normal file
69
frontend/src/pages/Notifications.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<header
|
||||
class="sticky top-0 z-10 flex flex-col md:flex-row md:items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
|
||||
>
|
||||
<Breadcrumbs :items="breadcrumbs" />
|
||||
</header>
|
||||
<div class="w-3/4 mx-auto">
|
||||
<div
|
||||
v-for="log in notifications.data"
|
||||
class="flex items-center border-b py-2 justify-between"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<UserAvatar :user="allUsers.data[log.from_user]" class="mr-2" />
|
||||
<div class="notification" v-html="log.subject"></div>
|
||||
</div>
|
||||
<Link
|
||||
v-if="log.link"
|
||||
:to="log.link"
|
||||
class="text-gray-600 font-medium text-sm hover:text-gray-700"
|
||||
>
|
||||
{{ __('View') }}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { createResource, Breadcrumbs, Link } from 'frappe-ui'
|
||||
import { computed, inject } from 'vue'
|
||||
import UserAvatar from '@/components/UserAvatar.vue'
|
||||
|
||||
const user = inject('$user')
|
||||
const allUsers = inject('$allUsers')
|
||||
|
||||
const notifications = createResource({
|
||||
url: 'frappe.client.get_list',
|
||||
makeParams: (values) => {
|
||||
return {
|
||||
doctype: 'Notification Log',
|
||||
fields: ['subject', 'from_user', 'link'],
|
||||
filters: {
|
||||
for_user: user.data?.name,
|
||||
},
|
||||
order_by: 'creation desc',
|
||||
}
|
||||
},
|
||||
auto: true,
|
||||
cache: user.data?.name,
|
||||
})
|
||||
|
||||
const breadcrumbs = computed(() => {
|
||||
let crumbs = [
|
||||
{
|
||||
label: 'Notifications',
|
||||
route: {
|
||||
name: 'Notifications',
|
||||
},
|
||||
},
|
||||
]
|
||||
return crumbs
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.notification strong {
|
||||
font-weight: 400;
|
||||
}
|
||||
.notification b {
|
||||
font-weight: 400;
|
||||
}
|
||||
</style>
|
||||
@@ -130,6 +130,11 @@ const routes = [
|
||||
name: 'CertifiedParticipants',
|
||||
component: () => import('@/pages/CertifiedParticipants.vue'),
|
||||
},
|
||||
{
|
||||
path: '/notifications',
|
||||
name: 'Notifications',
|
||||
component: () => import('@/pages/Notifications.vue'),
|
||||
},
|
||||
]
|
||||
|
||||
let router = createRouter({
|
||||
@@ -138,13 +143,21 @@ let router = createRouter({
|
||||
})
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const { userResource } = usersStore()
|
||||
const { userResource, allUsers } = usersStore()
|
||||
let { isLoggedIn } = sessionStore()
|
||||
|
||||
try {
|
||||
if (isLoggedIn) {
|
||||
await userResource.reload()
|
||||
}
|
||||
if (
|
||||
isLoggedIn &&
|
||||
(to.name == 'Lesson' ||
|
||||
to.name == 'Batch' ||
|
||||
to.name == 'Notifications')
|
||||
) {
|
||||
await allUsers.reload()
|
||||
}
|
||||
} catch (error) {
|
||||
isLoggedIn = false
|
||||
}
|
||||
|
||||
@@ -11,7 +11,21 @@ export const usersStore = defineStore('lms-users', () => {
|
||||
},
|
||||
})
|
||||
|
||||
const allUsers = createResource({
|
||||
url: 'lms.lms.api.get_all_users',
|
||||
cache: ['allUsers'],
|
||||
/* transform(data) {
|
||||
return data.map((user) => {
|
||||
return {
|
||||
value: user.name,
|
||||
label: user.full_name.trimEnd(),
|
||||
}
|
||||
})
|
||||
}, */
|
||||
})
|
||||
|
||||
return {
|
||||
userResource,
|
||||
allUsers,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
TrendingUp,
|
||||
Briefcase,
|
||||
GraduationCap,
|
||||
Bell,
|
||||
} from 'lucide-vue-next'
|
||||
import { Quiz } from '@/utils/quiz'
|
||||
import { Upload } from '@/utils/upload'
|
||||
@@ -350,6 +351,7 @@ export function getSidebarLinks() {
|
||||
label: 'Statistics',
|
||||
icon: TrendingUp,
|
||||
to: 'Statistics',
|
||||
activeFor: ['Statistics'],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user