@reidbuilds/slop 0.2.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.
Files changed (62) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/.firebaserc +5 -0
  3. package/README.md +73 -0
  4. package/cli/analyzer.js +150 -0
  5. package/cli/index.js +182 -0
  6. package/cli/learner.js +156 -0
  7. package/cli/reporter.js +126 -0
  8. package/cli/scanner.js +45 -0
  9. package/ff-slop.md +27 -0
  10. package/firebase.json +16 -0
  11. package/functions/index.js +30 -0
  12. package/functions/package-lock.json +2755 -0
  13. package/functions/package.json +12 -0
  14. package/hardcoresyn-slop.md +1887 -0
  15. package/package.json +17 -0
  16. package/slop-index/catches.jsonl +590 -0
  17. package/slop-index/patterns/001-hallucinated-imports.md +39 -0
  18. package/slop-index/patterns/002-comment-restatement.md +53 -0
  19. package/slop-index/patterns/003-unnecessary-abstraction.md +56 -0
  20. package/slop-index/patterns/004-unused-imports.md +41 -0
  21. package/slop-index/patterns/005-hardcoded-config.md +49 -0
  22. package/slop-index/patterns/006-deprecated-api-confidence.md +52 -0
  23. package/slop-index/patterns/007-try-catch-everything.md +63 -0
  24. package/slop-index/patterns/008-generic-variable-names.md +49 -0
  25. package/slop-index/patterns/009-stub-with-shell.md +61 -0
  26. package/slop-index/patterns/010-async-misuse.md +64 -0
  27. package/slop-index/patterns/011-console-log-left-in.md +53 -0
  28. package/slop-index/patterns/012-over-engineered-simple.md +64 -0
  29. package/slop-index/patterns/013-emoji-debugging.md +44 -0
  30. package/slop-index/patterns/014-fake-async-simulation.md +71 -0
  31. package/slop-index/patterns/015-credential-fallbacks.md +51 -0
  32. package/slop-index/patterns/016-mock-data-pollution.md +75 -0
  33. package/slop-index/proposed/.gitkeep +0 -0
  34. package/slop-index/proposed/017-emoji-progress-logging.md +44 -0
  35. package/slop-index/proposed/018-test-credentials-in-fallbacks.md +54 -0
  36. package/slop-index/proposed/019-fake-loading-simulation.md +75 -0
  37. package/slop-index/proposed/020-configuration-debugging-left-in.md +53 -0
  38. package/slop-index/proposed/021-emoji-production-logging.md +42 -0
  39. package/slop-index/proposed/022-fake-delay-simulation.md +70 -0
  40. package/slop-index/proposed/023-credential-hardcoding-with-fallbacks.md +57 -0
  41. package/slop-index/proposed/024-repetitive-error-pattern.md +76 -0
  42. package/slop-index/proposed/025-environment-specific-fallbacks.md +55 -0
  43. package/slop-index/proposed/026-emoji-production-logs.md +46 -0
  44. package/slop-index/proposed/027-credentials-in-debug-logs.md +48 -0
  45. package/slop-index/proposed/028-repetitive-service-wrappers.md +59 -0
  46. package/slop-index/proposed/029-forced-non-null-assertions.md +59 -0
  47. package/slop-index/proposed/030-production-credential-fallbacks.md +51 -0
  48. package/slop-index/proposed/031-fake-version-confidence.md +50 -0
  49. package/slop-index/proposed/032-forced-non-null-assertions.md +53 -0
  50. package/slop-index/proposed/033-emoji-production-logs.md +44 -0
  51. package/slop-index/proposed/034-realistic-mock-data-leakage.md +62 -0
  52. package/slop-index/proposed/035-production-credential-exposure.md +43 -0
  53. package/slop-index/proposed/036-identical-wrapper-proliferation.md +53 -0
  54. package/slop-index/proposed/037-forced-null-assertions.md +50 -0
  55. package/slop-index/proposed/038-emoji-production-logging.md +42 -0
  56. package/slop-index/proposed/039-fake-delay-operations.md +52 -0
  57. package/slop-index/proposed/040-forced-null-assertion-chains.md +45 -0
  58. package/slop-index/proposed/041-production-debug-configuration.md +45 -0
  59. package/slop-index/proposed/042-repetitive-firebase-wrappers.md +51 -0
  60. package/slop-index/proposed/043-hardcoded-process-timeouts.md +48 -0
  61. package/slop-index/proposed/044-fictional-package-versions.md +37 -0
  62. package/test-sample.js +89 -0
@@ -0,0 +1,1887 @@
1
+ # Slop Report
2
+
3
+ Generated: 2026-05-20
4
+
5
+ ## vite-env.d.ts
6
+
7
+ ✓ Clean
8
+
9
+ ## main.tsx
10
+
11
+ ✓ Clean
12
+
13
+ ## App.tsx
14
+
15
+ ✓ Clean
16
+
17
+ ## index.ts
18
+
19
+ ### [LOW] generic-variable-names — line 75
20
+
21
+ **Code:** `odiserId: string;`
22
+
23
+ **Issue:** The field name 'odiserId' appears to be a typo or generic placeholder - should likely be 'userId' based on context and other similar fields in the codebase
24
+
25
+ **Fix:** Rename to 'userId: string;' to match the pattern used in other interfaces
26
+
27
+ ## populateSweatStarterTest.ts
28
+
29
+ ### [MEDIUM] console-log-left-in — line 11
30
+
31
+ **Code:** `console.log('🔍 Finding "Sweat Starter Test 1" program...');
32
+ console.log('✓ Found program:', (targetProgram as any).id);
33
+ console.log('🔍 Fetching exercises from library...');
34
+ console.log(`✓ Found ${exercises.length} exercises`);
35
+ console.log(`✓ Created ${workouts.length} workouts`);
36
+ console.log('✅ Successfully populated "Sweat Starter Test 1" program!');
37
+ console.log(` - ${totalWeeks} weeks`);
38
+ console.log(` - ${workoutsPerWeek} workouts per week`);
39
+ console.log(` - ${totalWorkouts} total workouts`);
40
+ console.log(` - 2 exercises per workout`);`
41
+
42
+ **Issue:** Multiple console.log statements throughout the function that appear to be debug/status logging left in production code. While this is a script, these logs clutter output and suggest AI-generated debugging scaffolding.
43
+
44
+ **Fix:** Replace with proper logging using a logger library, or remove if this is truly a one-time script. For scripts, consider using a --verbose flag to control output.
45
+
46
+ ### [LOW] generic-variable-names — line 23
47
+
48
+ **Code:** `programsSnapshot.docs.forEach(doc => {
49
+ const data = doc.data() as any;
50
+ if (data.name === 'Sweat Starter Test 1') {`
51
+
52
+ **Issue:** Generic variable name 'data' used for what is specifically workout program data. This makes the code less readable and is a common AI pattern.
53
+
54
+ **Fix:** const programData = doc.data() as WorkoutProgram;
55
+
56
+ ## videoThumbnail.ts
57
+
58
+ ### [LOW] generic-variable-names — line 11
59
+
60
+ **Code:** `const maxW = options?.maxWidth ?? 1280;`
61
+
62
+ **Issue:** Variable abbreviated to 'maxW' instead of a clear descriptive name in non-trivial video processing context
63
+
64
+ **Fix:** const maxWidth = options?.maxWidth ?? 1280;
65
+
66
+ ### [LOW] generic-variable-names — line 34
67
+
68
+ **Code:** `const dur = video.duration;`
69
+
70
+ **Issue:** Variable abbreviated to 'dur' instead of clear 'duration' in complex video timing logic
71
+
72
+ **Fix:** const duration = video.duration;
73
+
74
+ ### [LOW] generic-variable-names — line 55
75
+
76
+ **Code:** `const vw = video.videoWidth;
77
+ const vh = video.videoHeight;`
78
+
79
+ **Issue:** Variables abbreviated to 'vw' and 'vh' instead of descriptive names in dimension calculation logic
80
+
81
+ **Fix:** const videoWidth = video.videoWidth;
82
+ const videoHeight = video.videoHeight;
83
+
84
+ ### [LOW] generic-variable-names — line 61
85
+
86
+ **Code:** `let dw = vw;
87
+ let dh = vh;`
88
+
89
+ **Issue:** Variables abbreviated to 'dw' and 'dh' instead of descriptive names like 'displayWidth' and 'displayHeight'
90
+
91
+ **Fix:** let displayWidth = videoWidth;
92
+ let displayHeight = videoHeight;
93
+
94
+ ## stripe.ts
95
+
96
+ ### [HIGH] hardcoded-config — line 7
97
+
98
+ **Code:** `const fallbackKey = 'pk_test_51SrKL12EWDoWzTlbooO1c6Y3k1oMpjc2JAk266LPVK6TGgRPthyf4eeGjhFh6lDGeZEz3YxDxDUhQ4wBcnemfU1v00BKalQrEu';`
99
+
100
+ **Issue:** Stripe publishable key hardcoded directly in source code. Even though publishable keys are less sensitive than secret keys, they should still be externalized to avoid version control coupling and environment management issues.
101
+
102
+ **Fix:** Remove hardcoded fallback and require the environment variable: `const STRIPE_PUBLISHABLE_KEY = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY?.trim();` with proper validation that throws if missing.
103
+
104
+ ### [MEDIUM] console-log-left-in — line 21
105
+
106
+ **Code:** `console.log('🔑 Loading Stripe with key:', STRIPE_PUBLISHABLE_KEY.substring(0, 20) + '...');
107
+ console.log('🔑 Key length:', STRIPE_PUBLISHABLE_KEY.length);
108
+ console.log('🔑 Key starts with pk_test_:', STRIPE_PUBLISHABLE_KEY.startsWith('pk_test_'));
109
+ console.log('🔑 Full key (for debugging):', STRIPE_PUBLISHABLE_KEY);`
110
+
111
+ **Issue:** Debug console.log statements left in production code, including one that logs the full Stripe key. While publishable keys are less sensitive, this creates log noise and reveals implementation details in production.
112
+
113
+ **Fix:** Remove debug console.log statements or replace with proper logging: `logger.debug('Initializing Stripe', { keyType: STRIPE_PUBLISHABLE_KEY.startsWith('pk_test_') ? 'test' : 'live' })`
114
+
115
+ ### [HIGH] hardcoded-config — line 45
116
+
117
+ **Code:** `'sweat-starter': import.meta.env.VITE_STRIPE_PRICE_SWEAT_STARTER || 'price_1SuKsG2EWDoWzTlbwUA9bdpb',`
118
+
119
+ **Issue:** Stripe price ID hardcoded as fallback value. Price IDs are environment-specific configuration that should not be embedded in source code.
120
+
121
+ **Fix:** Remove hardcoded fallback: `'sweat-starter': import.meta.env.VITE_STRIPE_PRICE_SWEAT_STARTER,` and validate that required price IDs are configured at startup.
122
+
123
+ ## nutritionUtils.ts
124
+
125
+ ### [MEDIUM] unnecessary-abstraction — line 17
126
+
127
+ **Code:** `export function macroDelta(consumed: number, target: number): {
128
+ pct: number;
129
+ over: boolean;
130
+ under: boolean;
131
+ diff: number;
132
+ label: string;
133
+ } {
134
+ if (target <= 0) {
135
+ return { pct: 0, over: false, under: false, diff: 0, label: '' };
136
+ }
137
+ const pct = Math.round((consumed / target) * 100);
138
+ const diff = consumed - target;
139
+ const over = diff > 0;
140
+ const under = diff < 0;
141
+ const abs = Math.abs(diff);
142
+ let label = 'On target';
143
+ if (over) label = `+${abs} over`;
144
+ else if (under) label = `${abs} under`;
145
+ return { pct, over, under, diff, label };
146
+ }
147
+
148
+ export function macroDeltaGrams(consumed: number, target: number): {
149
+ pct: number;
150
+ over: boolean;
151
+ under: boolean;
152
+ diff: number;
153
+ label: string;
154
+ } {
155
+ if (target <= 0) {
156
+ return { pct: 0, over: false, under: false, diff: 0, label: '' };
157
+ }
158
+ const pct = Math.round((consumed / target) * 100);
159
+ const diff = Math.round((consumed - target) * 10) / 10;
160
+ const over = diff > 0;
161
+ const under = diff < 0;
162
+ const abs = Math.abs(diff);
163
+ let label = 'On target';
164
+ if (over) label = `+${abs}g over`;
165
+ else if (under) label = `${abs}g under`;
166
+ return { pct, over, under, diff, label };
167
+ }`
168
+
169
+ **Issue:** Two nearly identical functions with the same signature and return type, differing only in decimal rounding and adding 'g' to the label. The abstraction creates unnecessary code duplication instead of parameterizing the difference.
170
+
171
+ **Fix:** Combine into a single function with an optional unit parameter: function macroDelta(consumed: number, target: number, unit?: string, precision = 0) and handle rounding/labeling based on the unit parameter.
172
+
173
+ ## firebase.ts
174
+
175
+ ### [HIGH] hardcoded-config — line 6
176
+
177
+ **Code:** ` apiKey: import.meta.env.VITE_FIREBASE_API_KEY || 'AIzaSyB0uWItoUyaozcnjntgG9kck6GJx84GQNY',
178
+ authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN || 'hardcore-synergy.firebaseapp.com',
179
+ projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID || 'hardcore-synergy',
180
+ storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET || 'hardcore-synergy.firebasestorage.app',
181
+ messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID || '277466650255',
182
+ appId: import.meta.env.VITE_FIREBASE_APP_ID || '1:277466650255:web:59e0aeeb3f36c9fde002fa',
183
+ measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID || 'G-NZ20RHHZR9',`
184
+
185
+ **Issue:** Real Firebase API keys and configuration values are hardcoded as fallbacks. This exposes production credentials in source code which will leak via git history and any public repositories.
186
+
187
+ **Fix:** Remove hardcoded fallbacks and fail explicitly when environment variables are missing: apiKey: import.meta.env.VITE_FIREBASE_API_KEY || (() => { throw new Error('VITE_FIREBASE_API_KEY is required') })()
188
+
189
+ ### [MEDIUM] console-log-left-in — line 15
190
+
191
+ **Code:** `console.log('🔥 Firebase Config Debug:');
192
+ console.log(' - API Key:', firebaseConfig.apiKey ? '✓ Set' : '✗ MISSING');
193
+ console.log(' - Auth Domain:', firebaseConfig.authDomain);
194
+ console.log(' - Project ID:', firebaseConfig.projectId);
195
+ console.log(' - Storage Bucket:', firebaseConfig.storageBucket);
196
+ console.log(' - Messaging Sender ID:', firebaseConfig.messagingSenderId ? '✓ Set' : '✗ MISSING');
197
+ console.log(' - App ID:', firebaseConfig.appId ? '✓ Set' : '✗ MISSING');`
198
+
199
+ **Issue:** Debug console.log statements left in production code. These will clutter production logs and potentially expose configuration details in browser console or server logs.
200
+
201
+ **Fix:** Replace with proper logging that can be filtered in production: import { logger } from './logger'; logger.debug('Firebase config status', { hasApiKey: !!firebaseConfig.apiKey, projectId: firebaseConfig.projectId })
202
+
203
+ ### [MEDIUM] console-log-left-in — line 29
204
+
205
+ **Code:** `console.log('✓ Firebase app initialized:', app.name);`
206
+
207
+ **Issue:** Production console.log statement logging Firebase app initialization details.
208
+
209
+ **Fix:** Remove or replace with proper logging: logger.info('Firebase app initialized')
210
+
211
+ ### [MEDIUM] console-log-left-in — line 41
212
+
213
+ **Code:** `console.log('✓ Firebase services initialized (auth, db, storage)');`
214
+
215
+ **Issue:** Production console.log statement logging service initialization details.
216
+
217
+ **Fix:** Remove or replace with proper logging: logger.info('Firebase services initialized')
218
+
219
+ ## coerceFirestoreDate.ts
220
+
221
+ ✓ Clean
222
+
223
+ ## api.ts
224
+
225
+ ### [MEDIUM] console-log-left-in — line 32
226
+
227
+ **Code:** `console.error('Failed to get auth token:', error);`
228
+
229
+ **Issue:** Console.error statement left in production code that logs authentication errors, potentially exposing sensitive information about auth failures
230
+
231
+ **Fix:** Replace with proper logging: logger.error('Failed to get auth token', { error: error.message })
232
+
233
+ ### [MEDIUM] console-log-left-in — line 61
234
+
235
+ **Code:** `console.warn(`API endpoint ${endpoint} returned non-JSON response (${contentType}). This endpoint may not exist.`);`
236
+
237
+ **Issue:** Console.warn statement left in production code that logs API endpoint information and content types, creating noise in production logs
238
+
239
+ **Fix:** Replace with proper logging: logger.warn('API endpoint returned non-JSON response', { endpoint, contentType })
240
+
241
+ ### [MEDIUM] console-log-left-in — line 79
242
+
243
+ **Code:** `console.error(`API call to ${endpoint} failed:`, error);`
244
+
245
+ **Issue:** Console.error statement left in production code that logs API call failures with potentially sensitive endpoint information
246
+
247
+ **Fix:** Replace with proper logging: logger.error('API call failed', { endpoint, error: error.message })
248
+
249
+ ### [MEDIUM] try-catch-everything — line 45
250
+
251
+ **Code:** `try {
252
+ // Get auth token for authenticated requests
253
+ const token = await getAuthToken();
254
+ // ... entire apiCall function body
255
+ } catch (error) {
256
+ console.error(`API call to ${endpoint} failed:`, error);
257
+ return {
258
+ success: false,
259
+ error: error instanceof Error ? error.message : 'An error occurred',
260
+ };
261
+ }`
262
+
263
+ **Issue:** Blanket try-catch around entire function body with generic error handling, masking different types of errors (network, auth, parsing) that might need distinct handling
264
+
265
+ **Fix:** Handle specific error types separately - auth failures, network errors, and JSON parsing errors should be handled with different logic rather than generic catch-all
266
+
267
+ ## useWorkouts.ts
268
+
269
+ ### [MEDIUM] try-catch-everything — line 16
270
+
271
+ **Code:** `try {
272
+ const response = await getWorkoutPrograms();
273
+ if (response.success && response.data) {
274
+ setPrograms(response.data.programs);
275
+ } else {
276
+ setError(response.error || 'Failed to fetch programs');
277
+ }
278
+ } catch (err) {
279
+ setError(err instanceof Error ? err.message : 'Failed to fetch programs');
280
+ }`
281
+
282
+ **Issue:** Generic try/catch with same error handling for both API response errors and network/runtime errors. Both paths set the same generic error message.
283
+
284
+ **Fix:** Handle API response errors separately from network errors, and let authentication/authorization errors propagate to be handled at a higher level
285
+
286
+ ### [MEDIUM] try-catch-everything — line 43
287
+
288
+ **Code:** `try {
289
+ const response = await getClientWorkouts(currentUser.uid, completed);
290
+ if (response.success && response.data) {
291
+ setWorkouts(response.data.workouts);
292
+ } else {
293
+ setError(response.error || 'Failed to fetch workouts');
294
+ }
295
+ } catch (err) {
296
+ setError(err instanceof Error ? err.message : 'Failed to fetch workouts');
297
+ }`
298
+
299
+ **Issue:** Same pattern repeated - generic try/catch that treats all errors the same way with identical error messages for different failure modes.
300
+
301
+ **Fix:** Differentiate between network errors, authentication errors, and API response errors with specific handling for each
302
+
303
+ ### [MEDIUM] try-catch-everything — line 74
304
+
305
+ **Code:** `try {
306
+ const response = await assignWorkoutProgram(currentUser.uid, programId);
307
+ if (response.success) {
308
+ return { success: true, assignmentId: response.data?.assignmentId };
309
+ } else {
310
+ setError(response.error || 'Failed to assign program');
311
+ return { success: false };
312
+ }
313
+ } catch (err) {
314
+ setError(err instanceof Error ? err.message : 'Failed to assign program');
315
+ return { success: false };
316
+ }`
317
+
318
+ **Issue:** Third instance of the same generic error handling pattern - no differentiation between error types that might need different user-facing messages or recovery strategies.
319
+
320
+ **Fix:** Handle specific error cases like network failures, permission errors, and invalid program IDs with appropriate user feedback
321
+
322
+ ### [MEDIUM] try-catch-everything — line 99
323
+
324
+ **Code:** `try {
325
+ const response = await logWorkout(workoutId, log);
326
+ if (response.success) {
327
+ return { success: true, logId: response.data?.logId };
328
+ } else {
329
+ setError(response.error || 'Failed to log workout');
330
+ return { success: false };
331
+ }
332
+ } catch (err) {
333
+ setError(err instanceof Error ? err.message : 'Failed to log workout');
334
+ return { success: false };
335
+ }`
336
+
337
+ **Issue:** Fourth repetition of identical error handling pattern. All four hooks use the exact same try/catch structure with generic fallback messages.
338
+
339
+ **Fix:** Create a shared error handling utility that can distinguish between different error types and provide appropriate responses
340
+
341
+ ## useSweatStarterWorkouts.ts
342
+
343
+ ### [MEDIUM] console-log-left-in — line 69
344
+
345
+ **Code:** `console.error('Failed to listen to program:', error);`
346
+
347
+ **Issue:** Debug console error statements left in production code that will clutter production logs with Firebase listener errors
348
+
349
+ **Fix:** Replace with proper error logging using a logger service or remove if error handling is done elsewhere
350
+
351
+ ### [MEDIUM] console-log-left-in — line 80
352
+
353
+ **Code:** `console.error('Failed to listen to assignments:', error);`
354
+
355
+ **Issue:** Debug console error statements left in production code that will clutter production logs with Firebase listener errors
356
+
357
+ **Fix:** Replace with proper error logging using a logger service or remove if error handling is done elsewhere
358
+
359
+ ### [MEDIUM] console-log-left-in — line 118
360
+
361
+ **Code:** `console.error('Failed to listen to progress:', error);`
362
+
363
+ **Issue:** Debug console error statements left in production code that will clutter production logs with Firebase listener errors
364
+
365
+ **Fix:** Replace with proper error logging using a logger service or remove if error handling is done elsewhere
366
+
367
+ ## useProgress.ts
368
+
369
+ ### [HIGH] async-misuse — line 67
370
+
371
+ **Code:** `const stats = {
372
+ currentWeight: latestEntry?.weight,
373
+ startingWeight: firstEntry?.weight,
374
+ weightChange: latestEntry && previousEntry
375
+ ? latestEntry.weight! - previousEntry.weight!
376
+ : 0,
377
+ totalChange: latestEntry && firstEntry
378
+ ? latestEntry.weight! - firstEntry.weight!
379
+ : 0,
380
+ entriesCount: entries.length,
381
+ averageEnergy: entries.length > 0
382
+ ? entries.reduce((sum, e) => sum + (e.energyLevel || 0), 0) / entries.length
383
+ : 0,
384
+ };`
385
+
386
+ **Issue:** The code uses non-null assertion operator (!) on optional weight properties without checking if they exist, which could cause runtime errors if weight is undefined
387
+
388
+ **Fix:** Replace with proper null checking: latestEntry.weight - previousEntry.weight instead of latestEntry.weight! - previousEntry.weight!, or add explicit undefined checks
389
+
390
+ ## useMealPlans.ts
391
+
392
+ ✓ Clean
393
+
394
+ ## ThemeContext.tsx
395
+
396
+ ✓ Clean
397
+
398
+ ## DemoDataContext.tsx
399
+
400
+ ### [LOW] generic-variable-names — line 102
401
+
402
+ **Code:** `const demoExercises: WorkoutExercise[] = [`
403
+
404
+ **Issue:** Variable name 'demoExercises' uses generic 'demo' prefix when it specifically contains lower body exercises based on the content (hip thrust, deadlift, squats). This makes it unclear when 'upperExercises' is defined later.
405
+
406
+ **Fix:** Rename to 'lowerBodyExercises' or 'gluteExercises' to reflect the actual exercise types
407
+
408
+ ### [MEDIUM] over-engineered-simple — line 75
409
+
410
+ **Code:** `interface DemoDataContextType {
411
+ demoClient: DemoClientData;
412
+ updateDemoClient: (updates: Partial<DemoClientData>) => void;
413
+ assignWorkout: (workout: Workout, scheduledDate: Date) => void;
414
+ assignMealPlan: (mealPlan: MealPlan) => void;
415
+ completeWorkout: (workoutId: string, duration: number) => void;
416
+ logProgress: (entry: Omit<ProgressEntry, 'id' | 'clientId' | 'date'>) => void;
417
+ resetDemoData: () => void;
418
+ }`
419
+
420
+ **Issue:** Complex context interface with multiple specialized methods for what appears to be demo/mock data. This creates unnecessary abstraction layers for demonstration purposes when simpler mock data objects would suffice.
421
+
422
+ **Fix:** Consider using plain mock data objects instead of a full context provider for demo scenarios, or simplify to a single 'updateDemoData' method
423
+
424
+ ## AuthContext.tsx
425
+
426
+ ### [MEDIUM] console-log-left-in — line 24
427
+
428
+ **Code:** `console.log('🔄 Initializing Firebase...');
429
+ // ...
430
+ console.log('✓ Firebase initialized successfully');
431
+ console.log(' - Auth:', auth ? '✓' : '✗');
432
+ console.log(' - Firestore:', db ? '✓' : '✗');
433
+ console.log(' - Google Provider:', googleProvider ? '✓' : '✗');`
434
+
435
+ **Issue:** Multiple console.log statements left in production code that will clutter production logs with implementation details about Firebase initialization status
436
+
437
+ **Fix:** Replace with proper logging using a logger library that can be filtered in production, or remove entirely if not needed for production debugging
438
+
439
+ ### [MEDIUM] console-log-left-in — line 31
440
+
441
+ **Code:** `console.error('❌ Firebase initialization failed:', firebaseError);
442
+ console.error(' Full error:', e);
443
+ console.warn(' Running in demo mode. To fix:');
444
+ console.warn(' 1. Create .env file in project root');
445
+ console.warn(' 2. Add VITE_FIREBASE_API_KEY=your-api-key');
446
+ console.warn(' 3. Restart the dev server');`
447
+
448
+ **Issue:** Console statements providing setup instructions that should not appear in production logs, revealing internal configuration details
449
+
450
+ **Fix:** Move setup instructions to documentation and use proper error logging that can be configured per environment
451
+
452
+ ### [MEDIUM] console-log-left-in — line 139
453
+
454
+ **Code:** `console.log(' 📄 Fetching profile for:', userId);`
455
+
456
+ **Issue:** Debug console.log statement logging user IDs in production, which could expose sensitive user data in logs
457
+
458
+ **Fix:** Remove or replace with proper debug logging that filters out sensitive data in production
459
+
460
+ ### [MEDIUM] console-log-left-in — line 141
461
+
462
+ **Code:** `console.warn(' ⚠️ Firestore not available');`
463
+
464
+ **Issue:** Console warning left in production code that reveals internal state about database availability
465
+
466
+ **Fix:** Use proper error logging or remove if this is expected behavior in demo mode
467
+
468
+ ### [MEDIUM] console-log-left-in — line 161
469
+
470
+ **Code:** `console.log(' 👑 Admin email detected, setting role to admin');`
471
+
472
+ **Issue:** Console.log revealing role assignment logic and potentially sensitive email information in production logs
473
+
474
+ **Fix:** Remove or replace with secure audit logging that doesn't expose role assignment logic in client-side logs
475
+
476
+ ## Skeleton.tsx
477
+
478
+ ✓ Clean
479
+
480
+ ## ProtectedRoute.tsx
481
+
482
+ ### [HIGH] hardcoded-config — line 57
483
+
484
+ **Code:** `const coachedTiers = ['body-blueprint', 'peach-elite'];`
485
+
486
+ **Issue:** Business tier configuration is hardcoded in component logic. Adding new tiers or changing tier names requires code changes rather than config updates.
487
+
488
+ **Fix:** Move tier configuration to environment variables or config file: const coachedTiers = process.env.COACHED_TIERS?.split(',') || ['body-blueprint', 'peach-elite'];
489
+
490
+ ## ProgressBar.tsx
491
+
492
+ ✓ Clean
493
+
494
+ ## PaymentForm.tsx
495
+
496
+ ### [HIGH] hardcoded-config — line 55
497
+
498
+ **Code:** `const FUNCTION_URL = 'https://us-central1-hardcore-synergy.cloudfunctions.net/createSubscription';`
499
+
500
+ **Issue:** Cloud function URL is hardcoded with a specific project ID and deployment region, making this code environment-specific and impossible to deploy to staging/dev without code changes
501
+
502
+ **Fix:** const FUNCTION_URL = process.env.REACT_APP_FUNCTION_URL || process.env.NEXT_PUBLIC_FUNCTION_URL;
503
+
504
+ ### [MEDIUM] try-catch-everything — line 29
505
+
506
+ **Code:** `try {
507
+ const card = elements.getElement(CardElement);
508
+ // ... entire payment flow ...
509
+ } catch (err) {
510
+ const message = err instanceof Error ? err.message : 'An error occurred';
511
+ setError(message);
512
+ onError(message);
513
+ }`
514
+
515
+ **Issue:** Single try-catch wraps the entire payment flow including authentication, payment method creation, backend API call, and payment confirmation. Different error types need distinct handling - auth errors, network errors, and payment failures should be handled differently
516
+
517
+ **Fix:** Handle auth errors separately before try block, catch API errors distinctly from Stripe errors, and let critical errors propagate with specific error types
518
+
519
+ ## PageHeader.tsx
520
+
521
+ ✓ Clean
522
+
523
+ ## NutritionChatWidget.tsx
524
+
525
+ ### [MEDIUM] console-log-left-in — line 74
526
+
527
+ **Code:** `console.log('estimateMacrosClientSide called with:', description, '-> lowercase:', lowerDesc);`
528
+
529
+ **Issue:** Debug console.log statement left in production code that logs internal state and function parameters
530
+
531
+ **Fix:** Remove the console.log statement or replace with proper logging: logger.debug('Estimating macros', { description })
532
+
533
+ ### [MEDIUM] console-log-left-in — line 62
534
+
535
+ **Code:** `console.error('Failed to load chat history:', error);`
536
+
537
+ **Issue:** Console.error statement in production code - should use proper error logging
538
+
539
+ **Fix:** Replace with structured logging: logger.error('Failed to load chat history', { error, userId: currentUser?.uid })
540
+
541
+ ## LoadingSpinner.tsx
542
+
543
+ ✓ Clean
544
+
545
+ ## Layout.tsx
546
+
547
+ ✓ Clean
548
+
549
+ ## Input.tsx
550
+
551
+ ✓ Clean
552
+
553
+ ## ExercisePicker.tsx
554
+
555
+ ### [MEDIUM] console-log-left-in — line 50
556
+
557
+ **Code:** `console.error('Failed to fetch exercises:', error);`
558
+
559
+ **Issue:** Debug console.error statement left in production code that will log full error objects to browser console, potentially exposing internal Firebase configuration or sensitive error details
560
+
561
+ **Fix:** Replace with proper error logging: import a logger and use logger.error('Failed to fetch exercises', { message: error.message }) or remove entirely if error handling is sufficient
562
+
563
+ ## ExerciseCardMedia.tsx
564
+
565
+ ✓ Clean
566
+
567
+ ## EmptyState.tsx
568
+
569
+ ✓ Clean
570
+
571
+ ## Card.tsx
572
+
573
+ ✓ Clean
574
+
575
+ ## Button.tsx
576
+
577
+ ### [HIGH] hallucinated-imports — line 2
578
+
579
+ **Code:** `import LoadingSpinner from './LoadingSpinner';`
580
+
581
+ **Issue:** Imports a component './LoadingSpinner' that is used in the code but may not exist. This is a common AI pattern of importing plausible-sounding components without verifying they exist in the project structure.
582
+
583
+ **Fix:** Verify that './LoadingSpinner' component exists, or replace with an actual loading spinner implementation or a verified component library import like 'import { Spinner } from '@/components/ui/spinner'
584
+
585
+ ## BottomNav.tsx
586
+
587
+ ✓ Clean
588
+
589
+ ## Badge.tsx
590
+
591
+ ✓ Clean
592
+
593
+ ## WorkoutHistory.tsx
594
+
595
+ ### [MEDIUM] console-log-left-in — line 45
596
+
597
+ **Code:** `console.error('Failed to fetch workout history:', error);`
598
+
599
+ **Issue:** Debug console.error statement left in production code that will clutter production logs and potentially leak internal error details
600
+
601
+ **Fix:** Replace with proper logging: logger.error('Failed to fetch workout history', { userId: currentUser.uid, error: error.message })
602
+
603
+ ## WorkoutDetail.tsx
604
+
605
+ ### [MEDIUM] console-log-left-in — line 119
606
+
607
+ **Code:** `console.error('Failed to fetch sweat starter workout:', error);`
608
+
609
+ **Issue:** Debug console statement left in production code that will clutter production logs and potentially leak implementation details about sweat starter workout fetching
610
+
611
+ **Fix:** Replace with proper logging: logger.error('Failed to fetch sweat starter workout', { error: error.message })
612
+
613
+ ### [MEDIUM] console-log-left-in — line 133
614
+
615
+ **Code:** `console.error('Failed to fetch workout:', error);`
616
+
617
+ **Issue:** Debug console statement left in production code that will clutter production logs and potentially leak implementation details about workout fetching
618
+
619
+ **Fix:** Replace with proper logging: logger.error('Failed to fetch workout', { error: error.message })
620
+
621
+ ## WorkoutBrowser.tsx
622
+
623
+ ### [MEDIUM] console-log-left-in — line 87
624
+
625
+ **Code:** `console.error('Failed to fetch workouts:', error);`
626
+
627
+ **Issue:** Debug console statement left in production code that will clutter production logs and potentially expose internal error details
628
+
629
+ **Fix:** Replace with proper logging: logger.error('Failed to fetch workouts', { error: error.message, userId: currentUser.uid })
630
+
631
+ ## TrainerWorkoutTemplates.tsx
632
+
633
+ ### [HIGH] stub-with-shell — line 69
634
+
635
+ **Code:** `const fetchTemplates = async () => {
636
+ setLoading(true);
637
+ await new Promise((r) => setTimeout(r, 500));
638
+ setTemplates(mockTemplates);
639
+ setLoading(false);
640
+ };`
641
+
642
+ **Issue:** Function simulates async data fetching with a hardcoded delay and mock data, but the rest of the component treats it as if it's making real API calls. This will break when integrated with a real backend.
643
+
644
+ **Fix:** Replace with actual API call or make the mock nature explicit: // TODO: Replace with actual API call - see issue #XX
645
+
646
+ ## TrainerWorkoutTemplateNew.tsx
647
+
648
+ ### [MEDIUM] over-engineered-simple — line 57
649
+
650
+ **Code:** `const mockTemplateData: Record<string, {
651
+ title: string;
652
+ description: string;
653
+ category: string;
654
+ focusAreas: string[];
655
+ difficulty: string;
656
+ duration: number;
657
+ equipment: string[];
658
+ warmUps: WarmUpItem[];
659
+ exercises: ExerciseItem[];
660
+ finishers: FinisherItem[];
661
+ }> = {`
662
+
663
+ **Issue:** Complex Record type definition for what is essentially a simple lookup object with 2 items. The verbose type annotation provides no value since TypeScript can infer the structure from the object literal.
664
+
665
+ **Fix:** const mockTemplateData = { '1': { title: 'Upper Body Strength', ... }, '2': { title: 'Lower Body Power', ... } } or extract to a separate constants file if it grows
666
+
667
+ ### [HIGH] hardcoded-config — line 123
668
+
669
+ **Code:** `const [duration, setDuration] = useState(35);`
670
+
671
+ **Issue:** Default workout duration of 35 minutes is hardcoded. This configuration value should be externalized to allow different defaults per user type or configurable by admins.
672
+
673
+ **Fix:** const [duration, setDuration] = useState(config.DEFAULT_WORKOUT_DURATION || 35);
674
+
675
+ ## TrainerWorkoutPrograms.tsx
676
+
677
+ ### [MEDIUM] console-log-left-in — line 37
678
+
679
+ **Code:** `console.error('Failed to fetch programs:', error);`
680
+
681
+ **Issue:** Console.error statement left in production code that will clutter production logs and potentially leak implementation details
682
+
683
+ **Fix:** Replace with proper logging: logger.error('Failed to fetch programs', { error }) or remove entirely
684
+
685
+ ### [MEDIUM] console-log-left-in — line 67
686
+
687
+ **Code:** `console.error('Failed to delete program:', error);`
688
+
689
+ **Issue:** Console.error statement left in production code that will clutter production logs and potentially leak implementation details
690
+
691
+ **Fix:** Replace with proper logging: logger.error('Failed to delete program', { error }) or remove entirely
692
+
693
+ ## TrainerWorkoutProgramNew.tsx
694
+
695
+ ### [LOW] generic-variable-names — line 122
696
+
697
+ **Code:** `for (let i = weeks.length; i < newDuration; i++) {`
698
+
699
+ **Issue:** Generic loop variable 'i' used in context where 'weekIndex' would be more descriptive
700
+
701
+ **Fix:** for (let weekIndex = weeks.length; weekIndex < newDuration; weekIndex++) {
702
+
703
+ ### [LOW] generic-variable-names — line 137
704
+
705
+ **Code:** `for (let i = 0; i < newWeeks.length; i++) {`
706
+
707
+ **Issue:** Generic loop variable 'i' used in context where 'weekIndex' would be more descriptive
708
+
709
+ **Fix:** for (let weekIndex = 0; weekIndex < newWeeks.length; weekIndex++) {
710
+
711
+ ### [LOW] generic-variable-names — line 138
712
+
713
+ **Code:** `if (i !== fromWeek) {`
714
+
715
+ **Issue:** Generic variable 'i' used where 'weekIndex' would be clearer
716
+
717
+ **Fix:** if (weekIndex !== fromWeek) {
718
+
719
+ ### [LOW] generic-variable-names — line 139
720
+
721
+ **Code:** `newWeeks[i] = newWeeks[fromWeek].map(day => ({ ...day }));`
722
+
723
+ **Issue:** Generic variable 'i' used where 'weekIndex' would be clearer
724
+
725
+ **Fix:** newWeeks[weekIndex] = newWeeks[fromWeek].map(day => ({ ...day }));
726
+
727
+ ### [LOW] generic-variable-names — line 213
728
+
729
+ **Code:** `exercises: currentWorkout.exercises.filter((_, i) => i !== index),`
730
+
731
+ **Issue:** Generic parameter 'i' in filter callback where 'exerciseIndex' would be more descriptive
732
+
733
+ **Fix:** exercises: currentWorkout.exercises.filter((_, exerciseIndex) => exerciseIndex !== index),
734
+
735
+ ## TrainerWorkoutProgramDetail.tsx
736
+
737
+ ### [HIGH] hardcoded-config — line 33
738
+
739
+ **Code:** `const mockPrograms: Record<string, WorkoutProgram & { weeks: { day: number; workout: DetailedWorkout | null }[][] }> = {
740
+ '4': {
741
+ id: '4',
742
+ name: 'Basic Muscle-Building (At Home)',
743
+ description: 'Build lean muscle and strength...',
744
+ // ... entire hardcoded workout program structure`
745
+
746
+ **Issue:** Large hardcoded workout program data structure embedded directly in component code with specific exercise names, reps, durations, and program details that should be externalized
747
+
748
+ **Fix:** Move workout program data to a separate data file, configuration, or fetch from an API/database: import { workoutPrograms } from '../data/workoutPrograms' or fetch from Firebase
749
+
750
+ ### [LOW] generic-variable-names — line 33
751
+
752
+ **Code:** `const mockPrograms: Record<string, WorkoutProgram & { weeks: { day: number; workout: DetailedWorkout | null }[][] }>`
753
+
754
+ **Issue:** Variable named 'mockPrograms' uses generic 'mock' prefix when it contains specific workout program data that could have a more descriptive domain name
755
+
756
+ **Fix:** Rename to something more specific like 'workoutProgramTemplates' or 'prebuiltPrograms' to indicate what type of programs these are
757
+
758
+ ## TrainerProfile.tsx
759
+
760
+ ### [HIGH] hardcoded-config — line 12
761
+
762
+ **Code:** `const [phone, setPhone] = useState('555-0123');`
763
+
764
+ **Issue:** Hardcoded phone number '555-0123' is a placeholder value that should come from user profile data or be empty initially
765
+
766
+ **Fix:** const [phone, setPhone] = useState(userProfile?.phone || '');
767
+
768
+ ### [HIGH] hardcoded-config — line 11
769
+
770
+ **Code:** `const [bio, setBio] = useState('Certified personal trainer with 5+ years of experience specializing in body recomposition and strength training.');`
771
+
772
+ **Issue:** Hardcoded bio text as default value should come from user profile data or be empty for user input
773
+
774
+ **Fix:** const [bio, setBio] = useState(userProfile?.bio || '');
775
+
776
+ ### [HIGH] stub-with-shell — line 33
777
+
778
+ **Code:** `const handleSave = async () => {
779
+ setSaving(true);
780
+ await new Promise((r) => setTimeout(r, 1000));
781
+ // TODO: API call to save profile
782
+ setSaving(false);
783
+ };`
784
+
785
+ **Issue:** Function has complete error handling structure but core business logic (saving profile) is a TODO stub with fake delay
786
+
787
+ **Fix:** Either implement the actual save API call or throw an error indicating it's not implemented yet
788
+
789
+ ## TrainerMessages.tsx
790
+
791
+ ### [LOW] generic-variable-names — line 115
792
+
793
+ **Code:** `await new Promise((r) => setTimeout(r, 500));`
794
+
795
+ **Issue:** Promise resolver callback parameter is named 'r' instead of a descriptive name like 'resolve'
796
+
797
+ **Fix:** await new Promise((resolve) => setTimeout(resolve, 500));
798
+
799
+ ### [LOW] generic-variable-names — line 152
800
+
801
+ **Code:** `const filteredConversations = conversations.filter((c) =>
802
+ c.clientName.toLowerCase().includes(searchQuery.toLowerCase())
803
+ );`
804
+
805
+ **Issue:** Loop variable named 'c' when iterating over conversations - should be more descriptive
806
+
807
+ **Fix:** const filteredConversations = conversations.filter((conversation) =>
808
+ conversation.clientName.toLowerCase().includes(searchQuery.toLowerCase())
809
+ );
810
+
811
+ ### [LOW] generic-variable-names — line 156
812
+
813
+ **Code:** `const selectedClient = conversations.find((c) => c.id === selectedConversation);`
814
+
815
+ **Issue:** Loop variable named 'c' when iterating over conversations - should be more descriptive
816
+
817
+ **Fix:** const selectedClient = conversations.find((conversation) => conversation.id === selectedConversation);
818
+
819
+ ## TrainerMealTemplates.tsx
820
+
821
+ ### [LOW] generic-variable-names — line 28
822
+
823
+ **Code:** `const filteredPlans = mealPlans.filter((p) =>`
824
+
825
+ **Issue:** Loop variable 'p' is generic when iterating over a typed collection of meal plans. 'plan' would be more descriptive.
826
+
827
+ **Fix:** const filteredPlans = mealPlans.filter((plan) => plan.name.toLowerCase().includes(searchQuery.toLowerCase()) || plan.description.toLowerCase().includes(searchQuery.toLowerCase()));
828
+
829
+ ### [LOW] generic-variable-names — line 18
830
+
831
+ **Code:** `const res = await getMealPlanTemplates();`
832
+
833
+ **Issue:** Variable 'res' is a generic name for what is specifically a meal plan templates API response.
834
+
835
+ **Fix:** const templatesResponse = await getMealPlanTemplates();
836
+
837
+ ## TrainerMealPlanNew.tsx
838
+
839
+ ### [HIGH] hardcoded-config — line 11
840
+
841
+ **Code:** `targetCalories: '2000',
842
+ targetProtein: '150',
843
+ targetCarbs: '200',
844
+ targetFat: '65',`
845
+
846
+ **Issue:** Default macro values are hardcoded in the component state. These nutritional targets should come from configuration or business logic rather than being embedded in the UI component.
847
+
848
+ **Fix:** Move default values to a config file or environment variables: const DEFAULT_MACROS = { calories: process.env.DEFAULT_CALORIES || 2000, ... }
849
+
850
+ ### [HIGH] hardcoded-config — line 28
851
+
852
+ **Code:** `targetCalories: Number(form.targetCalories) || 2000,
853
+ targetProtein: Number(form.targetProtein) || 150,
854
+ targetCarbs: Number(form.targetCarbs) || 200,
855
+ targetFat: Number(form.targetFat) || 65,`
856
+
857
+ **Issue:** Fallback macro values are duplicated and hardcoded in the submission logic. These magic numbers should be constants or come from configuration to ensure consistency and maintainability.
858
+
859
+ **Fix:** Extract to constants: const DEFAULT_MACROS = { calories: 2000, protein: 150, carbs: 200, fat: 65 }; then use DEFAULT_MACROS.calories, etc.
860
+
861
+ ## TrainerIntakes.tsx
862
+
863
+ ### [HIGH] hardcoded-config — line 14
864
+
865
+ **Code:** `const mockIntakes: PendingIntake[] = [
866
+ {
867
+ id: '1',
868
+ clientName: 'Emma Wilson',
869
+ email: 'emma@example.com',
870
+ tier: 'body-blueprint',
871
+ submittedAt: new Date(Date.now() - 2 * 60 * 60 * 1000),
872
+ primaryGoal: 'lose-fat',
873
+ },
874
+ // ... more mock data`
875
+
876
+ **Issue:** Mock data with hardcoded emails and configuration values embedded directly in the component. This creates coupling between test data and production code.
877
+
878
+ **Fix:** Move mock data to a separate test data file or environment-based configuration: import { mockIntakes } from './testData' or fetch from process.env.NODE_ENV === 'development'
879
+
880
+ ### [HIGH] stub-with-shell — line 42
881
+
882
+ **Code:** `const fetchIntakes = async () => {
883
+ setLoading(true);
884
+ await new Promise((r) => setTimeout(r, 500));
885
+ setIntakes(mockIntakes);
886
+ setLoading(false);
887
+ };`
888
+
889
+ **Issue:** Function has complete async structure with loading states but core logic is just a setTimeout delay returning mock data. This will appear to work but provides no real data fetching.
890
+
891
+ **Fix:** Replace with actual API call: const response = await fetch('/api/intakes'); const data = await response.json(); setIntakes(data);
892
+
893
+ ## TrainerIntakeReview.tsx
894
+
895
+ ### [HIGH] stub-with-shell — line 79
896
+
897
+ **Code:** `const fetchData = async () => {
898
+ setLoading(true);
899
+ await new Promise((r) => setTimeout(r, 500));
900
+ setIntakeData(mockIntakeData);
901
+ setLoading(false);
902
+ };`
903
+
904
+ **Issue:** The fetchData function has the structure of a real API call (async, loading states, error handling pattern) but only contains a setTimeout and uses mock data. This creates the illusion of working functionality while being a stub.
905
+
906
+ **Fix:** Replace with actual API call: `const response = await fetch(`/api/intakes/${id}`); setIntakeData(await response.json());` or make the stub explicit with a comment and throw for missing implementation.
907
+
908
+ ### [HIGH] stub-with-shell — line 92
909
+
910
+ **Code:** `setSubmitting(true);
911
+ await new Promise((r) => setTimeout(r, 1000));
912
+ // TODO: API call to approve intake
913
+ navigate('/trainer/intakes');`
914
+
915
+ **Issue:** The handleApprove function has complete error handling and loading states but contains only a setTimeout and TODO comment instead of the actual approval logic. This will appear to work in testing but do nothing in production.
916
+
917
+ **Fix:** Implement the actual API call: `await fetch('/api/intakes/${id}/approve', { method: 'POST', body: JSON.stringify({ program: selectedProgram, mealPlan: selectedMealPlan }) })` or throw an error if not ready for production.
918
+
919
+ ## TrainerDemoClientDetail.tsx
920
+
921
+ ### [LOW] generic-variable-names — line 131
922
+
923
+ **Code:** `demoClient.assignedWorkouts.filter(w => w.id !== workoutId)`
924
+
925
+ **Issue:** Loop variable 'w' is generic when iterating over a typed collection of workouts. 'workout' would be more descriptive.
926
+
927
+ **Fix:** demoClient.assignedWorkouts.filter(workout => workout.id !== workoutId)
928
+
929
+ ## TrainerDashboard.tsx
930
+
931
+ ### [HIGH] stub-with-shell — line 36
932
+
933
+ **Code:** `const fetchData = async () => {
934
+ setLoading(true);
935
+ // TODO: Replace with actual API calls
936
+ await new Promise((r) => setTimeout(r, 500));
937
+
938
+ setStats({
939
+ activeClients: 12,
940
+ pendingIntakes: 3,
941
+ pendingCheckins: 5,
942
+ unreadMessages: 8,
943
+ });
944
+
945
+ setRecentActivity([
946
+ {
947
+ id: '1',
948
+ type: 'workout',
949
+ clientName: 'Sarah M.',
950
+ description: 'Completed Lower Body Power',
951
+ timestamp: new Date(Date.now() - 30 * 60 * 1000),
952
+ },
953
+ // ... more hardcoded activity items
954
+ ]);`
955
+
956
+ **Issue:** Function has complete structure and error handling but core business logic (API calls) is stubbed with hardcoded mock data and a TODO comment. The dashboard will display fake data instead of real trainer statistics.
957
+
958
+ **Fix:** Replace with actual API calls to fetch real dashboard data, or make the stub explicit by throwing an error until implemented
959
+
960
+ ## TrainerClients.tsx
961
+
962
+ ### [LOW] generic-variable-names — line 112
963
+
964
+ **Code:** `const res = await getTrainerClients(currentUser.uid);`
965
+
966
+ **Issue:** Variable 'res' is a generic name that doesn't communicate what type of response or data it contains
967
+
968
+ **Fix:** const clientsResponse = await getTrainerClients(currentUser.uid);
969
+
970
+ ### [LOW] generic-variable-names — line 115
971
+
972
+ **Code:** `res.data.clients.map((c) => ({`
973
+
974
+ **Issue:** Parameter 'c' in the map function is generic when iterating over a typed collection of clients
975
+
976
+ **Fix:** res.data.clients.map((client) => ({
977
+
978
+ ## TrainerClientDetail.tsx
979
+
980
+ ### [LOW] generic-variable-names — line 166
981
+
982
+ **Code:** `const res = await getTrainerClient(currentUser.uid, id);`
983
+
984
+ **Issue:** Variable 'res' is a generic name that doesn't communicate what kind of response this is - it's specifically a trainer client fetch response
985
+
986
+ **Fix:** const clientResponse = await getTrainerClient(currentUser.uid, id);
987
+
988
+ ### [LOW] generic-variable-names — line 168
989
+
990
+ **Code:** `const c = res.data;`
991
+
992
+ **Issue:** Variable 'c' is a single-letter generic name that doesn't communicate it represents client data
993
+
994
+ **Fix:** const clientData = res.data;
995
+
996
+ ### [LOW] generic-variable-names — line 155
997
+
998
+ **Code:** `await new Promise((r) => setTimeout(r, 300));`
999
+
1000
+ **Issue:** Parameter 'r' is a generic name in the Promise resolve callback - while common in this pattern, 'resolve' would be clearer
1001
+
1002
+ **Fix:** await new Promise((resolve) => setTimeout(resolve, 300));
1003
+
1004
+ ## TrainerCheckins.tsx
1005
+
1006
+ ### [LOW] generic-variable-names — line 130
1007
+
1008
+ **Code:** `{[...Array(5)].map((_, i) => (`
1009
+
1010
+ **Issue:** Using generic variable name 'i' for array index in loading skeleton generation where 'skeletonIndex' would be more descriptive
1011
+
1012
+ **Fix:** {[...Array(5)].map((_, skeletonIndex) => (
1013
+
1014
+ ### [HIGH] hardcoded-config — line 118
1015
+
1016
+ **Code:** `await new Promise((r) => setTimeout(r, 500));`
1017
+
1018
+ **Issue:** Hardcoded 500ms delay for simulating API loading time should be configurable or removed in production
1019
+
1020
+ **Fix:** const MOCK_DELAY = process.env.NODE_ENV === 'development' ? 500 : 0; await new Promise((r) => setTimeout(r, MOCK_DELAY));
1021
+
1022
+ ### [HIGH] hardcoded-config — line 132
1023
+
1024
+ **Code:** `{[...Array(5)].map((_, i) => (`
1025
+
1026
+ **Issue:** Hardcoded number of skeleton loading items (5) should match expected data size or be configurable
1027
+
1028
+ **Fix:** const SKELETON_COUNT = 5; {[...Array(SKELETON_COUNT)].map((_, i) => (
1029
+
1030
+ ## TrainerCheckinReview.tsx
1031
+
1032
+ ### [HIGH] stub-with-shell — line 67
1033
+
1034
+ **Code:** `// TODO: API call to submit review`
1035
+
1036
+ **Issue:** The handleSubmit function appears complete with error handling and loading states, but the core functionality (submitting the review) is just a TODO comment. This will silently fail to save review data in production.
1037
+
1038
+ **Fix:** Replace TODO with actual API call: `await api.submitCheckinReview(id, { feedback, newCalories, newProtein, newCarbs, newFat, nextWeekFocus })`
1039
+
1040
+ ### [HIGH] hardcoded-config — line 22
1041
+
1042
+ **Code:** `progressPhotos: {
1043
+ front: 'https://placehold.co/400x600/e0e7ff/6366f1?text=Front',
1044
+ side: 'https://placehold.co/400x600/e0e7ff/6366f1?text=Side',
1045
+ }`
1046
+
1047
+ **Issue:** Hardcoded placeholder URLs in mock data that could accidentally make it to production, creating broken image links.
1048
+
1049
+ **Fix:** Move to environment config: `front: process.env.REACT_APP_PLACEHOLDER_IMAGE_BASE + '/front'` or use proper mock data service
1050
+
1051
+ ## ProgressTracking.tsx
1052
+
1053
+ ### [MEDIUM] console-log-left-in — line 79
1054
+
1055
+ **Code:** `console.log('Setting entries:', limitedEntries.length, 'entries for user', userId);`
1056
+
1057
+ **Issue:** Debug logging statement left in production code that logs user ID and entry count details
1058
+
1059
+ **Fix:** Remove the console.log statement or replace with proper logger: logger.debug('Progress entries loaded', { count: limitedEntries.length })
1060
+
1061
+ ### [MEDIUM] console-log-left-in — line 86
1062
+
1063
+ **Code:** `console.log('Setting up real-time listener for progress entries (fetching all, filtering client-side), userId:', userId);`
1064
+
1065
+ **Issue:** Debug logging statement left in production code that logs user ID and implementation details
1066
+
1067
+ **Fix:** Remove the console.log statement or replace with proper logger: logger.debug('Setting up progress listener')
1068
+
1069
+ ### [MEDIUM] console-log-left-in — line 91
1070
+
1071
+ **Code:** `console.log('Progress entries updated from Firestore:', snapshot.docs.length, 'total entries');`
1072
+
1073
+ **Issue:** Debug logging statement left in production code that logs database query details
1074
+
1075
+ **Fix:** Remove the console.log statement or replace with proper logger: logger.debug('Progress entries updated', { count: snapshot.docs.length })
1076
+
1077
+ ## Measurements.tsx
1078
+
1079
+ ### [MEDIUM] console-log-left-in — line 83
1080
+
1081
+ **Code:** `console.error('Failed to fetch measurements:', error);`
1082
+
1083
+ **Issue:** Debug console statement left in production code that will clutter production logs and potentially expose internal error details
1084
+
1085
+ **Fix:** Replace with proper error logging: logger.error('Failed to fetch measurements', { error: error.message })
1086
+
1087
+ ### [MEDIUM] try-catch-everything — line 58
1088
+
1089
+ **Code:** `try {
1090
+ // Try to get latest measurements from Firestore
1091
+ if (db) {
1092
+ const entriesRef = collection(db, 'progressEntries');
1093
+ const q = query(
1094
+ entriesRef,
1095
+ where('clientId', '==', currentUser.uid)
1096
+ );
1097
+
1098
+ const snapshot = await getDocs(q);
1099
+ // Sort by date descending client-side
1100
+ const sortedDocs = snapshot.docs.sort((a, b) => {
1101
+ const dateA = a.data().date?.toDate() || new Date(0);
1102
+ const dateB = b.data().date?.toDate() || new Date(0);
1103
+ return dateB.getTime() - dateA.getTime();
1104
+ });
1105
+ // Find the first entry with measurements
1106
+ for (const docSnap of sortedDocs.slice(0, 30)) {
1107
+ const data = docSnap.data();
1108
+ const measurements = data.measurements;
1109
+ if (measurements && (measurements.chest || measurements.waist || measurements.hips)) {
1110
+ setLatestMeasurements(measurements);
1111
+ setFormData({
1112
+ chest: measurements.chest?.toString() || '',
1113
+ waist: measurements.waist?.toString() || '',
1114
+ hips: measurements.hips?.toString() || '',
1115
+ glutes: measurements.glutes?.toString() || '',
1116
+ leftBicep: measurements.leftBicep?.toString() || '',
1117
+ rightBicep: measurements.rightBicep?.toString() || '',
1118
+ leftThigh: measurements.leftThigh?.toString() || '',
1119
+ rightThigh: measurements.rightThigh?.toString() || '',
1120
+ });
1121
+ break;
1122
+ }
1123
+ }
1124
+ }
1125
+ } catch (error) {
1126
+ console.error('Failed to fetch measurements:', error);
1127
+ }`
1128
+
1129
+ **Issue:** Blanket try/catch around entire Firestore operation with generic error handling that only logs and continues. Different Firebase errors (network, permissions, quota) should be handled differently
1130
+
1131
+ **Fix:** Handle specific Firebase errors differently - network errors might warrant retry, permission errors should redirect to auth, and only log unexpected errors
1132
+
1133
+ ## ProfileSupport.tsx
1134
+
1135
+ ### [HIGH] hardcoded-config — line 17
1136
+
1137
+ **Code:** `description: 'support@hardcoresynergy.com'`
1138
+
1139
+ **Issue:** Email address is hardcoded in source code, making it difficult to change for different environments or configurations
1140
+
1141
+ **Fix:** Move to environment variable: process.env.REACT_APP_SUPPORT_EMAIL || 'support@hardcoresynergy.com'
1142
+
1143
+ ### [HIGH] hardcoded-config — line 18
1144
+
1145
+ **Code:** `action: () => window.location.href = 'mailto:support@hardcoresynergy.com'`
1146
+
1147
+ **Issue:** Support email address is hardcoded again, duplicating the configuration value
1148
+
1149
+ **Fix:** Use a constant or environment variable to avoid duplication
1150
+
1151
+ ### [HIGH] hardcoded-config — line 68
1152
+
1153
+ **Code:** `onClick={() => window.location.href = 'mailto:support@hardcoresynergy.com'}`
1154
+
1155
+ **Issue:** Support email hardcoded a third time, creating maintenance burden when email needs to change
1156
+
1157
+ **Fix:** Extract to constant: const SUPPORT_EMAIL = process.env.REACT_APP_SUPPORT_EMAIL || 'support@hardcoresynergy.com'
1158
+
1159
+ ### [HIGH] stub-with-shell — line 14
1160
+
1161
+ **Code:** `action: () => alert('Support chat coming soon!')`
1162
+
1163
+ **Issue:** Function presents as working support contact but is just a placeholder alert that provides no actual functionality
1164
+
1165
+ **Fix:** Either implement the feature or disable/hide the option until ready: disabled: true, or remove from supportOptions array
1166
+
1167
+ ### [HIGH] stub-with-shell — line 23
1168
+
1169
+ **Code:** `action: () => alert('FAQs coming soon!')`
1170
+
1171
+ **Issue:** FAQs option appears functional but only shows a placeholder alert, misleading users who need help
1172
+
1173
+ **Fix:** Remove from supportOptions array until FAQ system is implemented, or navigate to existing FAQ page if available
1174
+
1175
+ ## ProfileSettings.tsx
1176
+
1177
+ ### [HIGH] stub-with-shell — line 25
1178
+
1179
+ **Code:** `const handleSave = async () => {
1180
+ setSaving(true);
1181
+ // TODO: Implement app settings API call (language, sound effects, haptic feedback)
1182
+ await new Promise((r) => setTimeout(r, 500));
1183
+ setSaving(false);
1184
+ alert('Settings saved!');
1185
+ navigate('/profile');
1186
+ };`
1187
+
1188
+ **Issue:** Function has complete error handling, loading states, and success flow but the core business logic is a TODO comment with a fake delay. This will appear to work but won't actually save settings.
1189
+
1190
+ **Fix:** Replace with actual API call: `await saveUserSettings({ language: settings.language, soundEffects: settings.soundEffects, hapticFeedback: settings.hapticFeedback });`
1191
+
1192
+ ### [LOW] comment-restatement — line 20
1193
+
1194
+ **Code:** `// Sync darkMode from theme context
1195
+ useEffect(() => {
1196
+ // Settings state is now managed by theme context
1197
+ }, [darkMode]);`
1198
+
1199
+ **Issue:** The comment simply restates what the useEffect dependency array already indicates - that it syncs with darkMode. The inner comment adds no meaningful information since the effect body is empty.
1200
+
1201
+ **Fix:** Remove the comments or add meaningful context about why this effect exists if it has a purpose, or remove the entire empty useEffect.
1202
+
1203
+ ### [LOW] comment-restatement — line 36
1204
+
1205
+ **Code:** `const handleDarkModeToggle = (enabled: boolean) => {
1206
+ setDarkMode(enabled);
1207
+ // Save immediately without needing to click "Save Settings"
1208
+ };`
1209
+
1210
+ **Issue:** Comment merely describes the mechanical difference from other settings rather than explaining the business reason or user experience rationale for this behavior.
1211
+
1212
+ **Fix:** Replace with meaningful context: `// Dark mode preference is persisted immediately for better UX` or remove if the behavior is self-evident.
1213
+
1214
+ ## ProfileNotifications.tsx
1215
+
1216
+ ### [HIGH] stub-with-shell — line 19
1217
+
1218
+ **Code:** `const handleSave = async () => {
1219
+ setSaving(true);
1220
+ // TODO: Implement notification preferences API call
1221
+ await new Promise((r) => setTimeout(r, 1000));
1222
+ setSaving(false);
1223
+ alert('Notification preferences saved!');
1224
+ navigate('/profile');
1225
+ };`
1226
+
1227
+ **Issue:** Function has complete structure with loading state management and navigation flow, but the core business logic (saving preferences to backend) is a TODO comment with a fake timeout. The UI shows success feedback even though no actual save operation occurred.
1228
+
1229
+ **Fix:** Either implement the actual API call or throw an error to fail loudly: throw new Error('Save preferences not implemented - see issue #X')
1230
+
1231
+ ## ProfileEdit.tsx
1232
+
1233
+ ### [HIGH] stub-with-shell — line 20
1234
+
1235
+ **Code:** `const handleSave = async () => {
1236
+ setSaving(true);
1237
+ // TODO: Implement profile update API call
1238
+ await new Promise((r) => setTimeout(r, 1000));
1239
+ setSaving(false);
1240
+ alert('Profile updated successfully!');
1241
+ navigate('/profile');
1242
+ };`
1243
+
1244
+ **Issue:** Function has complete error handling structure and UI feedback but the core business logic (saving profile data) is just a TODO comment with a fake delay. The function claims success without actually persisting any data.
1245
+
1246
+ **Fix:** Either implement the actual API call or make the stub explicit: throw new Error('Profile update not implemented - see issue #X') so it fails loudly instead of silently lying about success.
1247
+
1248
+ ## Profile.tsx
1249
+
1250
+ ### [MEDIUM] console-log-left-in — line 54
1251
+
1252
+ **Code:** `console.error('Failed to sign out:', error);`
1253
+
1254
+ **Issue:** Debug console statement left in production code within error handling. While this is console.error rather than console.log, it still exposes internal error details that should use proper logging.
1255
+
1256
+ **Fix:** Replace with proper error logging: logger.error('Sign out failed', { error: error.message }) or remove if error handling is sufficient
1257
+
1258
+ ## NutritionLog.tsx
1259
+
1260
+ ### [MEDIUM] console-log-left-in — line 131
1261
+
1262
+ **Code:** `console.error('Failed to log nutrition:', error);`
1263
+
1264
+ **Issue:** Debug console.error statement left in production code that logs internal error details
1265
+
1266
+ **Fix:** Replace with proper error logging: logger.error('Failed to log nutrition', { error: error.message }) or remove if error is already handled by alert
1267
+
1268
+ ## NutritionHistory.tsx
1269
+
1270
+ ### [MEDIUM] console-log-left-in — line 82
1271
+
1272
+ **Code:** `console.error('Failed to fetch nutrition logs:', error);`
1273
+
1274
+ **Issue:** Debug console.error statement left in production code that will clutter production logs and potentially leak implementation details
1275
+
1276
+ **Fix:** Replace with proper logging: import { logger } from './logger'; logger.error('Failed to fetch nutrition logs', { error: error.message });
1277
+
1278
+ ## MealPlan.tsx
1279
+
1280
+ ### [MEDIUM] console-log-left-in — line 133
1281
+
1282
+ **Code:** `console.error('Failed to fetch nutrition data:', error);`
1283
+
1284
+ **Issue:** Console.error statement left in production code that will log error details to browser console, potentially exposing internal error information
1285
+
1286
+ **Fix:** Replace with proper error logging using a logger service or remove if error handling is done elsewhere
1287
+
1288
+ ## MacroCalculator.tsx
1289
+
1290
+ ### [MEDIUM] console-log-left-in — line 100
1291
+
1292
+ **Code:** `console.error('No results to update');`
1293
+
1294
+ **Issue:** Debug console statements left in production code that will clutter production logs
1295
+
1296
+ **Fix:** Remove console.error or replace with proper logger
1297
+
1298
+ ### [MEDIUM] console-log-left-in — line 105
1299
+
1300
+ **Code:** `console.error('No user logged in');`
1301
+
1302
+ **Issue:** Debug console statements left in production code that will clutter production logs
1303
+
1304
+ **Fix:** Remove console.error or replace with proper logger
1305
+
1306
+ ### [MEDIUM] console-log-left-in — line 111
1307
+
1308
+ **Code:** `console.log('Updating macros:', {
1309
+ targetCalories: results.targetCalories,
1310
+ targetProtein: results.protein,
1311
+ targetCarbs: results.carbs,
1312
+ targetFat: results.fat,
1313
+ });`
1314
+
1315
+ **Issue:** Debug console.log statement left in production code that logs internal application state
1316
+
1317
+ **Fix:** Remove console.log or replace with proper logger that can be filtered in production
1318
+
1319
+ ### [MEDIUM] console-log-left-in — line 125
1320
+
1321
+ **Code:** `console.log('Macros updated successfully');`
1322
+
1323
+ **Issue:** Debug console.log statement left in production code that will clutter production logs
1324
+
1325
+ **Fix:** Remove console.log or replace with proper logger
1326
+
1327
+ ### [MEDIUM] console-log-left-in — line 130
1328
+
1329
+ **Code:** `console.error('Failed to update macros:', error);`
1330
+
1331
+ **Issue:** Debug console statements left in production code that will clutter production logs
1332
+
1333
+ **Fix:** Remove console.error or replace with proper logger
1334
+
1335
+ ## IntakeForm.tsx
1336
+
1337
+ ### [MEDIUM] console-log-left-in — line 69
1338
+
1339
+ **Code:** `console.log('Draft loaded from Firestore');`
1340
+
1341
+ **Issue:** Debug console.log statement left in production code that will clutter production logs
1342
+
1343
+ **Fix:** Remove debug log or replace with proper logger: logger.debug('Draft loaded from Firestore')
1344
+
1345
+ ### [MEDIUM] console-log-left-in — line 93
1346
+
1347
+ **Code:** `console.log('Draft saved to Firestore');`
1348
+
1349
+ **Issue:** Debug console.log statement left in production code that will clutter production logs
1350
+
1351
+ **Fix:** Remove debug log or replace with proper logger: logger.debug('Draft saved to Firestore')
1352
+
1353
+ ### [MEDIUM] console-log-left-in — line 125
1354
+
1355
+ **Code:** `console.log('Submitting intake form...');`
1356
+
1357
+ **Issue:** Debug console.log statement left in production code that will clutter production logs
1358
+
1359
+ **Fix:** Remove debug log or replace with proper logger: logger.info('Submitting intake form')
1360
+
1361
+ ### [MEDIUM] console-log-left-in — line 135
1362
+
1363
+ **Code:** `console.log('Client profile saved to Firestore');`
1364
+
1365
+ **Issue:** Debug console.log statement left in production code that will clutter production logs
1366
+
1367
+ **Fix:** Remove debug log or replace with proper logger: logger.info('Client profile saved')
1368
+
1369
+ ### [MEDIUM] console-log-left-in — line 139
1370
+
1371
+ **Code:** `console.log('Intake marked as completed');`
1372
+
1373
+ **Issue:** Debug console.log statement left in production code that will clutter production logs
1374
+
1375
+ **Fix:** Remove debug log or replace with proper logger: logger.info('Intake completed')
1376
+
1377
+ ## Home.tsx
1378
+
1379
+ ### [MEDIUM] console-log-left-in — line 125
1380
+
1381
+ **Code:** `console.log('📹 Loaded motivational content:', content);`
1382
+
1383
+ **Issue:** Debug console.log statement left in production code that logs internal application state and data structures
1384
+
1385
+ **Fix:** Remove the console.log or replace with a proper logger: logger.debug('Loaded motivational content', { contentId: content.id })
1386
+
1387
+ ### [MEDIUM] console-log-left-in — line 138
1388
+
1389
+ **Code:** `console.log('📹 Loaded video from all content (fallback):', videos[0]);`
1390
+
1391
+ **Issue:** Debug console.log statement left in production code that logs fallback data loading behavior
1392
+
1393
+ **Fix:** Remove the console.log or replace with a proper logger: logger.debug('Loaded video from fallback query', { videoId: videos[0].id })
1394
+
1395
+ ### [MEDIUM] console-log-left-in — line 140
1396
+
1397
+ **Code:** `console.log('⚠️ No video content found');`
1398
+
1399
+ **Issue:** Debug console.log statement left in production code that logs application flow information
1400
+
1401
+ **Fix:** Remove the console.log or replace with a proper logger: logger.warn('No video content found')
1402
+
1403
+ ### [MEDIUM] console-log-left-in — line 131
1404
+
1405
+ **Code:** `console.warn('Preferred query failed, trying fallback:', error);`
1406
+
1407
+ **Issue:** Debug console.warn statement left in production code that logs error details and fallback behavior
1408
+
1409
+ **Fix:** Remove the console.warn or replace with a proper logger: logger.warn('Preferred query failed, using fallback', { error: error.message })
1410
+
1411
+ ### [MEDIUM] console-log-left-in — line 93
1412
+
1413
+ **Code:** `console.error('Failed to fetch workouts:', error);`
1414
+
1415
+ **Issue:** Debug console.error statement left in production code that logs error information
1416
+
1417
+ **Fix:** Replace with a proper logger: logger.error('Failed to fetch workouts', { error: error.message, userId: currentUser.uid })
1418
+
1419
+ ## SignUp.tsx
1420
+
1421
+ ✓ Clean
1422
+
1423
+ ## SignIn.tsx
1424
+
1425
+ ### [MEDIUM] try-catch-everything — line 24
1426
+
1427
+ **Code:** `try {
1428
+ await signIn(email, password);
1429
+ // Redirect based on subscription status
1430
+ if (!subscriptionTier) {
1431
+ navigate('/pricing');
1432
+ } else {
1433
+ navigate(from, { replace: true });
1434
+ }
1435
+ } catch (err) {
1436
+ setError(err instanceof Error ? err.message : 'Failed to sign in');
1437
+ }`
1438
+
1439
+ **Issue:** Generic catch block that handles all errors the same way, whether they're network failures, authentication failures, or validation errors. Different error types should be handled distinctly for better UX.
1440
+
1441
+ **Fix:** Handle specific error types differently - authentication failures vs network errors vs validation errors should show different messages and potentially different recovery actions.
1442
+
1443
+ ### [MEDIUM] try-catch-everything — line 60
1444
+
1445
+ **Code:** `try {
1446
+ await signInWithGoogle();
1447
+ // Note: If using redirect, navigation won't happen here
1448
+ // The redirect result handler will navigate after successful auth
1449
+ if (!subscriptionTier) {
1450
+ navigate('/pricing');
1451
+ } else {
1452
+ navigate(from, { replace: true });
1453
+ }
1454
+ } catch (err) {
1455
+ setError(err instanceof Error ? err.message : 'Failed to sign in with Google');
1456
+ }`
1457
+
1458
+ **Issue:** Another generic catch block that treats all Google sign-in errors the same. Popup blocked, user cancelled, network errors, and OAuth errors should be handled differently.
1459
+
1460
+ **Fix:** Check error codes/types to provide specific handling - popup blocked should suggest alternative, user cancellation should not show error, OAuth errors should provide specific guidance.
1461
+
1462
+ ## Pricing.tsx
1463
+
1464
+ ### [MEDIUM] console-log-left-in — line 93
1465
+
1466
+ **Code:** `console.error('Failed to update subscription:', error);`
1467
+
1468
+ **Issue:** Console.error statement left in production code that will clutter production logs and expose internal implementation details
1469
+
1470
+ **Fix:** Replace with proper error logging: logger.error('Failed to update subscription', { error: error.message, userId: currentUser?.uid })
1471
+
1472
+ ### [MEDIUM] console-log-left-in — line 99
1473
+
1474
+ **Code:** `console.error('Payment error:', error);`
1475
+
1476
+ **Issue:** Console.error statement left in production code in the payment error handler
1477
+
1478
+ **Fix:** Replace with proper error logging: logger.error('Payment processing failed', { error }) or remove since comment indicates error is already shown in PaymentForm component
1479
+
1480
+ ## AdminWorkoutPrograms.tsx
1481
+
1482
+ ### [MEDIUM] console-log-left-in — line 48
1483
+
1484
+ **Code:** `console.error('Failed to fetch programs:', error);`
1485
+
1486
+ **Issue:** Debug console statement left in production code that will clutter production logs and potentially leak internal implementation details
1487
+
1488
+ **Fix:** Replace with proper error logging: logger.error('Failed to fetch programs', { error })
1489
+
1490
+ ### [MEDIUM] console-log-left-in — line 70
1491
+
1492
+ **Code:** `console.error('Failed to delete program:', error);`
1493
+
1494
+ **Issue:** Debug console statement left in production code that will clutter production logs and potentially leak internal implementation details
1495
+
1496
+ **Fix:** Replace with proper error logging: logger.error('Failed to delete program', { programId, error })
1497
+
1498
+ ## AdminUsers.tsx
1499
+
1500
+ ### [LOW] generic-variable-names — line 44
1501
+
1502
+ **Code:** `const res = await getAdminUsers({ limit: 500 });`
1503
+
1504
+ **Issue:** Variable 'res' is a generic name that doesn't communicate what the response contains - it's an admin users API response
1505
+
1506
+ **Fix:** const usersResponse = await getAdminUsers({ limit: 500 });
1507
+
1508
+ ### [LOW] generic-variable-names — line 46
1509
+
1510
+ **Code:** `setUsers(res.data.users.map((u) => normalizeAdminUser(u as unknown as Record<string, unknown>)));`
1511
+
1512
+ **Issue:** Variable 'u' in the map function is generic when 'user' or 'rawUser' would be more descriptive for the user data being normalized
1513
+
1514
+ **Fix:** setUsers(res.data.users.map((rawUser) => normalizeAdminUser(rawUser as unknown as Record<string, unknown>)));
1515
+
1516
+ ## AdminTrainers.tsx
1517
+
1518
+ ### [LOW] generic-variable-names — line 88
1519
+
1520
+ **Code:** `const openEdit = (t: TrainerProfile) => {`
1521
+
1522
+ **Issue:** Parameter named 't' instead of a descriptive name like 'trainer' makes the function less readable, especially given the complex logic that follows
1523
+
1524
+ **Fix:** const openEdit = (trainer: TrainerProfile) => {
1525
+
1526
+ ### [LOW] generic-variable-names — line 106
1527
+
1528
+ **Code:** `setTrainers(
1529
+ res.data.trainers.map((t) => mapUserDocToTrainer(t as unknown as Record<string, unknown>))
1530
+ );`
1531
+
1532
+ **Issue:** Loop variable 't' in map function should be named 'trainer' or 'trainerData' to clarify what's being transformed
1533
+
1534
+ **Fix:** res.data.trainers.map((trainer) => mapUserDocToTrainer(trainer as unknown as Record<string, unknown>))
1535
+
1536
+ ## AdminSweatStarterWorkouts.tsx
1537
+
1538
+ ### [MEDIUM] console-log-left-in — line 86
1539
+
1540
+ **Code:** `console.error('Failed to fetch data:', error);`
1541
+
1542
+ **Issue:** Debug console statement left in production code that will log error details to browser console
1543
+
1544
+ **Fix:** Replace with proper error logging: logger.error('Failed to fetch data', error) or remove if error handling is done elsewhere
1545
+
1546
+ ### [MEDIUM] console-log-left-in — line 152
1547
+
1548
+ **Code:** `console.warn('Workout missing ID:', workout);`
1549
+
1550
+ **Issue:** Debug console statement left in production code that logs workout data to browser console
1551
+
1552
+ **Fix:** Replace with proper logging or remove: use a logger service or handle the missing ID case appropriately without console output
1553
+
1554
+ ### [MEDIUM] console-log-left-in — line 164
1555
+
1556
+ **Code:** `console.log(` Added workout ${workout.id} (week ${weekNumber}, day ${dayIndex}) to week ${weekNumber}`);`
1557
+
1558
+ **Issue:** Debug console statement left in production code that logs detailed workout assignment information
1559
+
1560
+ **Fix:** Remove this debug logging statement or replace with proper logging service if needed for production monitoring
1561
+
1562
+ ## AdminSettings.tsx
1563
+
1564
+ ### [HIGH] hardcoded-config — line 12
1565
+
1566
+ **Code:** `appName: 'Hardcore Synergy',
1567
+ supportEmail: 'support@hardcoresynergy.com',
1568
+ contactInfo: '1-800-HARD-CORE',
1569
+ termsUrl: 'https://hardcoresynergy.com/terms',
1570
+ privacyUrl: 'https://hardcoresynergy.com/privacy'`
1571
+
1572
+ **Issue:** Company-specific configuration values are hardcoded directly in the React component. These values should be configurable without code changes, especially URLs and contact information that may need to be updated by administrators.
1573
+
1574
+ **Fix:** Move these values to environment variables or a configuration file: process.env.REACT_APP_NAME, process.env.REACT_APP_SUPPORT_EMAIL, etc., or load them from an API endpoint that admins can update.
1575
+
1576
+ ### [HIGH] async-misuse — line 29
1577
+
1578
+ **Code:** `const handleSave = async () => {
1579
+ setSaving(true);
1580
+ await new Promise((r) => setTimeout(r, 1000));
1581
+ setSaving(false);
1582
+ };`
1583
+
1584
+ **Issue:** Function is marked async and uses await, but only to create a fake delay with setTimeout. This simulates async behavior without actually performing any real async operation like saving data to a server.
1585
+
1586
+ **Fix:** Either remove async/await and make it synchronous if no real async work is needed, or implement actual async functionality like: 'await saveSettingsToAPI(settings)'
1587
+
1588
+ ### [HIGH] stub-with-shell — line 29
1589
+
1590
+ **Code:** `const handleSave = async () => {
1591
+ setSaving(true);
1592
+ await new Promise((r) => setTimeout(r, 1000));
1593
+ setSaving(false);
1594
+ };`
1595
+
1596
+ **Issue:** The save function has all the UI scaffolding (loading state, async signature) but contains only a fake delay instead of actual save logic. This will appear to work but won't persist any settings changes.
1597
+
1598
+ **Fix:** Implement actual save functionality: 'await fetch('/api/admin/settings', { method: 'PUT', body: JSON.stringify(settings) })' or throw an error if not yet implemented.
1599
+
1600
+ ## AdminExercises.tsx
1601
+
1602
+ ### [MEDIUM] console-log-left-in — line 69
1603
+
1604
+ **Code:** `console.log('🎭 Demo mode: Using empty exercise list');`
1605
+
1606
+ **Issue:** Debug console.log statement left in production code that logs internal application state
1607
+
1608
+ **Fix:** Remove debug log or replace with proper logging: logger.debug('Demo mode: Using empty exercise list')
1609
+
1610
+ ### [MEDIUM] console-log-left-in — line 75
1611
+
1612
+ **Code:** `console.error('Firestore database not initialized');`
1613
+
1614
+ **Issue:** Console.error used for application error handling instead of proper error logging
1615
+
1616
+ **Fix:** Use proper error logging: logger.error('Firestore database not initialized')
1617
+
1618
+ ### [MEDIUM] console-log-left-in — line 82
1619
+
1620
+ **Code:** `console.warn('No current user, cannot fetch exercises');`
1621
+
1622
+ **Issue:** Console.warn used for application warning instead of proper logging
1623
+
1624
+ **Fix:** Use proper logging: logger.warn('No current user, cannot fetch exercises')
1625
+
1626
+ ### [MEDIUM] console-log-left-in — line 87
1627
+
1628
+ **Code:** `console.log('Fetching exercises...', { userId: currentUser.uid, email: currentUser.email });`
1629
+
1630
+ **Issue:** Debug console.log statement left in production code that logs user identification data including email
1631
+
1632
+ **Fix:** Remove debug log or use proper logging without sensitive data: logger.debug('Fetching exercises', { userId: currentUser.uid })
1633
+
1634
+ ### [MEDIUM] console-log-left-in — line 93
1635
+
1636
+ **Code:** `console.log('Fetching exercises from Firestore...');`
1637
+
1638
+ **Issue:** Debug console.log statement left in production code
1639
+
1640
+ **Fix:** Remove debug log or use proper logging: logger.debug('Fetching exercises from Firestore')
1641
+
1642
+ ### [MEDIUM] console-log-left-in — line 95
1643
+
1644
+ **Code:** `console.log('Query successful, got', snapshot.docs.length, 'exercises');`
1645
+
1646
+ **Issue:** Debug console.log statement left in production code
1647
+
1648
+ **Fix:** Remove debug log or use proper logging: logger.debug('Query successful', { count: snapshot.docs.length })
1649
+
1650
+ ### [MEDIUM] console-log-left-in — line 103
1651
+
1652
+ **Code:** `console.log('Successfully loaded', exercisesData.length, 'exercises');`
1653
+
1654
+ **Issue:** Debug console.log statement left in production code
1655
+
1656
+ **Fix:** Remove debug log or use proper logging: logger.info('Successfully loaded exercises', { count: exercisesData.length })
1657
+
1658
+ ### [MEDIUM] console-log-left-in — line 105
1659
+
1660
+ **Code:** `console.error('Failed to fetch exercises:', error);`
1661
+
1662
+ **Issue:** Console.error used for application error handling instead of proper error logging
1663
+
1664
+ **Fix:** Use proper error logging: logger.error('Failed to fetch exercises', { error })
1665
+
1666
+ ### [HIGH] console-log-left-in — line 106
1667
+
1668
+ **Code:** `console.error('Error details:', {
1669
+ code: error?.code,
1670
+ message: error?.message,
1671
+ stack: error?.stack,
1672
+ userId: currentUser?.uid,
1673
+ email: currentUser?.email,
1674
+ });`
1675
+
1676
+ **Issue:** Console.error logging sensitive user data including email address and user ID in production code
1677
+
1678
+ **Fix:** Remove sensitive data from logs: logger.error('Error details', { code: error?.code, message: error?.message })
1679
+
1680
+ ### [MEDIUM] console-log-left-in — line 138
1681
+
1682
+ **Code:** `console.error('Cannot edit: exercise is null or undefined');`
1683
+
1684
+ **Issue:** Console.error used for application error handling instead of proper error logging
1685
+
1686
+ **Fix:** Use proper error logging: logger.error('Cannot edit: exercise is null or undefined')
1687
+
1688
+ ## AdminExerciseUpload.tsx
1689
+
1690
+ ### [MEDIUM] console-log-left-in — line 150
1691
+
1692
+ **Code:** `console.warn('Auto cover from video failed:', e);`
1693
+
1694
+ **Issue:** Debug console statement left in production code that will log errors to browser console in production, potentially exposing implementation details
1695
+
1696
+ **Fix:** Replace with proper error logging: logger.warn('Auto cover generation failed', { error: e.message }) or remove entirely if non-critical
1697
+
1698
+ ## AdminDashboard.tsx
1699
+
1700
+ ### [LOW] generic-variable-names — line 49
1701
+
1702
+ **Code:** `const res = await getPlatformAnalytics();`
1703
+
1704
+ **Issue:** Variable 'res' is a generic name that doesn't communicate what the response contains - analytics data in this case
1705
+
1706
+ **Fix:** const analyticsResponse = await getPlatformAnalytics();
1707
+
1708
+ ### [LOW] generic-variable-names — line 50
1709
+
1710
+ **Code:** `if (res.success && res.data) {`
1711
+
1712
+ **Issue:** Using generic 'res' variable makes the conditional logic less clear about what's being checked
1713
+
1714
+ **Fix:** if (analyticsResponse.success && analyticsResponse.data) {
1715
+
1716
+ ### [LOW] generic-variable-names — line 51
1717
+
1718
+ **Code:** `setAnalytics(res.data);`
1719
+
1720
+ **Issue:** Generic 'res' variable continues to obscure the intent - this is setting analytics data
1721
+
1722
+ **Fix:** setAnalytics(analyticsResponse.data);
1723
+
1724
+ ### [LOW] generic-variable-names — line 55
1725
+
1726
+ **Code:** `res.error ||`
1727
+
1728
+ **Issue:** Generic 'res' variable used in error handling where a more descriptive name would clarify this is an analytics API error
1729
+
1730
+ **Fix:** analyticsResponse.error ||
1731
+
1732
+ ## AdminContent.tsx
1733
+
1734
+ ### [MEDIUM] console-log-left-in — line 61
1735
+
1736
+ **Code:** `console.warn('OrderBy failed, fetching without order:', orderError);`
1737
+
1738
+ **Issue:** Debug console statement left in production code that exposes internal error handling logic and Firebase implementation details
1739
+
1740
+ **Fix:** Replace with proper logging: logger.warn('Firestore orderBy failed, using fallback query', { error: orderError.message })
1741
+
1742
+ ### [MEDIUM] console-log-left-in — line 78
1743
+
1744
+ **Code:** `console.error('Failed to fetch content:', error);`
1745
+
1746
+ **Issue:** Debug console statement left in production code in error handler
1747
+
1748
+ **Fix:** Replace with proper logging: logger.error('Content fetch failed', { error: error.message, userId: currentUser?.uid })
1749
+
1750
+ ### [MEDIUM] console-log-left-in — line 108
1751
+
1752
+ **Code:** `console.error('Failed to load content:', error);`
1753
+
1754
+ **Issue:** Debug console statement left in production code in error handler for content loading
1755
+
1756
+ **Fix:** Replace with proper logging: logger.error('Content load failed', { contentId: id, error: error.message })
1757
+
1758
+ ### [MEDIUM] console-log-left-in — line 136
1759
+
1760
+ **Code:** `console.error('Upload error:', error);`
1761
+
1762
+ **Issue:** Debug console statement left in production code in file upload error handler
1763
+
1764
+ **Fix:** Replace with proper logging: logger.error('File upload failed', { error: error.message, fileName: file.name })
1765
+
1766
+ ## AdminCommunity.tsx
1767
+
1768
+ ### [LOW] comment-restatement — line 79
1769
+
1770
+ **Code:** `{/* Reported Posts Alert */}`
1771
+
1772
+ **Issue:** Comment simply restates what's obvious from the JSX structure - the alert component for reported posts is self-evident from the content
1773
+
1774
+ **Fix:** Remove the comment or replace with context about why this alert appears conditionally
1775
+
1776
+ ### [LOW] comment-restatement — line 96
1777
+
1778
+ **Code:** `{/* Search & Filters */}`
1779
+
1780
+ **Issue:** Comment translates the JSX into English without adding any information about purpose or behavior
1781
+
1782
+ **Fix:** Remove the comment - the search input and filter select are self-documenting
1783
+
1784
+ ### [LOW] comment-restatement — line 119
1785
+
1786
+ **Code:** `{/* Posts List */}`
1787
+
1788
+ **Issue:** Comment simply describes what the following JSX does without providing context about data structure or behavior
1789
+
1790
+ **Fix:** Remove the comment or explain the post filtering/rendering logic
1791
+
1792
+ ### [LOW] comment-restatement — line 130
1793
+
1794
+ **Code:** `{/* Header */}`
1795
+
1796
+ **Issue:** Comment restates the obvious structure of the post header section
1797
+
1798
+ **Fix:** Remove the comment - the header structure is clear from the JSX elements
1799
+
1800
+ ## AdminAnalytics.tsx
1801
+
1802
+ ### [LOW] generic-variable-names — line 41
1803
+
1804
+ **Code:** `const res = await getPlatformAnalytics();
1805
+ if (cancelled) return;
1806
+ if (res.success && res.data) {`
1807
+
1808
+ **Issue:** Variable 'res' is a generic name that doesn't communicate what kind of response this is. In a function dealing with analytics data, a more descriptive name would improve readability.
1809
+
1810
+ **Fix:** const analyticsResponse = await getPlatformAnalytics();
1811
+
1812
+ ### [LOW] generic-variable-names — line 57
1813
+
1814
+ **Code:** `? analytics.revenueByTier.map((r) => ({ month: r.tier, mrr: r.amount }))`
1815
+
1816
+ **Issue:** Loop variable 'r' is generic when iterating over revenue data. A more descriptive name would clarify what each item represents.
1817
+
1818
+ **Fix:** ? analytics.revenueByTier.map((revenue) => ({ month: revenue.tier, mrr: revenue.amount }))
1819
+
1820
+ ### [LOW] generic-variable-names — line 64
1821
+
1822
+ **Code:** `? analytics.signupsByMonth.map((s) => ({`
1823
+
1824
+ **Issue:** Loop variable 's' is generic when iterating over signup data. A more descriptive name would improve code clarity.
1825
+
1826
+ **Fix:** ? analytics.signupsByMonth.map((signup) => ({
1827
+
1828
+ ### [LOW] generic-variable-names — line 73
1829
+
1830
+ **Code:** `return analytics.activeUsersByDay.map((d) => ({`
1831
+
1832
+ **Issue:** Loop variable 'd' is generic when iterating over daily user data. A more descriptive name would clarify the data structure.
1833
+
1834
+ **Fix:** return analytics.activeUsersByDay.map((dailyData) => ({
1835
+
1836
+ ### [LOW] generic-variable-names — line 85
1837
+
1838
+ **Code:** `const total = entries.reduce((s, [, v]) => s + Number(v), 0) || 1;`
1839
+
1840
+ **Issue:** Variables 's' and 'v' in the reduce function are generic. More descriptive names would clarify this is summing user counts.
1841
+
1842
+ **Fix:** const total = entries.reduce((sum, [, userCount]) => sum + Number(userCount), 0) || 1;
1843
+
1844
+ ### [LOW] generic-variable-names — line 86
1845
+
1846
+ **Code:** `return entries.map(([name, v]) => ({`
1847
+
1848
+ **Issue:** Variable 'v' is generic when destructuring tier data. A more descriptive name would improve readability.
1849
+
1850
+ **Fix:** return entries.map(([name, userCount]) => ({
1851
+
1852
+ ### [LOW] generic-variable-names — line 88
1853
+
1854
+ **Code:** `value: Math.round((Number(v) / total) * 100),`
1855
+
1856
+ **Issue:** Using generic variable 'v' from destructuring instead of the more descriptive name that should have been used.
1857
+
1858
+ **Fix:** value: Math.round((Number(userCount) / total) * 100),
1859
+
1860
+ ## TrainerSidebar.tsx
1861
+
1862
+ ✓ Clean
1863
+
1864
+ ## TrainerLayout.tsx
1865
+
1866
+ ✓ Clean
1867
+
1868
+ ## ClientCard.tsx
1869
+
1870
+ ✓ Clean
1871
+
1872
+ ## AdminSidebar.tsx
1873
+
1874
+ ✓ Clean
1875
+
1876
+ ## AdminLayout.tsx
1877
+
1878
+ ✓ Clean
1879
+
1880
+ ## Summary
1881
+
1882
+ | Severity | Count |
1883
+ |---|---|
1884
+ | High | 36 |
1885
+ | Medium | 81 |
1886
+ | Low | 46 |
1887
+ | **Total** | **163** |