@djangocfg/layouts 2.1.36 → 2.1.37
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.
- package/package.json +5 -5
- package/src/layouts/AppLayout/BaseApp.tsx +31 -25
- package/src/layouts/shared/types.ts +36 -0
- package/src/snippets/McpChat/context/ChatContext.tsx +9 -0
- package/src/snippets/PWA/@docs/research.md +576 -0
- package/src/snippets/PWA/@refactoring/ARCHITECTURE_ANALYSIS.md +1179 -0
- package/src/snippets/PWA/@refactoring/EXECUTIVE_SUMMARY.md +271 -0
- package/src/snippets/PWA/@refactoring/README.md +204 -0
- package/src/snippets/PWA/@refactoring/REFACTORING_PROPOSALS.md +1109 -0
- package/src/snippets/PWA/@refactoring2/COMPARISON-WITH-NEXTJS.md +718 -0
- package/src/snippets/PWA/@refactoring2/P1-FIXES-COMPLETED.md +188 -0
- package/src/snippets/PWA/@refactoring2/POST-P0-ANALYSIS.md +362 -0
- package/src/snippets/PWA/@refactoring2/README.md +85 -0
- package/src/snippets/PWA/@refactoring2/RECOMMENDATIONS.md +1321 -0
- package/src/snippets/PWA/@refactoring2/REMAINING-ISSUES.md +557 -0
- package/src/snippets/PWA/README.md +387 -0
- package/src/snippets/PWA/components/A2HSHint.tsx +226 -0
- package/src/snippets/PWA/components/IOSGuide.tsx +29 -0
- package/src/snippets/PWA/components/IOSGuideDrawer.tsx +101 -0
- package/src/snippets/PWA/components/IOSGuideModal.tsx +101 -0
- package/src/snippets/PWA/components/PushPrompt.tsx +165 -0
- package/src/snippets/PWA/config.ts +20 -0
- package/src/snippets/PWA/context/DjangoPushContext.tsx +105 -0
- package/src/snippets/PWA/context/InstallContext.tsx +118 -0
- package/src/snippets/PWA/context/PushContext.tsx +156 -0
- package/src/snippets/PWA/hooks/useDjangoPush.ts +277 -0
- package/src/snippets/PWA/hooks/useInstallPrompt.ts +164 -0
- package/src/snippets/PWA/hooks/useIsPWA.ts +115 -0
- package/src/snippets/PWA/hooks/usePushNotifications.ts +205 -0
- package/src/snippets/PWA/index.ts +95 -0
- package/src/snippets/PWA/types/components.ts +101 -0
- package/src/snippets/PWA/types/index.ts +26 -0
- package/src/snippets/PWA/types/install.ts +38 -0
- package/src/snippets/PWA/types/platform.ts +29 -0
- package/src/snippets/PWA/types/push.ts +21 -0
- package/src/snippets/PWA/utils/localStorage.ts +203 -0
- package/src/snippets/PWA/utils/logger.ts +149 -0
- package/src/snippets/PWA/utils/platform.ts +151 -0
- package/src/snippets/PWA/utils/vapid.ts +226 -0
- package/src/snippets/index.ts +30 -0
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
# Remaining Issues After P0 Refactoring
|
|
2
|
+
|
|
3
|
+
**Date**: December 2025
|
|
4
|
+
**Status**: Post-P0 Analysis
|
|
5
|
+
|
|
6
|
+
## Summary
|
|
7
|
+
|
|
8
|
+
Total remaining issues: **10**
|
|
9
|
+
|
|
10
|
+
| Priority | Count | Status |
|
|
11
|
+
|----------|-------|--------|
|
|
12
|
+
| **P1** (High) | 3 | ⚠️ Should fix before next release |
|
|
13
|
+
| **P2** (Medium) | 4 | ⏳ Can fix incrementally |
|
|
14
|
+
| **P3** (Low) | 3 | 💡 Nice to have |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## P1: High Priority Issues
|
|
19
|
+
|
|
20
|
+
Must be addressed before next production release.
|
|
21
|
+
|
|
22
|
+
### P1-1: Security Vulnerability in config.ts
|
|
23
|
+
|
|
24
|
+
**Location**: `config.ts:10-11`
|
|
25
|
+
|
|
26
|
+
**Issue**: Frontend package exposes server-side secrets
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
// ❌ SECURITY ISSUE
|
|
30
|
+
export const VAPID_PRIVATE_KEY = process.env.VAPID_PRIVATE_KEY || '';
|
|
31
|
+
export const VAPID_MAILTO = process.env.VAPID_MAILTO || '';
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Problem**:
|
|
35
|
+
- Private VAPID key should NEVER be in frontend code
|
|
36
|
+
- Even if accessed via env var, bundlers may include it
|
|
37
|
+
- This is a **critical security vulnerability**
|
|
38
|
+
|
|
39
|
+
**Impact**: 🔴 Critical
|
|
40
|
+
- Attackers can send unauthorized push notifications
|
|
41
|
+
- Private key compromise requires regeneration
|
|
42
|
+
- All existing subscriptions would need re-subscription
|
|
43
|
+
|
|
44
|
+
**Effort**: Low (5 minutes)
|
|
45
|
+
|
|
46
|
+
**Fix**: Remove these lines entirely from frontend package
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// ✅ FIXED - Only expose public key
|
|
50
|
+
export const DEFAULT_VAPID_PUBLIC_KEY = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY || '';
|
|
51
|
+
// Note: VAPID_PRIVATE_KEY should only exist in backend/API routes
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**See**: [RECOMMENDATIONS.md#fix-security-vulnerability](./RECOMMENDATIONS.md#fix-security-vulnerability)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
### P1-2: Inconsistent Error Logging
|
|
59
|
+
|
|
60
|
+
**Locations**:
|
|
61
|
+
- `components/PushPrompt.tsx:106`
|
|
62
|
+
- `components/A2HSHint.tsx:150`
|
|
63
|
+
- `context/PushContext.tsx:114`
|
|
64
|
+
|
|
65
|
+
**Issue**: 3 files still use `console.error` instead of `pwaLogger.error`
|
|
66
|
+
|
|
67
|
+
**Code Examples**:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// ❌ PushPrompt.tsx:106
|
|
71
|
+
console.error('[PushPrompt] Enable failed:', error);
|
|
72
|
+
|
|
73
|
+
// ❌ A2HSHint.tsx:150
|
|
74
|
+
console.error('[A2HSHint] Install error:', error);
|
|
75
|
+
|
|
76
|
+
// ❌ PushContext.tsx:114
|
|
77
|
+
console.error('Failed to send push:', error);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Problem**:
|
|
81
|
+
- Inconsistent with P0 refactoring (logger.ts)
|
|
82
|
+
- No debug mode control for these errors
|
|
83
|
+
- Breaks the conditional logging pattern
|
|
84
|
+
|
|
85
|
+
**Impact**: 🟡 Medium
|
|
86
|
+
- Console spam in production (errors only)
|
|
87
|
+
- Inconsistent DX
|
|
88
|
+
- Harder to debug with mixed logging patterns
|
|
89
|
+
|
|
90
|
+
**Effort**: Low (10 minutes)
|
|
91
|
+
|
|
92
|
+
**Fix**: Replace all with `pwaLogger.error()`
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// ✅ FIXED
|
|
96
|
+
import { pwaLogger } from '../utils/logger';
|
|
97
|
+
|
|
98
|
+
pwaLogger.error('[PushPrompt] Enable failed:', error);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Note**: `pwaLogger.error()` always logs (even in production), so behavior stays the same but now consistent.
|
|
102
|
+
|
|
103
|
+
**See**: [RECOMMENDATIONS.md#fix-inconsistent-logging](./RECOMMENDATIONS.md#fix-inconsistent-logging)
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### P1-3: Duplicated localStorage Keys
|
|
108
|
+
|
|
109
|
+
**Locations**:
|
|
110
|
+
- `components/A2HSHint.tsx:27`
|
|
111
|
+
- `components/PushPrompt.tsx:18`
|
|
112
|
+
|
|
113
|
+
**Issue**: Similar localStorage key patterns duplicated across files
|
|
114
|
+
|
|
115
|
+
**Code**:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// A2HSHint.tsx:27
|
|
119
|
+
const DISMISSED_KEY = 'cmdop-a2hs-dismissed';
|
|
120
|
+
|
|
121
|
+
// PushPrompt.tsx:18
|
|
122
|
+
const DISMISSED_KEY = 'pwa-push-dismissed';
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Problem**:
|
|
126
|
+
- DRY violation (Don't Repeat Yourself)
|
|
127
|
+
- If we want to change key prefix, must update in 2+ places
|
|
128
|
+
- Potential key collision if not careful
|
|
129
|
+
|
|
130
|
+
**Impact**: 🟡 Medium
|
|
131
|
+
- Maintenance overhead
|
|
132
|
+
- Risk of inconsistent key naming
|
|
133
|
+
- Harder to clear all PWA data
|
|
134
|
+
|
|
135
|
+
**Effort**: Low (15 minutes)
|
|
136
|
+
|
|
137
|
+
**Fix**: Centralize in `utils/localStorage.ts`
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// utils/localStorage.ts
|
|
141
|
+
export const STORAGE_KEYS = {
|
|
142
|
+
// ... existing keys ...
|
|
143
|
+
A2HS_DISMISSED: 'pwa_a2hs_dismissed_at',
|
|
144
|
+
PUSH_DISMISSED: 'pwa_push_dismissed_at',
|
|
145
|
+
} as const;
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**See**: [RECOMMENDATIONS.md#centralize-localstorage-keys](./RECOMMENDATIONS.md#centralize-localstorage-keys)
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## P2: Medium Priority Issues
|
|
153
|
+
|
|
154
|
+
Can be addressed incrementally over next few sprints.
|
|
155
|
+
|
|
156
|
+
### P2-1: Unused EngagementMetrics Code
|
|
157
|
+
|
|
158
|
+
**Location**: `utils/localStorage.ts:132-205`
|
|
159
|
+
|
|
160
|
+
**Issue**: Fully implemented engagement tracking but never used
|
|
161
|
+
|
|
162
|
+
**Code**: ~74 lines of dead code
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// utils/localStorage.ts - All unused
|
|
166
|
+
export function getEngagementMetrics(): EngagementMetrics { ... }
|
|
167
|
+
export function saveEngagementMetrics(metrics: EngagementMetrics): void { ... }
|
|
168
|
+
export function trackAction(): void { ... }
|
|
169
|
+
export function trackTimeSpent(ms: number): void { ... }
|
|
170
|
+
export function updateVisit(): void { ... }
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Problem**:
|
|
174
|
+
- Dead code increases bundle size
|
|
175
|
+
- Confusing for developers (is it used?)
|
|
176
|
+
- Maintenance burden
|
|
177
|
+
|
|
178
|
+
**Impact**: 🟡 Medium
|
|
179
|
+
- ~2-3 KB bundle size (after minification)
|
|
180
|
+
- Developer confusion
|
|
181
|
+
- Potential bugs if someone starts using it without testing
|
|
182
|
+
|
|
183
|
+
**Effort**: Low (choose option below)
|
|
184
|
+
|
|
185
|
+
**Options**:
|
|
186
|
+
|
|
187
|
+
**Option A**: Remove it entirely
|
|
188
|
+
```typescript
|
|
189
|
+
// Remove lines 132-205 from localStorage.ts
|
|
190
|
+
// Remove EngagementMetrics from types/components.ts
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Option B**: Actually use it
|
|
194
|
+
```typescript
|
|
195
|
+
// Add to InstallContext.tsx
|
|
196
|
+
const { actions, timeSpent } = useEngagement();
|
|
197
|
+
|
|
198
|
+
// Show install prompt based on engagement
|
|
199
|
+
if (actions > 10 && timeSpent > 60000) {
|
|
200
|
+
// User is engaged, show install prompt
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Recommendation**: Remove unless there's a plan to use it within 2 sprints
|
|
205
|
+
|
|
206
|
+
**See**: [RECOMMENDATIONS.md#handle-unused-engagement-metrics](./RECOMMENDATIONS.md#handle-unused-engagement-metrics)
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### P2-2: Context Composition Complexity
|
|
211
|
+
|
|
212
|
+
**Location**: `context/InstallContext.tsx:81-84`
|
|
213
|
+
|
|
214
|
+
**Issue**: Conditional context wrapping makes composition hard to follow
|
|
215
|
+
|
|
216
|
+
**Code**:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
// Wrap with PushProvider if configured
|
|
220
|
+
if (config.pushNotifications) {
|
|
221
|
+
content = <PushProvider {...config.pushNotifications}>{content}</PushProvider>;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Problem**:
|
|
226
|
+
- Magic wrapping based on config
|
|
227
|
+
- Hard to understand composition tree
|
|
228
|
+
- Difficult to test in isolation
|
|
229
|
+
|
|
230
|
+
**Impact**: 🟡 Medium
|
|
231
|
+
- Developer confusion
|
|
232
|
+
- Harder to test
|
|
233
|
+
- Implicit dependencies
|
|
234
|
+
|
|
235
|
+
**Effort**: Medium (30 minutes)
|
|
236
|
+
|
|
237
|
+
**Fix**: Make composition explicit
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// ✅ Explicit composition (recommended)
|
|
241
|
+
export function PwaProvider({ children, ...config }: PwaConfig & { children: React.ReactNode }) {
|
|
242
|
+
if (config.enabled === false) return <>{children}</>;
|
|
243
|
+
|
|
244
|
+
// Build context tree explicitly
|
|
245
|
+
return (
|
|
246
|
+
<InstallProvider {...config}>
|
|
247
|
+
<ConditionalPushProvider enabled={!!config.pushNotifications} {...config.pushNotifications}>
|
|
248
|
+
{children}
|
|
249
|
+
</ConditionalPushProvider>
|
|
250
|
+
</InstallProvider>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**See**: [RECOMMENDATIONS.md#simplify-context-composition](./RECOMMENDATIONS.md#simplify-context-composition)
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
### P2-3: No Server-Side Push Subscription Persistence
|
|
260
|
+
|
|
261
|
+
**Location**: `hooks/usePushNotifications.ts:117-123`
|
|
262
|
+
|
|
263
|
+
**Issue**: Push subscriptions only saved client-side
|
|
264
|
+
|
|
265
|
+
**Code**:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// Send subscription to server
|
|
269
|
+
if (options.subscribeEndpoint) {
|
|
270
|
+
await fetch(options.subscribeEndpoint, {
|
|
271
|
+
method: 'POST',
|
|
272
|
+
headers: { 'Content-Type': 'application/json' },
|
|
273
|
+
body: JSON.stringify(subscription),
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Problem**:
|
|
279
|
+
- No error handling for server failure
|
|
280
|
+
- No confirmation that server saved it
|
|
281
|
+
- No way to sync subscriptions across devices
|
|
282
|
+
- No unsubscribe endpoint
|
|
283
|
+
|
|
284
|
+
**Impact**: 🟡 Medium
|
|
285
|
+
- Silent failures possible
|
|
286
|
+
- Can't manage subscriptions on backend
|
|
287
|
+
- Can't send targeted push notifications
|
|
288
|
+
|
|
289
|
+
**Effort**: Medium (1-2 hours)
|
|
290
|
+
|
|
291
|
+
**Fix**: Add proper server-side persistence
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// Backend API route needed
|
|
295
|
+
POST /api/push/subscribe
|
|
296
|
+
DELETE /api/push/unsubscribe
|
|
297
|
+
GET /api/push/subscription
|
|
298
|
+
|
|
299
|
+
// Frontend changes
|
|
300
|
+
const response = await fetch(options.subscribeEndpoint, ...);
|
|
301
|
+
if (!response.ok) {
|
|
302
|
+
throw new Error('Server failed to save subscription');
|
|
303
|
+
}
|
|
304
|
+
const { success, subscriptionId } = await response.json();
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**See**: [RECOMMENDATIONS.md#add-server-side-persistence](./RECOMMENDATIONS.md#add-server-side-persistence)
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### P2-4: Limited Error Recovery for Push Subscriptions
|
|
312
|
+
|
|
313
|
+
**Location**: `hooks/usePushNotifications.ts:133-146`
|
|
314
|
+
|
|
315
|
+
**Issue**: Push subscription errors have no recovery mechanism
|
|
316
|
+
|
|
317
|
+
**Code**:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
} catch (error: any) {
|
|
321
|
+
pwaLogger.error('[usePushNotifications] Subscribe failed:', error);
|
|
322
|
+
|
|
323
|
+
// Diagnostic logging but no recovery
|
|
324
|
+
if (error.name === 'AbortError' || error.message?.includes('push service error')) {
|
|
325
|
+
pwaLogger.error('[usePushNotifications] Push service blocked. Possible causes:');
|
|
326
|
+
// ... more error logs
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return false; // Just fail, no retry
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Problem**:
|
|
334
|
+
- No retry logic for transient failures
|
|
335
|
+
- No user-facing error messages
|
|
336
|
+
- No recovery suggestions
|
|
337
|
+
|
|
338
|
+
**Impact**: 🟡 Medium
|
|
339
|
+
- Poor UX for temporary network issues
|
|
340
|
+
- Users confused why it failed
|
|
341
|
+
- No way to retry without page refresh
|
|
342
|
+
|
|
343
|
+
**Effort**: Medium (1 hour)
|
|
344
|
+
|
|
345
|
+
**Fix**: Add retry logic + user feedback
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// Add retry with exponential backoff
|
|
349
|
+
const subscribe = async (retries = 3): Promise<boolean> => {
|
|
350
|
+
for (let i = 0; i < retries; i++) {
|
|
351
|
+
try {
|
|
352
|
+
// ... subscription logic
|
|
353
|
+
return true;
|
|
354
|
+
} catch (error) {
|
|
355
|
+
if (i === retries - 1) {
|
|
356
|
+
// Last attempt failed - show user error
|
|
357
|
+
onError?.(getErrorMessage(error));
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
// Wait before retry (exponential backoff)
|
|
361
|
+
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return false;
|
|
365
|
+
};
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**See**: [RECOMMENDATIONS.md#improve-error-recovery](./RECOMMENDATIONS.md#improve-error-recovery)
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## P3: Nice to Have
|
|
373
|
+
|
|
374
|
+
Low priority improvements that would enhance quality but aren't blocking.
|
|
375
|
+
|
|
376
|
+
### P3-1: No Tests
|
|
377
|
+
|
|
378
|
+
**Location**: Entire `src/snippets/PWA/` directory
|
|
379
|
+
|
|
380
|
+
**Issue**: Zero unit tests, zero integration tests
|
|
381
|
+
|
|
382
|
+
**Problem**:
|
|
383
|
+
- Can't verify correctness
|
|
384
|
+
- Regressions possible
|
|
385
|
+
- Refactoring risky
|
|
386
|
+
|
|
387
|
+
**Impact**: 🟢 Low (for now)
|
|
388
|
+
- No issues currently
|
|
389
|
+
- But future changes risky
|
|
390
|
+
|
|
391
|
+
**Effort**: High (4-8 hours for full coverage)
|
|
392
|
+
|
|
393
|
+
**Fix**: Add tests incrementally
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
// utils/platform.test.ts
|
|
397
|
+
describe('isStandalone', () => {
|
|
398
|
+
it('returns false when window is undefined', () => {
|
|
399
|
+
expect(isStandalone()).toBe(false);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('checks matchMedia for standalone display mode', () => {
|
|
403
|
+
// ... test implementation
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Priority**: Start with utils (pure functions), then hooks, then components
|
|
409
|
+
|
|
410
|
+
**See**: [RECOMMENDATIONS.md#add-testing](./RECOMMENDATIONS.md#add-testing)
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
### P3-2: Limited Accessibility
|
|
415
|
+
|
|
416
|
+
**Location**:
|
|
417
|
+
- `components/A2HSHint.tsx`
|
|
418
|
+
- `components/PushPrompt.tsx`
|
|
419
|
+
- `components/IOSGuideModal.tsx`
|
|
420
|
+
|
|
421
|
+
**Issue**: Missing some ARIA labels and keyboard navigation
|
|
422
|
+
|
|
423
|
+
**Examples**:
|
|
424
|
+
- Close buttons have aria-label ✅
|
|
425
|
+
- But modals don't trap focus ❌
|
|
426
|
+
- No keyboard shortcut to dismiss ❌
|
|
427
|
+
- No screen reader announcements ❌
|
|
428
|
+
|
|
429
|
+
**Impact**: 🟢 Low
|
|
430
|
+
- Works with screen readers (basic)
|
|
431
|
+
- But not optimal
|
|
432
|
+
|
|
433
|
+
**Effort**: Medium (2-3 hours)
|
|
434
|
+
|
|
435
|
+
**Fix**: Enhance accessibility
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
// Add focus trap
|
|
439
|
+
import { useFocusTrap } from '@djangocfg/ui-nextjs/hooks';
|
|
440
|
+
|
|
441
|
+
export function IOSGuideModal({ open, onDismiss }: Props) {
|
|
442
|
+
const focusTrapRef = useFocusTrap<HTMLDivElement>(open);
|
|
443
|
+
|
|
444
|
+
return (
|
|
445
|
+
<Dialog open={open} onOpenChange={onDismiss}>
|
|
446
|
+
<DialogContent ref={focusTrapRef} role="alertdialog" aria-describedby="ios-guide-description">
|
|
447
|
+
{/* Add keyboard listener */}
|
|
448
|
+
<div onKeyDown={(e) => e.key === 'Escape' && onDismiss()}>
|
|
449
|
+
{/* content */}
|
|
450
|
+
</div>
|
|
451
|
+
</DialogContent>
|
|
452
|
+
</Dialog>
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**See**: [RECOMMENDATIONS.md#improve-accessibility](./RECOMMENDATIONS.md#improve-accessibility)
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
### P3-3: TypeScript Not in Strict Mode
|
|
462
|
+
|
|
463
|
+
**Location**: `tsconfig.json` (parent)
|
|
464
|
+
|
|
465
|
+
**Issue**: TypeScript strict mode not enabled
|
|
466
|
+
|
|
467
|
+
**Examples**:
|
|
468
|
+
```typescript
|
|
469
|
+
// These would be caught in strict mode
|
|
470
|
+
const value: any = something; // any should be avoided
|
|
471
|
+
element?.addEventListener('click', handler); // handler type unclear
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**Impact**: 🟢 Low
|
|
475
|
+
- Current code works fine
|
|
476
|
+
- But future changes could introduce bugs
|
|
477
|
+
|
|
478
|
+
**Effort**: Medium (2-4 hours to fix all errors)
|
|
479
|
+
|
|
480
|
+
**Fix**: Enable strict mode incrementally
|
|
481
|
+
|
|
482
|
+
```json
|
|
483
|
+
// tsconfig.json
|
|
484
|
+
{
|
|
485
|
+
"compilerOptions": {
|
|
486
|
+
"strict": true,
|
|
487
|
+
"noImplicitAny": true,
|
|
488
|
+
"strictNullChecks": true,
|
|
489
|
+
"strictFunctionTypes": true,
|
|
490
|
+
"strictPropertyInitialization": true
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
Then fix all resulting type errors.
|
|
496
|
+
|
|
497
|
+
**See**: [RECOMMENDATIONS.md#enable-typescript-strict-mode](./RECOMMENDATIONS.md#enable-typescript-strict-mode)
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Issue Summary by File
|
|
502
|
+
|
|
503
|
+
| File | P1 Issues | P2 Issues | P3 Issues | Total |
|
|
504
|
+
|------|-----------|-----------|-----------|-------|
|
|
505
|
+
| config.ts | 1 | 0 | 0 | 1 |
|
|
506
|
+
| PushPrompt.tsx | 1 | 0 | 1 | 2 |
|
|
507
|
+
| A2HSHint.tsx | 1 | 0 | 1 | 2 |
|
|
508
|
+
| PushContext.tsx | 1 | 1 | 0 | 2 |
|
|
509
|
+
| InstallContext.tsx | 0 | 1 | 0 | 1 |
|
|
510
|
+
| usePushNotifications.ts | 0 | 1 | 0 | 1 |
|
|
511
|
+
| localStorage.ts | 1 | 1 | 0 | 2 |
|
|
512
|
+
| IOSGuide components | 0 | 0 | 1 | 1 |
|
|
513
|
+
| Testing/TS Config | 0 | 0 | 2 | 2 |
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## Recommended Fix Order
|
|
518
|
+
|
|
519
|
+
### Sprint 1 (P1 Issues - ~30 minutes total)
|
|
520
|
+
|
|
521
|
+
1. Fix security vulnerability (config.ts) - **5 min**
|
|
522
|
+
2. Replace console.error with pwaLogger (3 files) - **10 min**
|
|
523
|
+
3. Centralize localStorage keys - **15 min**
|
|
524
|
+
|
|
525
|
+
**Impact**: Eliminates all P1 issues
|
|
526
|
+
|
|
527
|
+
### Sprint 2 (P2 High-Value Issues - ~2 hours)
|
|
528
|
+
|
|
529
|
+
4. Remove unused EngagementMetrics OR implement usage - **30 min**
|
|
530
|
+
5. Add server-side push subscription persistence - **1.5 hours**
|
|
531
|
+
|
|
532
|
+
**Impact**: Reduces bundle size, enables proper push management
|
|
533
|
+
|
|
534
|
+
### Sprint 3 (P2 Polish - ~1.5 hours)
|
|
535
|
+
|
|
536
|
+
6. Simplify context composition - **30 min**
|
|
537
|
+
7. Improve error recovery for push subscriptions - **1 hour**
|
|
538
|
+
|
|
539
|
+
**Impact**: Better DX and UX
|
|
540
|
+
|
|
541
|
+
### Sprint 4+ (P3 - Ongoing)
|
|
542
|
+
|
|
543
|
+
8. Add tests (incrementally)
|
|
544
|
+
9. Improve accessibility
|
|
545
|
+
10. Enable TypeScript strict mode
|
|
546
|
+
|
|
547
|
+
**Impact**: Long-term quality improvements
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Conclusion
|
|
552
|
+
|
|
553
|
+
**Critical**: Only 3 P1 issues, all fixable in ~30 minutes
|
|
554
|
+
**Important**: 4 P2 issues, addressable over 2-3 sprints
|
|
555
|
+
**Optional**: 3 P3 issues for long-term quality
|
|
556
|
+
|
|
557
|
+
**Next Steps**: See [RECOMMENDATIONS.md](./RECOMMENDATIONS.md) for detailed fixes with code examples.
|