--- import BaseLayout from "@/layouts/BaseLayout.astro"; import { getDatabase, schema } from "@/db"; import { eq, and, isNull } from "drizzle-orm"; import { Bell, Mail, MessageSquare, Smartphone, Clock, Save, AtSign, Users, GitPullRequest, CheckCircle2, XCircle, Bot, Star, Eye, } from "lucide-react"; const user = Astro.locals.user; if (!user) { return Astro.redirect("/login"); } const db = getDatabase(); // Define all notification event types const eventTypes = [ { id: "mention", label: "Mentions", description: "When someone @mentions you", icon: AtSign, category: "activity", }, { id: "assign", label: "Assignments", description: "When you're assigned to an issue or PR", icon: Users, category: "activity", }, { id: "review_request", label: "Review Requests", description: "When your review is requested", icon: Eye, category: "reviews", }, { id: "review_submitted", label: "Review Submitted", description: "When someone reviews your PR", icon: GitPullRequest, category: "reviews", }, { id: "pr_approved", label: "PR Approved", description: "When your PR is approved", icon: CheckCircle2, category: "reviews", }, { id: "pr_changes_requested", label: "Changes Requested", description: "When changes are requested on your PR", icon: XCircle, category: "reviews", }, { id: "pr_merged", label: "PR Merged", description: "When your PR is merged", icon: GitPullRequest, category: "prs", }, { id: "pr_closed", label: "PR Closed", description: "When your PR is closed", icon: XCircle, category: "prs", }, { id: "comment", label: "Comments", description: "New comments on your issues/PRs", icon: MessageSquare, category: "activity", }, { id: "ci_passed", label: "CI Passed", description: "When CI passes on your PR", icon: CheckCircle2, category: "ci", }, { id: "ci_failed", label: "CI Failed", description: "When CI fails on your PR", icon: XCircle, category: "ci", }, { id: "merge_queue", label: "Merge Queue", description: "Merge queue status updates", icon: Clock, category: "ci", }, { id: "ai_review", label: "AI Review", description: "When AI review is completed", icon: Bot, category: "reviews", }, { id: "star", label: "Stars", description: "When your repo is starred", icon: Star, category: "activity", }, ]; const categories = [ { id: "reviews", label: "Code Reviews" }, { id: "prs", label: "Pull Requests" }, { id: "ci", label: "CI/CD" }, { id: "activity", label: "Activity" }, ]; // Get current preferences interface Preference { eventType: string; emailEnabled: boolean; slackEnabled: boolean; inAppEnabled: boolean; browserPushEnabled: boolean; } let preferences: Record = {}; let quietHours = { isEnabled: false, startTime: "22:00", endTime: "08:00", allowUrgent: true, }; let digestSettings = { digestType: "none" as "none" | "daily" | "weekly", digestTime: "09:00", digestDay: 1, timezone: "UTC", }; try { const dbPrefs = await db.query.notificationPreferences.findMany({ where: and( eq(schema.notificationPreferences.userId, user.id), isNull(schema.notificationPreferences.repositoryId), // Global preferences ), }); for (const pref of dbPrefs) { preferences[pref.eventType] = { eventType: pref.eventType, emailEnabled: pref.emailEnabled ?? true, slackEnabled: pref.slackEnabled ?? false, inAppEnabled: pref.inAppEnabled ?? true, browserPushEnabled: pref.browserPushEnabled ?? false, }; } // Get quiet hours const dbQuietHours = await db.query.notificationQuietHours.findFirst({ where: eq(schema.notificationQuietHours.userId, user.id), }); if (dbQuietHours) { quietHours = { isEnabled: dbQuietHours.isEnabled ?? false, startTime: dbQuietHours.startTime, endTime: dbQuietHours.endTime, allowUrgent: dbQuietHours.allowUrgent ?? true, }; } // Get digest settings const dbDigest = await db.query.emailDigestSettings.findFirst({ where: eq(schema.emailDigestSettings.userId, user.id), }); if (dbDigest) { digestSettings = { digestType: dbDigest.digestType as "none" | "daily" | "weekly", digestTime: dbDigest.digestTime || "09:00", digestDay: dbDigest.digestDay ?? 1, timezone: dbDigest.timezone || "UTC", }; } } catch (e) { console.error("Failed to fetch notification preferences:", e); } // Fill in defaults for missing preferences for (const event of eventTypes) { if (!preferences[event.id]) { preferences[event.id] = { eventType: event.id, emailEnabled: true, slackEnabled: false, inAppEnabled: true, browserPushEnabled: false, }; } } ---

Notification Preferences

Choose how you want to be notified

Email
Slack
In-App
Browser Push
{ categories.map((category) => { const categoryEvents = eventTypes.filter( (e) => e.category === category.id, ); return (

{category.label}

{categoryEvents.map((event) => { const pref = preferences[event.id]; const EventIcon = event.icon; return (
{event.label}
{event.description}
{/* Email */} {/* Slack */} {/* In-App */} {/* Browser Push */}
); })}
); }) }

Quiet Hours

Email Digest