@croacroa/react-native-template 1.0.0 โ†’ 2.0.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.
Files changed (69) hide show
  1. package/.github/workflows/ci.yml +187 -184
  2. package/.github/workflows/eas-build.yml +55 -55
  3. package/.github/workflows/eas-update.yml +50 -50
  4. package/CHANGELOG.md +106 -106
  5. package/CONTRIBUTING.md +377 -377
  6. package/README.md +399 -399
  7. package/__tests__/components/snapshots.test.tsx +131 -0
  8. package/__tests__/integration/auth-api.test.tsx +227 -0
  9. package/__tests__/performance/VirtualizedList.perf.test.tsx +362 -0
  10. package/app/(public)/onboarding.tsx +5 -5
  11. package/app.config.ts +45 -2
  12. package/assets/images/.gitkeep +7 -7
  13. package/components/onboarding/OnboardingScreen.tsx +370 -370
  14. package/components/onboarding/index.ts +2 -2
  15. package/components/providers/SuspenseBoundary.tsx +357 -0
  16. package/components/providers/index.ts +13 -0
  17. package/components/ui/Avatar.tsx +316 -316
  18. package/components/ui/Badge.tsx +416 -416
  19. package/components/ui/BottomSheet.tsx +307 -307
  20. package/components/ui/Checkbox.tsx +261 -261
  21. package/components/ui/OptimizedImage.tsx +369 -369
  22. package/components/ui/Select.tsx +240 -240
  23. package/components/ui/VirtualizedList.tsx +285 -0
  24. package/components/ui/index.ts +23 -18
  25. package/constants/config.ts +97 -54
  26. package/docs/adr/001-state-management.md +79 -79
  27. package/docs/adr/002-styling-approach.md +130 -130
  28. package/docs/adr/003-data-fetching.md +155 -155
  29. package/docs/adr/004-auth-adapter-pattern.md +144 -144
  30. package/docs/adr/README.md +78 -78
  31. package/hooks/index.ts +27 -25
  32. package/hooks/useApi.ts +102 -5
  33. package/hooks/useAuth.tsx +82 -0
  34. package/hooks/useBiometrics.ts +295 -295
  35. package/hooks/useDeepLinking.ts +256 -256
  36. package/hooks/useMFA.ts +499 -0
  37. package/hooks/useNotifications.ts +39 -0
  38. package/hooks/useOffline.ts +32 -2
  39. package/hooks/usePerformance.ts +434 -434
  40. package/hooks/useTheme.tsx +76 -0
  41. package/hooks/useUpdates.ts +358 -358
  42. package/i18n/index.ts +194 -77
  43. package/i18n/locales/ar.json +101 -0
  44. package/i18n/locales/de.json +101 -0
  45. package/i18n/locales/en.json +101 -101
  46. package/i18n/locales/es.json +101 -0
  47. package/i18n/locales/fr.json +101 -101
  48. package/jest.config.js +4 -4
  49. package/maestro/README.md +113 -113
  50. package/maestro/config.yaml +35 -35
  51. package/maestro/flows/login.yaml +62 -62
  52. package/maestro/flows/mfa-login.yaml +92 -0
  53. package/maestro/flows/mfa-setup.yaml +86 -0
  54. package/maestro/flows/navigation.yaml +68 -68
  55. package/maestro/flows/offline-conflict.yaml +101 -0
  56. package/maestro/flows/offline-sync.yaml +128 -0
  57. package/maestro/flows/offline.yaml +60 -60
  58. package/maestro/flows/register.yaml +94 -94
  59. package/package.json +175 -170
  60. package/services/analytics.ts +428 -428
  61. package/services/api.ts +340 -340
  62. package/services/authAdapter.ts +333 -333
  63. package/services/backgroundSync.ts +626 -0
  64. package/services/index.ts +54 -22
  65. package/services/security.ts +229 -0
  66. package/tailwind.config.js +47 -47
  67. package/utils/accessibility.ts +446 -446
  68. package/utils/index.ts +52 -43
  69. package/utils/withAccessibility.tsx +272 -0
package/README.md CHANGED
@@ -1,399 +1,399 @@
1
- # @croacroa/react-native-template
2
-
3
- [![npm version](https://img.shields.io/npm/v/@croacroa/react-native-template.svg)](https://www.npmjs.com/package/@croacroa/react-native-template)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
5
-
6
- A production-ready React Native template with Expo SDK 52, featuring authentication, i18n, biometrics, offline support, and more.
7
-
8
- ## โœจ Features
9
-
10
- ### Core
11
-
12
- - **Expo SDK 52** with TypeScript
13
- - **Expo Router** for file-based navigation
14
- - **NativeWind** (Tailwind CSS) for styling
15
- - **Zustand** for state management
16
- - **TanStack Query** with offline persistence
17
- - **React Hook Form + Zod** for form validation
18
-
19
- ### Authentication & Security
20
-
21
- - **Auth Adapter Pattern** - Easy switching between Supabase, Firebase, etc.
22
- - **Biometric Auth** - Face ID / Touch ID support
23
- - **Secure token storage** with expo-secure-store
24
- - **Automatic token refresh** with race condition handling
25
-
26
- ### Internationalization
27
-
28
- - **i18n** with expo-localization + i18next
29
- - **English & French** translations included
30
- - **Language detection** and persistence
31
-
32
- ### UX Features
33
-
34
- - **Dark/Light Theme** with system preference support
35
- - **Onboarding Screens** with animated pagination
36
- - **Push Notifications** with Expo Notifications
37
- - **Toast Notifications** with Burnt
38
- - **Deep Linking** support with route parsing
39
- - **Skeleton Loaders** with shimmer animation
40
- - **Offline Support** with connection status toasts
41
- - **OTA Updates** with expo-updates integration
42
-
43
- ### UI Components
44
-
45
- - Button, Input, Card, Modal, Skeleton
46
- - **Select/Dropdown**, Checkbox, Switch
47
- - **BottomSheet** with @gorhom/bottom-sheet
48
- - **Avatar** with initials fallback
49
- - **Badge, Chip, CountBadge**
50
- - **OptimizedImage** with expo-image
51
-
52
- ### DevOps & Quality
53
-
54
- - **GitHub Actions** CI/CD workflows
55
- - **Maestro** E2E tests
56
- - **Sentry** for crash reporting
57
- - **Analytics Adapter** for multiple providers
58
- - **Performance Monitoring** hooks
59
- - **Accessibility** utilities and hooks
60
- - **Jest + Testing Library** with 58+ tests
61
- - **Storybook** for component documentation
62
- - **ESLint + Prettier + Husky** for code quality
63
-
64
- ## ๐Ÿš€ Quick Start
65
-
66
- ### Option 1: Using npx (Recommended)
67
-
68
- ```bash
69
- npx create-expo-app my-app --template @croacroa/react-native-template
70
- cd my-app
71
- npm install
72
- ```
73
-
74
- ### Option 2: Using degit
75
-
76
- ```bash
77
- npx degit croacroa-dev-team/template-react-native my-app
78
- cd my-app
79
- ./scripts/init.sh # macOS/Linux
80
- # or
81
- .\scripts\init.ps1 # Windows PowerShell
82
- ```
83
-
84
- ### Option 3: Clone Repository
85
-
86
- ```bash
87
- git clone https://github.com/croacroa-dev-team/template-react-native my-app
88
- cd my-app
89
- rm -rf .git
90
- npm install
91
- cp .env.example .env
92
- ```
93
-
94
- Then update:
95
-
96
- - `app.config.ts` - App name, bundle ID, scheme
97
- - `package.json` - Package name
98
- - `constants/config.ts` - API URLs
99
-
100
- ### Run the App
101
-
102
- ```bash
103
- npm start # Start development server
104
- npm run ios # Run on iOS simulator
105
- npm run android # Run on Android emulator
106
- ```
107
-
108
- ## ๐Ÿ“ Project Structure
109
-
110
- ```
111
- โ”œโ”€โ”€ app/ # Expo Router pages
112
- โ”‚ โ”œโ”€โ”€ (auth)/ # Protected routes (home, profile, settings)
113
- โ”‚ โ”œโ”€โ”€ (public)/ # Public routes (login, register, forgot-password)
114
- โ”‚ โ””โ”€โ”€ _layout.tsx # Root layout with providers
115
- โ”œโ”€โ”€ components/
116
- โ”‚ โ”œโ”€โ”€ ui/ # UI components (Button, Card, Modal, Skeleton)
117
- โ”‚ โ”œโ”€โ”€ forms/ # Form components (FormInput)
118
- โ”‚ โ””โ”€โ”€ ErrorBoundary.tsx # Global error handling
119
- โ”œโ”€โ”€ hooks/ # useAuth, useTheme, useNotifications, useApi, useOffline
120
- โ”œโ”€โ”€ stores/ # Zustand stores (appStore, notificationStore)
121
- โ”œโ”€โ”€ services/
122
- โ”‚ โ”œโ”€โ”€ api.ts # HTTP client with 401 retry
123
- โ”‚ โ”œโ”€โ”€ queryClient.ts # TanStack Query with persistence
124
- โ”‚ โ”œโ”€โ”€ sentry.ts # Crash reporting
125
- โ”‚ โ””โ”€โ”€ storage.ts # AsyncStorage & SecureStore helpers
126
- โ”œโ”€โ”€ utils/ # cn, toast, validation schemas
127
- โ”œโ”€โ”€ constants/ # App configuration
128
- โ”œโ”€โ”€ types/ # TypeScript types
129
- โ”œโ”€โ”€ __tests__/ # Test files (58+ tests)
130
- โ””โ”€โ”€ scripts/ # Init scripts for template setup
131
- ```
132
-
133
- ## ๐Ÿ” Authentication
134
-
135
- Complete auth flow with automatic token refresh:
136
-
137
- ```tsx
138
- import { useAuth } from "@/hooks/useAuth";
139
-
140
- function MyComponent() {
141
- const {
142
- user,
143
- isAuthenticated,
144
- isLoading,
145
- signIn,
146
- signUp,
147
- signOut,
148
- updateUser,
149
- refreshSession,
150
- } = useAuth();
151
- }
152
- ```
153
-
154
- Features:
155
-
156
- - Tokens stored securely with expo-secure-store
157
- - Automatic refresh 5 minutes before expiry
158
- - Race condition handling for concurrent requests
159
- - Redirect to login on session expiry
160
-
161
- ## ๐Ÿ“ก API Client
162
-
163
- Robust HTTP client with automatic retry:
164
-
165
- ```tsx
166
- import { api } from "@/services/api";
167
-
168
- // Basic requests
169
- const users = await api.get<User[]>("/users");
170
- const user = await api.post<User>("/users", { name: "John" });
171
- await api.put("/users/1", { name: "Jane" });
172
- await api.delete("/users/1");
173
-
174
- // Skip auth for public endpoints
175
- await api.get("/public", { requiresAuth: false });
176
- ```
177
-
178
- ### 401 Handling
179
-
180
- The API client automatically:
181
-
182
- 1. Catches 401 responses
183
- 2. Refreshes the access token
184
- 3. Retries the original request
185
- 4. Redirects to login if refresh fails
186
-
187
- ## ๐Ÿ“Š Data Fetching
188
-
189
- TanStack Query with offline persistence:
190
-
191
- ```tsx
192
- import { useCurrentUser, useUpdateUser } from "@/hooks/useApi";
193
-
194
- function Profile() {
195
- const { data: user, isLoading, error } = useCurrentUser();
196
- const updateUser = useUpdateUser();
197
-
198
- const handleUpdate = () => {
199
- updateUser.mutate(
200
- { name: "New Name" },
201
- { onSuccess: () => toast.success("Updated!") }
202
- );
203
- };
204
- }
205
- ```
206
-
207
- ### CRUD Factory
208
-
209
- Create hooks for any resource:
210
-
211
- ```tsx
212
- import { createCrudHooks } from "@/hooks/useApi";
213
-
214
- const postsApi = createCrudHooks<Post>({
215
- baseKey: ["posts"],
216
- endpoint: "/posts",
217
- entityName: "Post",
218
- });
219
-
220
- // Usage
221
- const { data: posts } = postsApi.useList();
222
- const { data: post } = postsApi.useById("123");
223
- const createPost = postsApi.useCreate();
224
- ```
225
-
226
- ## ๐Ÿ“ด Offline Support
227
-
228
- Automatic offline handling:
229
-
230
- ```tsx
231
- import { useOffline } from "@/hooks/useOffline";
232
-
233
- function MyComponent() {
234
- const { isOffline, isOnline } = useOffline({ showToast: true });
235
- // Shows toast when connection lost/restored
236
- }
237
- ```
238
-
239
- Query cache persisted to AsyncStorage - data available offline.
240
-
241
- ## ๐ŸŽจ Skeleton Loaders
242
-
243
- Pre-built skeleton components:
244
-
245
- ```tsx
246
- import {
247
- Skeleton,
248
- SkeletonText,
249
- SkeletonCard,
250
- SkeletonProfile,
251
- SkeletonList,
252
- } from "@/components/ui/Skeleton";
253
-
254
- // Single skeleton
255
- <Skeleton width={200} height={20} />
256
-
257
- // Profile placeholder
258
- <SkeletonProfile />
259
-
260
- // List of cards
261
- <SkeletonList count={5} variant="card" />
262
- ```
263
-
264
- ## ๐Ÿ”” Toast Notifications
265
-
266
- Centralized toast system:
267
-
268
- ```tsx
269
- import { toast, handleApiError } from "@/utils/toast";
270
-
271
- // Simple toasts
272
- toast.success("Profile updated");
273
- toast.error("Something went wrong", "Please try again");
274
- toast.info("New message received");
275
-
276
- // Handle API errors automatically
277
- try {
278
- await api.post("/endpoint", data);
279
- } catch (error) {
280
- handleApiError(error); // Shows appropriate toast
281
- }
282
- ```
283
-
284
- ## ๐Ÿ›ก๏ธ Error Boundary
285
-
286
- Global error handling with Sentry:
287
-
288
- ```tsx
289
- // Already wrapped in _layout.tsx
290
- <ErrorBoundary>
291
- <App />
292
- </ErrorBoundary>;
293
-
294
- // Or use HOC for specific components
295
- import { withErrorBoundary } from "@/components/ErrorBoundary";
296
-
297
- const SafeComponent = withErrorBoundary(RiskyComponent);
298
- ```
299
-
300
- ## ๐Ÿ“‹ Form Validation
301
-
302
- React Hook Form + Zod:
303
-
304
- ```tsx
305
- import { useForm } from "react-hook-form";
306
- import { zodResolver } from "@hookform/resolvers/zod";
307
- import { FormInput } from "@/components/forms";
308
- import { loginSchema, LoginFormData } from "@/utils/validation";
309
-
310
- function LoginForm() {
311
- const { control, handleSubmit } = useForm<LoginFormData>({
312
- resolver: zodResolver(loginSchema),
313
- });
314
-
315
- return (
316
- <FormInput
317
- name="email"
318
- control={control}
319
- label="Email"
320
- keyboardType="email-address"
321
- />
322
- );
323
- }
324
- ```
325
-
326
- Pre-built schemas: `loginSchema`, `registerSchema`, `forgotPasswordSchema`, `profileSchema`
327
-
328
- ## ๐ŸŽญ Theming
329
-
330
- Dark/light mode with persistence:
331
-
332
- ```tsx
333
- import { useTheme } from "@/hooks/useTheme";
334
-
335
- function MyComponent() {
336
- const { isDark, mode, toggleTheme, setMode } = useTheme();
337
- // mode: 'light' | 'dark' | 'system'
338
- }
339
- ```
340
-
341
- ## ๐Ÿ”ง Configuration
342
-
343
- ### Environment Variables
344
-
345
- ```env
346
- # .env
347
- EXPO_PUBLIC_SENTRY_DSN=your-sentry-dsn
348
- ```
349
-
350
- ### Sentry Setup
351
-
352
- 1. Create project at [sentry.io](https://sentry.io)
353
- 2. Copy DSN to `.env`
354
- 3. Errors automatically reported in production
355
-
356
- ## ๐Ÿงช Testing
357
-
358
- 58+ tests included:
359
-
360
- ```bash
361
- npm test # Run all tests
362
- npm run test:watch # Watch mode
363
- npm run test:coverage # With coverage
364
- ```
365
-
366
- Test coverage:
367
-
368
- - `useAuth` hook - 24 tests
369
- - `ApiClient` - 22 tests
370
- - UI components - 12 tests
371
-
372
- ## ๐Ÿ“œ Available Scripts
373
-
374
- | Command | Description |
375
- | ----------------------- | ------------------------ |
376
- | `npm start` | Start Expo dev server |
377
- | `npm run ios` | Run on iOS simulator |
378
- | `npm run android` | Run on Android emulator |
379
- | `npm test` | Run tests |
380
- | `npm run storybook` | Start Storybook |
381
- | `npm run lint` | Run ESLint |
382
- | `npm run typecheck` | TypeScript check |
383
- | `npm run build:dev` | Build development client |
384
- | `npm run build:preview` | Build preview APK/IPA |
385
- | `npm run build:prod` | Build production release |
386
-
387
- ## โœ… Customization Checklist
388
-
389
- - [ ] Run init script or manually update placeholders
390
- - [ ] Replace icons in `assets/images/`
391
- - [ ] Configure API URL in `constants/config.ts`
392
- - [ ] Set up Sentry DSN in `.env`
393
- - [ ] Configure EAS: `eas build:configure`
394
- - [ ] Implement real API calls in `services/api.ts`
395
- - [ ] Add your analytics
396
-
397
- ## ๐Ÿ“„ License
398
-
399
- MIT
1
+ # @croacroa/react-native-template
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@croacroa/react-native-template.svg)](https://www.npmjs.com/package/@croacroa/react-native-template)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A production-ready React Native template with Expo SDK 52, featuring authentication, i18n, biometrics, offline support, and more.
7
+
8
+ ## โœจ Features
9
+
10
+ ### Core
11
+
12
+ - **Expo SDK 52** with TypeScript
13
+ - **Expo Router** for file-based navigation
14
+ - **NativeWind** (Tailwind CSS) for styling
15
+ - **Zustand** for state management
16
+ - **TanStack Query** with offline persistence
17
+ - **React Hook Form + Zod** for form validation
18
+
19
+ ### Authentication & Security
20
+
21
+ - **Auth Adapter Pattern** - Easy switching between Supabase, Firebase, etc.
22
+ - **Biometric Auth** - Face ID / Touch ID support
23
+ - **Secure token storage** with expo-secure-store
24
+ - **Automatic token refresh** with race condition handling
25
+
26
+ ### Internationalization
27
+
28
+ - **i18n** with expo-localization + i18next
29
+ - **English & French** translations included
30
+ - **Language detection** and persistence
31
+
32
+ ### UX Features
33
+
34
+ - **Dark/Light Theme** with system preference support
35
+ - **Onboarding Screens** with animated pagination
36
+ - **Push Notifications** with Expo Notifications
37
+ - **Toast Notifications** with Burnt
38
+ - **Deep Linking** support with route parsing
39
+ - **Skeleton Loaders** with shimmer animation
40
+ - **Offline Support** with connection status toasts
41
+ - **OTA Updates** with expo-updates integration
42
+
43
+ ### UI Components
44
+
45
+ - Button, Input, Card, Modal, Skeleton
46
+ - **Select/Dropdown**, Checkbox, Switch
47
+ - **BottomSheet** with @gorhom/bottom-sheet
48
+ - **Avatar** with initials fallback
49
+ - **Badge, Chip, CountBadge**
50
+ - **OptimizedImage** with expo-image
51
+
52
+ ### DevOps & Quality
53
+
54
+ - **GitHub Actions** CI/CD workflows
55
+ - **Maestro** E2E tests
56
+ - **Sentry** for crash reporting
57
+ - **Analytics Adapter** for multiple providers
58
+ - **Performance Monitoring** hooks
59
+ - **Accessibility** utilities and hooks
60
+ - **Jest + Testing Library** with 58+ tests
61
+ - **Storybook** for component documentation
62
+ - **ESLint + Prettier + Husky** for code quality
63
+
64
+ ## ๐Ÿš€ Quick Start
65
+
66
+ ### Option 1: Using npx (Recommended)
67
+
68
+ ```bash
69
+ npx create-expo-app my-app --template @croacroa/react-native-template
70
+ cd my-app
71
+ npm install
72
+ ```
73
+
74
+ ### Option 2: Using degit
75
+
76
+ ```bash
77
+ npx degit croacroa-dev-team/template-react-native my-app
78
+ cd my-app
79
+ ./scripts/init.sh # macOS/Linux
80
+ # or
81
+ .\scripts\init.ps1 # Windows PowerShell
82
+ ```
83
+
84
+ ### Option 3: Clone Repository
85
+
86
+ ```bash
87
+ git clone https://github.com/croacroa-dev-team/template-react-native my-app
88
+ cd my-app
89
+ rm -rf .git
90
+ npm install
91
+ cp .env.example .env
92
+ ```
93
+
94
+ Then update:
95
+
96
+ - `app.config.ts` - App name, bundle ID, scheme
97
+ - `package.json` - Package name
98
+ - `constants/config.ts` - API URLs
99
+
100
+ ### Run the App
101
+
102
+ ```bash
103
+ npm start # Start development server
104
+ npm run ios # Run on iOS simulator
105
+ npm run android # Run on Android emulator
106
+ ```
107
+
108
+ ## ๐Ÿ“ Project Structure
109
+
110
+ ```
111
+ โ”œโ”€โ”€ app/ # Expo Router pages
112
+ โ”‚ โ”œโ”€โ”€ (auth)/ # Protected routes (home, profile, settings)
113
+ โ”‚ โ”œโ”€โ”€ (public)/ # Public routes (login, register, forgot-password)
114
+ โ”‚ โ””โ”€โ”€ _layout.tsx # Root layout with providers
115
+ โ”œโ”€โ”€ components/
116
+ โ”‚ โ”œโ”€โ”€ ui/ # UI components (Button, Card, Modal, Skeleton)
117
+ โ”‚ โ”œโ”€โ”€ forms/ # Form components (FormInput)
118
+ โ”‚ โ””โ”€โ”€ ErrorBoundary.tsx # Global error handling
119
+ โ”œโ”€โ”€ hooks/ # useAuth, useTheme, useNotifications, useApi, useOffline
120
+ โ”œโ”€โ”€ stores/ # Zustand stores (appStore, notificationStore)
121
+ โ”œโ”€โ”€ services/
122
+ โ”‚ โ”œโ”€โ”€ api.ts # HTTP client with 401 retry
123
+ โ”‚ โ”œโ”€โ”€ queryClient.ts # TanStack Query with persistence
124
+ โ”‚ โ”œโ”€โ”€ sentry.ts # Crash reporting
125
+ โ”‚ โ””โ”€โ”€ storage.ts # AsyncStorage & SecureStore helpers
126
+ โ”œโ”€โ”€ utils/ # cn, toast, validation schemas
127
+ โ”œโ”€โ”€ constants/ # App configuration
128
+ โ”œโ”€โ”€ types/ # TypeScript types
129
+ โ”œโ”€โ”€ __tests__/ # Test files (58+ tests)
130
+ โ””โ”€โ”€ scripts/ # Init scripts for template setup
131
+ ```
132
+
133
+ ## ๐Ÿ” Authentication
134
+
135
+ Complete auth flow with automatic token refresh:
136
+
137
+ ```tsx
138
+ import { useAuth } from "@/hooks/useAuth";
139
+
140
+ function MyComponent() {
141
+ const {
142
+ user,
143
+ isAuthenticated,
144
+ isLoading,
145
+ signIn,
146
+ signUp,
147
+ signOut,
148
+ updateUser,
149
+ refreshSession,
150
+ } = useAuth();
151
+ }
152
+ ```
153
+
154
+ Features:
155
+
156
+ - Tokens stored securely with expo-secure-store
157
+ - Automatic refresh 5 minutes before expiry
158
+ - Race condition handling for concurrent requests
159
+ - Redirect to login on session expiry
160
+
161
+ ## ๐Ÿ“ก API Client
162
+
163
+ Robust HTTP client with automatic retry:
164
+
165
+ ```tsx
166
+ import { api } from "@/services/api";
167
+
168
+ // Basic requests
169
+ const users = await api.get<User[]>("/users");
170
+ const user = await api.post<User>("/users", { name: "John" });
171
+ await api.put("/users/1", { name: "Jane" });
172
+ await api.delete("/users/1");
173
+
174
+ // Skip auth for public endpoints
175
+ await api.get("/public", { requiresAuth: false });
176
+ ```
177
+
178
+ ### 401 Handling
179
+
180
+ The API client automatically:
181
+
182
+ 1. Catches 401 responses
183
+ 2. Refreshes the access token
184
+ 3. Retries the original request
185
+ 4. Redirects to login if refresh fails
186
+
187
+ ## ๐Ÿ“Š Data Fetching
188
+
189
+ TanStack Query with offline persistence:
190
+
191
+ ```tsx
192
+ import { useCurrentUser, useUpdateUser } from "@/hooks/useApi";
193
+
194
+ function Profile() {
195
+ const { data: user, isLoading, error } = useCurrentUser();
196
+ const updateUser = useUpdateUser();
197
+
198
+ const handleUpdate = () => {
199
+ updateUser.mutate(
200
+ { name: "New Name" },
201
+ { onSuccess: () => toast.success("Updated!") }
202
+ );
203
+ };
204
+ }
205
+ ```
206
+
207
+ ### CRUD Factory
208
+
209
+ Create hooks for any resource:
210
+
211
+ ```tsx
212
+ import { createCrudHooks } from "@/hooks/useApi";
213
+
214
+ const postsApi = createCrudHooks<Post>({
215
+ baseKey: ["posts"],
216
+ endpoint: "/posts",
217
+ entityName: "Post",
218
+ });
219
+
220
+ // Usage
221
+ const { data: posts } = postsApi.useList();
222
+ const { data: post } = postsApi.useById("123");
223
+ const createPost = postsApi.useCreate();
224
+ ```
225
+
226
+ ## ๐Ÿ“ด Offline Support
227
+
228
+ Automatic offline handling:
229
+
230
+ ```tsx
231
+ import { useOffline } from "@/hooks/useOffline";
232
+
233
+ function MyComponent() {
234
+ const { isOffline, isOnline } = useOffline({ showToast: true });
235
+ // Shows toast when connection lost/restored
236
+ }
237
+ ```
238
+
239
+ Query cache persisted to AsyncStorage - data available offline.
240
+
241
+ ## ๐ŸŽจ Skeleton Loaders
242
+
243
+ Pre-built skeleton components:
244
+
245
+ ```tsx
246
+ import {
247
+ Skeleton,
248
+ SkeletonText,
249
+ SkeletonCard,
250
+ SkeletonProfile,
251
+ SkeletonList,
252
+ } from "@/components/ui/Skeleton";
253
+
254
+ // Single skeleton
255
+ <Skeleton width={200} height={20} />
256
+
257
+ // Profile placeholder
258
+ <SkeletonProfile />
259
+
260
+ // List of cards
261
+ <SkeletonList count={5} variant="card" />
262
+ ```
263
+
264
+ ## ๐Ÿ”” Toast Notifications
265
+
266
+ Centralized toast system:
267
+
268
+ ```tsx
269
+ import { toast, handleApiError } from "@/utils/toast";
270
+
271
+ // Simple toasts
272
+ toast.success("Profile updated");
273
+ toast.error("Something went wrong", "Please try again");
274
+ toast.info("New message received");
275
+
276
+ // Handle API errors automatically
277
+ try {
278
+ await api.post("/endpoint", data);
279
+ } catch (error) {
280
+ handleApiError(error); // Shows appropriate toast
281
+ }
282
+ ```
283
+
284
+ ## ๐Ÿ›ก๏ธ Error Boundary
285
+
286
+ Global error handling with Sentry:
287
+
288
+ ```tsx
289
+ // Already wrapped in _layout.tsx
290
+ <ErrorBoundary>
291
+ <App />
292
+ </ErrorBoundary>;
293
+
294
+ // Or use HOC for specific components
295
+ import { withErrorBoundary } from "@/components/ErrorBoundary";
296
+
297
+ const SafeComponent = withErrorBoundary(RiskyComponent);
298
+ ```
299
+
300
+ ## ๐Ÿ“‹ Form Validation
301
+
302
+ React Hook Form + Zod:
303
+
304
+ ```tsx
305
+ import { useForm } from "react-hook-form";
306
+ import { zodResolver } from "@hookform/resolvers/zod";
307
+ import { FormInput } from "@/components/forms";
308
+ import { loginSchema, LoginFormData } from "@/utils/validation";
309
+
310
+ function LoginForm() {
311
+ const { control, handleSubmit } = useForm<LoginFormData>({
312
+ resolver: zodResolver(loginSchema),
313
+ });
314
+
315
+ return (
316
+ <FormInput
317
+ name="email"
318
+ control={control}
319
+ label="Email"
320
+ keyboardType="email-address"
321
+ />
322
+ );
323
+ }
324
+ ```
325
+
326
+ Pre-built schemas: `loginSchema`, `registerSchema`, `forgotPasswordSchema`, `profileSchema`
327
+
328
+ ## ๐ŸŽญ Theming
329
+
330
+ Dark/light mode with persistence:
331
+
332
+ ```tsx
333
+ import { useTheme } from "@/hooks/useTheme";
334
+
335
+ function MyComponent() {
336
+ const { isDark, mode, toggleTheme, setMode } = useTheme();
337
+ // mode: 'light' | 'dark' | 'system'
338
+ }
339
+ ```
340
+
341
+ ## ๐Ÿ”ง Configuration
342
+
343
+ ### Environment Variables
344
+
345
+ ```env
346
+ # .env
347
+ EXPO_PUBLIC_SENTRY_DSN=your-sentry-dsn
348
+ ```
349
+
350
+ ### Sentry Setup
351
+
352
+ 1. Create project at [sentry.io](https://sentry.io)
353
+ 2. Copy DSN to `.env`
354
+ 3. Errors automatically reported in production
355
+
356
+ ## ๐Ÿงช Testing
357
+
358
+ 58+ tests included:
359
+
360
+ ```bash
361
+ npm test # Run all tests
362
+ npm run test:watch # Watch mode
363
+ npm run test:coverage # With coverage
364
+ ```
365
+
366
+ Test coverage:
367
+
368
+ - `useAuth` hook - 24 tests
369
+ - `ApiClient` - 22 tests
370
+ - UI components - 12 tests
371
+
372
+ ## ๐Ÿ“œ Available Scripts
373
+
374
+ | Command | Description |
375
+ | ----------------------- | ------------------------ |
376
+ | `npm start` | Start Expo dev server |
377
+ | `npm run ios` | Run on iOS simulator |
378
+ | `npm run android` | Run on Android emulator |
379
+ | `npm test` | Run tests |
380
+ | `npm run storybook` | Start Storybook |
381
+ | `npm run lint` | Run ESLint |
382
+ | `npm run typecheck` | TypeScript check |
383
+ | `npm run build:dev` | Build development client |
384
+ | `npm run build:preview` | Build preview APK/IPA |
385
+ | `npm run build:prod` | Build production release |
386
+
387
+ ## โœ… Customization Checklist
388
+
389
+ - [ ] Run init script or manually update placeholders
390
+ - [ ] Replace icons in `assets/images/`
391
+ - [ ] Configure API URL in `constants/config.ts`
392
+ - [ ] Set up Sentry DSN in `.env`
393
+ - [ ] Configure EAS: `eas build:configure`
394
+ - [ ] Implement real API calls in `services/api.ts`
395
+ - [ ] Add your analytics
396
+
397
+ ## ๐Ÿ“„ License
398
+
399
+ MIT