@djangocfg/layouts 2.1.37 → 2.1.38

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 (77) hide show
  1. package/README.md +204 -18
  2. package/package.json +5 -5
  3. package/src/components/errors/index.ts +9 -0
  4. package/src/components/errors/types.ts +38 -0
  5. package/src/layouts/AppLayout/AppLayout.tsx +33 -45
  6. package/src/layouts/AppLayout/BaseApp.tsx +104 -33
  7. package/src/layouts/AuthLayout/AuthContext.tsx +7 -1
  8. package/src/layouts/AuthLayout/OAuthProviders.tsx +1 -10
  9. package/src/layouts/AuthLayout/OTPForm.tsx +1 -0
  10. package/src/layouts/PrivateLayout/PrivateLayout.tsx +1 -1
  11. package/src/layouts/PublicLayout/PublicLayout.tsx +1 -1
  12. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +1 -1
  13. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +1 -1
  14. package/src/layouts/_components/UserMenu.tsx +1 -1
  15. package/src/layouts/index.ts +1 -1
  16. package/src/layouts/types/index.ts +47 -0
  17. package/src/layouts/types/layout.types.ts +61 -0
  18. package/src/layouts/types/providers.types.ts +65 -0
  19. package/src/layouts/types/ui.types.ts +103 -0
  20. package/src/snippets/Analytics/index.ts +1 -0
  21. package/src/snippets/Analytics/types.ts +10 -0
  22. package/src/snippets/PWAInstall/@docs/README.md +92 -0
  23. package/src/snippets/PWAInstall/README.md +185 -0
  24. package/src/snippets/{PWA → PWAInstall}/components/A2HSHint.tsx +85 -84
  25. package/src/snippets/PWAInstall/components/DesktopGuide.tsx +229 -0
  26. package/src/snippets/PWAInstall/context/InstallContext.tsx +102 -0
  27. package/src/snippets/{PWA → PWAInstall}/hooks/useInstallPrompt.ts +3 -0
  28. package/src/snippets/{PWA → PWAInstall}/index.ts +12 -31
  29. package/src/snippets/{PWA → PWAInstall}/types/components.ts +0 -6
  30. package/src/snippets/PWAInstall/types/config.ts +22 -0
  31. package/src/snippets/{PWA → PWAInstall}/types/index.ts +4 -4
  32. package/src/snippets/{PWA → PWAInstall}/utils/localStorage.ts +1 -23
  33. package/src/snippets/PushNotifications/@docs/README.md +191 -0
  34. package/src/snippets/PushNotifications/@docs/guides/django-integration.md +648 -0
  35. package/src/snippets/PushNotifications/@docs/guides/service-worker.md +467 -0
  36. package/src/snippets/PushNotifications/@docs/guides/vapid-setup.md +352 -0
  37. package/src/snippets/PushNotifications/README.md +328 -0
  38. package/src/snippets/{PWA → PushNotifications}/config.ts +2 -2
  39. package/src/snippets/PushNotifications/context/DjangoPushContext.tsx +190 -0
  40. package/src/snippets/{PWA → PushNotifications}/hooks/useDjangoPush.ts +63 -81
  41. package/src/snippets/{PWA → PushNotifications}/hooks/usePushNotifications.ts +12 -8
  42. package/src/snippets/PushNotifications/index.ts +87 -0
  43. package/src/snippets/PushNotifications/types/config.ts +28 -0
  44. package/src/snippets/PushNotifications/types/index.ts +9 -0
  45. package/src/snippets/PushNotifications/utils/localStorage.ts +60 -0
  46. package/src/snippets/PushNotifications/utils/logger.ts +149 -0
  47. package/src/snippets/PushNotifications/utils/platform.ts +151 -0
  48. package/src/snippets/index.ts +37 -12
  49. package/src/layouts/shared/index.ts +0 -21
  50. package/src/layouts/shared/types.ts +0 -247
  51. package/src/snippets/PWA/@refactoring/ARCHITECTURE_ANALYSIS.md +0 -1179
  52. package/src/snippets/PWA/@refactoring/EXECUTIVE_SUMMARY.md +0 -271
  53. package/src/snippets/PWA/@refactoring/README.md +0 -204
  54. package/src/snippets/PWA/@refactoring/REFACTORING_PROPOSALS.md +0 -1109
  55. package/src/snippets/PWA/@refactoring2/COMPARISON-WITH-NEXTJS.md +0 -718
  56. package/src/snippets/PWA/@refactoring2/P1-FIXES-COMPLETED.md +0 -188
  57. package/src/snippets/PWA/@refactoring2/POST-P0-ANALYSIS.md +0 -362
  58. package/src/snippets/PWA/@refactoring2/README.md +0 -85
  59. package/src/snippets/PWA/@refactoring2/RECOMMENDATIONS.md +0 -1321
  60. package/src/snippets/PWA/@refactoring2/REMAINING-ISSUES.md +0 -557
  61. package/src/snippets/PWA/README.md +0 -387
  62. package/src/snippets/PWA/context/DjangoPushContext.tsx +0 -105
  63. package/src/snippets/PWA/context/InstallContext.tsx +0 -118
  64. package/src/snippets/PWA/context/PushContext.tsx +0 -156
  65. /package/src/layouts/{shared → types}/README.md +0 -0
  66. /package/src/snippets/{PWA/@docs/research.md → PWAInstall/@docs/research/ios-android-install-flows.md} +0 -0
  67. /package/src/snippets/{PWA → PWAInstall}/components/IOSGuide.tsx +0 -0
  68. /package/src/snippets/{PWA → PWAInstall}/components/IOSGuideDrawer.tsx +0 -0
  69. /package/src/snippets/{PWA → PWAInstall}/components/IOSGuideModal.tsx +0 -0
  70. /package/src/snippets/{PWA → PWAInstall}/hooks/useIsPWA.ts +0 -0
  71. /package/src/snippets/{PWA → PWAInstall}/types/install.ts +0 -0
  72. /package/src/snippets/{PWA → PWAInstall}/types/platform.ts +0 -0
  73. /package/src/snippets/{PWA → PWAInstall}/utils/logger.ts +0 -0
  74. /package/src/snippets/{PWA → PWAInstall}/utils/platform.ts +0 -0
  75. /package/src/snippets/{PWA → PushNotifications}/components/PushPrompt.tsx +0 -0
  76. /package/src/snippets/{PWA → PushNotifications}/types/push.ts +0 -0
  77. /package/src/snippets/{PWA → PushNotifications}/utils/vapid.ts +0 -0
@@ -0,0 +1,229 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Desktop Installation Guide Modal
5
+ *
6
+ * Visual step-by-step guide for installing PWA on desktop browsers
7
+ * Uses platform detection from InstallContext
8
+ * Supports: Chrome, Edge, Brave, Arc, Vivaldi, Opera, Yandex, Firefox, Safari
9
+ */
10
+
11
+ import React, { useMemo } from 'react';
12
+ import { Monitor, Check, ArrowDownToLine, Menu, Search, Plus } from 'lucide-react';
13
+
14
+ import {
15
+ Dialog,
16
+ DialogContent,
17
+ DialogDescription,
18
+ DialogFooter,
19
+ DialogHeader,
20
+ DialogTitle,
21
+ Button,
22
+ Card,
23
+ CardContent,
24
+ } from '@djangocfg/ui-nextjs';
25
+
26
+ import type { IOSGuideModalProps, InstallStep } from '../types';
27
+ import { useInstall } from '../context/InstallContext';
28
+
29
+ type BrowserCategory = 'chromium' | 'firefox' | 'safari' | 'unknown';
30
+
31
+ function getBrowserCategory(browser: {
32
+ isChromium: boolean;
33
+ isFirefox: boolean;
34
+ isSafari: boolean;
35
+ }): BrowserCategory {
36
+ if (browser.isChromium) return 'chromium';
37
+ if (browser.isFirefox) return 'firefox';
38
+ if (browser.isSafari) return 'safari';
39
+ return 'unknown';
40
+ }
41
+
42
+ function getBrowserSteps(category: BrowserCategory, browserName: string): InstallStep[] {
43
+ switch (category) {
44
+ case 'chromium':
45
+ // Chrome, Edge, Brave, Arc, Vivaldi, Opera, Yandex, etc.
46
+ return [
47
+ {
48
+ number: 1,
49
+ title: 'Find Install Icon',
50
+ icon: ArrowDownToLine,
51
+ description: 'Look for install icon in address bar (right side)',
52
+ },
53
+ {
54
+ number: 2,
55
+ title: 'Click Install',
56
+ icon: Plus,
57
+ description: 'Click the icon and select "Install"',
58
+ },
59
+ {
60
+ number: 3,
61
+ title: 'Confirm',
62
+ icon: Check,
63
+ description: 'Click "Install" in the popup dialog',
64
+ },
65
+ ];
66
+
67
+ case 'firefox':
68
+ return [
69
+ {
70
+ number: 1,
71
+ title: 'Open Menu',
72
+ icon: Menu,
73
+ description: 'Click the menu button (three lines)',
74
+ },
75
+ {
76
+ number: 2,
77
+ title: 'Find Install Option',
78
+ icon: Search,
79
+ description: 'Look for "Install" or "Add to Home Screen"',
80
+ },
81
+ {
82
+ number: 3,
83
+ title: 'Confirm',
84
+ icon: Check,
85
+ description: 'Follow the installation prompts',
86
+ },
87
+ ];
88
+
89
+ case 'safari':
90
+ return [
91
+ {
92
+ number: 1,
93
+ title: 'Limited Support',
94
+ icon: Monitor,
95
+ description: 'Safari on macOS has limited PWA support',
96
+ },
97
+ {
98
+ number: 2,
99
+ title: 'Use Chromium Browser',
100
+ icon: ArrowDownToLine,
101
+ description: 'Consider using Chrome, Edge, or Brave for full PWA experience',
102
+ },
103
+ ];
104
+
105
+ default:
106
+ return [
107
+ {
108
+ number: 1,
109
+ title: 'Check Address Bar',
110
+ icon: ArrowDownToLine,
111
+ description: 'Look for an install or download icon',
112
+ },
113
+ {
114
+ number: 2,
115
+ title: 'Or Use Menu',
116
+ icon: Menu,
117
+ description: 'Check browser menu for install option',
118
+ },
119
+ {
120
+ number: 3,
121
+ title: 'Confirm',
122
+ icon: Check,
123
+ description: 'Follow the installation prompts',
124
+ },
125
+ ];
126
+ }
127
+ }
128
+
129
+ function StepCard({ step }: { step: InstallStep }) {
130
+ return (
131
+ <Card className="border border-border">
132
+ <CardContent className="p-4">
133
+ <div className="flex items-start gap-3">
134
+ <div
135
+ className="flex items-center justify-center rounded-full bg-primary text-primary-foreground flex-shrink-0"
136
+ style={{ width: '32px', height: '32px' }}
137
+ >
138
+ <span className="text-sm font-semibold">{step.number}</span>
139
+ </div>
140
+
141
+ <div className="flex-1 min-w-0">
142
+ <div className="flex items-center gap-2 mb-1">
143
+ <step.icon className="w-5 h-5 text-primary" />
144
+ <h3 className="font-semibold text-foreground">{step.title}</h3>
145
+ </div>
146
+ <p className="text-sm text-muted-foreground">{step.description}</p>
147
+ </div>
148
+ </div>
149
+ </CardContent>
150
+ </Card>
151
+ );
152
+ }
153
+
154
+ export function DesktopGuide({ onDismiss, open = true }: IOSGuideModalProps) {
155
+ const {
156
+ browserName,
157
+ isChromium,
158
+ isFirefox,
159
+ isSafari,
160
+ isEdge,
161
+ isBrave,
162
+ isArc,
163
+ isVivaldi,
164
+ isOpera,
165
+ isYandex,
166
+ } = useInstall();
167
+
168
+ const category = useMemo(
169
+ () => getBrowserCategory({ isChromium, isFirefox, isSafari }),
170
+ [isChromium, isFirefox, isSafari]
171
+ );
172
+
173
+ const steps = useMemo(() => getBrowserSteps(category, browserName), [category, browserName]);
174
+
175
+ // Get specific browser display name with emoji
176
+ const displayName = useMemo(() => {
177
+ if (isEdge) return 'Edge';
178
+ if (isBrave) return 'Brave';
179
+ if (isArc) return 'Arc';
180
+ if (isVivaldi) return 'Vivaldi';
181
+ if (isOpera) return 'Opera';
182
+ if (isYandex) return 'Yandex Browser';
183
+ return browserName;
184
+ }, [browserName, isEdge, isBrave, isArc, isVivaldi, isOpera, isYandex]);
185
+
186
+ return (
187
+ <Dialog open={open} onOpenChange={(isOpen) => !isOpen && onDismiss()}>
188
+ <DialogContent className="sm:max-w-md">
189
+ <DialogHeader className="text-left">
190
+ <DialogTitle className="flex items-center gap-2">
191
+ <Monitor className="w-5 h-5 text-primary" />
192
+ Install App on Desktop
193
+ </DialogTitle>
194
+ <DialogDescription className="text-left">
195
+ {isSafari
196
+ ? 'Safari on macOS has limited PWA support. For the best experience, use Chrome, Edge, or Brave.'
197
+ : `Install this app on ${displayName} for quick access from your desktop`
198
+ }
199
+ </DialogDescription>
200
+ </DialogHeader>
201
+
202
+ <div className="space-y-3 py-4">
203
+ {steps.map((step) => (
204
+ <StepCard key={step.number} step={step} />
205
+ ))}
206
+ </div>
207
+
208
+ {category === 'chromium' && (
209
+ <div className="p-3 bg-muted/30 rounded-lg text-xs text-muted-foreground">
210
+ 💡 Tip: You can also right-click the page and look for "Install" option in {displayName}
211
+ </div>
212
+ )}
213
+
214
+ {category === 'firefox' && (
215
+ <div className="p-3 bg-amber-500/10 rounded-lg text-xs text-amber-700 dark:text-amber-400">
216
+ ℹ️ Note: Firefox has limited PWA support. Some features may not work as expected.
217
+ </div>
218
+ )}
219
+
220
+ <DialogFooter>
221
+ <Button onClick={onDismiss} variant="default" className="w-full">
222
+ <Check className="w-4 h-4 mr-2" />
223
+ Got It
224
+ </Button>
225
+ </DialogFooter>
226
+ </DialogContent>
227
+ </Dialog>
228
+ );
229
+ }
@@ -0,0 +1,102 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * PWA Install Context
5
+ *
6
+ * Minimal global state for PWA installation
7
+ * No tracking, no metrics, no engagement — just install state
8
+ */
9
+
10
+ import React, { createContext, useContext, ReactNode } from 'react';
11
+
12
+ import type { InstallOutcome } from '../types';
13
+ import { useInstallPrompt } from '../hooks/useInstallPrompt';
14
+
15
+ export interface PwaContextValue {
16
+ // Platform
17
+ isIOS: boolean;
18
+ isAndroid: boolean;
19
+ isDesktop: boolean;
20
+
21
+ // Browsers
22
+ isSafari: boolean;
23
+ isChrome: boolean;
24
+ isFirefox: boolean;
25
+ isEdge: boolean;
26
+ isOpera: boolean;
27
+ isBrave: boolean;
28
+ isArc: boolean;
29
+ isVivaldi: boolean;
30
+ isYandex: boolean;
31
+ isSamsungBrowser: boolean;
32
+ isUCBrowser: boolean;
33
+ isChromium: boolean; // Any Chromium-based browser
34
+ browserName: string;
35
+
36
+ // State
37
+ isInstalled: boolean;
38
+ canPrompt: boolean;
39
+
40
+ // Actions
41
+ install: () => Promise<InstallOutcome>;
42
+ }
43
+
44
+ const PwaContext = createContext<PwaContextValue | undefined>(undefined);
45
+
46
+ export interface PwaConfig {
47
+ enabled?: boolean;
48
+ }
49
+
50
+ export function PwaProvider({ children, ...config }: PwaConfig & { children: ReactNode }) {
51
+ // If not enabled, acts as a simple pass-through
52
+ if (config.enabled === false) {
53
+ return <>{children}</>;
54
+ }
55
+
56
+ const prompt = useInstallPrompt();
57
+
58
+ const value: PwaContextValue = {
59
+ // Platform
60
+ isIOS: prompt.isIOS,
61
+ isAndroid: prompt.isAndroid,
62
+ isDesktop: !prompt.isIOS && !prompt.isAndroid,
63
+
64
+ // Browsers (from useBrowserDetect)
65
+ isSafari: prompt.browser.isSafari && !prompt.browser.isChromium, // Real Safari only
66
+ isChrome: prompt.browser.isChrome,
67
+ isFirefox: prompt.browser.isFirefox,
68
+ isEdge: prompt.browser.isEdge,
69
+ isOpera: prompt.browser.isOpera,
70
+ isBrave: prompt.browser.isBrave,
71
+ isArc: prompt.browser.isArc,
72
+ isVivaldi: prompt.browser.isVivaldi,
73
+ isYandex: prompt.browser.isYandex,
74
+ isSamsungBrowser: prompt.browser.isSamsungBrowser,
75
+ isUCBrowser: prompt.browser.isUCBrowser,
76
+ isChromium: prompt.browser.isChromium,
77
+ browserName: prompt.browser.browserName,
78
+
79
+ // State
80
+ isInstalled: prompt.isInstalled,
81
+ canPrompt: prompt.canPrompt,
82
+
83
+ // Actions
84
+ install: prompt.promptInstall,
85
+ };
86
+
87
+ return <PwaContext.Provider value={value}>{children}</PwaContext.Provider>;
88
+ }
89
+
90
+ /**
91
+ * Use install context
92
+ * Must be used within <PwaProvider>
93
+ */
94
+ export function useInstall(): PwaContextValue {
95
+ const context = useContext(PwaContext);
96
+
97
+ if (context === undefined) {
98
+ throw new Error('useInstall must be used within <PwaProvider>');
99
+ }
100
+
101
+ return context;
102
+ }
@@ -160,5 +160,8 @@ export function useInstallPrompt() {
160
160
  return {
161
161
  ...state,
162
162
  promptInstall,
163
+ // Expose full browser info
164
+ browser,
165
+ device,
163
166
  };
164
167
  }
@@ -1,20 +1,19 @@
1
1
  /**
2
- * PWA Install Flow (Simplified)
2
+ * PWA Install Snippet
3
3
  *
4
- * Ultra-simple PWA installation for Cmdop
5
- * No tracking, no metrics, no complexity just install
4
+ * Simplified PWA installation for web apps
5
+ * Handles Add to Home Screen (A2HS) for iOS Safari and Android Chrome
6
6
  *
7
7
  * @example Basic usage
8
8
  * ```tsx
9
- * import { InstallProvider, A2HSHint } from './PwaInstall';
10
- * import { DEFAULT_VAPID_PUBLIC_KEY } from './config';
9
+ * import { PwaProvider, A2HSHint } from '@/snippets/PWAInstall';
11
10
  *
12
11
  * export default function Layout({ children }) {
13
12
  * return (
14
- * <InstallProvider>
13
+ * <PwaProvider>
15
14
  * {children}
16
15
  * <A2HSHint resetAfterDays={3} />
17
- * </InstallProvider>
16
+ * </PwaProvider>
18
17
  * );
19
18
  * }
20
19
  * ```
@@ -22,19 +21,12 @@
22
21
 
23
22
  // Main API
24
23
  export { PwaProvider, useInstall } from './context/InstallContext';
25
- export { PushProvider, usePush } from './context/PushContext';
26
- export type { PushMessage, PushContextValue } from './context/PushContext';
27
-
28
- // Django Integration
29
- export { DjangoPushProvider, useDjangoPushContext } from './context/DjangoPushContext';
30
24
  export { A2HSHint } from './components/A2HSHint';
31
- export { PushPrompt } from './components/PushPrompt';
32
- export { DEFAULT_VAPID_PUBLIC_KEY } from './config';
25
+ export { IOSGuide } from './components/IOSGuide';
26
+ export { DesktopGuide } from './components/DesktopGuide';
33
27
 
34
28
  // Hooks
35
29
  export { useIsPWA, clearIsPWACache, type UseIsPWAOptions } from './hooks/useIsPWA';
36
- export { usePushNotifications } from './hooks/usePushNotifications';
37
- export { useDjangoPush } from './hooks/useDjangoPush';
38
30
 
39
31
  // Utilities
40
32
  export {
@@ -53,24 +45,16 @@ export {
53
45
  isPWADebugEnabled,
54
46
  } from './utils/logger';
55
47
 
56
- export {
57
- urlBase64ToUint8Array,
58
- isValidVapidKey,
59
- getVapidKeyInfo,
60
- safeUrlBase64ToUint8Array,
61
- VapidKeyError,
62
- type VapidKeyErrorCode,
63
- } from './utils/vapid';
64
-
65
48
  export {
66
49
  STORAGE_KEYS,
67
50
  markA2HSDismissed,
68
- markPushDismissed,
69
51
  isA2HSDismissedRecently,
70
- isPushDismissedRecently,
71
- clearAllPWAData,
52
+ clearAllPWAInstallData,
72
53
  } from './utils/localStorage';
73
54
 
55
+ // Types - Configuration
56
+ export type { PwaInstallConfig } from './types';
57
+
74
58
  // Types - Platform
75
59
  export type { PlatformInfo } from './types';
76
60
 
@@ -82,9 +66,6 @@ export type {
82
66
  IOSGuideState,
83
67
  } from './types';
84
68
 
85
- // Types - Push Notifications
86
- export type { PushNotificationState, PushNotificationOptions } from './types';
87
-
88
69
  // Types - Components
89
70
  export type {
90
71
  InstallContextType,
@@ -4,7 +4,6 @@
4
4
 
5
5
  import type { PlatformInfo } from './platform';
6
6
  import type { InstallOutcome } from './install';
7
- import type { PushNotificationState } from './push';
8
7
 
9
8
  /**
10
9
  * Install context type
@@ -22,11 +21,6 @@ export interface InstallContextType {
22
21
  // Actions
23
22
  promptInstall: () => Promise<InstallOutcome>;
24
23
  dismissIOSGuide: () => void;
25
-
26
- // Push Notifications
27
- pushState: PushNotificationState;
28
- subscribeToPush: () => Promise<boolean>;
29
- unsubscribeFromPush: () => Promise<boolean>;
30
24
  }
31
25
 
32
26
  /**
@@ -0,0 +1,22 @@
1
+ /**
2
+ * PWA Install Configuration Types
3
+ *
4
+ * Configuration for Progressive Web App installation features
5
+ */
6
+
7
+ export interface PwaInstallConfig {
8
+ /** Enable PWA installation features */
9
+ enabled?: boolean;
10
+
11
+ /** Show A2HS (Add to Home Screen) hint (enabled by default when enabled is true) */
12
+ showInstallHint?: boolean;
13
+
14
+ /** Number of days before re-showing dismissed hint (null = never show again) */
15
+ resetAfterDays?: number | null;
16
+
17
+ /** Delay before showing hint (ms) */
18
+ delayMs?: number;
19
+
20
+ /** App logo URL to display in hint */
21
+ logo?: string;
22
+ }
@@ -1,7 +1,10 @@
1
1
  /**
2
- * PWA Types - Central Export
2
+ * PWA Install Types - Central Export
3
3
  */
4
4
 
5
+ // Configuration
6
+ export type { PwaInstallConfig } from './config';
7
+
5
8
  // Platform
6
9
  export type { PlatformInfo } from './platform';
7
10
 
@@ -13,9 +16,6 @@ export type {
13
16
  IOSGuideState,
14
17
  } from './install';
15
18
 
16
- // Push Notifications
17
- export type { PushNotificationState, PushNotificationOptions } from './push';
18
-
19
19
  // Components
20
20
  export type {
21
21
  InstallContextType,
@@ -11,7 +11,6 @@ export const STORAGE_KEYS = {
11
11
  IOS_GUIDE_DISMISSED: 'pwa_ios_guide_dismissed_at',
12
12
  APP_INSTALLED: 'pwa_app_installed',
13
13
  A2HS_DISMISSED: 'pwa_a2hs_dismissed_at',
14
- PUSH_DISMISSED: 'pwa_push_dismissed_at',
15
14
  } as const;
16
15
 
17
16
  /**
@@ -149,26 +148,6 @@ export function markA2HSDismissed(): void {
149
148
  }
150
149
  }
151
150
 
152
- /**
153
- * Check if push prompt was dismissed recently
154
- * @param resetDays Number of days before re-showing (default: 7)
155
- */
156
- export function isPushDismissedRecently(resetDays: number = 7): boolean {
157
- return isDismissedRecentlyHelper(resetDays, STORAGE_KEYS.PUSH_DISMISSED);
158
- }
159
-
160
- /**
161
- * Mark push prompt as dismissed
162
- */
163
- export function markPushDismissed(): void {
164
- if (typeof window === 'undefined') return;
165
- try {
166
- localStorage.setItem(STORAGE_KEYS.PUSH_DISMISSED, Date.now().toString());
167
- } catch {
168
- // Fail silently
169
- }
170
- }
171
-
172
151
  /**
173
152
  * Helper: Check if a key was dismissed recently
174
153
  * @internal
@@ -189,14 +168,13 @@ function isDismissedRecentlyHelper(resetDays: number, key: string): boolean {
189
168
  /**
190
169
  * Clear all PWA install data
191
170
  */
192
- export function clearAllPWAData(): void {
171
+ export function clearAllPWAInstallData(): void {
193
172
  if (typeof window === 'undefined') return;
194
173
 
195
174
  try {
196
175
  localStorage.removeItem(STORAGE_KEYS.IOS_GUIDE_DISMISSED);
197
176
  localStorage.removeItem(STORAGE_KEYS.APP_INSTALLED);
198
177
  localStorage.removeItem(STORAGE_KEYS.A2HS_DISMISSED);
199
- localStorage.removeItem(STORAGE_KEYS.PUSH_DISMISSED);
200
178
  } catch {
201
179
  // Fail silently
202
180
  }