diff --git a/components/header/header.vue b/components/header/header.vue index 8ce7e40..abede01 100644 --- a/components/header/header.vue +++ b/components/header/header.vue @@ -105,73 +105,10 @@ @@ -269,10 +206,10 @@ import { } from 'vue'; import navigate from '#/src/navigate.js'; -import { get, patch, del } from '#/src/api.js'; -import { formatDate } from '#/utils/format.js'; +import { del } from '#/src/api.js'; // import getPath from '#/src/get-path.js'; +import Notifications from '#/components/header/notifications.vue'; import Settings from '#/components/settings/settings.vue'; import AlertDialog from '#/components/alerts/create.vue'; @@ -281,9 +218,7 @@ import logo from '../../assets/img/logo.svg?raw'; // eslint-disable-line import/ const pageContext = inject('pageContext'); const user = pageContext.user; -const notifications = ref(pageContext.notifications.notifications); -const unseen = ref(pageContext.notifications.unseen); -const done = ref(true); +const unseen = ref(pageContext.meta.unseenNotifications); const query = ref(pageContext.urlParsed.search.q || ''); const allowLogin = pageContext.env.allowLogin; const searchFocused = ref(false); @@ -297,41 +232,6 @@ function search() { navigate('/search', { q: query.value }, { redirect: true }); } -async function fetchNotifications() { - const res = await get(`/users/${user?.id}/notifications`); - - notifications.value = res.notifications; - unseen.value = res.unseen; -} - -async function markSeen(notif) { - if (notif.isSeen || !done.value) { - return; - } - - done.value = false; - - await patch(`/users/${user?.id}/notifications/${notif.id}`, { - seen: true, - }); - - await fetchNotifications(); - - done.value = true; -} - -async function markAllSeen() { - done.value = false; - - await patch(`/users/${user?.id}/notifications`, { - seen: true, - }); - - await fetchNotifications(); - - done.value = true; -} - async function logout() { await del('/session'); navigate('/login', null, { redirect: true }); @@ -514,119 +414,6 @@ function blurSearch(event) { fill: var(--shadow); } -.notifs { - width: 30rem; - height: 20rem; - max-width: 100%; - max-height: 100%; - overflow-y: auto; - overflow-x: hidden; -} - -.notifs-header { - display: flex; - justify-content: space-between; - box-shadow: inset 0 0 3px var(--shadow-weak-30); - - .icon { - fill: var(--shadow-strong-10); - - &:hover { - fill: var(--primary); - cursor: pointer; - } - } -} - -.notifs-heading { - font-size: 1rem; - padding: .75rem 1rem; - margin: 0; - font-weight: normal; -} - -.notifs-actions { - align-items: stretch; - - .icon { - height: 100%; - padding: 0 .75rem; - - &:last-child { - padding-right: 1rem; - } - } -} - -.notif { - display: flex; - align-items: center; - width: 100%; - overflow: hidden; - - &:not(:last-child) { - border-bottom: solid 1px var(--shadow-weak-40); - } - - &:before { - width: 2.5rem; - flex-shrink: 0; - content: '•'; - color: var(--shadow-weak-20); - text-align: center; - } - - &.unseen:before { - color: var(--primary); - } - - &.unseen:hover:before { - content: '✓'; - } -} - -.notif-body { - display: flex; - flex-direction: column; - flex-grow: 1; - overflow: hidden; - box-sizing: border-box; - font-size: .9rem; -} - -.notif-details { - padding: .5rem 0 .15rem 0; - box-sizing: border-box; - color: var(--shadow-strong); - font-weight: bold; -} - -.notif-link { - overflow: hidden; -} - -.notif-scene { - display: flex; - padding: .15rem 0 .5rem 0; -} - -.notif-date { - flex-shrink: 0; - color: var(--shadow-strong-10); - - &:after { - content: '•'; - padding: 0 .5rem; - color: var(--shadow-weak-20); - } -} - -.notif-thumb { - width: 5rem; - height: 3rem; - object-fit: cover; -} - .login { display: flex; align-items: center; diff --git a/components/header/notifications.vue b/components/header/notifications.vue new file mode 100644 index 0000000..b05dfc2 --- /dev/null +++ b/components/header/notifications.vue @@ -0,0 +1,245 @@ + + + + + diff --git a/renderer/+config.h.js b/renderer/+config.h.js index 6756388..3e26487 100644 --- a/renderer/+config.h.js +++ b/renderer/+config.h.js @@ -6,6 +6,6 @@ export default { 'urlParsed', 'env', 'user', - 'notifications', + 'meta', ], }; diff --git a/src/alerts.js b/src/alerts.js index 9ca844d..4dbfaf0 100755 --- a/src/alerts.js +++ b/src/alerts.js @@ -145,12 +145,26 @@ export async function removeAlert(alertId, reqUser) { .delete(); } +export async function fetchUnseenNotificationsCount(reqUser) { + if (!reqUser) { + return null; + } + + const rawUnseen = await knex('notifications') + .select(knex.raw('count(id)')) + .where('user_id', reqUser.id) + .where('seen', false) + .first(); + + return Number(rawUnseen.count); +} + export async function fetchNotifications(reqUser, options = {}) { if (!reqUser) { return []; } - const [notifications, rawUnseen] = await Promise.all([ + const [notifications, unseen] = await Promise.all([ knex('notifications') .select( 'notifications.*', @@ -169,15 +183,10 @@ export async function fetchNotifications(reqUser, options = {}) { .limit(options.limit) .groupBy('notifications.id', 'alerts.id') .orderBy('created_at', 'desc'), - knex('notifications') - .select(knex.raw('count(id)')) - .where('user_id', reqUser.id) - .where('seen', false) - .first(), + fetchUnseenNotificationsCount(reqUser), ]); const scenes = await fetchScenesById(notifications.map((notification) => notification.scene_id)); - const unseen = Number(rawUnseen.count); const curatedNotifications = notifications.map((notification) => { const scene = scenes.find((sceneX) => sceneX.id === notification.scene_id); diff --git a/src/web/server.js b/src/web/server.js index 1a0d280..b39e84a 100644 --- a/src/web/server.js +++ b/src/web/server.js @@ -52,7 +52,7 @@ import { updateNotificationsApi, } from './alerts.js'; -import { fetchNotifications } from '../alerts.js'; +import { fetchUnseenNotificationsCount } from '../alerts.js'; import initLogger from '../logger.js'; @@ -168,7 +168,7 @@ export default async function initServer() { router.get('/api/tags', fetchTagsApi); router.get('*', async (req, res, next) => { - const notifications = await fetchNotifications(req.user, { limit: 20 }); + const unseenNotifications = await fetchUnseenNotificationsCount(req.user); const pageContextInit = { urlOriginal: req.originalUrl, @@ -191,7 +191,9 @@ export default async function initServer() { maxAggregateSize: config.database.manticore.maxAggregateSize, media: config.media, }, - notifications, + meta: { + unseenNotifications, + }, }; const pageContext = await renderPage(pageContextInit);