Skip to content

Commit f556c5f

Browse files
Justin322322KishonShrill
authored andcommitted
refactor: replace GitHub integration with email-based reporting
- Remove GitHub API integration and token requirement - Implement email-based reporting using MailChannels - Send reports to [email protected] - Make reporter email optional for anonymous reporting - Simplify UI by removing 'Open in GitHub' button - Add fallback console logging if email fails - Update error messages to be more user-friendly
1 parent f558bb7 commit f556c5f

File tree

2 files changed

+72
-177
lines changed

2 files changed

+72
-177
lines changed

functions/api/report-hotline.ts

Lines changed: 64 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -74,163 +74,99 @@ export async function onRequest(context: {
7474
);
7575
}
7676

77-
// Create GitHub issue via API
78-
const githubToken = env.GITHUB_TOKEN;
79-
if (!githubToken) {
80-
return new Response(
81-
JSON.stringify({
82-
error: 'GitHub integration not configured',
83-
fallback:
84-
'Please report directly at https://github.com/bettergovph/bettergov/issues/new',
85-
}),
86-
{
87-
status: 503,
88-
headers: { 'Content-Type': 'application/json' },
89-
}
90-
);
91-
}
92-
93-
// Log report submission (no PII)
77+
// Log report submission (no PII in logs)
9478
console.log(
95-
`[Report Submission] Creating issue for hotline: "${data.hotlineName}"`
79+
`[Report Submission] Received report for hotline: "${data.hotlineName}"`
9680
);
9781

98-
// Construct issue body (NO PII included)
99-
const issueBody = `## Hotline Information Issue
82+
// Construct email body
83+
const emailBody = `
84+
New Hotline Report Submission
85+
=============================
10086
101-
### Which hotline has outdated information?
102-
${data.hotlineName}
87+
Hotline Name: ${data.hotlineName}
10388
104-
### What is incorrect?
89+
What is incorrect:
10590
${data.issue}
10691
107-
${data.correctInfo ? `### What should it be?\n${data.correctInfo}\n\n` : ''}
108-
${data.source ? `### Source\n${data.source}\n\n` : ''}
92+
${data.correctInfo ? `What should it be:\n${data.correctInfo}\n\n` : ''}
93+
${data.source ? `Source:\n${data.source}\n\n` : ''}
94+
${data.reporterEmail ? `Reporter Email: ${data.reporterEmail}\n\n` : ''}
10995
---
110-
Reported via API from: /philippines/hotlines
111-
Timestamp: ${new Date().toISOString()}`;
112-
113-
// Create GitHub issue with timeout handling
114-
const controller = new AbortController();
115-
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s timeout
96+
Reported from: /philippines/hotlines
97+
Timestamp: ${new Date().toISOString()}
98+
`.trim();
99+
100+
// Send email using Cloudflare Email Workers (MailChannels)
101+
// This is a free service available on Cloudflare Workers
102+
const emailPayload = {
103+
personalizations: [
104+
{
105+
to: [{ email: '[email protected]', name: 'BetterGov Team' }],
106+
},
107+
],
108+
from: {
109+
110+
name: 'BetterGov Hotline Reporter',
111+
},
112+
subject: `Hotline Report: ${data.hotlineName}`,
113+
content: [
114+
{
115+
type: 'text/plain',
116+
value: emailBody,
117+
},
118+
],
119+
};
116120

117-
let githubResponse: Response;
121+
// Try to send email via MailChannels (free on Cloudflare Workers)
118122
try {
119-
githubResponse = await fetch(
120-
'https://api.github.com/repos/bettergovph/bettergov/issues',
123+
const emailResponse = await fetch(
124+
'https://api.mailchannels.net/tx/v1/send',
121125
{
122126
method: 'POST',
123127
headers: {
124-
Authorization: `Bearer ${githubToken}`,
125128
'Content-Type': 'application/json',
126-
'User-Agent': 'BetterGov-Hotline-Reporter',
127-
Accept: 'application/vnd.github.v3+json',
128129
},
129-
body: JSON.stringify({
130-
title: `Outdated Hotline: ${data.hotlineName}`,
131-
body: issueBody,
132-
labels: ['hotline', 'data-update', 'user-report'],
133-
}),
134-
signal: controller.signal,
130+
body: JSON.stringify(emailPayload),
135131
}
136132
);
137-
} catch (fetchError) {
138-
clearTimeout(timeoutId);
139133

140-
// Handle abort/timeout error
141-
if (fetchError instanceof Error && fetchError.name === 'AbortError') {
142-
console.error('GitHub API request timed out');
143-
return new Response(
144-
JSON.stringify({
145-
error: 'Request timed out',
146-
message: 'GitHub API did not respond in time',
147-
}),
148-
{
149-
status: 504,
150-
headers: { 'Content-Type': 'application/json' },
151-
}
134+
if (!emailResponse.ok) {
135+
const errorText = await emailResponse.text();
136+
console.error(
137+
`Email sending failed (status ${emailResponse.status}):`,
138+
errorText
139+
);
140+
// Don't fail the request - just log it
141+
console.log(
142+
'[Fallback] Report logged to console for manual processing'
152143
);
144+
} else {
145+
console.log('[Report Success] Email sent successfully');
153146
}
154-
155-
// Handle other fetch errors (network issues, etc.)
156-
console.error('GitHub API fetch error:', fetchError);
157-
return new Response(
158-
JSON.stringify({
159-
error: 'Failed to connect to GitHub',
160-
message:
161-
fetchError instanceof Error ? fetchError.message : 'Network error',
162-
}),
163-
{
164-
status: 503,
165-
headers: { 'Content-Type': 'application/json' },
166-
}
167-
);
168-
} finally {
169-
clearTimeout(timeoutId);
170-
}
171-
172-
if (!githubResponse.ok) {
173-
const errorText = await githubResponse.text();
174-
// Log detailed error server-side for debugging
175-
console.error(
176-
`GitHub API error (status ${githubResponse.status}):`,
177-
errorText
178-
);
179-
// Return generic error to client without exposing sensitive details
180-
return new Response(
181-
JSON.stringify({
182-
error: 'Failed to create GitHub issue',
183-
}),
184-
{
185-
status: githubResponse.status,
186-
headers: { 'Content-Type': 'application/json' },
187-
}
188-
);
147+
} catch (emailError) {
148+
console.error('Email sending error:', emailError);
149+
console.log('[Fallback] Report logged to console for manual processing');
189150
}
190151

191-
const githubData: unknown = await githubResponse.json();
192-
193-
// Runtime validation of GitHub response
194-
if (
195-
!githubData ||
196-
typeof githubData !== 'object' ||
197-
!('html_url' in githubData) ||
198-
!('number' in githubData) ||
199-
typeof githubData.html_url !== 'string' ||
200-
typeof githubData.number !== 'number'
201-
) {
202-
console.error(
203-
'Invalid GitHub API response structure:',
204-
JSON.stringify(githubData)
205-
);
206-
return new Response(
207-
JSON.stringify({
208-
error: 'Failed to create GitHub issue',
209-
message: 'Invalid response from GitHub API',
210-
}),
211-
{
212-
status: 500,
213-
headers: { 'Content-Type': 'application/json' },
214-
}
215-
);
216-
}
217-
218-
const issue = {
219-
html_url: githubData.html_url,
220-
number: githubData.number,
221-
};
222-
223-
// Log successful issue creation (no PII)
152+
// Always log the full report to console for backup
224153
console.log(
225-
`[Report Success] GitHub Issue #${issue.number} created for hotline: "${data.hotlineName}"`
154+
'[Report Details]',
155+
JSON.stringify({
156+
hotlineName: data.hotlineName,
157+
issue: data.issue,
158+
correctInfo: data.correctInfo,
159+
source: data.source,
160+
hasEmail: !!data.reporterEmail,
161+
timestamp: new Date().toISOString(),
162+
})
226163
);
227164

165+
// Return success to user regardless of email status
228166
return new Response(
229167
JSON.stringify({
230168
success: true,
231169
message: 'Report submitted successfully',
232-
issueUrl: issue.html_url,
233-
issueNumber: issue.number,
234170
}),
235171
{
236172
status: 201,

src/components/ReportHotlineModal.tsx

Lines changed: 8 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FC, useState, useEffect, useRef } from 'react';
2-
import { AlertCircleIcon, XIcon, ExternalLinkIcon } from 'lucide-react';
2+
import { AlertCircleIcon, XIcon } from 'lucide-react';
33

44
interface ReportHotlineModalProps {
55
isOpen: boolean;
@@ -161,8 +161,7 @@ const ReportHotlineModal: FC<ReportHotlineModalProps> = ({
161161
if (response.ok) {
162162
setSubmitStatus({
163163
type: 'success',
164-
message: 'Report submitted successfully!',
165-
issueUrl: data.issueUrl,
164+
message: 'Report submitted successfully! We will review it soon.',
166165
});
167166
// Reset form
168167
setFormData({
@@ -191,13 +190,13 @@ const ReportHotlineModal: FC<ReportHotlineModalProps> = ({
191190
setSubmitStatus({
192191
type: 'error',
193192
message:
194-
'Request timed out. Please check your connection and try again, or report directly on GitHub.',
193+
'Request timed out. Please check your connection and try again.',
195194
});
196195
} else {
197196
setSubmitStatus({
198197
type: 'error',
199198
message:
200-
'Network error. Please try again or report directly on GitHub.',
199+
'Network error. Please try again or contact us at [email protected]',
201200
});
202201
}
203202
} finally {
@@ -208,27 +207,6 @@ const ReportHotlineModal: FC<ReportHotlineModalProps> = ({
208207
}
209208
};
210209

211-
const openGitHubIssue = () => {
212-
const issueTitle = encodeURIComponent('Outdated Hotline Information');
213-
const issueBody = encodeURIComponent(
214-
`## Hotline Information Issue\n\n` +
215-
`### Which hotline has outdated information?\n` +
216-
`${formData.hotlineName || '<!-- Please specify the hotline name -->'}\n\n` +
217-
`### What is incorrect?\n` +
218-
`${formData.issue || '<!-- Describe what information is outdated or incorrect -->'}\n\n` +
219-
`### What should it be?\n` +
220-
`${formData.correctInfo || '<!-- Provide the correct information if you know it -->'}\n\n` +
221-
`### Source (optional)\n` +
222-
`${formData.source || '<!-- Link to official source confirming the correct information -->'}\n\n` +
223-
`---\n` +
224-
`Reported from: /philippines/hotlines`
225-
);
226-
window.open(
227-
`https://github.com/bettergovph/bettergov/issues/new?title=${issueTitle}&body=${issueBody}&labels=hotline,data-update`,
228-
'_blank'
229-
);
230-
};
231-
232210
return (
233211
<div
234212
className='fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4'
@@ -275,17 +253,6 @@ const ReportHotlineModal: FC<ReportHotlineModalProps> = ({
275253
</div>
276254
<h3 className='text-xl font-semibold mb-2'>Thank you!</h3>
277255
<p className='text-gray-600 mb-4'>{submitStatus.message}</p>
278-
{submitStatus.issueUrl && (
279-
<a
280-
href={submitStatus.issueUrl}
281-
target='_blank'
282-
rel='noopener noreferrer'
283-
className='inline-flex items-center text-blue-600 hover:underline'
284-
>
285-
View your report on GitHub
286-
<ExternalLinkIcon className='h-4 w-4 ml-1' />
287-
</a>
288-
)}
289256
<div className='mt-6'>
290257
<button
291258
onClick={onClose}
@@ -299,7 +266,7 @@ const ReportHotlineModal: FC<ReportHotlineModalProps> = ({
299266
<>
300267
<p className='text-gray-600 mb-6'>
301268
Help us keep hotline information accurate and up-to-date. Your
302-
report will be submitted as a GitHub issue.
269+
report will be reviewed by our team.
303270
</p>
304271

305272
{submitStatus.type === 'error' && (
@@ -416,24 +383,16 @@ const ReportHotlineModal: FC<ReportHotlineModalProps> = ({
416383
<button
417384
type='submit'
418385
disabled={isSubmitting}
419-
className='flex-1 px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed'
386+
className='w-full px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed'
420387
>
421388
{isSubmitting ? 'Submitting...' : 'Submit Report'}
422389
</button>
423-
<button
424-
type='button'
425-
onClick={openGitHubIssue}
426-
className='flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors flex items-center justify-center'
427-
>
428-
<ExternalLinkIcon className='h-4 w-4 mr-2' />
429-
Open in GitHub
430-
</button>
431390
</div>
432391
</form>
433392

434393
<p className='text-xs text-gray-500 mt-4 text-center'>
435-
Don&apos;t have a GitHub account? No problem! Use the form above
436-
to submit your report.
394+
Your report will be sent to our team for review. If you provided
395+
an email, we may contact you for clarification.
437396
</p>
438397
</>
439398
)}

0 commit comments

Comments
 (0)