@croacroa/react-native-template 2.1.0 → 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 -21
- package/README.md +446 -402
- 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 -418
- package/components/ui/UploadProgress.tsx +189 -0
- package/components/ui/VirtualizedList.tsx +288 -285
- package/components/ui/index.ts +28 -30
- 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 -40
- package/hooks/useAnimatedEntry.ts +204 -0
- package/hooks/useApi.ts +5 -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 -375
- 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 -176
- 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,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview React hooks for feature flag evaluation
|
|
3
|
+
* Provides `useFeatureFlag` for boolean checks and `useFeatureFlagValue`
|
|
4
|
+
* for typed flag values, both backed by the FeatureFlags facade.
|
|
5
|
+
* @module hooks/useFeatureFlag
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useState, useEffect } from "react";
|
|
9
|
+
import { FeatureFlags } from "@/services/feature-flags/feature-flag-adapter";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Hook that resolves a boolean feature flag.
|
|
13
|
+
*
|
|
14
|
+
* @param flag - The flag key to evaluate
|
|
15
|
+
* @param defaultValue - Value used until the flag is resolved (default `false`)
|
|
16
|
+
* @returns `{ isEnabled, isLoading }`
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* const { isEnabled, isLoading } = useFeatureFlag("new_checkout");
|
|
21
|
+
* if (isLoading) return <Loader />;
|
|
22
|
+
* return isEnabled ? <NewCheckout /> : <OldCheckout />;
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function useFeatureFlag(flag: string, defaultValue = false) {
|
|
26
|
+
const [isEnabled, setIsEnabled] = useState(defaultValue);
|
|
27
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
setIsEnabled(FeatureFlags.isEnabled(flag, defaultValue));
|
|
31
|
+
setIsLoading(false);
|
|
32
|
+
}, [flag, defaultValue]);
|
|
33
|
+
|
|
34
|
+
return { isEnabled, isLoading };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Hook that resolves a feature flag with an arbitrary type.
|
|
39
|
+
*
|
|
40
|
+
* @param flag - The flag key to evaluate
|
|
41
|
+
* @param defaultValue - Value used until the flag is resolved
|
|
42
|
+
* @returns `{ value, isLoading }`
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* const { value: maxItems } = useFeatureFlagValue("max_cart_items", 10);
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function useFeatureFlagValue<T>(flag: string, defaultValue: T) {
|
|
50
|
+
const [value, setValue] = useState<T>(defaultValue);
|
|
51
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setValue(FeatureFlags.getValue(flag, defaultValue));
|
|
55
|
+
setIsLoading(false);
|
|
56
|
+
}, [flag, defaultValue]);
|
|
57
|
+
|
|
58
|
+
return { value, isLoading };
|
|
59
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Hook for app force-update checks
|
|
3
|
+
* Checks on mount whether the running app version satisfies the server's
|
|
4
|
+
* minimum version requirement and exposes the result to the UI.
|
|
5
|
+
* @module hooks/useForceUpdate
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useEffect, useState } from "react";
|
|
9
|
+
import Constants from "expo-constants";
|
|
10
|
+
|
|
11
|
+
import { FORCE_UPDATE } from "@/constants/config";
|
|
12
|
+
import { checkForUpdate } from "@/services/force-update";
|
|
13
|
+
import type { ForceUpdateResult } from "@/services/force-update";
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Types
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
export interface UseForceUpdateReturn extends ForceUpdateResult {
|
|
20
|
+
/** Whether the check is still in progress */
|
|
21
|
+
isChecking: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Hook
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check on mount whether the app requires a mandatory native update.
|
|
30
|
+
*
|
|
31
|
+
* Uses `Constants.expoConfig?.version` as the current version and the
|
|
32
|
+
* `FORCE_UPDATE` configuration from `constants/config.ts`.
|
|
33
|
+
*
|
|
34
|
+
* When `FORCE_UPDATE.ENABLED` is `false` or `FORCE_UPDATE.CHECK_URL` is
|
|
35
|
+
* empty the hook returns immediately with `isUpdateRequired: false`.
|
|
36
|
+
*
|
|
37
|
+
* @returns Force-update state including loading indicator
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* function App() {
|
|
42
|
+
* const { isUpdateRequired, isChecking, storeUrl, currentVersion, minimumVersion } =
|
|
43
|
+
* useForceUpdate();
|
|
44
|
+
*
|
|
45
|
+
* if (isChecking) return <SplashScreen />;
|
|
46
|
+
*
|
|
47
|
+
* if (isUpdateRequired) {
|
|
48
|
+
* return (
|
|
49
|
+
* <ForceUpdateScreen
|
|
50
|
+
* storeUrl={storeUrl}
|
|
51
|
+
* currentVersion={currentVersion}
|
|
52
|
+
* minimumVersion={minimumVersion}
|
|
53
|
+
* />
|
|
54
|
+
* );
|
|
55
|
+
* }
|
|
56
|
+
*
|
|
57
|
+
* return <MainApp />;
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function useForceUpdate(): UseForceUpdateReturn {
|
|
62
|
+
const [isChecking, setIsChecking] = useState(true);
|
|
63
|
+
const [result, setResult] = useState<ForceUpdateResult>({
|
|
64
|
+
isUpdateRequired: false,
|
|
65
|
+
currentVersion: "",
|
|
66
|
+
minimumVersion: "",
|
|
67
|
+
storeUrl: "",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
// Skip the check entirely when force-update is disabled or unconfigured
|
|
72
|
+
if (!FORCE_UPDATE.ENABLED || !FORCE_UPDATE.CHECK_URL) {
|
|
73
|
+
setIsChecking(false);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const currentVersion = Constants.expoConfig?.version ?? "1.0.0";
|
|
78
|
+
|
|
79
|
+
checkForUpdate({
|
|
80
|
+
checkUrl: FORCE_UPDATE.CHECK_URL,
|
|
81
|
+
currentVersion,
|
|
82
|
+
})
|
|
83
|
+
.then(setResult)
|
|
84
|
+
.finally(() => setIsChecking(false));
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
...result,
|
|
89
|
+
isChecking,
|
|
90
|
+
};
|
|
91
|
+
}
|