--- import { Icon } from 'astro-icon/components' import { actions, isInputError } from 'astro:actions' import { z } from 'astro:schema' import { adminAnnouncementActions } from '../../../actions/admin/announcement' import SortArrowIcon from '../../../components/SortArrowIcon.astro' import TimeFormatted from '../../../components/TimeFormatted.astro' import Tooltip from '../../../components/Tooltip.astro' import BaseLayout from '../../../layouts/BaseLayout.astro' import { zodParseQueryParamsStoringErrors } from '../../../lib/parseUrlFilters' import { prisma } from '../../../lib/prisma' import type { AnnouncementType, Prisma } from '@prisma/client' const { data: filters } = zodParseQueryParamsStoringErrors( { 'sort-by': z .enum(['title', 'type', 'startDate', 'endDate', 'isActive', 'createdAt']) .default('createdAt'), 'sort-order': z.enum(['asc', 'desc']).default('desc'), search: z.string().optional(), type: z.enum(['INFO', 'WARNING', 'ALERT']).optional(), status: z.enum(['active', 'inactive']).optional(), }, Astro ) // Set up Prisma orderBy with correct typing const prismaOrderBy = { [filters['sort-by']]: filters['sort-order'] === 'asc' ? 'asc' : 'desc', } as const satisfies Prisma.AnnouncementOrderByWithRelationInput // Build where clause based on filters const whereClause: Prisma.AnnouncementWhereInput = {} if (filters.search) { whereClause.OR = [ { title: { contains: filters.search, mode: 'insensitive' } }, { content: { contains: filters.search, mode: 'insensitive' } }, ] } if (filters.type) { whereClause.type = filters.type as AnnouncementType } if (filters.status) { whereClause.isActive = filters.status === 'active' } // Retrieve announcements from the database const announcements = await prisma.announcement.findMany({ where: whereClause, orderBy: prismaOrderBy, }) // Helper for generating sort URLs const makeSortUrl = (slug: NonNullable<(typeof filters)['sort-by']>) => { const currentSortBy = filters['sort-by'] const currentSortOrder = filters['sort-order'] const newSortOrder = currentSortBy === slug && currentSortOrder === 'asc' ? 'desc' : 'asc' const searchParams = new URLSearchParams(Astro.url.search) searchParams.set('sort-by', slug) searchParams.set('sort-order', newSortOrder) return `/admin/announcements?${searchParams.toString()}` } // Get type badge class based on announcement type const getTypeBadgeClass = (type: AnnouncementType) => { switch (type) { case 'INFO': return 'bg-blue-900/30 text-blue-400' case 'WARNING': return 'bg-yellow-900/30 text-yellow-400' case 'ALERT': return 'bg-red-900/30 text-red-400' default: return 'bg-zinc-900/30 text-zinc-400' } } // Current date for form min values const currentDate = new Date().toISOString().slice(0, 16) // Format: YYYY-MM-DDThh:mm // Default new announcement const newAnnouncement = { title: '', content: '', type: 'INFO' as const, startDate: currentDate, endDate: '', isActive: true, } // Get action results const createResult = Astro.getActionResult(adminAnnouncementActions.create) const updateResult = Astro.getActionResult(adminAnnouncementActions.update) const deleteResult = Astro.getActionResult(adminAnnouncementActions.delete) const toggleResult = Astro.getActionResult(adminAnnouncementActions.toggleActive) // Add success messages to banners Astro.locals.banners.addIfSuccess(createResult, 'Announcement created successfully!') Astro.locals.banners.addIfSuccess(updateResult, 'Announcement updated successfully!') Astro.locals.banners.addIfSuccess(deleteResult, 'Announcement deleted successfully!') Astro.locals.banners.addIfSuccess( toggleResult, (data) => `Announcement ${data.updatedAnnouncement.isActive ? 'activated' : 'deactivated'} successfully!` ) // Add error messages to banners if (createResult?.error) { const err = createResult.error Astro.locals.banners.add({ uiMessage: err.message, type: 'error', origin: 'action', error: err, }) } if (updateResult?.error) { const err = updateResult.error Astro.locals.banners.add({ uiMessage: err.message, type: 'error', origin: 'action', error: err, }) } if (deleteResult?.error) { const err = deleteResult.error Astro.locals.banners.add({ uiMessage: err.message, type: 'error', origin: 'action', error: err, }) } if (toggleResult?.error) { const err = toggleResult.error Astro.locals.banners.add({ uiMessage: err.message, type: 'error', origin: 'action', error: err, }) } --- Announcement Management {announcements.length} announcements Search Type All Types Info Warning Alert Status All Statuses Active Inactive Create New Announcement Create New Announcement Title* Content* {newAnnouncement.content} Type* Info Warning Alert Start Date & Time* End Date & Time (Optional) Active Create Announcement Cancel Edit Announcement Title* Content* Type* Info Warning Alert Start Date & Time* End Date & Time (Optional) Active Update Announcement Cancel Confirm Deletion Are you sure you want to delete this announcement? This action cannot be undone. Cancel Delete Announcements List Scroll horizontally to see more → Title Type Start Date End Date Status Created At Actions { announcements.length === 0 && ( No announcements found matching your criteria. Try adjusting your search or filters, or create a new announcement. ) } { announcements.map((announcement) => ( {announcement.title} {announcement.content} {announcement.type} {announcement.endDate ? ( ) : ( — )} {announcement.isActive ? 'Active' : 'Inactive'} )) }
Are you sure you want to delete this announcement? This action cannot be undone.
No announcements found matching your criteria.
Try adjusting your search or filters, or create a new announcement.