Skip to content

Commit 12e46a5

Browse files
committed
Refactor email notifications system
Consolidated notification email functions and refactored the email sending logic to use a centralized emailer utility. Removed outdated email templates and added better support for email frequency configurations in notification settings, with new components for user preferences management. This improves code maintainability and ensures more robust email notifications. Took 13 minutes
1 parent a4edda2 commit 12e46a5

23 files changed

+1546
-443
lines changed
Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,32 @@
1-
import { NextResponse } from 'next/server'
2-
import { sendDailySummaries, sendWeeklySummaries } from '@/lib/notifications/petition-summary'
1+
import { logger } from "@/lib/logger"
2+
import {
3+
sendDailySummaries,
4+
sendWeeklySummaries,
5+
} from "@/lib/notifications/petition-notifications"
36

4-
export const runtime = 'edge'
7+
const log = logger.forService("cron-petition-summaries")
58

6-
export async function GET(request: Request) {
9+
export async function GET() {
710
try {
8-
const { searchParams } = new URL(request.url)
9-
const type = searchParams.get('type')
11+
log.info("Starting petition summary notifications")
1012

11-
if (type === 'daily') {
12-
await sendDailySummaries()
13-
} else if (type === 'weekly') {
14-
await sendWeeklySummaries()
15-
}
13+
await Promise.all([sendDailySummaries(), sendWeeklySummaries()])
1614

17-
return NextResponse.json({ success: true })
15+
log.info("Completed petition summary notifications")
16+
17+
return new Response("OK", { status: 200 })
1818
} catch (error) {
19-
console.error('Cron job failed:', error)
20-
return NextResponse.json({ error: 'Failed to process summaries' }, { status: 500 })
19+
log.error("Failed to send petition summaries", {
20+
error:
21+
error instanceof Error
22+
? {
23+
name: error.name,
24+
message: error.message,
25+
stack: error.stack,
26+
}
27+
: { message: String(error) },
28+
})
29+
30+
return new Response("Internal Server Error", { status: 500 })
2131
}
22-
}
32+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"use client"
2+
3+
import { useState } from "react"
4+
import { EmailFrequency } from "@prisma/client"
5+
import { useSession } from "next-auth/react"
6+
7+
import { Button } from "@/components/ui/button"
8+
import { Select } from "@/components/ui/select"
9+
import { Switch } from "@/components/ui/switch"
10+
import { useToast } from "@/components/ui/use-toast"
11+
12+
interface NotificationSettingsProps {
13+
petitionId: string
14+
initialSettings?: {
15+
notifyOnComment: boolean
16+
notifyOnMilestone: boolean
17+
notifyOnUpdate: boolean
18+
notifyOnSignature: boolean
19+
emailFrequency: EmailFrequency
20+
}
21+
onUpdate: (
22+
petitionId: string,
23+
settings: {
24+
notifyOnComment: boolean
25+
notifyOnMilestone: boolean
26+
notifyOnUpdate: boolean
27+
notifyOnSignature: boolean
28+
emailFrequency: EmailFrequency
29+
}
30+
) => Promise<void>
31+
}
32+
33+
export function NotificationSettings({
34+
petitionId,
35+
initialSettings,
36+
onUpdate,
37+
}: NotificationSettingsProps) {
38+
const { data: session } = useSession()
39+
const { toast } = useToast()
40+
const [loading, setLoading] = useState(false)
41+
42+
const [notifications, setNotifications] = useState(
43+
initialSettings
44+
? initialSettings.notifyOnComment &&
45+
initialSettings.notifyOnMilestone &&
46+
initialSettings.notifyOnUpdate &&
47+
initialSettings.notifyOnSignature
48+
: true
49+
)
50+
51+
const [emailFrequency, setEmailFrequency] = useState<EmailFrequency>(
52+
initialSettings?.emailFrequency || "INSTANT"
53+
)
54+
55+
const handleUpdate = async () => {
56+
setLoading(true)
57+
try {
58+
await onUpdate(petitionId, {
59+
notifyOnComment: notifications,
60+
notifyOnMilestone: notifications,
61+
notifyOnUpdate: notifications,
62+
notifyOnSignature: notifications,
63+
emailFrequency,
64+
})
65+
toast({
66+
title: "Success",
67+
description: "Notification settings updated",
68+
})
69+
} catch (error) {
70+
console.error("Failed to update notification settings:", error)
71+
toast({
72+
title: "Error",
73+
description: "Failed to update notification settings",
74+
variant: "destructive",
75+
})
76+
} finally {
77+
setLoading(false)
78+
}
79+
}
80+
81+
if (!session) return null
82+
83+
return (
84+
<div className="space-y-4 rounded-lg bg-white p-4 shadow">
85+
<h3 className="mb-4 text-lg font-semibold">Notification Settings</h3>
86+
87+
<div className="flex items-center justify-between">
88+
<label className="font-medium">Notifications</label>
89+
<Switch checked={notifications} onCheckedChange={setNotifications} />
90+
</div>
91+
92+
{notifications && (
93+
<div className="flex items-center justify-between">
94+
<label className="font-medium">Email Frequency</label>
95+
<Select
96+
value={emailFrequency}
97+
onValueChange={(value: EmailFrequency) => setEmailFrequency(value)}
98+
>
99+
<option value="INSTANT">Instant</option>
100+
<option value="DAILY">Daily Digest</option>
101+
<option value="WEEKLY">Weekly Digest</option>
102+
</Select>
103+
</div>
104+
)}
105+
106+
<Button onClick={handleUpdate} disabled={loading} className="w-full">
107+
{loading ? "Saving..." : "Save Settings"}
108+
</Button>
109+
</div>
110+
)
111+
}

0 commit comments

Comments
 (0)