@fatagnus/convex-feedback 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +177 -0
- package/README.md +382 -0
- package/dist/convex/agents/bugReportAgent.d.ts +30 -0
- package/dist/convex/agents/bugReportAgent.d.ts.map +1 -0
- package/dist/convex/agents/bugReportAgent.js +243 -0
- package/dist/convex/agents/bugReportAgent.js.map +1 -0
- package/dist/convex/agents/feedbackAgent.d.ts +29 -0
- package/dist/convex/agents/feedbackAgent.d.ts.map +1 -0
- package/dist/convex/agents/feedbackAgent.js +232 -0
- package/dist/convex/agents/feedbackAgent.js.map +1 -0
- package/dist/convex/bugReports.d.ts +49 -0
- package/dist/convex/bugReports.d.ts.map +1 -0
- package/dist/convex/bugReports.js +321 -0
- package/dist/convex/bugReports.js.map +1 -0
- package/dist/convex/convex.config.d.ts +3 -0
- package/dist/convex/convex.config.d.ts.map +1 -0
- package/dist/convex/convex.config.js +6 -0
- package/dist/convex/convex.config.js.map +1 -0
- package/dist/convex/emails/bugReportEmails.d.ts +16 -0
- package/dist/convex/emails/bugReportEmails.d.ts.map +1 -0
- package/dist/convex/emails/bugReportEmails.js +403 -0
- package/dist/convex/emails/bugReportEmails.js.map +1 -0
- package/dist/convex/emails/feedbackEmails.d.ts +16 -0
- package/dist/convex/emails/feedbackEmails.d.ts.map +1 -0
- package/dist/convex/emails/feedbackEmails.js +389 -0
- package/dist/convex/emails/feedbackEmails.js.map +1 -0
- package/dist/convex/feedback.d.ts +49 -0
- package/dist/convex/feedback.d.ts.map +1 -0
- package/dist/convex/feedback.js +327 -0
- package/dist/convex/feedback.js.map +1 -0
- package/dist/convex/index.d.ts +10 -0
- package/dist/convex/index.d.ts.map +1 -0
- package/dist/convex/index.js +12 -0
- package/dist/convex/index.js.map +1 -0
- package/dist/convex/schema.d.ts +200 -0
- package/dist/convex/schema.d.ts.map +1 -0
- package/dist/convex/schema.js +150 -0
- package/dist/convex/schema.js.map +1 -0
- package/dist/convex/supportTeams.d.ts +29 -0
- package/dist/convex/supportTeams.d.ts.map +1 -0
- package/dist/convex/supportTeams.js +159 -0
- package/dist/convex/supportTeams.js.map +1 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/react/BugReportButton.d.ts +70 -0
- package/dist/react/BugReportButton.d.ts.map +1 -0
- package/dist/react/BugReportButton.js +371 -0
- package/dist/react/BugReportButton.js.map +1 -0
- package/dist/react/BugReportContext.d.ts +59 -0
- package/dist/react/BugReportContext.d.ts.map +1 -0
- package/dist/react/BugReportContext.js +107 -0
- package/dist/react/BugReportContext.js.map +1 -0
- package/dist/react/index.d.ts +36 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +36 -0
- package/dist/react/index.js.map +1 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +101 -0
- package/src/convex/agents/bugReportAgent.ts +277 -0
- package/src/convex/agents/feedbackAgent.ts +264 -0
- package/src/convex/bugReports.ts +350 -0
- package/src/convex/convex.config.ts +7 -0
- package/src/convex/emails/bugReportEmails.ts +479 -0
- package/src/convex/emails/feedbackEmails.ts +465 -0
- package/src/convex/feedback.ts +356 -0
- package/src/convex/index.ts +28 -0
- package/src/convex/schema.ts +207 -0
- package/src/convex/supportTeams.ts +179 -0
- package/src/index.ts +77 -0
- package/src/react/BugReportButton.tsx +755 -0
- package/src/react/BugReportContext.tsx +146 -0
- package/src/react/index.ts +46 -0
- package/src/types.ts +93 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug Report Email Notifications
|
|
3
|
+
*
|
|
4
|
+
* Sends email notifications using Resend when bug reports are analyzed.
|
|
5
|
+
* - Reporter receives a thank-you email with summary
|
|
6
|
+
* - Team members receive full analysis report
|
|
7
|
+
*/
|
|
8
|
+
import { v } from "convex/values";
|
|
9
|
+
import { internalAction, internalQuery } from "../_generated/server";
|
|
10
|
+
import { internal } from "../_generated/api";
|
|
11
|
+
import { Resend } from "resend";
|
|
12
|
+
// Severity labels and colors
|
|
13
|
+
const severityConfig = {
|
|
14
|
+
low: { label: "Low", color: "#22c55e" },
|
|
15
|
+
medium: { label: "Medium", color: "#f59e0b" },
|
|
16
|
+
high: { label: "High", color: "#ea580c" },
|
|
17
|
+
critical: { label: "Critical", color: "#ef4444" },
|
|
18
|
+
};
|
|
19
|
+
// Effort labels
|
|
20
|
+
const effortLabels = {
|
|
21
|
+
low: "Low (< 1 week)",
|
|
22
|
+
medium: "Medium (1-4 weeks)",
|
|
23
|
+
high: "High (> 4 weeks)",
|
|
24
|
+
};
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Internal Queries
|
|
27
|
+
// ============================================================================
|
|
28
|
+
/**
|
|
29
|
+
* Get full bug report data for email
|
|
30
|
+
*/
|
|
31
|
+
export const getBugReportForEmail = internalQuery({
|
|
32
|
+
args: {
|
|
33
|
+
reportId: v.id("bugReports"),
|
|
34
|
+
},
|
|
35
|
+
returns: v.union(v.object({
|
|
36
|
+
_id: v.id("bugReports"),
|
|
37
|
+
title: v.string(),
|
|
38
|
+
description: v.string(),
|
|
39
|
+
severity: v.string(),
|
|
40
|
+
status: v.string(),
|
|
41
|
+
reporterName: v.string(),
|
|
42
|
+
reporterEmail: v.string(),
|
|
43
|
+
url: v.string(),
|
|
44
|
+
consoleErrors: v.optional(v.string()),
|
|
45
|
+
createdAt: v.number(),
|
|
46
|
+
}), v.null()),
|
|
47
|
+
handler: async (ctx, args) => {
|
|
48
|
+
const report = await ctx.db.get(args.reportId);
|
|
49
|
+
if (!report) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
_id: report._id,
|
|
54
|
+
title: report.title,
|
|
55
|
+
description: report.description,
|
|
56
|
+
severity: report.severity,
|
|
57
|
+
status: report.status,
|
|
58
|
+
reporterName: report.reporterName,
|
|
59
|
+
reporterEmail: report.reporterEmail,
|
|
60
|
+
url: report.url,
|
|
61
|
+
consoleErrors: report.consoleErrors,
|
|
62
|
+
createdAt: report.createdAt,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// Email Templates
|
|
68
|
+
// ============================================================================
|
|
69
|
+
function generateReporterEmailHtml(report) {
|
|
70
|
+
return `
|
|
71
|
+
<!DOCTYPE html>
|
|
72
|
+
<html>
|
|
73
|
+
<head>
|
|
74
|
+
<meta charset="utf-8">
|
|
75
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
76
|
+
<title>Thank You for Your Bug Report</title>
|
|
77
|
+
</head>
|
|
78
|
+
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
79
|
+
<div style="background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
|
80
|
+
<h1 style="color: white; margin: 0; font-size: 24px;">Thank You for Your Bug Report!</h1>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div style="background: #f8f9fa; padding: 30px; border: 1px solid #e9ecef; border-top: none; border-radius: 0 0 10px 10px;">
|
|
84
|
+
<p style="margin-top: 0;">Hi ${report.reporterName},</p>
|
|
85
|
+
|
|
86
|
+
<p>Thank you for reporting this issue. We've received your bug report and our team is already investigating.</p>
|
|
87
|
+
|
|
88
|
+
<div style="background: white; padding: 20px; border-radius: 8px; border-left: 4px solid #ef4444; margin: 20px 0;">
|
|
89
|
+
<h3 style="margin: 0 0 10px 0; color: #ef4444;">${report.title}</h3>
|
|
90
|
+
<p style="margin: 0; color: #666;">${report.summary}</p>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<p>We take all bug reports seriously and will work to resolve this issue as quickly as possible. You may receive updates as we make progress.</p>
|
|
94
|
+
|
|
95
|
+
<p style="margin-bottom: 0;">Best regards,<br><strong>The Support Team</strong></p>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div style="text-align: center; padding: 20px; color: #999; font-size: 12px;">
|
|
99
|
+
<p>This is an automated message. Please do not reply directly to this email.</p>
|
|
100
|
+
</div>
|
|
101
|
+
</body>
|
|
102
|
+
</html>
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
function generateTeamEmailHtml(report, analysis) {
|
|
106
|
+
const severityInfo = severityConfig[report.severity] || severityConfig.medium;
|
|
107
|
+
const effortLabel = effortLabels[analysis.estimatedEffort] || analysis.estimatedEffort;
|
|
108
|
+
const submittedDate = new Date(report.createdAt).toLocaleString();
|
|
109
|
+
const reproductionStepsHtml = analysis.reproductionSteps
|
|
110
|
+
.map((step) => `<li style="margin-bottom: 8px;">${step}</li>`)
|
|
111
|
+
.join("");
|
|
112
|
+
let consoleErrorsHtml = "";
|
|
113
|
+
if (report.consoleErrors) {
|
|
114
|
+
try {
|
|
115
|
+
const errors = JSON.parse(report.consoleErrors);
|
|
116
|
+
if (Array.isArray(errors) && errors.length > 0) {
|
|
117
|
+
const errorItems = errors
|
|
118
|
+
.slice(0, 10)
|
|
119
|
+
.map((err) => `<li style="margin-bottom: 4px; font-family: monospace; font-size: 12px; word-break: break-all;">${typeof err === 'string' ? err : err.message || JSON.stringify(err)}</li>`)
|
|
120
|
+
.join("");
|
|
121
|
+
consoleErrorsHtml = `
|
|
122
|
+
<div style="background: #fef2f2; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
|
|
123
|
+
<h3 style="margin: 0 0 10px 0; color: #991b1b; font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px;">🔴 Console Errors</h3>
|
|
124
|
+
<ul style="margin: 0; padding-left: 20px; color: #333;">
|
|
125
|
+
${errorItems}
|
|
126
|
+
</ul>
|
|
127
|
+
</div>`;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Invalid JSON, skip console errors section
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return `
|
|
135
|
+
<!DOCTYPE html>
|
|
136
|
+
<html>
|
|
137
|
+
<head>
|
|
138
|
+
<meta charset="utf-8">
|
|
139
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
140
|
+
<title>New Bug Report Analysis</title>
|
|
141
|
+
</head>
|
|
142
|
+
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; line-height: 1.6; color: #333; max-width: 700px; margin: 0 auto; padding: 20px; background: #f5f5f5;">
|
|
143
|
+
<div style="background: white; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); overflow: hidden;">
|
|
144
|
+
<!-- Header -->
|
|
145
|
+
<div style="background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); padding: 25px 30px;">
|
|
146
|
+
<h1 style="color: white; margin: 0; font-size: 22px;">New Bug Report Received</h1>
|
|
147
|
+
<p style="color: rgba(255,255,255,0.9); margin: 10px 0 0 0; font-size: 14px;">AI-Analyzed Bug Report</p>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<!-- Content -->
|
|
151
|
+
<div style="padding: 30px;">
|
|
152
|
+
<!-- Title & Severity Badge -->
|
|
153
|
+
<div style="margin-bottom: 25px;">
|
|
154
|
+
<h2 style="margin: 0 0 10px 0; color: #1a1a2e;">${report.title}</h2>
|
|
155
|
+
<span style="display: inline-block; background: ${severityInfo.color}; color: white; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600;">
|
|
156
|
+
${severityInfo.label} Severity
|
|
157
|
+
</span>
|
|
158
|
+
<span style="display: inline-block; background: #e0e7ff; color: #4338ca; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600; margin-left: 8px;">
|
|
159
|
+
${effortLabel}
|
|
160
|
+
</span>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<!-- AI Summary -->
|
|
164
|
+
<div style="background: #f0f4ff; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
|
|
165
|
+
<h3 style="margin: 0 0 10px 0; color: #4338ca; font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px;">📋 AI Summary</h3>
|
|
166
|
+
<p style="margin: 0; color: #333;">${analysis.summary}</p>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<!-- Root Cause Analysis -->
|
|
170
|
+
<div style="background: #fff7ed; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
|
|
171
|
+
<h3 style="margin: 0 0 10px 0; color: #c2410c; font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px;">🔍 Root Cause Analysis</h3>
|
|
172
|
+
<p style="margin: 0; color: #333;">${analysis.rootCauseAnalysis}</p>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<!-- Reproduction Steps -->
|
|
176
|
+
<div style="background: #fefce8; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
|
|
177
|
+
<h3 style="margin: 0 0 15px 0; color: #854d0e; font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px;">🔄 Reproduction Steps</h3>
|
|
178
|
+
<ol style="margin: 0; padding-left: 20px; color: #333;">
|
|
179
|
+
${reproductionStepsHtml}
|
|
180
|
+
</ol>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<!-- Suggested Fix -->
|
|
184
|
+
<div style="background: #f0fdf4; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
|
|
185
|
+
<h3 style="margin: 0 0 10px 0; color: #166534; font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px;">💡 Suggested Fix</h3>
|
|
186
|
+
<p style="margin: 0; color: #333;">${analysis.suggestedFix}</p>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
${consoleErrorsHtml}
|
|
190
|
+
|
|
191
|
+
<!-- Original Bug Description -->
|
|
192
|
+
<div style="border: 1px solid #e5e7eb; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
|
|
193
|
+
<h3 style="margin: 0 0 10px 0; color: #6b7280; font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px;">📝 Original Bug Description</h3>
|
|
194
|
+
<p style="margin: 0; color: #333; white-space: pre-wrap;">${report.description}</p>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<!-- Reporter Info -->
|
|
198
|
+
<div style="background: #f9fafb; padding: 15px 20px; border-radius: 8px; font-size: 14px;">
|
|
199
|
+
<table style="width: 100%; border-collapse: collapse;">
|
|
200
|
+
<tr>
|
|
201
|
+
<td style="padding: 5px 0; color: #6b7280;"><strong>Reporter:</strong></td>
|
|
202
|
+
<td style="padding: 5px 0;">${report.reporterName}</td>
|
|
203
|
+
</tr>
|
|
204
|
+
<tr>
|
|
205
|
+
<td style="padding: 5px 0; color: #6b7280;"><strong>Email:</strong></td>
|
|
206
|
+
<td style="padding: 5px 0;"><a href="mailto:${report.reporterEmail}" style="color: #4338ca;">${report.reporterEmail}</a></td>
|
|
207
|
+
</tr>
|
|
208
|
+
<tr>
|
|
209
|
+
<td style="padding: 5px 0; color: #6b7280;"><strong>Submitted:</strong></td>
|
|
210
|
+
<td style="padding: 5px 0;">${submittedDate}</td>
|
|
211
|
+
</tr>
|
|
212
|
+
<tr>
|
|
213
|
+
<td style="padding: 5px 0; color: #6b7280;"><strong>Page URL:</strong></td>
|
|
214
|
+
<td style="padding: 5px 0;"><a href="${report.url}" style="color: #4338ca; word-break: break-all;">${report.url}</a></td>
|
|
215
|
+
</tr>
|
|
216
|
+
</table>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<div style="text-align: center; padding: 20px; color: #999; font-size: 12px;">
|
|
222
|
+
<p>This analysis was generated by AI. Please review and verify before taking action.</p>
|
|
223
|
+
</div>
|
|
224
|
+
</body>
|
|
225
|
+
</html>
|
|
226
|
+
`;
|
|
227
|
+
}
|
|
228
|
+
function generateSimpleTeamEmailHtml(report) {
|
|
229
|
+
const severityInfo = severityConfig[report.severity] || severityConfig.medium;
|
|
230
|
+
const submittedDate = new Date(report.createdAt).toLocaleString();
|
|
231
|
+
return `
|
|
232
|
+
<!DOCTYPE html>
|
|
233
|
+
<html>
|
|
234
|
+
<head>
|
|
235
|
+
<meta charset="utf-8">
|
|
236
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
237
|
+
<title>New Bug Report</title>
|
|
238
|
+
</head>
|
|
239
|
+
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; line-height: 1.6; color: #333; max-width: 700px; margin: 0 auto; padding: 20px; background: #f5f5f5;">
|
|
240
|
+
<div style="background: white; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); overflow: hidden;">
|
|
241
|
+
<div style="background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); padding: 25px 30px;">
|
|
242
|
+
<h1 style="color: white; margin: 0; font-size: 22px;">New Bug Report Received</h1>
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
<div style="padding: 30px;">
|
|
246
|
+
<div style="margin-bottom: 25px;">
|
|
247
|
+
<h2 style="margin: 0 0 10px 0; color: #1a1a2e;">${report.title}</h2>
|
|
248
|
+
<span style="display: inline-block; background: ${severityInfo.color}; color: white; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600;">
|
|
249
|
+
${severityInfo.label} Severity
|
|
250
|
+
</span>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<div style="border: 1px solid #e5e7eb; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
|
|
254
|
+
<h3 style="margin: 0 0 10px 0; color: #6b7280; font-size: 14px;">Description</h3>
|
|
255
|
+
<p style="margin: 0; color: #333; white-space: pre-wrap;">${report.description}</p>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<div style="background: #f9fafb; padding: 15px 20px; border-radius: 8px; font-size: 14px;">
|
|
259
|
+
<table style="width: 100%; border-collapse: collapse;">
|
|
260
|
+
<tr>
|
|
261
|
+
<td style="padding: 5px 0; color: #6b7280;"><strong>Reporter:</strong></td>
|
|
262
|
+
<td style="padding: 5px 0;">${report.reporterName} (${report.reporterEmail})</td>
|
|
263
|
+
</tr>
|
|
264
|
+
<tr>
|
|
265
|
+
<td style="padding: 5px 0; color: #6b7280;"><strong>Submitted:</strong></td>
|
|
266
|
+
<td style="padding: 5px 0;">${submittedDate}</td>
|
|
267
|
+
</tr>
|
|
268
|
+
<tr>
|
|
269
|
+
<td style="padding: 5px 0; color: #6b7280;"><strong>Page URL:</strong></td>
|
|
270
|
+
<td style="padding: 5px 0;"><a href="${report.url}" style="color: #4338ca;">${report.url}</a></td>
|
|
271
|
+
</tr>
|
|
272
|
+
</table>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
</body>
|
|
277
|
+
</html>
|
|
278
|
+
`;
|
|
279
|
+
}
|
|
280
|
+
// ============================================================================
|
|
281
|
+
// Email Sending Action
|
|
282
|
+
// ============================================================================
|
|
283
|
+
/**
|
|
284
|
+
* Send bug report notifications to reporter and team.
|
|
285
|
+
*/
|
|
286
|
+
export const sendBugReportNotifications = internalAction({
|
|
287
|
+
args: {
|
|
288
|
+
reportId: v.id("bugReports"),
|
|
289
|
+
analysis: v.union(v.object({
|
|
290
|
+
summary: v.string(),
|
|
291
|
+
rootCauseAnalysis: v.string(),
|
|
292
|
+
reproductionSteps: v.array(v.string()),
|
|
293
|
+
suggestedFix: v.string(),
|
|
294
|
+
estimatedEffort: v.string(),
|
|
295
|
+
}), v.null()),
|
|
296
|
+
},
|
|
297
|
+
returns: v.object({
|
|
298
|
+
success: v.boolean(),
|
|
299
|
+
reporterEmailSent: v.boolean(),
|
|
300
|
+
teamEmailsSent: v.number(),
|
|
301
|
+
error: v.optional(v.string()),
|
|
302
|
+
}),
|
|
303
|
+
handler: async (ctx, args) => {
|
|
304
|
+
// Check for Resend API key
|
|
305
|
+
const resendApiKey = process.env.RESEND_API_KEY;
|
|
306
|
+
if (!resendApiKey) {
|
|
307
|
+
console.warn("RESEND_API_KEY not configured. Skipping email notifications.");
|
|
308
|
+
return {
|
|
309
|
+
success: false,
|
|
310
|
+
reporterEmailSent: false,
|
|
311
|
+
teamEmailsSent: 0,
|
|
312
|
+
error: "RESEND_API_KEY not configured",
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const resend = new Resend(resendApiKey);
|
|
316
|
+
const fromEmail = process.env.RESEND_FROM_EMAIL || "bugs@resend.dev";
|
|
317
|
+
// Get bug report data
|
|
318
|
+
const report = await ctx.runQuery(internal.emails.bugReportEmails.getBugReportForEmail, {
|
|
319
|
+
reportId: args.reportId,
|
|
320
|
+
});
|
|
321
|
+
if (!report) {
|
|
322
|
+
return {
|
|
323
|
+
success: false,
|
|
324
|
+
reporterEmailSent: false,
|
|
325
|
+
teamEmailsSent: 0,
|
|
326
|
+
error: "Bug report not found",
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
let reporterEmailSent = false;
|
|
330
|
+
let teamEmailsSent = 0;
|
|
331
|
+
// Send email to reporter
|
|
332
|
+
try {
|
|
333
|
+
const summary = args.analysis?.summary || "We are investigating your report.";
|
|
334
|
+
const reporterHtml = generateReporterEmailHtml({
|
|
335
|
+
title: report.title,
|
|
336
|
+
summary,
|
|
337
|
+
reporterName: report.reporterName,
|
|
338
|
+
});
|
|
339
|
+
await resend.emails.send({
|
|
340
|
+
from: fromEmail,
|
|
341
|
+
to: [report.reporterEmail],
|
|
342
|
+
subject: `Thank you for your bug report: ${report.title}`,
|
|
343
|
+
html: reporterHtml,
|
|
344
|
+
});
|
|
345
|
+
reporterEmailSent = true;
|
|
346
|
+
console.log(`Reporter email sent to ${report.reporterEmail}`);
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
console.error("Failed to send reporter email:", error);
|
|
350
|
+
}
|
|
351
|
+
// Get teams that handle this bug report severity
|
|
352
|
+
const teams = await ctx.runQuery(internal.supportTeams.getTeamsForBugReportSeverity, {
|
|
353
|
+
severity: report.severity,
|
|
354
|
+
});
|
|
355
|
+
// Generate team email HTML
|
|
356
|
+
const teamHtml = args.analysis
|
|
357
|
+
? generateTeamEmailHtml({
|
|
358
|
+
title: report.title,
|
|
359
|
+
description: report.description,
|
|
360
|
+
severity: report.severity,
|
|
361
|
+
reporterName: report.reporterName,
|
|
362
|
+
reporterEmail: report.reporterEmail,
|
|
363
|
+
url: report.url,
|
|
364
|
+
consoleErrors: report.consoleErrors,
|
|
365
|
+
createdAt: report.createdAt,
|
|
366
|
+
}, args.analysis)
|
|
367
|
+
: generateSimpleTeamEmailHtml({
|
|
368
|
+
title: report.title,
|
|
369
|
+
description: report.description,
|
|
370
|
+
severity: report.severity,
|
|
371
|
+
reporterName: report.reporterName,
|
|
372
|
+
reporterEmail: report.reporterEmail,
|
|
373
|
+
url: report.url,
|
|
374
|
+
createdAt: report.createdAt,
|
|
375
|
+
});
|
|
376
|
+
// Send email to all team members from all matching teams
|
|
377
|
+
for (const team of teams) {
|
|
378
|
+
if (team.isActive && team.memberEmails.length > 0) {
|
|
379
|
+
for (const email of team.memberEmails) {
|
|
380
|
+
try {
|
|
381
|
+
await resend.emails.send({
|
|
382
|
+
from: fromEmail,
|
|
383
|
+
to: [email],
|
|
384
|
+
subject: `[Bug Report - ${severityConfig[report.severity]?.label || report.severity}] ${report.title}${args.analysis ? " - AI Analysis" : ""}`,
|
|
385
|
+
html: teamHtml,
|
|
386
|
+
});
|
|
387
|
+
teamEmailsSent++;
|
|
388
|
+
console.log(`Team email sent to ${email}`);
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
console.error(`Failed to send team email to ${email}:`, error);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return {
|
|
397
|
+
success: true,
|
|
398
|
+
reporterEmailSent,
|
|
399
|
+
teamEmailsSent,
|
|
400
|
+
};
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
//# sourceMappingURL=bugReportEmails.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bugReportEmails.js","sourceRoot":"","sources":["../../../src/convex/emails/bugReportEmails.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feedback Email Notifications
|
|
3
|
+
*
|
|
4
|
+
* Sends email notifications using Resend when feedback is analyzed.
|
|
5
|
+
* - Reporter receives a thank-you email with summary
|
|
6
|
+
* - Team members receive full analysis report
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Get full feedback data for email
|
|
10
|
+
*/
|
|
11
|
+
export declare const getFeedbackForEmail: any;
|
|
12
|
+
/**
|
|
13
|
+
* Send feedback notifications to reporter and team.
|
|
14
|
+
*/
|
|
15
|
+
export declare const sendFeedbackNotifications: any;
|
|
16
|
+
//# sourceMappingURL=feedbackEmails.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedbackEmails.d.ts","sourceRoot":"","sources":["../../../src/convex/emails/feedbackEmails.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiCH;;GAEG;AACH,eAAO,MAAM,mBAAmB,KAqC9B,CAAC;AA2OH;;GAEG;AACH,eAAO,MAAM,yBAAyB,KAmJpC,CAAC"}
|