Skip to content

Commit 5f64248

Browse files
Copilotaramb-dev
andcommitted
Fix code quality issues: readonly props, array keys, unused props, optional chaining, cognitive complexity
Co-authored-by: aramb-dev <65731416+aramb-dev@users.noreply.github.com>
1 parent 33a448b commit 5f64248

4 files changed

Lines changed: 151 additions & 137 deletions

File tree

src/components/ChangelogModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { scaleDown } from "../lib/animations";
55
import { AnimatedBackdrop } from "./ui/animated-backdrop";
66

77
interface ChangelogModalProps {
8-
onClose: () => void;
8+
readonly onClose: () => void;
99
}
1010

1111
export function ChangelogModal({ onClose }: ChangelogModalProps) {

src/components/MobileChangelog.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { motion, AnimatePresence } from "framer-motion";
77
import { changelogItems } from "../data/changelog";
88

99
interface MobileChangelogProps {
10-
isModal?: boolean;
11-
onClose?: () => void;
10+
readonly isModal?: boolean;
11+
readonly onClose?: () => void;
1212
}
1313

1414
export function MobileChangelog({
@@ -148,7 +148,7 @@ export function MobileChangelog({
148148
<div className="space-y-2 px-4 py-3">
149149
{item.changes.new.map((change, changeIndex) => (
150150
<motion.div
151-
key={changeIndex}
151+
key={`${item.version}-new-${change.slice(0, 20)}-${changeIndex}`}
152152
initial={{ opacity: 0, x: -10 }}
153153
animate={{ opacity: 1, x: 0 }}
154154
transition={{ delay: changeIndex * 0.05 }}
@@ -219,7 +219,7 @@ export function MobileChangelog({
219219
{item.changes.improved.map(
220220
(change, changeIndex) => (
221221
<motion.div
222-
key={changeIndex}
222+
key={`${item.version}-improved-${change.slice(0, 20)}-${changeIndex}`}
223223
initial={{ opacity: 0, x: -10 }}
224224
animate={{ opacity: 1, x: 0 }}
225225
transition={{
@@ -287,7 +287,7 @@ export function MobileChangelog({
287287
{item.changes.fixed.map(
288288
(change, changeIndex) => (
289289
<motion.div
290-
key={changeIndex}
290+
key={`${item.version}-fixed-${change.slice(0, 20)}-${changeIndex}`}
291291
initial={{ opacity: 0, x: -10 }}
292292
animate={{ opacity: 1, x: 0 }}
293293
transition={{ delay: changeIndex * 0.05 }}

src/components/UnsupportedFormatHelp.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { Button } from "./ui/button";
44
import { ConversionErrorReporter } from "./issue-reporting";
55

66
interface UnsupportedFormatHelpProps {
7-
fileName: string;
8-
fileType: string;
9-
errorMessage?: string;
10-
cloudConvertJobId?: string;
11-
fileSize?: number;
7+
readonly fileName: string;
8+
readonly fileType: string;
9+
readonly errorMessage?: string;
10+
readonly cloudConvertJobId?: string;
11+
readonly fileSize?: number;
1212
}
1313

1414
export function UnsupportedFormatHelp({

src/components/UploadAudio.tsx

Lines changed: 140 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,16 @@ import { getAllSupportedFormats } from "@/lib/file-format-utils";
1010
import { uploadLargeFile } from "@/lib/storage-service";
1111

1212
interface UploadAudioProps {
13-
onUpload: (
13+
readonly onUpload: (
1414
data:
1515
| FormData
1616
| { audioUrl: string; originalFile?: { name: string; size: number } },
1717
options: { language: string; diarize: boolean },
1818
) => void;
19-
disabled?: boolean;
20-
maxFileSize?: number;
21-
onConversionStart?: () => void;
22-
onConversionComplete?: () => void;
23-
onConversionError?: (error: string) => void;
24-
onApiResponse?: (response: { timestamp: Date; data: unknown }) => void;
19+
readonly onConversionStart?: () => void;
20+
readonly onConversionComplete?: () => void;
21+
readonly onConversionError?: (error: string) => void;
22+
readonly onApiResponse?: (response: { timestamp: Date; data: unknown }) => void;
2523
}
2624

2725
// --- URL Validation Helpers (can be moved to a util file if needed elsewhere) ---
@@ -86,7 +84,7 @@ export function UploadAudio({
8684
const handleFileChange = useCallback(
8785
(e: React.ChangeEvent<HTMLInputElement>) => {
8886
handleFileSelect(e); // Let the hook handle validation
89-
if (e.target.files && e.target.files[0]) {
87+
if (e.target.files?.[0]) {
9088
setFile(e.target.files[0]);
9189
setAudioUrl(""); // Clear URL if a file is selected
9290
} else {
@@ -121,126 +119,144 @@ export function UploadAudio({
121119
[],
122120
);
123121

124-
const handleSubmit = useCallback(async () => {
125-
if (activeTab === "file" && file && !fileError) {
126-
// Check if the file requires conversion
127-
if (requiresConversion) {
128-
try {
129-
// Start conversion state IMMEDIATELY before any async operations
130-
onConversionStart?.();
131-
132-
// Log conversion start
133-
onApiResponse?.({
134-
timestamp: new Date(),
135-
data: {
136-
message: `Starting conversion: ${file.name} (${file.type || "unknown type"}) → MP3`,
137-
originalFile: file.name,
138-
originalFormat:
139-
file.name.split(".").pop()?.toLowerCase() || "unknown",
140-
targetFormat: "mp3",
141-
fileSize: file.size,
142-
},
143-
});
144-
145-
// Add a small delay to ensure state updates are processed
146-
await new Promise((resolve) => setTimeout(resolve, 100));
147-
148-
// First upload the file to Firebase to get a public URL
149-
onApiResponse?.({
150-
timestamp: new Date(),
151-
data: {
152-
message: `Uploading ${file.name} to Firebase for conversion...`,
153-
},
154-
});
155-
156-
const uploadResult = await uploadLargeFile(file);
157-
158-
onApiResponse?.({
159-
timestamp: new Date(),
160-
data: {
161-
message: `File uploaded successfully`,
162-
firebaseUrl: uploadResult.url,
163-
firebasePath: uploadResult.path,
164-
},
165-
});
166-
167-
const fileExtension = file.name.split(".").pop()?.toLowerCase() || "";
168-
169-
// Call conversion endpoint with the uploaded file URL
170-
onApiResponse?.({
171-
timestamp: new Date(),
172-
data: {
173-
message: `Calling CloudConvert API for ${fileExtension.toUpperCase()} → MP3 conversion...`,
174-
},
175-
});
122+
// Helper function to upload file to Firebase
123+
const uploadFileToFirebase = useCallback(async (file: File) => {
124+
onApiResponse?.({
125+
timestamp: new Date(),
126+
data: {
127+
message: `Uploading ${file.name} to Firebase for conversion...`,
128+
},
129+
});
130+
131+
const uploadResult = await uploadLargeFile(file);
132+
133+
onApiResponse?.({
134+
timestamp: new Date(),
135+
data: {
136+
message: `File uploaded successfully`,
137+
firebaseUrl: uploadResult.url,
138+
firebasePath: uploadResult.path,
139+
},
140+
});
141+
142+
return uploadResult;
143+
}, [onApiResponse]);
144+
145+
// Helper function to convert file using CloudConvert
146+
const convertFileToMp3 = useCallback(async (fileUrl: string, originalFile: File) => {
147+
const fileExtension = originalFile.name.split(".").pop()?.toLowerCase() || "";
148+
149+
onApiResponse?.({
150+
timestamp: new Date(),
151+
data: {
152+
message: `Calling CloudConvert API for ${fileExtension.toUpperCase()} → MP3 conversion...`,
153+
},
154+
});
155+
156+
const response = await fetch("/api/convert/cloud", {
157+
method: "POST",
158+
headers: {
159+
"Content-Type": "application/json",
160+
},
161+
body: JSON.stringify({
162+
fileUrl,
163+
originalFormat: fileExtension,
164+
targetFormat: "mp3",
165+
}),
166+
});
167+
168+
if (!response.ok) {
169+
throw new Error(`Conversion failed: ${response.statusText}`);
170+
}
176171

177-
const response = await fetch("/api/convert/cloud", {
178-
method: "POST",
179-
headers: {
180-
"Content-Type": "application/json",
181-
},
182-
body: JSON.stringify({
183-
fileUrl: uploadResult.url,
184-
originalFormat: fileExtension,
185-
targetFormat: "mp3",
186-
}),
187-
});
188-
189-
if (!response.ok) {
190-
throw new Error(`Conversion failed: ${response.statusText}`);
191-
}
192-
193-
const conversionResult = await response.json();
194-
195-
onApiResponse?.({
196-
timestamp: new Date(),
197-
data: {
198-
message: `CloudConvert API response received`,
199-
success: conversionResult.success,
200-
jobId: conversionResult.jobId,
201-
convertedUrl: conversionResult.convertedUrl
202-
? "URL generated"
203-
: "No URL",
204-
},
205-
});
172+
const conversionResult = await response.json();
206173

207-
if (!conversionResult.success) {
208-
throw new Error(conversionResult.error || "Conversion failed");
209-
}
174+
onApiResponse?.({
175+
timestamp: new Date(),
176+
data: {
177+
message: `CloudConvert API response received`,
178+
success: conversionResult.success,
179+
jobId: conversionResult.jobId,
180+
convertedUrl: conversionResult.convertedUrl ? "URL generated" : "No URL",
181+
},
182+
});
210183

211-
onConversionComplete?.();
184+
if (!conversionResult.success) {
185+
throw new Error(conversionResult.error || "Conversion failed");
186+
}
212187

213-
onApiResponse?.({
214-
timestamp: new Date(),
215-
data: {
216-
message: `Conversion completed successfully! Proceeding to transcription...`,
217-
convertedUrl: conversionResult.convertedUrl,
218-
},
219-
});
188+
return conversionResult;
189+
}, [onApiResponse]);
190+
191+
// Helper function to handle conversion errors
192+
const handleConversionError = useCallback((error: unknown) => {
193+
const errorMessage = error instanceof Error ? error.message : "Conversion failed";
194+
195+
onApiResponse?.({
196+
timestamp: new Date(),
197+
data: {
198+
message: `Conversion failed: ${errorMessage}`,
199+
error: errorMessage,
200+
step: "conversion",
201+
},
202+
});
203+
204+
onConversionError?.(errorMessage);
205+
console.error("Conversion error:", error);
206+
}, [onApiResponse, onConversionError]);
207+
208+
// Helper function to handle file conversion workflow
209+
const handleFileConversion = useCallback(async (file: File) => {
210+
onConversionStart?.();
211+
212+
// Log conversion start
213+
onApiResponse?.({
214+
timestamp: new Date(),
215+
data: {
216+
message: `Starting conversion: ${file.name} (${file.type || "unknown type"}) → MP3`,
217+
originalFile: file.name,
218+
originalFormat: file.name.split(".").pop()?.toLowerCase() || "unknown",
219+
targetFormat: "mp3",
220+
fileSize: file.size,
221+
},
222+
});
223+
224+
// Add a small delay to ensure state updates are processed
225+
await new Promise((resolve) => setTimeout(resolve, 100));
226+
227+
// Upload file to Firebase
228+
const uploadResult = await uploadFileToFirebase(file);
229+
230+
// Convert file using CloudConvert
231+
const conversionResult = await convertFileToMp3(uploadResult.url, file);
232+
233+
onConversionComplete?.();
234+
235+
onApiResponse?.({
236+
timestamp: new Date(),
237+
data: {
238+
message: `Conversion completed successfully! Proceeding to transcription...`,
239+
convertedUrl: conversionResult.convertedUrl,
240+
},
241+
});
242+
243+
// Submit converted file for transcription
244+
onUpload(
245+
{
246+
audioUrl: conversionResult.convertedUrl,
247+
originalFile: { name: file.name, size: file.size },
248+
},
249+
transcriptionOptions,
250+
);
251+
}, [onConversionStart, onApiResponse, onConversionComplete, onUpload, transcriptionOptions, uploadFileToFirebase, convertFileToMp3]);
220252

221-
// Now submit the converted file URL for transcription WITH original file metadata
222-
onUpload(
223-
{
224-
audioUrl: conversionResult.convertedUrl,
225-
originalFile: { name: file.name, size: file.size },
226-
},
227-
transcriptionOptions,
228-
);
253+
const handleSubmit = useCallback(async () => {
254+
if (activeTab === "file" && file && !fileError) {
255+
if (requiresConversion) {
256+
try {
257+
await handleFileConversion(file);
229258
} catch (error) {
230-
const errorMessage =
231-
error instanceof Error ? error.message : "Conversion failed";
232-
233-
onApiResponse?.({
234-
timestamp: new Date(),
235-
data: {
236-
message: `Conversion failed: ${errorMessage}`,
237-
error: errorMessage,
238-
step: "conversion",
239-
},
240-
});
241-
242-
onConversionError?.(errorMessage);
243-
console.error("Conversion error:", error);
259+
handleConversionError(error);
244260
}
245261
} else {
246262
// File doesn't need conversion, proceed normally
@@ -261,11 +277,9 @@ export function UploadAudio({
261277
audioUrl,
262278
isUrlPotentiallyValid,
263279
onUpload,
264-
onConversionStart,
265-
onConversionComplete,
266-
onConversionError,
267-
onApiResponse,
268280
transcriptionOptions,
281+
handleFileConversion,
282+
handleConversionError,
269283
]);
270284

271285
const handleResetFile = useCallback(() => {

0 commit comments

Comments
 (0)