You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

179 lines
3.7 KiB

<!--
/**
* Notifications View - Manage Scheduled Notifications
*
* @author Matthew Raymer
* @version 1.0.0
*/
-->
<template>
<div class="notifications-view">
<div class="view-header">
<h1 class="page-title">📱 Scheduled Notifications</h1>
<p class="page-subtitle">Manage your daily notifications</p>
</div>
<div v-if="hasScheduledNotifications" class="notifications-list">
<NotificationCard
v-for="notification in scheduledNotifications"
:key="notification.id"
:notification="notification"
@cancel="handleCancelNotification"
/>
</div>
<div v-else class="no-notifications">
<div class="empty-state">
<span class="empty-icon">📅</span>
<h3 class="empty-title">No Notifications Scheduled</h3>
<p class="empty-description">
Schedule your first daily notification to get started
</p>
<button class="empty-action" @click="navigateToSchedule">
📅 Schedule Notification
</button>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-facing-decorator'
import NotificationCard from '@/components/cards/NotificationCard.vue'
import { useNotificationsStore } from '@/stores/notifications'
@Component({
components: {
NotificationCard
}
})
export default class NotificationsView extends Vue {
private notificationsStore = useNotificationsStore()
get hasScheduledNotifications(): boolean {
return this.notificationsStore.hasScheduledNotifications
}
get scheduledNotifications() {
return this.notificationsStore.scheduledNotifications
}
private async handleCancelNotification(notificationId: string): Promise<void> {
try {
await this.notificationsStore.cancelReminder(notificationId)
} catch (error) {
console.error('❌ Failed to cancel notification:', error)
}
}
private navigateToSchedule(): void {
this.$router.push('/schedule')
}
}
</script>
<style scoped>
.notifications-view {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.view-header {
text-align: center;
margin-bottom: 32px;
}
.page-title {
font-size: 2rem;
font-weight: 700;
color: white;
margin: 0 0 8px 0;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.page-subtitle {
font-size: 1.1rem;
color: rgba(255, 255, 255, 0.9);
margin: 0;
font-weight: 300;
}
.notifications-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.no-notifications {
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
}
.empty-state {
text-align: center;
padding: 40px 20px;
background: rgba(255, 255, 255, 0.1);
border-radius: 16px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.empty-icon {
font-size: 4rem;
display: block;
margin-bottom: 16px;
}
.empty-title {
font-size: 1.5rem;
font-weight: 600;
color: white;
margin: 0 0 8px 0;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.empty-description {
font-size: 1rem;
color: rgba(255, 255, 255, 0.8);
margin: 0 0 24px 0;
line-height: 1.5;
}
.empty-action {
background: linear-gradient(135deg, #4caf50, #45a049);
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.empty-action:hover {
background: linear-gradient(135deg, #45a049, #3d8b40);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(76, 175, 80, 0.3);
}
/* Responsive design */
@media (max-width: 768px) {
.notifications-view {
padding: 16px;
}
.empty-state {
padding: 32px 16px;
}
.empty-icon {
font-size: 3rem;
}
}
</style>