@moontra/moonui-pro 2.20.2 → 2.20.4

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 (153) hide show
  1. package/package.json +8 -3
  2. package/plugin/index.d.ts +86 -0
  3. package/plugin/index.js +308 -0
  4. package/scripts/postinstall.js +191 -23
  5. package/src/components/advanced-chart/index.tsx +0 -1246
  6. package/src/components/advanced-forms/index.tsx +0 -585
  7. package/src/components/animated-button/index.tsx +0 -385
  8. package/src/components/calendar/event-dialog.tsx +0 -377
  9. package/src/components/calendar/index.tsx +0 -1220
  10. package/src/components/calendar-pro/index.tsx +0 -1697
  11. package/src/components/color-picker/index.tsx +0 -432
  12. package/src/components/credit-card-input/index.tsx +0 -406
  13. package/src/components/dashboard/dashboard-grid.tsx +0 -480
  14. package/src/components/dashboard/demo.tsx +0 -425
  15. package/src/components/dashboard/index.tsx +0 -1046
  16. package/src/components/dashboard/time-range-picker.tsx +0 -336
  17. package/src/components/dashboard/types.ts +0 -225
  18. package/src/components/dashboard/widgets/activity-feed.tsx +0 -349
  19. package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
  20. package/src/components/dashboard/widgets/comparison-widget.tsx +0 -177
  21. package/src/components/dashboard/widgets/index.ts +0 -5
  22. package/src/components/dashboard/widgets/metric-card.tsx +0 -363
  23. package/src/components/dashboard/widgets/progress-widget.tsx +0 -113
  24. package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
  25. package/src/components/data-table/data-table-column-toggle.tsx +0 -169
  26. package/src/components/data-table/data-table-export.ts +0 -156
  27. package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
  28. package/src/components/data-table/index.tsx +0 -845
  29. package/src/components/draggable-list/index.tsx +0 -100
  30. package/src/components/error-boundary/index.tsx +0 -232
  31. package/src/components/file-upload/index.tsx +0 -1660
  32. package/src/components/floating-action-button/index.tsx +0 -206
  33. package/src/components/form-wizard/form-wizard-context.tsx +0 -335
  34. package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
  35. package/src/components/form-wizard/form-wizard-progress.tsx +0 -329
  36. package/src/components/form-wizard/form-wizard-step.tsx +0 -111
  37. package/src/components/form-wizard/index.tsx +0 -102
  38. package/src/components/form-wizard/types.ts +0 -77
  39. package/src/components/gesture-drawer/index.tsx +0 -551
  40. package/src/components/github-stars/github-api.ts +0 -426
  41. package/src/components/github-stars/hooks.ts +0 -517
  42. package/src/components/github-stars/index.tsx +0 -375
  43. package/src/components/github-stars/types.ts +0 -148
  44. package/src/components/github-stars/variants.tsx +0 -515
  45. package/src/components/health-check/index.tsx +0 -439
  46. package/src/components/hover-card-3d/index.tsx +0 -529
  47. package/src/components/index.ts +0 -130
  48. package/src/components/internal/index.ts +0 -78
  49. package/src/components/kanban/add-card-modal.tsx +0 -502
  50. package/src/components/kanban/card-detail-modal.tsx +0 -761
  51. package/src/components/kanban/index.ts +0 -13
  52. package/src/components/kanban/kanban.tsx +0 -1689
  53. package/src/components/kanban/types.ts +0 -168
  54. package/src/components/lazy-component/index.tsx +0 -823
  55. package/src/components/license-error/index.tsx +0 -31
  56. package/src/components/magnetic-button/index.tsx +0 -216
  57. package/src/components/memory-efficient-data/index.tsx +0 -1018
  58. package/src/components/moonui-quiz-form/index.tsx +0 -817
  59. package/src/components/navbar/index.tsx +0 -781
  60. package/src/components/optimized-image/index.tsx +0 -425
  61. package/src/components/performance-debugger/index.tsx +0 -613
  62. package/src/components/performance-monitor/index.tsx +0 -808
  63. package/src/components/phone-number-input/index.tsx +0 -343
  64. package/src/components/phone-number-input/phone-number-input-simple.tsx +0 -167
  65. package/src/components/pinch-zoom/index.tsx +0 -566
  66. package/src/components/quiz-form/index.tsx +0 -479
  67. package/src/components/rich-text-editor/index.tsx +0 -2322
  68. package/src/components/rich-text-editor/slash-commands-extension.ts +0 -230
  69. package/src/components/rich-text-editor/slash-commands.css +0 -35
  70. package/src/components/rich-text-editor/table-styles.css +0 -65
  71. package/src/components/sidebar/index.tsx +0 -884
  72. package/src/components/spotlight-card/index.tsx +0 -191
  73. package/src/components/swipeable-card/index.tsx +0 -100
  74. package/src/components/timeline/index.tsx +0 -1183
  75. package/src/components/ui/accordion.tsx +0 -581
  76. package/src/components/ui/alert-dialog.tsx +0 -141
  77. package/src/components/ui/alert.tsx +0 -141
  78. package/src/components/ui/aspect-ratio.tsx +0 -245
  79. package/src/components/ui/avatar.tsx +0 -155
  80. package/src/components/ui/badge.tsx +0 -230
  81. package/src/components/ui/breadcrumb.tsx +0 -216
  82. package/src/components/ui/button.tsx +0 -228
  83. package/src/components/ui/calendar.tsx +0 -387
  84. package/src/components/ui/card.tsx +0 -216
  85. package/src/components/ui/checkbox.tsx +0 -259
  86. package/src/components/ui/collapsible.tsx +0 -631
  87. package/src/components/ui/color-picker.tsx +0 -97
  88. package/src/components/ui/command.tsx +0 -948
  89. package/src/components/ui/dialog.tsx +0 -752
  90. package/src/components/ui/dropdown-menu.tsx +0 -706
  91. package/src/components/ui/gesture-drawer.tsx +0 -11
  92. package/src/components/ui/hover-card.tsx +0 -29
  93. package/src/components/ui/index.ts +0 -222
  94. package/src/components/ui/input.tsx +0 -224
  95. package/src/components/ui/label.tsx +0 -29
  96. package/src/components/ui/lightbox.tsx +0 -606
  97. package/src/components/ui/magnetic-button.tsx +0 -129
  98. package/src/components/ui/media-gallery.tsx +0 -611
  99. package/src/components/ui/navigation-menu.tsx +0 -130
  100. package/src/components/ui/pagination.tsx +0 -125
  101. package/src/components/ui/popover.tsx +0 -185
  102. package/src/components/ui/progress.tsx +0 -30
  103. package/src/components/ui/radio-group.tsx +0 -257
  104. package/src/components/ui/scroll-area.tsx +0 -47
  105. package/src/components/ui/select.tsx +0 -378
  106. package/src/components/ui/separator.tsx +0 -145
  107. package/src/components/ui/sheet.tsx +0 -139
  108. package/src/components/ui/skeleton.tsx +0 -20
  109. package/src/components/ui/slider.tsx +0 -354
  110. package/src/components/ui/spotlight-card.tsx +0 -119
  111. package/src/components/ui/switch.tsx +0 -86
  112. package/src/components/ui/table.tsx +0 -331
  113. package/src/components/ui/tabs-pro.tsx +0 -542
  114. package/src/components/ui/tabs.tsx +0 -54
  115. package/src/components/ui/textarea.tsx +0 -28
  116. package/src/components/ui/toast.tsx +0 -317
  117. package/src/components/ui/toggle.tsx +0 -119
  118. package/src/components/ui/tooltip.tsx +0 -151
  119. package/src/components/virtual-list/index.tsx +0 -668
  120. package/src/hooks/use-chart.ts +0 -205
  121. package/src/hooks/use-data-table.ts +0 -182
  122. package/src/hooks/use-docs-pro-access.ts +0 -13
  123. package/src/hooks/use-license-check.ts +0 -65
  124. package/src/hooks/use-subscription.ts +0 -19
  125. package/src/hooks/use-toast.ts +0 -15
  126. package/src/index.ts +0 -22
  127. package/src/lib/ai-providers.ts +0 -377
  128. package/src/lib/component-metadata.ts +0 -18
  129. package/src/lib/micro-interactions.ts +0 -255
  130. package/src/lib/paddle.ts +0 -17
  131. package/src/lib/utils.ts +0 -6
  132. package/src/patterns/login-form/index.tsx +0 -276
  133. package/src/patterns/login-form/types.ts +0 -67
  134. package/src/setupTests.ts +0 -41
  135. package/src/styles/advanced-chart.css +0 -239
  136. package/src/styles/calendar.css +0 -35
  137. package/src/styles/design-system.css +0 -363
  138. package/src/styles/index.css +0 -681
  139. package/src/styles/tailwind.css +0 -7
  140. package/src/styles/tokens.css +0 -455
  141. package/src/types/next-auth.d.ts +0 -21
  142. package/src/use-intersection-observer.tsx +0 -154
  143. package/src/use-local-storage.tsx +0 -71
  144. package/src/use-paddle.ts +0 -138
  145. package/src/use-performance-optimizer.ts +0 -389
  146. package/src/use-pro-access.ts +0 -141
  147. package/src/use-scroll-animation.ts +0 -219
  148. package/src/use-subscription.ts +0 -37
  149. package/src/use-toast.ts +0 -32
  150. package/src/utils/chart-helpers.ts +0 -357
  151. package/src/utils/cn.ts +0 -6
  152. package/src/utils/data-processing.ts +0 -151
  153. package/src/utils/license-validator.tsx +0 -183
package/src/use-paddle.ts DELETED
@@ -1,138 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { getPaddleInstance } from '@/lib/paddle';
3
- import type { Paddle } from '@paddle/paddle-js';
4
-
5
- interface UsePaddleReturn {
6
- paddle: Paddle | null;
7
- isLoading: boolean;
8
- error: string | null;
9
- openCheckout: (planId: string) => Promise<void>;
10
- }
11
-
12
- /**
13
- * Custom hook for Paddle integration
14
- * Handles Paddle initialization and checkout operations
15
- */
16
- export function usePaddle(): UsePaddleReturn {
17
- const [paddle, setPaddle] = useState<Paddle | null>(null);
18
- const [isLoading, setIsLoading] = useState(true);
19
- const [error, setError] = useState<string | null>(null);
20
-
21
- // Initialize Paddle on mount
22
- useEffect(() => {
23
- let mounted = true;
24
-
25
- const initPaddle = async () => {
26
- try {
27
- setIsLoading(true);
28
- setError(null);
29
-
30
- const paddleInstance = await getPaddleInstance();
31
-
32
- if (mounted) {
33
- if (paddleInstance) {
34
- setPaddle(paddleInstance);
35
- } else {
36
- setError('Failed to initialize Paddle');
37
- }
38
- }
39
- } catch (err) {
40
- if (mounted) {
41
- setError(err instanceof Error ? err.message : 'Unknown error');
42
- }
43
- } finally {
44
- if (mounted) {
45
- setIsLoading(false);
46
- }
47
- }
48
- };
49
-
50
- initPaddle();
51
-
52
- return () => {
53
- mounted = false;
54
- };
55
- }, []);
56
-
57
- /**
58
- * Open Paddle checkout for a specific plan
59
- */
60
- const openCheckout = async (planId: string) => {
61
- if (!paddle) {
62
- throw new Error('Paddle not initialized');
63
- }
64
-
65
- try {
66
- // Call our API to handle the checkout
67
- const response = await fetch('/api/paddle', {
68
- method: 'POST',
69
- headers: {
70
- 'Content-Type': 'application/json',
71
- },
72
- body: JSON.stringify({ plan: planId }),
73
- });
74
-
75
- if (!response.ok) {
76
- const errorText = await response.text();
77
- throw new Error(errorText || 'Failed to create checkout');
78
- }
79
-
80
- const result = await response.json();
81
-
82
- if (!result.success) {
83
- throw new Error(result.message || 'Checkout failed');
84
- }
85
-
86
- // For mock mode, we need to manually trigger checkout
87
- if (process.env.NEXT_PUBLIC_USE_MOCK_PADDLE === 'true') {
88
- console.log('🧪 [Hook] Mock mode detected, triggering checkout');
89
-
90
- // Import paddle config to get price ID
91
- const { PADDLE_CONFIG } = await import('@/lib/paddle');
92
- const priceId = PADDLE_CONFIG.priceIds[planId as keyof typeof PADDLE_CONFIG.priceIds];
93
-
94
- console.log('🧪 [Hook] Using price ID:', priceId, 'for plan:', planId);
95
- console.log('🧪 [Hook] Paddle instance:', paddle);
96
-
97
- // Trigger mock checkout
98
- const checkoutData = {
99
- items: [{ priceId, quantity: 1 }],
100
- settings: {
101
- displayMode: 'overlay' as const,
102
- theme: 'light' as const,
103
- locale: 'en' as const,
104
- successUrl: `${window.location.origin}/dashboard?success=true`
105
- },
106
- customData: {
107
- planId,
108
- userId: 'test_user',
109
- timestamp: new Date().toISOString()
110
- }
111
- };
112
-
113
- console.log('🧪 [Hook] Opening checkout with data:', checkoutData);
114
-
115
- try {
116
- paddle.Checkout.open(checkoutData);
117
- console.log('🧪 [Hook] Checkout.open called successfully');
118
- } catch (checkoutError) {
119
- console.error('🧪 [Hook] Checkout.open error:', checkoutError);
120
- }
121
- }
122
-
123
- // Checkout is opened inline by Paddle
124
- console.log('✅ Paddle checkout opened for plan:', planId);
125
-
126
- } catch (error) {
127
- console.error('❌ Checkout error:', error);
128
- throw error;
129
- }
130
- };
131
-
132
- return {
133
- paddle,
134
- isLoading,
135
- error,
136
- openCheckout,
137
- };
138
- }
@@ -1,389 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- // Performance profiler implementation
5
- const performanceProfiler = {
6
- getPerformanceSummary: () => ({}),
7
- getMeasurements: (type: string) => [] as any[],
8
- measureComponent: (name: string, callback: () => void) => {
9
- const start = performance.now();
10
- callback();
11
- const duration = performance.now() - start;
12
- return { name, duration };
13
- }
14
- };
15
-
16
- // Performance optimization hooks
17
- export function usePerformanceOptimizer() {
18
- const [optimizations, setOptimizations] = React.useState<OptimizationSuggestion[]>([]);
19
- const [isAnalyzing, setIsAnalyzing] = React.useState(false);
20
-
21
- const analyzePerformance = React.useCallback(async () => {
22
- setIsAnalyzing(true);
23
-
24
- try {
25
- const metrics = performanceProfiler.getPerformanceSummary();
26
- const suggestions: OptimizationSuggestion[] = [];
27
-
28
- // Analyze component render times
29
- const componentMetrics = performanceProfiler.getMeasurements('component');
30
- if (componentMetrics.length > 0) {
31
- const slowComponents = componentMetrics
32
- .filter(m => m.duration > 16.67) // Slower than 60fps
33
- .sort((a, b) => b.duration - a.duration)
34
- .slice(0, 5);
35
-
36
- slowComponents.forEach(component => {
37
- suggestions.push({
38
- type: 'component',
39
- severity: component.duration > 50 ? 'high' : 'medium',
40
- title: `Slow component: ${component.name}`,
41
- description: `Component takes ${component.duration.toFixed(2)}ms to render`,
42
- solution: 'Consider using React.memo, useMemo, or useCallback',
43
- impact: 'high',
44
- });
45
- });
46
- }
47
-
48
- // Analyze memory usage
49
- if ('memory' in performance) {
50
- const memory = (performance as any).memory;
51
- const usagePercent = (memory.usedJSHeapSize / memory.totalJSHeapSize) * 100;
52
-
53
- if (usagePercent > 80) {
54
- suggestions.push({
55
- type: 'memory',
56
- severity: 'high',
57
- title: 'High memory usage',
58
- description: `Memory usage is at ${usagePercent.toFixed(1)}%`,
59
- solution: 'Review for memory leaks, optimize data structures, use lazy loading',
60
- impact: 'high',
61
- });
62
- }
63
- }
64
-
65
- // Analyze layout shifts
66
- const layoutShifts = performanceProfiler.getMeasurements('layout-shift');
67
- if (layoutShifts.length > 0) {
68
- const totalShift = layoutShifts.reduce((sum, shift) => sum + (shift.value || 0), 0);
69
-
70
- if (totalShift > 0.1) {
71
- suggestions.push({
72
- type: 'layout',
73
- severity: 'medium',
74
- title: 'Layout shifts detected',
75
- description: `Cumulative Layout Shift: ${totalShift.toFixed(3)}`,
76
- solution: 'Add dimensions to images, reserve space for dynamic content',
77
- impact: 'medium',
78
- });
79
- }
80
- }
81
-
82
- // Analyze bundle size (if available)
83
- if (typeof window !== 'undefined' && window.performance) {
84
- const resources = performance.getEntriesByType('resource') as PerformanceResourceTiming[];
85
- const jsResources = resources.filter(r => r.name.includes('.js'));
86
- const largeResources = jsResources.filter(r => r.transferSize > 100000); // >100KB
87
-
88
- if (largeResources.length > 0) {
89
- suggestions.push({
90
- type: 'bundle',
91
- severity: 'medium',
92
- title: 'Large JavaScript bundles',
93
- description: `${largeResources.length} JavaScript files exceed 100KB`,
94
- solution: 'Implement code splitting, lazy loading, and tree shaking',
95
- impact: 'medium',
96
- });
97
- }
98
- }
99
-
100
- setOptimizations(suggestions);
101
- } catch (error) {
102
- console.error('Performance analysis failed:', error);
103
- } finally {
104
- setIsAnalyzing(false);
105
- }
106
- }, []);
107
-
108
- return {
109
- optimizations,
110
- isAnalyzing,
111
- analyzePerformance,
112
- };
113
- }
114
-
115
- // Hook for render optimization
116
- export function useRenderOptimization<T>(
117
- value: T,
118
- dependencies: React.DependencyList
119
- ): T {
120
- const memoizedValue = React.useMemo(() => value, dependencies);
121
-
122
- React.useEffect(() => {
123
- if (process.env.NODE_ENV === 'development') {
124
- const componentName = 'useRenderOptimization';
125
- performanceProfiler.measureComponent(componentName, () => {
126
- // Measure the impact of memoization
127
- });
128
- }
129
- }, dependencies);
130
-
131
- return memoizedValue;
132
- }
133
-
134
- // Hook for debounced performance tracking
135
- export function useDebouncePerformance<T extends (...args: any[]) => void>(
136
- callback: T,
137
- delay: number = 300
138
- ): T {
139
- const timeoutRef = React.useRef<NodeJS.Timeout | undefined>(undefined);
140
-
141
- const debouncedCallback = React.useCallback(
142
- (...args: Parameters<T>) => {
143
- if (timeoutRef.current) {
144
- clearTimeout(timeoutRef.current);
145
- }
146
-
147
- timeoutRef.current = setTimeout(() => {
148
- performanceProfiler.measureComponent('debounced-callback', () => {
149
- callback(...args);
150
- });
151
- }, delay);
152
- },
153
- [callback, delay]
154
- ) as T;
155
-
156
- React.useEffect(() => {
157
- return () => {
158
- if (timeoutRef.current) {
159
- clearTimeout(timeoutRef.current);
160
- }
161
- };
162
- }, []);
163
-
164
- return debouncedCallback;
165
- }
166
-
167
- // Hook for throttled performance tracking
168
- export function useThrottlePerformance<T extends (...args: any[]) => void>(
169
- callback: T,
170
- delay: number = 100
171
- ): T {
172
- const lastCallRef = React.useRef<number>(0);
173
-
174
- const throttledCallback = React.useCallback(
175
- (...args: Parameters<T>) => {
176
- const now = Date.now();
177
-
178
- if (now - lastCallRef.current >= delay) {
179
- lastCallRef.current = now;
180
- performanceProfiler.measureComponent('throttled-callback', () => {
181
- callback(...args);
182
- });
183
- }
184
- },
185
- [callback, delay]
186
- ) as T;
187
-
188
- return throttledCallback;
189
- }
190
-
191
- // Hook for measuring component lifecycle
192
- export function useComponentLifecycleTracking(componentName: string) {
193
- const mountTime = React.useRef<number>(0);
194
- const updateCount = React.useRef<number>(0);
195
-
196
- React.useEffect(() => {
197
- // Component mount
198
- mountTime.current = performance.now();
199
-
200
- performanceProfiler.measureComponent(`${componentName}-mount`, () => {
201
- // Measure mount time
202
- });
203
-
204
- return () => {
205
- // Component unmount
206
- const lifetime = performance.now() - mountTime.current;
207
- performanceProfiler.measureComponent(`${componentName}-unmount`, () => {
208
- // Record component lifetime
209
- });
210
- };
211
- }, [componentName]);
212
-
213
- React.useEffect(() => {
214
- // Component update
215
- updateCount.current++;
216
-
217
- if (updateCount.current > 1) {
218
- performanceProfiler.measureComponent(`${componentName}-update`, () => {
219
- // Measure update time
220
- });
221
- }
222
- });
223
-
224
- return {
225
- mountTime: mountTime.current,
226
- updateCount: updateCount.current,
227
- };
228
- }
229
-
230
- // Hook for virtual scrolling optimization
231
- export function useVirtualScrolling<T>(
232
- items: T[],
233
- itemHeight: number,
234
- containerHeight: number,
235
- overscan: number = 3
236
- ) {
237
- const [scrollTop, setScrollTop] = React.useState(0);
238
-
239
- const visibleRange = React.useMemo(() => {
240
- const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
241
- const endIndex = Math.min(
242
- items.length - 1,
243
- Math.ceil((scrollTop + containerHeight) / itemHeight) + overscan
244
- );
245
-
246
- return { startIndex, endIndex };
247
- }, [scrollTop, itemHeight, containerHeight, overscan, items.length]);
248
-
249
- const visibleItems = React.useMemo(() => {
250
- return items.slice(visibleRange.startIndex, visibleRange.endIndex + 1);
251
- }, [items, visibleRange]);
252
-
253
- const totalHeight = items.length * itemHeight;
254
- const offsetY = visibleRange.startIndex * itemHeight;
255
-
256
- return {
257
- visibleItems,
258
- totalHeight,
259
- offsetY,
260
- startIndex: visibleRange.startIndex,
261
- endIndex: visibleRange.endIndex,
262
- setScrollTop,
263
- };
264
- }
265
-
266
- // Hook for image lazy loading optimization
267
- export function useLazyImageOptimization(src: string, threshold: number = 0.1) {
268
- const [isLoaded, setIsLoaded] = React.useState(false);
269
- const [isIntersecting, setIsIntersecting] = React.useState(false);
270
- const imgRef = React.useRef<HTMLImageElement>(null);
271
-
272
- React.useEffect(() => {
273
- const observer = new IntersectionObserver(
274
- ([entry]) => {
275
- if (entry.isIntersecting) {
276
- setIsIntersecting(true);
277
-
278
- // Measure image load time
279
- const startTime = performance.now();
280
- const img = new Image();
281
-
282
- img.onload = () => {
283
- const loadTime = performance.now() - startTime;
284
- performanceProfiler.measureComponent('image-load', () => {
285
- // Record image load time
286
- });
287
- setIsLoaded(true);
288
- };
289
-
290
- img.src = src;
291
- observer.disconnect();
292
- }
293
- },
294
- { threshold }
295
- );
296
-
297
- if (imgRef.current) {
298
- observer.observe(imgRef.current);
299
- }
300
-
301
- return () => observer.disconnect();
302
- }, [src, threshold]);
303
-
304
- return {
305
- imgRef,
306
- isLoaded,
307
- isIntersecting,
308
- shouldLoad: isIntersecting,
309
- };
310
- }
311
-
312
- // Performance optimization interfaces
313
- interface OptimizationSuggestion {
314
- type: 'component' | 'memory' | 'layout' | 'bundle' | 'network';
315
- severity: 'low' | 'medium' | 'high';
316
- title: string;
317
- description: string;
318
- solution: string;
319
- impact: 'low' | 'medium' | 'high';
320
- }
321
-
322
- // Hook for automatic performance optimization
323
- export function useAutoPerformanceOptimization() {
324
- const [isOptimizing, setIsOptimizing] = React.useState(false);
325
- const [optimizations, setOptimizations] = React.useState<string[]>([]);
326
-
327
- const applyOptimizations = React.useCallback(async () => {
328
- setIsOptimizing(true);
329
- const applied: string[] = [];
330
-
331
- try {
332
- // Apply automatic optimizations
333
-
334
- // 1. Prefetch critical resources
335
- const criticalResources = document.querySelectorAll('link[rel="preload"]');
336
- if (criticalResources.length === 0) {
337
- // Add preload hints for critical resources
338
- const cssLinks = document.querySelectorAll('link[rel="stylesheet"]');
339
- cssLinks.forEach(link => {
340
- const preloadLink = document.createElement('link');
341
- preloadLink.rel = 'preload';
342
- preloadLink.href = (link as HTMLLinkElement).href;
343
- preloadLink.as = 'style';
344
- document.head.appendChild(preloadLink);
345
- });
346
- applied.push('Added preload hints for CSS');
347
- }
348
-
349
- // 2. Optimize images
350
- const images = document.querySelectorAll('img:not([loading])');
351
- images.forEach(img => {
352
- (img as HTMLImageElement).loading = 'lazy';
353
- });
354
- if (images.length > 0) {
355
- applied.push(`Applied lazy loading to ${images.length} images`);
356
- }
357
-
358
- // 3. Add intersection observers for below-fold content
359
- const belowFoldElements = document.querySelectorAll('[data-optimize="lazy"]');
360
- belowFoldElements.forEach(element => {
361
- const observer = new IntersectionObserver(
362
- ([entry]) => {
363
- if (entry.isIntersecting) {
364
- element.classList.add('optimized');
365
- observer.disconnect();
366
- }
367
- },
368
- { threshold: 0.1 }
369
- );
370
- observer.observe(element);
371
- });
372
- if (belowFoldElements.length > 0) {
373
- applied.push(`Added intersection observers to ${belowFoldElements.length} elements`);
374
- }
375
-
376
- setOptimizations(applied);
377
- } catch (error) {
378
- console.error('Auto-optimization failed:', error);
379
- } finally {
380
- setIsOptimizing(false);
381
- }
382
- }, []);
383
-
384
- return {
385
- isOptimizing,
386
- optimizations,
387
- applyOptimizations,
388
- };
389
- }
@@ -1,141 +0,0 @@
1
- // Pro Access Hook
2
- // Kullanıcının pro componentlere erişim durumunu kontrol eder
3
-
4
- import React from 'react'
5
- import { useSession } from 'next-auth/react'
6
- import { useQuery } from '@tanstack/react-query'
7
- import { getComponentAccess } from '@/lib/component-metadata'
8
-
9
- interface UserSubscription {
10
- userId: string
11
- plan: 'free' | 'pro_monthly' | 'pro_annual' | 'pro_lifetime'
12
- status: 'active' | 'expired' | 'cancelled' | 'trial'
13
- expiresAt: Date | null // lifetime için null
14
- createdAt: Date
15
- updatedAt: Date
16
- }
17
-
18
- interface ProAccessStatus {
19
- hasProAccess: boolean
20
- subscription: UserSubscription | null | undefined
21
- isLoading: boolean
22
- error: Error | null
23
- daysUntilExpiry: number | null
24
- }
25
-
26
- // Subscription durumunu API'den çek
27
- async function fetchSubscriptionStatus(): Promise<UserSubscription | null> {
28
- const response = await fetch('/api/user/subscription-status')
29
-
30
- if (!response.ok) {
31
- throw new Error('Subscription status fetch failed')
32
- }
33
-
34
- const data = await response.json()
35
- return data.subscription
36
- }
37
-
38
- // Pro erişim durumunu hesapla
39
- function calculateProAccess(subscription: UserSubscription | null | undefined): {
40
- hasProAccess: boolean
41
- daysUntilExpiry: number | null
42
- } {
43
- if (!subscription) {
44
- return { hasProAccess: false, daysUntilExpiry: null }
45
- }
46
-
47
- // Lifetime üyelik
48
- if (subscription.plan === 'pro_lifetime') {
49
- return { hasProAccess: true, daysUntilExpiry: null }
50
- }
51
-
52
- // Aktif olmayan subscription
53
- if (subscription.status !== 'active') {
54
- return { hasProAccess: false, daysUntilExpiry: null }
55
- }
56
-
57
- // Süre kontrolü
58
- if (subscription.expiresAt) {
59
- const now = new Date()
60
- const expiryDate = new Date(subscription.expiresAt)
61
- const daysUntilExpiry = Math.ceil((expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
62
-
63
- return {
64
- hasProAccess: daysUntilExpiry > 0,
65
- daysUntilExpiry: daysUntilExpiry > 0 ? daysUntilExpiry : 0
66
- }
67
- }
68
-
69
- return { hasProAccess: false, daysUntilExpiry: null }
70
- }
71
-
72
- export function useProAccess(): ProAccessStatus {
73
- const { data: session, status } = useSession()
74
-
75
- const {
76
- data: subscription,
77
- isLoading,
78
- error
79
- } = useQuery({
80
- queryKey: ['subscription-status', session?.user?.id],
81
- queryFn: fetchSubscriptionStatus,
82
- enabled: !!session?.user?.id && status === 'authenticated',
83
- staleTime: 5 * 60 * 1000, // 5 dakika cache
84
- refetchInterval: 10 * 60 * 1000, // 10 dakikada bir otomatik refresh
85
- })
86
-
87
- const { hasProAccess, daysUntilExpiry } = calculateProAccess(subscription)
88
-
89
- return {
90
- hasProAccess,
91
- subscription,
92
- isLoading: status === 'loading' || isLoading,
93
- error: error as Error | null,
94
- daysUntilExpiry
95
- }
96
- }
97
-
98
- // Component erişim kontrolü için helper hook
99
- export function useComponentAccess(componentId: string) {
100
- const { hasProAccess, isLoading } = useProAccess()
101
-
102
- const access = React.useMemo(() => {
103
- return getComponentAccess(componentId, hasProAccess ? 'pro' : 'free')
104
- }, [componentId, hasProAccess])
105
-
106
- return {
107
- ...access,
108
- isLoading,
109
- canUse: access.access === 'unlocked',
110
- isLocked: access.access === 'locked'
111
- }
112
- }
113
-
114
- // Subscription durumu için utility functions
115
- export function getSubscriptionDisplayName(plan: string): string {
116
- switch (plan) {
117
- case 'pro_monthly':
118
- return 'Pro Monthly'
119
- case 'pro_annual':
120
- return 'Pro Annual'
121
- case 'pro_lifetime':
122
- return 'Pro Lifetime'
123
- default:
124
- return 'Free'
125
- }
126
- }
127
-
128
- export function getSubscriptionColor(status: string): string {
129
- switch (status) {
130
- case 'active':
131
- return 'green'
132
- case 'trial':
133
- return 'blue'
134
- case 'expired':
135
- return 'red'
136
- case 'cancelled':
137
- return 'gray'
138
- default:
139
- return 'gray'
140
- }
141
- }