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