Skip to content

Commit 33a448b

Browse files
Copilotaramb-dev
andcommitted
Implement advanced issue reporting components with specialized forms
Co-authored-by: aramb-dev <65731416+aramb-dev@users.noreply.github.com>
1 parent c42bb35 commit 33a448b

File tree

7 files changed

+871
-9
lines changed

7 files changed

+871
-9
lines changed

src/components/UnsupportedFormatHelp.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,46 @@
1-
import { ExternalLink } from "lucide-react";
1+
import React, { useState } from "react";
2+
import { ExternalLink, MessageSquare } from "lucide-react";
23
import { Button } from "./ui/button";
4+
import { ConversionErrorReporter } from "./issue-reporting";
35

46
interface UnsupportedFormatHelpProps {
57
fileName: string;
68
fileType: string;
9+
errorMessage?: string;
10+
cloudConvertJobId?: string;
11+
fileSize?: number;
712
}
813

914
export function UnsupportedFormatHelp({
1015
fileName,
1116
fileType,
17+
errorMessage = "Conversion failed",
18+
cloudConvertJobId,
19+
fileSize,
1220
}: UnsupportedFormatHelpProps) {
21+
const [showReporter, setShowReporter] = useState(false);
22+
1323
const fileExtension =
1424
fileName.split(".").pop()?.toLowerCase() ||
1525
fileType.split("/").pop() ||
1626
"unknown";
1727

28+
if (showReporter) {
29+
return (
30+
<div className="mt-4">
31+
<ConversionErrorReporter
32+
fileName={fileName}
33+
originalFormat={fileExtension}
34+
targetFormat="mp3"
35+
fileSize={fileSize}
36+
cloudConvertJobId={cloudConvertJobId}
37+
errorMessage={errorMessage}
38+
onClose={() => setShowReporter(false)}
39+
/>
40+
</div>
41+
);
42+
}
43+
1844
return (
1945
<div className="mt-4 rounded-lg border border-yellow-300 bg-yellow-50 p-4 dark:border-yellow-800 dark:bg-yellow-950/50">
2046
<h3 className="mb-2 font-medium text-yellow-800 dark:text-yellow-300">
@@ -51,11 +77,10 @@ export function UnsupportedFormatHelp({
5177
variant="outline"
5278
size="sm"
5379
className="text-xs"
54-
onClick={() =>
55-
window.open("https://github.com/aramb-dev/transcriptr", "_blank")
56-
}
80+
onClick={() => setShowReporter(true)}
5781
>
58-
Report Issue <ExternalLink className="ml-1.5 h-3 w-3" />
82+
<MessageSquare className="mr-1.5 h-3 w-3" />
83+
Report Issue
5984
</Button>
6085
</div>
6186
</div>

src/components/feedback/FeedbackModals.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FeedbackForm } from "./FeedbackForm";
33
import { motion, AnimatePresence } from "framer-motion";
44
import { X } from "lucide-react";
55
import { AnimatedBackdrop } from "../ui/animated-backdrop";
6+
import { IssueReportManager } from "../issue-reporting";
67

78
type FeedbackType = "general" | "issue" | "feature";
89

@@ -58,10 +59,14 @@ export function FeedbackModals() {
5859
</button>
5960
</div>
6061

61-
<FeedbackForm
62-
initialType={activeModal}
63-
onClose={() => setActiveModal(null)}
64-
/>
62+
{activeModal === "issue" ? (
63+
<IssueReportManager onClose={() => setActiveModal(null)} />
64+
) : (
65+
<FeedbackForm
66+
initialType={activeModal}
67+
onClose={() => setActiveModal(null)}
68+
/>
69+
)}
6570
</div>
6671
</motion.div>
6772
</AnimatedBackdrop>
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
import React, { useState } from 'react';
2+
import { Button } from '../ui/button';
3+
import { Input } from '../ui/input';
4+
import { Textarea } from '../ui/textarea';
5+
import { Label } from '../ui/label';
6+
import { AlertCircle, CheckCircle2, Send } from 'lucide-react';
7+
import { ConversionErrorData } from './types';
8+
import { generateIssueTemplate, getSystemInfo } from './issue-templates';
9+
10+
interface ConversionErrorReporterProps {
11+
fileName: string;
12+
originalFormat: string;
13+
targetFormat?: string;
14+
fileSize?: number;
15+
cloudConvertJobId?: string;
16+
errorMessage: string;
17+
errorCode?: string;
18+
onClose?: () => void;
19+
}
20+
21+
export function ConversionErrorReporter({
22+
fileName,
23+
originalFormat,
24+
targetFormat = 'mp3',
25+
fileSize,
26+
cloudConvertJobId,
27+
errorMessage,
28+
errorCode,
29+
onClose,
30+
}: ConversionErrorReporterProps) {
31+
const [userName, setUserName] = useState('');
32+
const [userEmail, setUserEmail] = useState('');
33+
const [additionalDetails, setAdditionalDetails] = useState('');
34+
const [isSubmitting, setIsSubmitting] = useState(false);
35+
const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle');
36+
37+
const handleSubmit = async (e: React.FormEvent) => {
38+
e.preventDefault();
39+
setIsSubmitting(true);
40+
setSubmitStatus('idle');
41+
42+
try {
43+
const systemInfo = getSystemInfo();
44+
45+
const issueData: ConversionErrorData = {
46+
type: 'conversion-error',
47+
title: `Conversion Error: ${originalFormat.toUpperCase()}${targetFormat.toUpperCase()}`,
48+
description: additionalDetails || 'User reported conversion error without additional details.',
49+
userEmail: userEmail || undefined,
50+
userName: userName || undefined,
51+
timestamp: systemInfo.timestamp,
52+
userAgent: systemInfo.userAgent,
53+
url: systemInfo.url,
54+
originalFormat,
55+
targetFormat,
56+
fileSize,
57+
fileName,
58+
cloudConvertJobId,
59+
errorMessage,
60+
errorCode,
61+
};
62+
63+
const template = generateIssueTemplate(issueData);
64+
65+
// Create GitHub issue URL with pre-filled template
66+
const githubUrl = new URL('https://github.com/aramb-dev/transcriptr/issues/new');
67+
githubUrl.searchParams.set('title', template.title);
68+
githubUrl.searchParams.set('body', template.body);
69+
githubUrl.searchParams.set('labels', template.labels.join(','));
70+
71+
// Open GitHub in new tab
72+
window.open(githubUrl.toString(), '_blank');
73+
74+
setSubmitStatus('success');
75+
} catch (error) {
76+
console.error('Error creating issue report:', error);
77+
setSubmitStatus('error');
78+
} finally {
79+
setIsSubmitting(false);
80+
}
81+
};
82+
83+
const formatFileSize = (bytes?: number) => {
84+
if (!bytes) return 'Unknown';
85+
const k = 1024;
86+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
87+
const i = Math.floor(Math.log(bytes) / Math.log(k));
88+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
89+
};
90+
91+
if (submitStatus === 'success') {
92+
return (
93+
<div className="w-full max-w-md rounded-lg bg-white p-6 shadow-md dark:bg-gray-800">
94+
<div className="flex items-start rounded-md border border-green-200 bg-green-50 p-4 dark:border-green-700 dark:bg-green-900/30">
95+
<CheckCircle2 className="mt-0.5 mr-3 h-5 w-5 text-green-500 dark:text-green-400" />
96+
<div>
97+
<p className="font-medium text-green-700 dark:text-green-300">
98+
Issue Report Created!
99+
</p>
100+
<p className="mt-1 text-sm text-green-600 dark:text-green-400">
101+
A GitHub issue has been opened with your conversion error details. The development team will investigate this issue.
102+
</p>
103+
</div>
104+
</div>
105+
{onClose && (
106+
<Button onClick={onClose} className="mt-4 w-full">
107+
Close
108+
</Button>
109+
)}
110+
</div>
111+
);
112+
}
113+
114+
return (
115+
<div className="w-full max-w-md rounded-lg bg-white p-6 shadow-md dark:bg-gray-800">
116+
<div className="mb-4 flex items-center">
117+
<AlertCircle className="mr-2 h-5 w-5 text-red-500" />
118+
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
119+
Report Conversion Error
120+
</h2>
121+
</div>
122+
123+
{/* Error Summary */}
124+
<div className="mb-4 rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-700 dark:bg-red-900/30">
125+
<h3 className="font-medium text-red-800 dark:text-red-200 mb-2">Error Details</h3>
126+
<div className="space-y-1 text-sm text-red-700 dark:text-red-300">
127+
<p><strong>File:</strong> {fileName}</p>
128+
<p><strong>Conversion:</strong> {originalFormat.toUpperCase()}{targetFormat.toUpperCase()}</p>
129+
<p><strong>Size:</strong> {formatFileSize(fileSize)}</p>
130+
{cloudConvertJobId && <p><strong>Job ID:</strong> {cloudConvertJobId}</p>}
131+
{errorCode && <p><strong>Error Code:</strong> {errorCode}</p>}
132+
<p><strong>Error:</strong> {errorMessage}</p>
133+
</div>
134+
</div>
135+
136+
<form onSubmit={handleSubmit} className="space-y-4">
137+
<div>
138+
<Label htmlFor="user-name" className="mb-1 block text-sm font-medium">
139+
Name <span className="text-gray-500 font-normal">(optional)</span>
140+
</Label>
141+
<Input
142+
id="user-name"
143+
type="text"
144+
value={userName}
145+
onChange={(e) => setUserName(e.target.value)}
146+
placeholder="Your name"
147+
className="w-full"
148+
/>
149+
</div>
150+
151+
<div>
152+
<Label htmlFor="user-email" className="mb-1 block text-sm font-medium">
153+
Email <span className="text-gray-500 font-normal">(optional)</span>
154+
</Label>
155+
<Input
156+
id="user-email"
157+
type="email"
158+
value={userEmail}
159+
onChange={(e) => setUserEmail(e.target.value)}
160+
placeholder="your.email@example.com"
161+
className="w-full"
162+
/>
163+
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
164+
We'll only use this to follow up on your report if needed.
165+
</p>
166+
</div>
167+
168+
<div>
169+
<Label htmlFor="additional-details" className="mb-1 block text-sm font-medium">
170+
Additional Details <span className="text-gray-500 font-normal">(optional)</span>
171+
</Label>
172+
<Textarea
173+
id="additional-details"
174+
value={additionalDetails}
175+
onChange={(e) => setAdditionalDetails(e.target.value)}
176+
placeholder="Any additional information about what you were trying to do, when the error occurred, or other relevant details..."
177+
className="min-h-[80px] w-full"
178+
/>
179+
</div>
180+
181+
{submitStatus === 'error' && (
182+
<div className="flex items-start rounded-md border border-red-200 bg-red-50 p-3 dark:border-red-700 dark:bg-red-900/30">
183+
<AlertCircle className="mt-0.5 mr-3 h-5 w-5 text-red-500" />
184+
<div>
185+
<p className="font-medium text-red-700 dark:text-red-300">
186+
Failed to create issue report
187+
</p>
188+
<p className="mt-1 text-sm text-red-600 dark:text-red-400">
189+
Please try again or report this issue manually on GitHub.
190+
</p>
191+
</div>
192+
</div>
193+
)}
194+
195+
<div className="flex space-x-2">
196+
{onClose && (
197+
<Button
198+
type="button"
199+
variant="outline"
200+
onClick={onClose}
201+
className="flex-1"
202+
>
203+
Cancel
204+
</Button>
205+
)}
206+
<Button
207+
type="submit"
208+
disabled={isSubmitting}
209+
className={onClose ? "flex-1" : "w-full"}
210+
>
211+
{isSubmitting ? (
212+
<>Submitting...</>
213+
) : (
214+
<>
215+
<Send className="mr-2 h-4 w-4" />
216+
Report Issue
217+
</>
218+
)}
219+
</Button>
220+
</div>
221+
</form>
222+
223+
<div className="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
224+
<p className="text-xs text-gray-500 dark:text-gray-400 text-center">
225+
This will open a GitHub issue with your error details and system information.
226+
</p>
227+
</div>
228+
</div>
229+
);
230+
}

0 commit comments

Comments
 (0)