@croacroa/react-native-template 2.0.1 → 3.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.
- package/.env.example +5 -0
- package/.eslintrc.js +8 -0
- package/.github/workflows/ci.yml +187 -187
- package/.github/workflows/eas-build.yml +55 -55
- package/.github/workflows/eas-update.yml +50 -50
- package/.github/workflows/npm-publish.yml +57 -0
- package/CHANGELOG.md +195 -106
- package/CONTRIBUTING.md +377 -377
- package/LICENSE +21 -0
- package/README.md +446 -399
- package/__tests__/accessibility/components.test.tsx +285 -0
- package/__tests__/components/Button.test.tsx +2 -4
- package/__tests__/components/__snapshots__/snapshots.test.tsx.snap +512 -0
- package/__tests__/components/snapshots.test.tsx +131 -131
- package/__tests__/helpers/a11y.ts +54 -0
- package/__tests__/hooks/useAnalytics.test.ts +100 -0
- package/__tests__/hooks/useAnimations.test.ts +70 -0
- package/__tests__/hooks/useAuth.test.tsx +71 -28
- package/__tests__/hooks/useMedia.test.ts +318 -0
- package/__tests__/hooks/usePayments.test.tsx +307 -0
- package/__tests__/hooks/usePermission.test.ts +230 -0
- package/__tests__/hooks/useWebSocket.test.ts +329 -0
- package/__tests__/integration/auth-api.test.tsx +224 -227
- package/__tests__/performance/VirtualizedList.perf.test.tsx +385 -362
- package/__tests__/services/api.test.ts +24 -6
- package/app/(auth)/home.tsx +11 -9
- package/app/(auth)/profile.tsx +8 -6
- package/app/(auth)/settings.tsx +11 -9
- package/app/(public)/forgot-password.tsx +25 -15
- package/app/(public)/login.tsx +48 -12
- package/app/(public)/onboarding.tsx +5 -5
- package/app/(public)/register.tsx +24 -15
- package/app/_layout.tsx +6 -3
- package/app.config.ts +27 -2
- package/assets/images/.gitkeep +7 -7
- package/assets/images/adaptive-icon.png +0 -0
- package/assets/images/favicon.png +0 -0
- package/assets/images/icon.png +0 -0
- package/assets/images/notification-icon.png +0 -0
- package/assets/images/splash.png +0 -0
- package/components/ErrorBoundary.tsx +73 -28
- package/components/auth/SocialLoginButtons.tsx +168 -0
- package/components/forms/FormInput.tsx +5 -3
- package/components/onboarding/OnboardingScreen.tsx +370 -370
- package/components/onboarding/index.ts +2 -2
- package/components/providers/AnalyticsProvider.tsx +67 -0
- package/components/providers/SuspenseBoundary.tsx +359 -357
- package/components/providers/index.ts +24 -21
- package/components/ui/AnimatedButton.tsx +1 -9
- package/components/ui/AnimatedList.tsx +98 -0
- package/components/ui/AnimatedScreen.tsx +89 -0
- package/components/ui/Avatar.tsx +319 -316
- package/components/ui/Badge.tsx +416 -416
- package/components/ui/BottomSheet.tsx +307 -307
- package/components/ui/Button.tsx +11 -3
- package/components/ui/Checkbox.tsx +261 -261
- package/components/ui/FeatureGate.tsx +57 -0
- package/components/ui/ForceUpdateScreen.tsx +108 -0
- package/components/ui/ImagePickerButton.tsx +180 -0
- package/components/ui/Input.stories.tsx +2 -10
- package/components/ui/Input.tsx +2 -10
- package/components/ui/OptimizedImage.tsx +369 -369
- package/components/ui/Paywall.tsx +253 -0
- package/components/ui/PermissionGate.tsx +155 -0
- package/components/ui/PurchaseButton.tsx +84 -0
- package/components/ui/Select.tsx +240 -240
- package/components/ui/Skeleton.tsx +3 -1
- package/components/ui/Toast.tsx +427 -0
- package/components/ui/UploadProgress.tsx +189 -0
- package/components/ui/VirtualizedList.tsx +288 -285
- package/components/ui/index.ts +28 -23
- package/constants/config.ts +135 -97
- package/docs/adr/001-state-management.md +79 -79
- package/docs/adr/002-styling-approach.md +130 -130
- package/docs/adr/003-data-fetching.md +155 -155
- package/docs/adr/004-auth-adapter-pattern.md +144 -144
- package/docs/adr/README.md +78 -78
- package/docs/guides/analytics-posthog.md +121 -0
- package/docs/guides/auth-supabase.md +162 -0
- package/docs/guides/feature-flags-launchdarkly.md +150 -0
- package/docs/guides/payments-revenuecat.md +169 -0
- package/docs/plans/2026-02-22-phase6-implementation.md +3222 -0
- package/docs/plans/2026-02-22-phase6-template-completion-design.md +196 -0
- package/docs/plans/2026-02-23-npm-publish-design.md +31 -0
- package/docs/plans/2026-02-23-phase7-polish-documentation-design.md +79 -0
- package/docs/plans/2026-02-23-phase8-additional-features-design.md +136 -0
- package/eas.json +2 -1
- package/hooks/index.ts +70 -27
- package/hooks/useAnimatedEntry.ts +204 -0
- package/hooks/useApi.ts +64 -4
- package/hooks/useAuth.tsx +7 -3
- package/hooks/useBiometrics.ts +295 -295
- package/hooks/useChannel.ts +111 -0
- package/hooks/useDeepLinking.ts +256 -256
- package/hooks/useExperiment.ts +36 -0
- package/hooks/useFeatureFlag.ts +59 -0
- package/hooks/useForceUpdate.ts +91 -0
- package/hooks/useImagePicker.ts +281 -0
- package/hooks/useInAppReview.ts +64 -0
- package/hooks/useMFA.ts +509 -499
- package/hooks/useParallax.ts +142 -0
- package/hooks/usePerformance.ts +434 -434
- package/hooks/usePermission.ts +190 -0
- package/hooks/usePresence.ts +129 -0
- package/hooks/useProducts.ts +36 -0
- package/hooks/usePurchase.ts +103 -0
- package/hooks/useRateLimit.ts +70 -0
- package/hooks/useSubscription.ts +49 -0
- package/hooks/useTrackEvent.ts +52 -0
- package/hooks/useTrackScreen.ts +40 -0
- package/hooks/useUpdates.ts +358 -358
- package/hooks/useUpload.ts +165 -0
- package/hooks/useWebSocket.ts +111 -0
- package/i18n/index.ts +197 -194
- package/i18n/locales/ar.json +170 -101
- package/i18n/locales/de.json +170 -101
- package/i18n/locales/en.json +170 -101
- package/i18n/locales/es.json +170 -101
- package/i18n/locales/fr.json +170 -101
- package/jest.config.js +1 -1
- package/maestro/README.md +113 -113
- package/maestro/config.yaml +35 -35
- package/maestro/flows/login.yaml +62 -62
- package/maestro/flows/mfa-login.yaml +92 -92
- package/maestro/flows/mfa-setup.yaml +86 -86
- package/maestro/flows/navigation.yaml +68 -68
- package/maestro/flows/offline-conflict.yaml +101 -101
- package/maestro/flows/offline-sync.yaml +128 -128
- package/maestro/flows/offline.yaml +60 -60
- package/maestro/flows/register.yaml +94 -94
- package/package.json +188 -175
- package/scripts/generate-placeholders.js +38 -0
- package/services/analytics/adapters/console.ts +50 -0
- package/services/analytics/analytics-adapter.ts +94 -0
- package/services/analytics/types.ts +73 -0
- package/services/analytics.ts +428 -428
- package/services/api.ts +419 -340
- package/services/auth/social/apple.ts +110 -0
- package/services/auth/social/google.ts +159 -0
- package/services/auth/social/social-auth.ts +100 -0
- package/services/auth/social/types.ts +80 -0
- package/services/authAdapter.ts +333 -333
- package/services/backgroundSync.ts +652 -626
- package/services/feature-flags/adapters/mock.ts +108 -0
- package/services/feature-flags/feature-flag-adapter.ts +174 -0
- package/services/feature-flags/types.ts +79 -0
- package/services/force-update.ts +140 -0
- package/services/index.ts +116 -54
- package/services/media/compression.ts +91 -0
- package/services/media/media-picker.ts +151 -0
- package/services/media/media-upload.ts +160 -0
- package/services/payments/adapters/mock.ts +159 -0
- package/services/payments/payment-adapter.ts +118 -0
- package/services/payments/types.ts +131 -0
- package/services/permissions/permission-manager.ts +284 -0
- package/services/permissions/types.ts +104 -0
- package/services/realtime/types.ts +100 -0
- package/services/realtime/websocket-manager.ts +441 -0
- package/services/security.ts +289 -286
- package/services/sentry.ts +4 -4
- package/stores/appStore.ts +9 -0
- package/stores/notificationStore.ts +3 -1
- package/tailwind.config.js +47 -47
- package/tsconfig.json +37 -13
- package/types/user.ts +1 -1
- package/utils/accessibility.ts +446 -446
- package/utils/animations/presets.ts +182 -0
- package/utils/animations/transitions.ts +62 -0
- package/utils/index.ts +63 -52
- package/utils/toast.ts +9 -2
- package/utils/validation.ts +4 -1
- package/utils/withAccessibility.tsx +272 -272
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
2
|
+
import { ViewStyle } from "react-native";
|
|
3
|
+
import {
|
|
4
|
+
useSharedValue,
|
|
5
|
+
useAnimatedStyle,
|
|
6
|
+
withTiming,
|
|
7
|
+
withDelay,
|
|
8
|
+
interpolate,
|
|
9
|
+
} from "react-native-reanimated";
|
|
10
|
+
import type { WithTimingConfig, SharedValue } from "react-native-reanimated";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
TIMING,
|
|
14
|
+
ENTRY_CONFIGS,
|
|
15
|
+
staggerDelay,
|
|
16
|
+
} from "@/utils/animations/presets";
|
|
17
|
+
import type { EntryAnimation } from "@/utils/animations/presets";
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Types
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export interface UseAnimatedEntryOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Which entry animation to use
|
|
26
|
+
* @default 'fadeIn'
|
|
27
|
+
*/
|
|
28
|
+
animation?: EntryAnimation;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Delay before the animation starts (ms)
|
|
32
|
+
* @default 0
|
|
33
|
+
*/
|
|
34
|
+
delay?: number;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Timing configuration for the animation
|
|
38
|
+
* @default TIMING.normal
|
|
39
|
+
*/
|
|
40
|
+
timing?: WithTimingConfig;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Whether the animation plays automatically on mount
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
autoPlay?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface UseAnimatedEntryReturn {
|
|
50
|
+
/** Animated style to spread onto an Animated.View */
|
|
51
|
+
animatedStyle: ViewStyle;
|
|
52
|
+
|
|
53
|
+
/** Manually trigger the entry animation */
|
|
54
|
+
play: () => void;
|
|
55
|
+
|
|
56
|
+
/** Reset animation back to start (progress = 0) */
|
|
57
|
+
reset: () => void;
|
|
58
|
+
|
|
59
|
+
/** Shared value tracking animation progress (0 = start, 1 = done) */
|
|
60
|
+
progress: SharedValue<number>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Hook Implementation
|
|
65
|
+
// ============================================================================
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Hook for declarative entry animations.
|
|
69
|
+
*
|
|
70
|
+
* Returns an animated style that interpolates opacity, translateX, translateY,
|
|
71
|
+
* and scale from the chosen preset's initial values to their identity values
|
|
72
|
+
* as `progress` goes from 0 to 1.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* function MyComponent() {
|
|
77
|
+
* const { animatedStyle } = useAnimatedEntry({
|
|
78
|
+
* animation: 'slideUp',
|
|
79
|
+
* delay: 200,
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* return (
|
|
83
|
+
* <Animated.View style={animatedStyle}>
|
|
84
|
+
* <Text>Hello</Text>
|
|
85
|
+
* </Animated.View>
|
|
86
|
+
* );
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export function useAnimatedEntry(
|
|
91
|
+
options: UseAnimatedEntryOptions = {}
|
|
92
|
+
): UseAnimatedEntryReturn {
|
|
93
|
+
const {
|
|
94
|
+
animation = "fadeIn",
|
|
95
|
+
delay = 0,
|
|
96
|
+
timing = TIMING.normal,
|
|
97
|
+
autoPlay = true,
|
|
98
|
+
} = options;
|
|
99
|
+
|
|
100
|
+
const progress = useSharedValue(0);
|
|
101
|
+
const config = ENTRY_CONFIGS[animation];
|
|
102
|
+
|
|
103
|
+
// Store timing config in a ref to avoid infinite re-renders when
|
|
104
|
+
// callers pass an inline object literal for `timing`.
|
|
105
|
+
const timingRef = useRef(timing);
|
|
106
|
+
timingRef.current = timing;
|
|
107
|
+
|
|
108
|
+
const play = useCallback(() => {
|
|
109
|
+
progress.value = 0;
|
|
110
|
+
if (delay > 0) {
|
|
111
|
+
progress.value = withDelay(delay, withTiming(1, timingRef.current));
|
|
112
|
+
} else {
|
|
113
|
+
progress.value = withTiming(1, timingRef.current);
|
|
114
|
+
}
|
|
115
|
+
}, [delay, progress]);
|
|
116
|
+
|
|
117
|
+
const reset = useCallback(() => {
|
|
118
|
+
progress.value = 0;
|
|
119
|
+
}, [progress]);
|
|
120
|
+
|
|
121
|
+
// Auto-play on mount
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (autoPlay) {
|
|
124
|
+
play();
|
|
125
|
+
}
|
|
126
|
+
}, [autoPlay, play]);
|
|
127
|
+
|
|
128
|
+
const animatedStyle = useAnimatedStyle((): ViewStyle => {
|
|
129
|
+
return {
|
|
130
|
+
opacity: interpolate(progress.value, [0, 1], [config.opacity, 1]),
|
|
131
|
+
transform: [
|
|
132
|
+
{
|
|
133
|
+
translateX: interpolate(
|
|
134
|
+
progress.value,
|
|
135
|
+
[0, 1],
|
|
136
|
+
[config.translateX, 0]
|
|
137
|
+
),
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
translateY: interpolate(
|
|
141
|
+
progress.value,
|
|
142
|
+
[0, 1],
|
|
143
|
+
[config.translateY, 0]
|
|
144
|
+
),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
scale: interpolate(progress.value, [0, 1], [config.scale, 1]),
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return { animatedStyle, play, reset, progress };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// Staggered Entry
|
|
158
|
+
// ============================================================================
|
|
159
|
+
|
|
160
|
+
export interface UseStaggeredEntryOptions extends Omit<
|
|
161
|
+
UseAnimatedEntryOptions,
|
|
162
|
+
"delay"
|
|
163
|
+
> {
|
|
164
|
+
/**
|
|
165
|
+
* Base delay between each staggered item (ms)
|
|
166
|
+
* @default 50
|
|
167
|
+
*/
|
|
168
|
+
staggerDelay?: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Convenience wrapper around `useAnimatedEntry` that adds an index-based
|
|
173
|
+
* stagger delay. Use this for list items that should animate in sequentially.
|
|
174
|
+
*
|
|
175
|
+
* @param index - The item's position in the list (0-based)
|
|
176
|
+
* @param options - Same as useAnimatedEntry options, plus `staggerDelay`
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```tsx
|
|
180
|
+
* function ListItem({ index }: { index: number }) {
|
|
181
|
+
* const { animatedStyle } = useStaggeredEntry(index, {
|
|
182
|
+
* animation: 'slideUp',
|
|
183
|
+
* staggerDelay: 80,
|
|
184
|
+
* });
|
|
185
|
+
*
|
|
186
|
+
* return (
|
|
187
|
+
* <Animated.View style={animatedStyle}>
|
|
188
|
+
* <Text>Item {index}</Text>
|
|
189
|
+
* </Animated.View>
|
|
190
|
+
* );
|
|
191
|
+
* }
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
export function useStaggeredEntry(
|
|
195
|
+
index: number,
|
|
196
|
+
options: UseStaggeredEntryOptions = {}
|
|
197
|
+
): UseAnimatedEntryReturn {
|
|
198
|
+
const { staggerDelay: baseDelay = 50, ...rest } = options;
|
|
199
|
+
|
|
200
|
+
return useAnimatedEntry({
|
|
201
|
+
...rest,
|
|
202
|
+
delay: staggerDelay(index, baseDelay),
|
|
203
|
+
});
|
|
204
|
+
}
|
package/hooks/useApi.ts
CHANGED
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
useQuery,
|
|
9
9
|
useMutation,
|
|
10
10
|
useQueryClient,
|
|
11
|
+
useSuspenseQuery,
|
|
11
12
|
UseQueryOptions,
|
|
12
13
|
UseMutationOptions,
|
|
14
|
+
UseSuspenseQueryOptions,
|
|
13
15
|
} from "@tanstack/react-query";
|
|
14
16
|
import { api } from "@/services/api";
|
|
15
17
|
import { toast, handleApiError } from "@/utils/toast";
|
|
@@ -36,14 +38,15 @@ export const queryKeys = {
|
|
|
36
38
|
},
|
|
37
39
|
posts: {
|
|
38
40
|
all: ["posts"] as const,
|
|
39
|
-
list: (filters: Record<string, unknown>) =>
|
|
41
|
+
list: (filters: Record<string, unknown>) =>
|
|
42
|
+
["posts", "list", filters] as const,
|
|
40
43
|
detail: (id: string) => ["posts", id] as const,
|
|
41
44
|
},
|
|
42
45
|
// Add more query keys as needed
|
|
43
46
|
} as const;
|
|
44
47
|
|
|
45
48
|
// Generic types for API responses
|
|
46
|
-
interface
|
|
49
|
+
interface _PaginatedResponse<T> {
|
|
47
50
|
data: T[];
|
|
48
51
|
page: number;
|
|
49
52
|
pageSize: number;
|
|
@@ -120,6 +123,63 @@ export function useUser(
|
|
|
120
123
|
});
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
// ===========================================
|
|
127
|
+
// Suspense-Ready Hooks (React 19 compatible)
|
|
128
|
+
// ===========================================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Suspense-ready version of useCurrentUser.
|
|
132
|
+
* Use inside a Suspense boundary - throws promise while loading.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```tsx
|
|
136
|
+
* function Profile() {
|
|
137
|
+
* const { data: user } = useSuspenseCurrentUser();
|
|
138
|
+
* // No loading check needed - Suspense handles it
|
|
139
|
+
* return <Text>Hello, {user.name}</Text>;
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* // Wrap with Suspense
|
|
143
|
+
* <Suspense fallback={<Skeleton />}>
|
|
144
|
+
* <Profile />
|
|
145
|
+
* </Suspense>
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export function useSuspenseCurrentUser(
|
|
149
|
+
options?: Omit<UseSuspenseQueryOptions<User, Error>, "queryKey" | "queryFn">
|
|
150
|
+
) {
|
|
151
|
+
return useSuspenseQuery({
|
|
152
|
+
queryKey: queryKeys.users.me(),
|
|
153
|
+
queryFn: () => api.get<User>("/users/me"),
|
|
154
|
+
staleTime: 1000 * 60 * 5,
|
|
155
|
+
...options,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Suspense-ready version of useUser.
|
|
161
|
+
* Use inside a Suspense boundary - throws promise while loading.
|
|
162
|
+
*
|
|
163
|
+
* @param userId - The unique identifier of the user to fetch
|
|
164
|
+
* @example
|
|
165
|
+
* ```tsx
|
|
166
|
+
* function UserCard({ userId }: { userId: string }) {
|
|
167
|
+
* const { data: user } = useSuspenseUser(userId);
|
|
168
|
+
* return <Avatar name={user.name} />;
|
|
169
|
+
* }
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export function useSuspenseUser(
|
|
173
|
+
userId: string,
|
|
174
|
+
options?: Omit<UseSuspenseQueryOptions<User, Error>, "queryKey" | "queryFn">
|
|
175
|
+
) {
|
|
176
|
+
return useSuspenseQuery({
|
|
177
|
+
queryKey: queryKeys.users.detail(userId),
|
|
178
|
+
queryFn: () => api.get<User>(`/users/${userId}`),
|
|
179
|
+
...options,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
123
183
|
/**
|
|
124
184
|
* Update the current user's profile.
|
|
125
185
|
* Automatically updates the cache and shows a success/error toast.
|
|
@@ -163,7 +223,7 @@ export function useUpdateUser() {
|
|
|
163
223
|
// Generic CRUD Hooks Factory
|
|
164
224
|
// ===========================================
|
|
165
225
|
|
|
166
|
-
interface CrudHooksConfig<
|
|
226
|
+
interface CrudHooksConfig<_T, _CreateDTO, _UpdateDTO> {
|
|
167
227
|
baseKey: readonly string[];
|
|
168
228
|
endpoint: string;
|
|
169
229
|
entityName: string;
|
|
@@ -205,7 +265,7 @@ interface CrudHooksConfig<T, CreateDTO, UpdateDTO> {
|
|
|
205
265
|
export function createCrudHooks<
|
|
206
266
|
T extends { id: string },
|
|
207
267
|
CreateDTO = Omit<T, "id">,
|
|
208
|
-
UpdateDTO = Partial<T
|
|
268
|
+
UpdateDTO = Partial<T>,
|
|
209
269
|
>(config: CrudHooksConfig<T, CreateDTO, UpdateDTO>) {
|
|
210
270
|
const { baseKey, endpoint, entityName } = config;
|
|
211
271
|
|
package/hooks/useAuth.tsx
CHANGED
|
@@ -128,7 +128,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|
|
128
128
|
// Check if tokens are expired
|
|
129
129
|
if (parsedTokens.expiresAt < Date.now()) {
|
|
130
130
|
// Try to refresh
|
|
131
|
-
const refreshed = await tryRefreshWithToken(
|
|
131
|
+
const refreshed = await tryRefreshWithToken(
|
|
132
|
+
parsedTokens.refreshToken
|
|
133
|
+
);
|
|
132
134
|
if (!refreshed) {
|
|
133
135
|
await clearAuth();
|
|
134
136
|
return;
|
|
@@ -146,7 +148,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|
|
146
148
|
}
|
|
147
149
|
};
|
|
148
150
|
|
|
149
|
-
const tryRefreshWithToken = async (
|
|
151
|
+
const tryRefreshWithToken = async (
|
|
152
|
+
_refreshToken: string
|
|
153
|
+
): Promise<boolean> => {
|
|
150
154
|
try {
|
|
151
155
|
// TODO: Replace with your actual API call
|
|
152
156
|
// const response = await api.post('/auth/refresh', { refreshToken });
|
|
@@ -190,7 +194,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|
|
190
194
|
setUser(null);
|
|
191
195
|
};
|
|
192
196
|
|
|
193
|
-
const signIn = useCallback(async (email: string,
|
|
197
|
+
const signIn = useCallback(async (email: string, _password: string) => {
|
|
194
198
|
try {
|
|
195
199
|
// TODO: Replace with your actual API call
|
|
196
200
|
// const response = await api.post('/auth/login', { email, password });
|