teacher-tools/app/src/components/AnnouncementsBanner.vue

111 lines
3.0 KiB
Vue

<script setup lang="ts">
import { AnnouncementAPIClient, type Announcement } from '@/api/announcement';
import { APIError } from '@/api/base';
import { useAuthStore } from '@/stores/auth';
import { onMounted, onUnmounted, ref, useTemplateRef, type Ref } from 'vue';
import ConfirmDialog from './ConfirmDialog.vue';
const REFRESH_INTERVAL_MS = 5000
const authStore = useAuthStore()
const client = new AnnouncementAPIClient(authStore)
const announcements: Ref<Announcement[]> = ref([])
const dismissedIds: Ref<number[]> = ref([])
const refreshTimerId: Ref<number | undefined> = ref(undefined)
const deleteAnnouncementConfirmDialog = useTemplateRef('deleteAnnouncementConfirmDialog')
onMounted(() => {
refreshAnnouncements()
refreshTimerId.value = setInterval(refreshAnnouncements, REFRESH_INTERVAL_MS)
})
onUnmounted(() => clearInterval(refreshTimerId.value))
function refreshAnnouncements() {
client.getAnnouncements().result.then(value => {
if (value instanceof APIError) {
console.warn('Failed to get announcements: ', value.message)
announcements.value = []
} else {
announcements.value = value
}
})
}
function getVisibleAnnouncements(): Announcement[] {
return announcements.value.filter(a => !dismissedIds.value.includes(a.id))
}
function getBannerClasses(a: Announcement) {
return {
'announcement-banner-info': a.type === 'INFO',
'announcement-banner-error': a.type === 'ERROR'
}
}
function dismiss(a: Announcement) {
dismissedIds.value.push(a.id)
}
async function deleteAnnouncement(a: Announcement) {
const result = await deleteAnnouncementConfirmDialog.value?.show()
if (result) {
await client.deleteAnnouncement(a.id).handleErrorsWithAlert()
}
}
</script>
<template>
<div>
<div v-for="a in getVisibleAnnouncements()" :key="a.id" class="announcement-banner" :class="getBannerClasses(a)">
<p class="announcement-banner-message">{{ a.message }}</p>
<button class="announcement-banner-button" @click="dismiss(a)">Dismiss</button>
<button v-if="authStore.admin" class="announcement-banner-button" @click="deleteAnnouncement(a)">Delete</button>
</div>
<ConfirmDialog ref="deleteAnnouncementConfirmDialog">
<p>
Are you sure you want to delete this announcement? It will take a few
seconds for the announcement to disappear from users' screens.
</p>
</ConfirmDialog>
</div>
</template>
<style scoped>
.announcement-banner {
padding: 1rem;
margin: 1rem 1rem 0 1rem;
border-radius: 15px;
border-width: 2px;
border-style: solid;
display: flex;
color: rgb(207, 207, 207);
}
.announcement-banner-message {
margin: 0;
flex-grow: 1;
color: inherit;
}
.announcement-banner-button {
background-color: inherit;
border: none;
font-size: small;
color: inherit;
}
.announcement-banner-button:hover {
color: white;
cursor: pointer;
}
.announcement-banner-info {
background-color: rgb(19, 19, 85);
border-color: rgb(70, 70, 201);
}
.announcement-banner-error {
background-color: rgb(146, 14, 14);
border-color: rgb(228, 110, 106);
}
</style>