funkwhale/front/src/views/Notifications.vue

264 lines
8.2 KiB
Vue

<script setup lang="ts">
import type { Notification } from '~/types'
import moment from 'moment'
import axios from 'axios'
import { ref, reactive, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useStore } from '~/store'
import NotificationRow from '~/components/notifications/NotificationRow.vue'
import useWebSocketHandler from '~/composables/useWebSocketHandler'
import useErrorHandler from '~/composables/useErrorHandler'
import useMarkdown from '~/composables/useMarkdown'
import Layout from '~/components/ui/Layout.vue'
import Loader from '~/components/ui/Loader.vue'
import Spacer from '~/components/ui/Spacer.vue'
import Header from '~/components/ui/Header.vue'
import Toggle from '~/components/ui/Toggle.vue'
import Button from '~/components/ui/Button.vue'
import Alert from '~/components/ui/Alert.vue'
import Table from '~/components/ui/Table.vue'
const store = useStore()
const supportMessage = useMarkdown(() => store.state.instance.settings.instance.support_message.value)
const { t } = useI18n()
const additionalNotifications = computed(() => store.getters['ui/additionalNotifications'])
const showInstanceSupportMessage = computed(() => store.getters['ui/showInstanceSupportMessage'])
const showFunkwhaleSupportMessage = computed(() => store.getters['ui/showFunkwhaleSupportMessage'])
const labels = computed(() => ({
title: t('views.Notifications.title')
}))
const filters = reactive({
is_read: false
})
const isLoading = ref(false)
const notifications = reactive({ count: 0, results: [] as Notification[] })
const fetchData = async () => {
isLoading.value = true
try {
const response = await axios.get('federation/inbox/', { params: filters })
notifications.count = response.data.count
notifications.results = response.data.results
} catch (error) {
useErrorHandler(error as Error)
}
isLoading.value = false
}
watch(filters, fetchData, { immediate: true })
useWebSocketHandler('inbox.item_added', (event) => {
notifications.count += 1
notifications.results.unshift(event.item)
})
const instanceSupportMessageDelay = ref(60)
const funkwhaleSupportMessageDelay = ref(60)
const setDisplayDate = async (field: string, days: number) => {
try {
const response = await axios.patch(`users/${store.state.auth.username}/`, {
[field]: days
? moment().add({ days })
: undefined
})
store.commit('auth/profilePartialUpdate', response.data)
} catch (error) {
useErrorHandler(error as Error)
}
}
const markAllAsRead = async () => {
try {
await axios.post('federation/inbox/action/', {
action: 'read',
objects: 'all',
filters: {
is_read: false,
before: notifications.results[0]?.id
}
})
store.commit('ui/notifications', { type: 'inbox', count: 0 })
notifications.results = notifications.results.map(notification => ({ ...notification, is_read: true }))
} catch (error) {
useErrorHandler(error as Error)
}
}
</script>
<template>
<Layout
v-title="labels.title"
main
stack
class="main page-notifications"
>
<div
v-if="additionalNotifications"
>
<Header
page-heading
:h1="t('views.Notifications.header.messages')"
/>
<Layout flex>
<div
v-if="showInstanceSupportMessage"
>
<Alert blue>
<h4 class="header">
{{ t('views.Notifications.header.instanceSupport') }}
</h4>
<sanitized-html :html="supportMessage" />
</Alert>
<div class="ui bottom attached segment">
<form
class="ui inline form"
@submit.prevent="setDisplayDate('instance_support_message_display_date', instanceSupportMessageDelay)"
>
<div class="inline field">
<label for="instance-reminder-delay">
{{ t('views.Notifications.label.reminder') }}
</label>
<select
id="instance-reminder-delay"
v-model="instanceSupportMessageDelay"
>
<option :value="30">
{{ t('views.Notifications.option.delay.30') }}
</option>
<option :value="60">
{{ t('views.Notifications.option.delay.60') }}
</option>
<option :value="90">
{{ t('views.Notifications.option.delay.90') }}
</option>
<!-- NOTE: Postpone notification 100 years, so that the user never sees it -->
<option :value="36500">
{{ t('views.Notifications.option.delay.never') }}
</option>
</select>
<Button
type="submit"
secondary
>
{{ t('views.Notifications.button.submit') }}
</Button>
</div>
</form>
</div>
</div>
<Alert
v-if="showFunkwhaleSupportMessage"
blue
>
<h4 class="header">
{{ t('views.Notifications.header.funkwhaleSupport') }}
</h4>
<p>
{{ t('views.Notifications.message.funkwhaleSupport') }}
</p>
<a
href="https://funkwhale.audio/donate"
target="_blank"
rel="noopener"
class="ui primary inverted button"
>
{{ t('views.Notifications.link.donate') }}
</a>
<a
href="https://contribute.funkwhale.audio"
target="_blank"
rel="noopener"
class="ui secondary inverted button"
>
{{ t('views.Notifications.link.help') }}
</a>
<template #actions>
<form
class="ui inline form"
@submit.prevent="setDisplayDate('funkwhale_support_message_display_date', funkwhaleSupportMessageDelay)"
>
<Layout flex>
<label for="funkwhale-reminder-delay" style="align-self: center;">
{{ t('views.Notifications.label.reminder') }}
</label>
<select
id="funkwhale-reminder-delay"
class="ui dropdown"
style="margin-top: 0px;"
v-model="funkwhaleSupportMessageDelay"
>
<option :value="30">
{{ t('views.Notifications.option.delay.30') }}
</option>
<option :value="60">
{{ t('views.Notifications.option.delay.60') }}
</option>
<option :value="90">
{{ t('views.Notifications.option.delay.90') }}
</option>
<!-- NOTE: Postpone notification 100 years, so that the user never sees it -->
<option :value="36500">
{{ t('views.Notifications.option.delay.never') }}
</option>
</select>
<Button
type="submit"
primary
>
{{ t('views.Notifications.button.submit') }}
</Button>
</Layout>
</form>
</template>
</Alert>
</Layout>
</div>
<Header
page-heading
:h1="t('views.Notifications.header.notifications')"
/>
<Toggle
id="show-read-notifications"
v-model="filters.is_read"
:label="t('views.Notifications.label.showRead')"
/>
<Button
v-if="filters.is_read === false && notifications.count > 0"
secondary
@click.prevent="markAllAsRead"
icon="bi-check-all"
>
{{ t('views.Notifications.button.read') }}
</Button>
<Loader v-if="isLoading" />
<Table
v-else-if="notifications.count > 0"
:gridTemplateColumns="['auto', 'auto', 'auto', 'auto']"
>
<notification-row
v-for="item in notifications.results"
:key="item.id"
:initial-item="item"
/>
</Table>
<p v-else-if="additionalNotifications === 0">
{{ t('views.Notifications.empty.notifications') }}
</p>
</Layout>
</template>