342 lines
7.9 KiB
Vue
342 lines
7.9 KiB
Vue
<template>
|
|
<div>
|
|
<p class="loading" v-if="tokenValid === null">
|
|
{{ $t('notification.loading') }}
|
|
</p>
|
|
|
|
<p class="invalid" v-if="tokenValid === false">
|
|
{{ $t('notification.tokenInvalid') }}
|
|
</p>
|
|
|
|
<div class="notifications" v-if="tokenValid === true">
|
|
<div class="header">{{ $t('notification.listHeader') }}</div>
|
|
|
|
<div class="list">
|
|
<div class="notification" v-for="notification in orderedNotifications" :key="notification.id">
|
|
<div class="title">{{ notification.title }}</div>
|
|
<div class="content">
|
|
<div class="info">
|
|
<p class="latchTime">{{ $t('notification.latchTime', { latchTime: formatDateTime(notification.latchTime) }) }}</p>
|
|
<p class="latched">{{ $t('notification.latched') }}</p>
|
|
</div>
|
|
|
|
<div class="actions">
|
|
<a href="#" @click.prevent="enableNotification(notification)" class="enable" :class="{ active: !notification.enabling }">{{ $t('notification.enableNotification') }}</a>
|
|
</div>
|
|
|
|
<div class="reminders" v-if="reminders.enabled">
|
|
<p class="interval">{{ $t('notification.reminders', { interval: formattedReminderInterval })}}</p>
|
|
|
|
<div class="actions">
|
|
<a href="#" @click.prevent="enableReminders(notification)" class="reminders-enabled" :class="{ active: !notification.updatingReminders && notification.reminders }">{{ $t('notification.remindersEnabled') }}</a>
|
|
<a href="#" @click.prevent="disableReminders(notification)" class="reminders-disabled" :class="{ active: !notification.updatingReminders && !notification.reminders }">{{ $t('notification.remindersDisabled') }}</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent } from 'vue';
|
|
import axios from 'axios';
|
|
import { DateTime, Duration } from 'luxon';
|
|
import { ILatchedNotifications, INotificationReminders, INotification } from '../model/notifications';
|
|
|
|
|
|
interface INotificationViewModel extends INotification
|
|
{
|
|
enabling: boolean;
|
|
updatingReminders: boolean;
|
|
}
|
|
|
|
|
|
export default defineComponent({
|
|
props: [
|
|
'token'
|
|
],
|
|
|
|
|
|
data()
|
|
{
|
|
return {
|
|
tokenValid: null as null | boolean,
|
|
reminders: null as null | INotificationReminders,
|
|
notifications: null as null | Array<INotificationViewModel>
|
|
};
|
|
},
|
|
|
|
|
|
mounted()
|
|
{
|
|
this.refreshToken();
|
|
},
|
|
|
|
|
|
watch: {
|
|
token()
|
|
{
|
|
this.refreshToken();
|
|
}
|
|
},
|
|
|
|
|
|
computed: {
|
|
formattedReminderInterval(): string
|
|
{
|
|
if (this.reminders === null || !this.reminders.enabled)
|
|
return '';
|
|
|
|
const duration = Duration.fromObject(this.reminders.interval);
|
|
const interval = duration.shiftTo('days', 'hours', 'minutes', 'seconds');
|
|
const units = [];
|
|
|
|
if (interval.days)
|
|
units.push(this.$tc('duration.days', interval.days));
|
|
|
|
if (interval.hours)
|
|
units.push(this.$tc('duration.hours', interval.hours));
|
|
|
|
if (interval.minutes)
|
|
units.push(this.$tc('duration.minutes', interval.minutes));
|
|
|
|
if (interval.seconds)
|
|
units.push(this.$tc('duration.seconds', interval.seconds));
|
|
|
|
if (units.length == 0)
|
|
return '<error>';
|
|
|
|
if (units.length == 1)
|
|
return units[0];
|
|
|
|
const lastUnit = units.pop();
|
|
return units.join(this.$t('duration.glue')) + this.$t('duration.lastGlue') + lastUnit;
|
|
},
|
|
|
|
|
|
orderedNotifications(): Array<INotificationViewModel>
|
|
{
|
|
if (this.notifications === null)
|
|
return [];
|
|
|
|
return [...this.notifications].sort((a, b) =>
|
|
{
|
|
if (a.token === this.token)
|
|
return -1;
|
|
|
|
if (b.token === this.token)
|
|
return 1;
|
|
|
|
return a.title.localeCompare(b.title);
|
|
});
|
|
}
|
|
},
|
|
|
|
|
|
methods: {
|
|
async refreshToken()
|
|
{
|
|
try
|
|
{
|
|
const response = await axios.get<ILatchedNotifications>('/api/notification/latched', {
|
|
headers: {
|
|
'Authorization': 'Bearer ' + this.token
|
|
}
|
|
});
|
|
|
|
this.reminders = response.data.reminders;
|
|
this.notifications = response.data.notifications.map(notification =>
|
|
{
|
|
return {
|
|
token: notification.token,
|
|
id: notification.id,
|
|
title: notification.title,
|
|
latched: notification.latched,
|
|
latchTime: notification.latchTime,
|
|
resetTime: notification.resetTime,
|
|
reminders: notification.reminders,
|
|
remindTime: notification.remindTime,
|
|
|
|
enabling: false,
|
|
updatingReminders: false
|
|
} as INotificationViewModel;
|
|
});
|
|
this.tokenValid = true;
|
|
}
|
|
catch
|
|
{
|
|
this.tokenValid = false;
|
|
}
|
|
},
|
|
|
|
|
|
async enableNotification(notification: INotificationViewModel)
|
|
{
|
|
if (this.notifications == null || notification.enabling)
|
|
return;
|
|
|
|
notification.enabling = true;
|
|
try
|
|
{
|
|
await axios.post('/api/notification/' + notification.token + '/reset');
|
|
this.notifications = this.notifications.filter((n: INotification) => n !== notification);
|
|
}
|
|
finally
|
|
{
|
|
notification.enabling = false;
|
|
}
|
|
},
|
|
|
|
|
|
async enableReminders(notification: INotificationViewModel)
|
|
{
|
|
if (notification.updatingReminders)
|
|
return;
|
|
|
|
notification.updatingReminders = true;
|
|
try
|
|
{
|
|
await axios.post('/api/notification/' + notification.token + '/reminders/enable');
|
|
notification.reminders = true;
|
|
}
|
|
finally
|
|
{
|
|
notification.updatingReminders = false;
|
|
}
|
|
},
|
|
|
|
|
|
async disableReminders(notification: INotificationViewModel)
|
|
{
|
|
if (notification.updatingReminders)
|
|
return;
|
|
|
|
notification.updatingReminders = true;
|
|
try
|
|
{
|
|
await axios.post('/api/notification/' + notification.token + '/reminders/disable');
|
|
notification.reminders = false;
|
|
}
|
|
finally
|
|
{
|
|
notification.updatingReminders = false;
|
|
}
|
|
},
|
|
|
|
|
|
formatDateTime(unixTimestamp: number)
|
|
{
|
|
return DateTime.fromSeconds(unixTimestamp).toLocaleString(DateTime.DATETIME_FULL);
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.notifications
|
|
{
|
|
margin: 1rem;
|
|
|
|
.header
|
|
{
|
|
font-size: 1.25rem;
|
|
font-weight: bold;
|
|
margin-bottom: 2rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.list
|
|
{
|
|
color: black;
|
|
|
|
.notification
|
|
{
|
|
background: #fcfcfc;
|
|
border: solid 1px #2b5074;
|
|
border-radius: 5px;
|
|
margin-bottom: 3rem;
|
|
|
|
.title
|
|
{
|
|
background: #d4e1ee;
|
|
border-top-left-radius: 5px;
|
|
border-top-right-radius: 5px;
|
|
font-weight: bold;
|
|
padding: .5rem;
|
|
}
|
|
|
|
.content
|
|
{
|
|
margin: .5rem;
|
|
}
|
|
|
|
.info
|
|
{
|
|
font-size: .75rem;
|
|
|
|
.latchTime
|
|
{
|
|
color: gray;
|
|
margin-top: 0;
|
|
}
|
|
}
|
|
|
|
.actions
|
|
{
|
|
margin-top: .25rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.enable,
|
|
.reminders-disabled,
|
|
.reminders-enabled
|
|
{
|
|
display: inline-block;
|
|
padding: .5em;
|
|
text-decoration: none;
|
|
border-radius: 5px;
|
|
margin-right: .5rem;
|
|
color: gray;
|
|
background: white;
|
|
border: solid 1px darkgray;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.active
|
|
{
|
|
cursor: default;
|
|
|
|
&.enable,
|
|
&.reminders-enabled
|
|
{
|
|
color: white;
|
|
background: #248f24;
|
|
border: solid 1px green;
|
|
}
|
|
|
|
&.enable
|
|
{
|
|
cursor: pointer;
|
|
}
|
|
|
|
&.reminders-disabled
|
|
{
|
|
color: white;
|
|
background: darkred;
|
|
border: solid 1px red;
|
|
}
|
|
}
|
|
|
|
.reminders
|
|
{
|
|
.interval
|
|
{
|
|
font-size: .75rem;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style> |