@croacroa/react-native-template 1.0.0 → 2.0.1
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/.github/workflows/ci.yml +187 -184
- package/.github/workflows/eas-build.yml +55 -55
- package/.github/workflows/eas-update.yml +50 -50
- package/CHANGELOG.md +106 -106
- package/CONTRIBUTING.md +377 -377
- package/README.md +399 -399
- package/__tests__/components/snapshots.test.tsx +131 -0
- package/__tests__/integration/auth-api.test.tsx +227 -0
- package/__tests__/performance/VirtualizedList.perf.test.tsx +362 -0
- package/app/(public)/onboarding.tsx +5 -5
- package/app.config.ts +45 -2
- package/assets/images/.gitkeep +7 -7
- package/components/onboarding/OnboardingScreen.tsx +370 -370
- package/components/onboarding/index.ts +2 -2
- package/components/providers/SuspenseBoundary.tsx +357 -0
- package/components/providers/index.ts +21 -0
- package/components/ui/Avatar.tsx +316 -316
- package/components/ui/Badge.tsx +416 -416
- package/components/ui/BottomSheet.tsx +307 -307
- package/components/ui/Checkbox.tsx +261 -261
- package/components/ui/OptimizedImage.tsx +369 -369
- package/components/ui/Select.tsx +240 -240
- package/components/ui/VirtualizedList.tsx +285 -0
- package/components/ui/index.ts +23 -18
- package/constants/config.ts +97 -54
- 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/hooks/index.ts +27 -25
- package/hooks/useApi.ts +102 -5
- package/hooks/useAuth.tsx +82 -0
- package/hooks/useBiometrics.ts +295 -295
- package/hooks/useDeepLinking.ts +256 -256
- package/hooks/useMFA.ts +499 -0
- package/hooks/useNotifications.ts +39 -0
- package/hooks/useOffline.ts +60 -6
- package/hooks/usePerformance.ts +434 -434
- package/hooks/useTheme.tsx +76 -0
- package/hooks/useUpdates.ts +358 -358
- package/i18n/index.ts +194 -77
- package/i18n/locales/ar.json +101 -0
- package/i18n/locales/de.json +101 -0
- package/i18n/locales/en.json +101 -101
- package/i18n/locales/es.json +101 -0
- package/i18n/locales/fr.json +101 -101
- package/jest.config.js +4 -4
- 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 -0
- package/maestro/flows/mfa-setup.yaml +86 -0
- package/maestro/flows/navigation.yaml +68 -68
- package/maestro/flows/offline-conflict.yaml +101 -0
- package/maestro/flows/offline-sync.yaml +128 -0
- package/maestro/flows/offline.yaml +60 -60
- package/maestro/flows/register.yaml +94 -94
- package/package.json +175 -170
- package/services/analytics.ts +428 -428
- package/services/api.ts +340 -340
- package/services/authAdapter.ts +333 -333
- package/services/backgroundSync.ts +626 -0
- package/services/index.ts +54 -22
- package/services/security.ts +286 -0
- package/tailwind.config.js +47 -47
- package/utils/accessibility.ts +446 -446
- package/utils/index.ts +52 -43
- package/utils/validation.ts +2 -1
- package/utils/withAccessibility.tsx +272 -0
|
@@ -1,144 +1,144 @@
|
|
|
1
|
-
# ADR-004: Auth Adapter Pattern for Authentication
|
|
2
|
-
|
|
3
|
-
## Status
|
|
4
|
-
|
|
5
|
-
Accepted
|
|
6
|
-
|
|
7
|
-
## Date
|
|
8
|
-
|
|
9
|
-
2024-01-15
|
|
10
|
-
|
|
11
|
-
## Context
|
|
12
|
-
|
|
13
|
-
The template needs to support multiple authentication providers (Supabase, Firebase, Auth0, custom backends) without requiring significant code changes. We need:
|
|
14
|
-
|
|
15
|
-
1. Easy switching between auth providers
|
|
16
|
-
2. Consistent API regardless of provider
|
|
17
|
-
3. Type safety
|
|
18
|
-
4. Testability with mock implementations
|
|
19
|
-
|
|
20
|
-
## Decision
|
|
21
|
-
|
|
22
|
-
Implement an **Adapter Pattern** for authentication that abstracts the auth provider behind a common interface.
|
|
23
|
-
|
|
24
|
-
## Rationale
|
|
25
|
-
|
|
26
|
-
1. **Flexibility**: Change auth providers without touching app code
|
|
27
|
-
2. **Testing**: Easy to mock for unit tests
|
|
28
|
-
3. **Consistency**: Same API for all providers
|
|
29
|
-
4. **Gradual Migration**: Can switch providers incrementally
|
|
30
|
-
|
|
31
|
-
## Implementation
|
|
32
|
-
|
|
33
|
-
### Interface Definition
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
// services/authAdapter.ts
|
|
37
|
-
export interface AuthAdapter {
|
|
38
|
-
signIn(email: string, password: string): Promise<AuthResult>;
|
|
39
|
-
signUp(email: string, password: string, name: string): Promise<AuthResult>;
|
|
40
|
-
signOut(): Promise<void>;
|
|
41
|
-
refreshToken(refreshToken: string): Promise<AuthTokens>;
|
|
42
|
-
forgotPassword(email: string): Promise<void>;
|
|
43
|
-
resetPassword(token: string, newPassword: string): Promise<void>;
|
|
44
|
-
getSession(): Promise<AuthResult | null>;
|
|
45
|
-
onAuthStateChange?(callback: (user: User | null) => void): () => void;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface AuthResult {
|
|
49
|
-
user: User;
|
|
50
|
-
tokens: AuthTokens;
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Mock Implementation
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
export const mockAuthAdapter: AuthAdapter = {
|
|
58
|
-
async signIn(email, password) {
|
|
59
|
-
await delay(1000); // Simulate network
|
|
60
|
-
return {
|
|
61
|
-
user: { id: '1', email, name: email.split('@')[0] },
|
|
62
|
-
tokens: { accessToken: 'mock', refreshToken: 'mock', expiresAt: ... },
|
|
63
|
-
};
|
|
64
|
-
},
|
|
65
|
-
// ... other methods
|
|
66
|
-
};
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Supabase Implementation
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
export const supabaseAuthAdapter: AuthAdapter = {
|
|
73
|
-
async signIn(email, password) {
|
|
74
|
-
const { data, error } = await supabase.auth.signInWithPassword({
|
|
75
|
-
email,
|
|
76
|
-
password,
|
|
77
|
-
});
|
|
78
|
-
if (error) throw error;
|
|
79
|
-
return transformSupabaseSession(data);
|
|
80
|
-
},
|
|
81
|
-
// ... other methods
|
|
82
|
-
};
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Usage
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
// services/authAdapter.ts
|
|
89
|
-
// Change this line to switch providers
|
|
90
|
-
export const authAdapter: AuthAdapter = mockAuthAdapter;
|
|
91
|
-
// export const authAdapter: AuthAdapter = supabaseAuthAdapter;
|
|
92
|
-
// export const authAdapter: AuthAdapter = firebaseAuthAdapter;
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## Consequences
|
|
96
|
-
|
|
97
|
-
### Positive
|
|
98
|
-
|
|
99
|
-
- Provider-agnostic code
|
|
100
|
-
- Easy to test with mocks
|
|
101
|
-
- Clear contract for auth operations
|
|
102
|
-
- Can support multiple providers simultaneously
|
|
103
|
-
|
|
104
|
-
### Negative
|
|
105
|
-
|
|
106
|
-
- Some provider-specific features may not fit the interface
|
|
107
|
-
- Additional abstraction layer
|
|
108
|
-
- Need to maintain multiple implementations
|
|
109
|
-
|
|
110
|
-
### Mitigation
|
|
111
|
-
|
|
112
|
-
- Allow optional methods in interface
|
|
113
|
-
- Document provider-specific extensions
|
|
114
|
-
- Keep interface focused on common operations
|
|
115
|
-
|
|
116
|
-
## Testing
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
// __tests__/auth.test.ts
|
|
120
|
-
import { mockAuthAdapter } from "@/services/authAdapter";
|
|
121
|
-
|
|
122
|
-
describe("Auth", () => {
|
|
123
|
-
it("signs in successfully", async () => {
|
|
124
|
-
const result = await mockAuthAdapter.signIn("test@example.com", "password");
|
|
125
|
-
expect(result.user.email).toBe("test@example.com");
|
|
126
|
-
expect(result.tokens.accessToken).toBeDefined();
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## Migration Guide
|
|
132
|
-
|
|
133
|
-
To switch from mock to Supabase:
|
|
134
|
-
|
|
135
|
-
1. Install Supabase: `npx expo install @supabase/supabase-js`
|
|
136
|
-
2. Configure environment variables
|
|
137
|
-
3. Implement `supabaseAuthAdapter`
|
|
138
|
-
4. Update export in `authAdapter.ts`
|
|
139
|
-
|
|
140
|
-
## References
|
|
141
|
-
|
|
142
|
-
- [Adapter Pattern](https://refactoring.guru/design-patterns/adapter)
|
|
143
|
-
- [Supabase Auth](https://supabase.com/docs/guides/auth)
|
|
144
|
-
- [Firebase Auth](https://firebase.google.com/docs/auth)
|
|
1
|
+
# ADR-004: Auth Adapter Pattern for Authentication
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted
|
|
6
|
+
|
|
7
|
+
## Date
|
|
8
|
+
|
|
9
|
+
2024-01-15
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
|
|
13
|
+
The template needs to support multiple authentication providers (Supabase, Firebase, Auth0, custom backends) without requiring significant code changes. We need:
|
|
14
|
+
|
|
15
|
+
1. Easy switching between auth providers
|
|
16
|
+
2. Consistent API regardless of provider
|
|
17
|
+
3. Type safety
|
|
18
|
+
4. Testability with mock implementations
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
Implement an **Adapter Pattern** for authentication that abstracts the auth provider behind a common interface.
|
|
23
|
+
|
|
24
|
+
## Rationale
|
|
25
|
+
|
|
26
|
+
1. **Flexibility**: Change auth providers without touching app code
|
|
27
|
+
2. **Testing**: Easy to mock for unit tests
|
|
28
|
+
3. **Consistency**: Same API for all providers
|
|
29
|
+
4. **Gradual Migration**: Can switch providers incrementally
|
|
30
|
+
|
|
31
|
+
## Implementation
|
|
32
|
+
|
|
33
|
+
### Interface Definition
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// services/authAdapter.ts
|
|
37
|
+
export interface AuthAdapter {
|
|
38
|
+
signIn(email: string, password: string): Promise<AuthResult>;
|
|
39
|
+
signUp(email: string, password: string, name: string): Promise<AuthResult>;
|
|
40
|
+
signOut(): Promise<void>;
|
|
41
|
+
refreshToken(refreshToken: string): Promise<AuthTokens>;
|
|
42
|
+
forgotPassword(email: string): Promise<void>;
|
|
43
|
+
resetPassword(token: string, newPassword: string): Promise<void>;
|
|
44
|
+
getSession(): Promise<AuthResult | null>;
|
|
45
|
+
onAuthStateChange?(callback: (user: User | null) => void): () => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface AuthResult {
|
|
49
|
+
user: User;
|
|
50
|
+
tokens: AuthTokens;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Mock Implementation
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
export const mockAuthAdapter: AuthAdapter = {
|
|
58
|
+
async signIn(email, password) {
|
|
59
|
+
await delay(1000); // Simulate network
|
|
60
|
+
return {
|
|
61
|
+
user: { id: '1', email, name: email.split('@')[0] },
|
|
62
|
+
tokens: { accessToken: 'mock', refreshToken: 'mock', expiresAt: ... },
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
// ... other methods
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Supabase Implementation
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
export const supabaseAuthAdapter: AuthAdapter = {
|
|
73
|
+
async signIn(email, password) {
|
|
74
|
+
const { data, error } = await supabase.auth.signInWithPassword({
|
|
75
|
+
email,
|
|
76
|
+
password,
|
|
77
|
+
});
|
|
78
|
+
if (error) throw error;
|
|
79
|
+
return transformSupabaseSession(data);
|
|
80
|
+
},
|
|
81
|
+
// ... other methods
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Usage
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// services/authAdapter.ts
|
|
89
|
+
// Change this line to switch providers
|
|
90
|
+
export const authAdapter: AuthAdapter = mockAuthAdapter;
|
|
91
|
+
// export const authAdapter: AuthAdapter = supabaseAuthAdapter;
|
|
92
|
+
// export const authAdapter: AuthAdapter = firebaseAuthAdapter;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Consequences
|
|
96
|
+
|
|
97
|
+
### Positive
|
|
98
|
+
|
|
99
|
+
- Provider-agnostic code
|
|
100
|
+
- Easy to test with mocks
|
|
101
|
+
- Clear contract for auth operations
|
|
102
|
+
- Can support multiple providers simultaneously
|
|
103
|
+
|
|
104
|
+
### Negative
|
|
105
|
+
|
|
106
|
+
- Some provider-specific features may not fit the interface
|
|
107
|
+
- Additional abstraction layer
|
|
108
|
+
- Need to maintain multiple implementations
|
|
109
|
+
|
|
110
|
+
### Mitigation
|
|
111
|
+
|
|
112
|
+
- Allow optional methods in interface
|
|
113
|
+
- Document provider-specific extensions
|
|
114
|
+
- Keep interface focused on common operations
|
|
115
|
+
|
|
116
|
+
## Testing
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// __tests__/auth.test.ts
|
|
120
|
+
import { mockAuthAdapter } from "@/services/authAdapter";
|
|
121
|
+
|
|
122
|
+
describe("Auth", () => {
|
|
123
|
+
it("signs in successfully", async () => {
|
|
124
|
+
const result = await mockAuthAdapter.signIn("test@example.com", "password");
|
|
125
|
+
expect(result.user.email).toBe("test@example.com");
|
|
126
|
+
expect(result.tokens.accessToken).toBeDefined();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Migration Guide
|
|
132
|
+
|
|
133
|
+
To switch from mock to Supabase:
|
|
134
|
+
|
|
135
|
+
1. Install Supabase: `npx expo install @supabase/supabase-js`
|
|
136
|
+
2. Configure environment variables
|
|
137
|
+
3. Implement `supabaseAuthAdapter`
|
|
138
|
+
4. Update export in `authAdapter.ts`
|
|
139
|
+
|
|
140
|
+
## References
|
|
141
|
+
|
|
142
|
+
- [Adapter Pattern](https://refactoring.guru/design-patterns/adapter)
|
|
143
|
+
- [Supabase Auth](https://supabase.com/docs/guides/auth)
|
|
144
|
+
- [Firebase Auth](https://firebase.google.com/docs/auth)
|
package/docs/adr/README.md
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
# Architecture Decision Records (ADRs)
|
|
2
|
-
|
|
3
|
-
This directory contains Architecture Decision Records (ADRs) documenting significant technical decisions made in this project.
|
|
4
|
-
|
|
5
|
-
## What is an ADR?
|
|
6
|
-
|
|
7
|
-
An ADR is a document that captures an important architectural decision made along with its context and consequences.
|
|
8
|
-
|
|
9
|
-
## ADR Template
|
|
10
|
-
|
|
11
|
-
```markdown
|
|
12
|
-
# ADR-XXX: Title
|
|
13
|
-
|
|
14
|
-
## Status
|
|
15
|
-
|
|
16
|
-
[Proposed | Accepted | Deprecated | Superseded by ADR-XXX]
|
|
17
|
-
|
|
18
|
-
## Date
|
|
19
|
-
|
|
20
|
-
YYYY-MM-DD
|
|
21
|
-
|
|
22
|
-
## Context
|
|
23
|
-
|
|
24
|
-
[What is the issue that we're seeing that is motivating this decision?]
|
|
25
|
-
|
|
26
|
-
## Decision
|
|
27
|
-
|
|
28
|
-
[What is the change that we're proposing and/or doing?]
|
|
29
|
-
|
|
30
|
-
## Consequences
|
|
31
|
-
|
|
32
|
-
### Positive
|
|
33
|
-
|
|
34
|
-
[What are the benefits?]
|
|
35
|
-
|
|
36
|
-
### Negative
|
|
37
|
-
|
|
38
|
-
[What are the drawbacks?]
|
|
39
|
-
|
|
40
|
-
### Mitigation
|
|
41
|
-
|
|
42
|
-
[How do we address the drawbacks?]
|
|
43
|
-
|
|
44
|
-
## References
|
|
45
|
-
|
|
46
|
-
[Links to relevant documentation, articles, or discussions]
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Index
|
|
50
|
-
|
|
51
|
-
| ADR | Title | Status | Date |
|
|
52
|
-
| ------------------------------------ | --------------------------------- | -------- | ---------- |
|
|
53
|
-
| [001](./001-state-management.md) | Use Zustand for State Management | Accepted | 2024-01-01 |
|
|
54
|
-
| [002](./002-styling-approach.md) | Use NativeWind for Styling | Accepted | 2024-01-01 |
|
|
55
|
-
| [003](./003-data-fetching.md) | Use React Query for Data Fetching | Accepted | 2024-01-01 |
|
|
56
|
-
| [004](./004-auth-adapter-pattern.md) | Auth Adapter Pattern | Accepted | 2024-01-15 |
|
|
57
|
-
|
|
58
|
-
## When to Write an ADR
|
|
59
|
-
|
|
60
|
-
Write an ADR when:
|
|
61
|
-
|
|
62
|
-
1. Making a significant architectural decision
|
|
63
|
-
2. Choosing between multiple valid options
|
|
64
|
-
3. The decision will be hard to change later
|
|
65
|
-
4. Team members need to understand "why"
|
|
66
|
-
|
|
67
|
-
## How to Create a New ADR
|
|
68
|
-
|
|
69
|
-
1. Copy the template above
|
|
70
|
-
2. Number it sequentially (e.g., `005-your-decision.md`)
|
|
71
|
-
3. Fill in all sections
|
|
72
|
-
4. Add it to the index in this README
|
|
73
|
-
5. Submit for review with your PR
|
|
74
|
-
|
|
75
|
-
## Resources
|
|
76
|
-
|
|
77
|
-
- [ADR GitHub Organization](https://adr.github.io/)
|
|
78
|
-
- [Documenting Architecture Decisions](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions)
|
|
1
|
+
# Architecture Decision Records (ADRs)
|
|
2
|
+
|
|
3
|
+
This directory contains Architecture Decision Records (ADRs) documenting significant technical decisions made in this project.
|
|
4
|
+
|
|
5
|
+
## What is an ADR?
|
|
6
|
+
|
|
7
|
+
An ADR is a document that captures an important architectural decision made along with its context and consequences.
|
|
8
|
+
|
|
9
|
+
## ADR Template
|
|
10
|
+
|
|
11
|
+
```markdown
|
|
12
|
+
# ADR-XXX: Title
|
|
13
|
+
|
|
14
|
+
## Status
|
|
15
|
+
|
|
16
|
+
[Proposed | Accepted | Deprecated | Superseded by ADR-XXX]
|
|
17
|
+
|
|
18
|
+
## Date
|
|
19
|
+
|
|
20
|
+
YYYY-MM-DD
|
|
21
|
+
|
|
22
|
+
## Context
|
|
23
|
+
|
|
24
|
+
[What is the issue that we're seeing that is motivating this decision?]
|
|
25
|
+
|
|
26
|
+
## Decision
|
|
27
|
+
|
|
28
|
+
[What is the change that we're proposing and/or doing?]
|
|
29
|
+
|
|
30
|
+
## Consequences
|
|
31
|
+
|
|
32
|
+
### Positive
|
|
33
|
+
|
|
34
|
+
[What are the benefits?]
|
|
35
|
+
|
|
36
|
+
### Negative
|
|
37
|
+
|
|
38
|
+
[What are the drawbacks?]
|
|
39
|
+
|
|
40
|
+
### Mitigation
|
|
41
|
+
|
|
42
|
+
[How do we address the drawbacks?]
|
|
43
|
+
|
|
44
|
+
## References
|
|
45
|
+
|
|
46
|
+
[Links to relevant documentation, articles, or discussions]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Index
|
|
50
|
+
|
|
51
|
+
| ADR | Title | Status | Date |
|
|
52
|
+
| ------------------------------------ | --------------------------------- | -------- | ---------- |
|
|
53
|
+
| [001](./001-state-management.md) | Use Zustand for State Management | Accepted | 2024-01-01 |
|
|
54
|
+
| [002](./002-styling-approach.md) | Use NativeWind for Styling | Accepted | 2024-01-01 |
|
|
55
|
+
| [003](./003-data-fetching.md) | Use React Query for Data Fetching | Accepted | 2024-01-01 |
|
|
56
|
+
| [004](./004-auth-adapter-pattern.md) | Auth Adapter Pattern | Accepted | 2024-01-15 |
|
|
57
|
+
|
|
58
|
+
## When to Write an ADR
|
|
59
|
+
|
|
60
|
+
Write an ADR when:
|
|
61
|
+
|
|
62
|
+
1. Making a significant architectural decision
|
|
63
|
+
2. Choosing between multiple valid options
|
|
64
|
+
3. The decision will be hard to change later
|
|
65
|
+
4. Team members need to understand "why"
|
|
66
|
+
|
|
67
|
+
## How to Create a New ADR
|
|
68
|
+
|
|
69
|
+
1. Copy the template above
|
|
70
|
+
2. Number it sequentially (e.g., `005-your-decision.md`)
|
|
71
|
+
3. Fill in all sections
|
|
72
|
+
4. Add it to the index in this README
|
|
73
|
+
5. Submit for review with your PR
|
|
74
|
+
|
|
75
|
+
## Resources
|
|
76
|
+
|
|
77
|
+
- [ADR GitHub Organization](https://adr.github.io/)
|
|
78
|
+
- [Documenting Architecture Decisions](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions)
|
package/hooks/index.ts
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
export { useAuth, AuthProvider, getAuthToken } from "./useAuth";
|
|
2
|
-
export { useTheme, ThemeProvider } from "./useTheme";
|
|
3
|
-
export { useNotifications } from "./useNotifications";
|
|
4
|
-
export {
|
|
5
|
-
useCurrentUser,
|
|
6
|
-
useUser,
|
|
7
|
-
useUpdateUser,
|
|
8
|
-
queryKeys,
|
|
9
|
-
createCrudHooks,
|
|
10
|
-
postsApi,
|
|
11
|
-
} from "./useApi";
|
|
12
|
-
export {
|
|
13
|
-
useDeepLinking,
|
|
14
|
-
createDeepLink,
|
|
15
|
-
getDeepLinkPrefix,
|
|
16
|
-
} from "./useDeepLinking";
|
|
17
|
-
export { useBiometrics, getBiometricName } from "./useBiometrics";
|
|
18
|
-
export { useOffline, usePendingMutations } from "./useOffline";
|
|
19
|
-
export { useUpdates, getUpdateInfo, forceUpdate } from "./useUpdates";
|
|
20
|
-
export {
|
|
21
|
-
usePerformance,
|
|
22
|
-
measureAsync,
|
|
23
|
-
measureSync,
|
|
24
|
-
runAfterInteractions,
|
|
25
|
-
} from "./usePerformance";
|
|
1
|
+
export { useAuth, AuthProvider, getAuthToken } from "./useAuth";
|
|
2
|
+
export { useTheme, ThemeProvider } from "./useTheme";
|
|
3
|
+
export { useNotifications } from "./useNotifications";
|
|
4
|
+
export {
|
|
5
|
+
useCurrentUser,
|
|
6
|
+
useUser,
|
|
7
|
+
useUpdateUser,
|
|
8
|
+
queryKeys,
|
|
9
|
+
createCrudHooks,
|
|
10
|
+
postsApi,
|
|
11
|
+
} from "./useApi";
|
|
12
|
+
export {
|
|
13
|
+
useDeepLinking,
|
|
14
|
+
createDeepLink,
|
|
15
|
+
getDeepLinkPrefix,
|
|
16
|
+
} from "./useDeepLinking";
|
|
17
|
+
export { useBiometrics, getBiometricName } from "./useBiometrics";
|
|
18
|
+
export { useOffline, usePendingMutations } from "./useOffline";
|
|
19
|
+
export { useUpdates, getUpdateInfo, forceUpdate } from "./useUpdates";
|
|
20
|
+
export {
|
|
21
|
+
usePerformance,
|
|
22
|
+
measureAsync,
|
|
23
|
+
measureSync,
|
|
24
|
+
runAfterInteractions,
|
|
25
|
+
} from "./usePerformance";
|
|
26
|
+
export { useMFA, generateTOTP } from "./useMFA";
|
|
27
|
+
export type { MFAMethod, MFASetupData } from "./useMFA";
|
package/hooks/useApi.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Data fetching hooks built on TanStack Query
|
|
3
|
+
* Provides type-safe query keys, user hooks, and a CRUD factory for rapid API integration.
|
|
4
|
+
* @module hooks/useApi
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import {
|
|
2
8
|
useQuery,
|
|
3
9
|
useMutation,
|
|
@@ -8,7 +14,19 @@ import {
|
|
|
8
14
|
import { api } from "@/services/api";
|
|
9
15
|
import { toast, handleApiError } from "@/utils/toast";
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Query keys factory for type-safe and organized cache management.
|
|
19
|
+
* Use these keys with React Query to ensure consistent cache invalidation.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* // Invalidate all user queries
|
|
24
|
+
* queryClient.invalidateQueries({ queryKey: queryKeys.users.all });
|
|
25
|
+
*
|
|
26
|
+
* // Invalidate specific user
|
|
27
|
+
* queryClient.invalidateQueries({ queryKey: queryKeys.users.detail('123') });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
12
30
|
export const queryKeys = {
|
|
13
31
|
all: ["api"] as const,
|
|
14
32
|
users: {
|
|
@@ -45,7 +63,23 @@ interface User {
|
|
|
45
63
|
}
|
|
46
64
|
|
|
47
65
|
/**
|
|
48
|
-
* Fetch current user profile
|
|
66
|
+
* Fetch current user profile.
|
|
67
|
+
* Automatically caches the result for 5 minutes.
|
|
68
|
+
*
|
|
69
|
+
* @param options - Additional React Query options
|
|
70
|
+
* @returns Query result with user data, loading state, and error
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* function Profile() {
|
|
75
|
+
* const { data: user, isLoading, error } = useCurrentUser();
|
|
76
|
+
*
|
|
77
|
+
* if (isLoading) return <Skeleton />;
|
|
78
|
+
* if (error) return <ErrorMessage error={error} />;
|
|
79
|
+
*
|
|
80
|
+
* return <Text>Hello, {user.name}</Text>;
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
49
83
|
*/
|
|
50
84
|
export function useCurrentUser(
|
|
51
85
|
options?: Omit<UseQueryOptions<User, Error>, "queryKey" | "queryFn">
|
|
@@ -59,7 +93,20 @@ export function useCurrentUser(
|
|
|
59
93
|
}
|
|
60
94
|
|
|
61
95
|
/**
|
|
62
|
-
* Fetch user by ID
|
|
96
|
+
* Fetch a user by their ID.
|
|
97
|
+
* Query is automatically disabled if no userId is provided.
|
|
98
|
+
*
|
|
99
|
+
* @param userId - The unique identifier of the user to fetch
|
|
100
|
+
* @param options - Additional React Query options
|
|
101
|
+
* @returns Query result with user data, loading state, and error
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```tsx
|
|
105
|
+
* function UserProfile({ userId }: { userId: string }) {
|
|
106
|
+
* const { data: user, isLoading } = useUser(userId);
|
|
107
|
+
* return isLoading ? <Skeleton /> : <Avatar name={user?.name} />;
|
|
108
|
+
* }
|
|
109
|
+
* ```
|
|
63
110
|
*/
|
|
64
111
|
export function useUser(
|
|
65
112
|
userId: string,
|
|
@@ -74,7 +121,27 @@ export function useUser(
|
|
|
74
121
|
}
|
|
75
122
|
|
|
76
123
|
/**
|
|
77
|
-
* Update user profile
|
|
124
|
+
* Update the current user's profile.
|
|
125
|
+
* Automatically updates the cache and shows a success/error toast.
|
|
126
|
+
*
|
|
127
|
+
* @returns Mutation object with mutate function and state
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```tsx
|
|
131
|
+
* function EditProfile() {
|
|
132
|
+
* const updateUser = useUpdateUser();
|
|
133
|
+
*
|
|
134
|
+
* const handleSave = () => {
|
|
135
|
+
* updateUser.mutate({ name: 'New Name' });
|
|
136
|
+
* };
|
|
137
|
+
*
|
|
138
|
+
* return (
|
|
139
|
+
* <Button onPress={handleSave} isLoading={updateUser.isPending}>
|
|
140
|
+
* Save
|
|
141
|
+
* </Button>
|
|
142
|
+
* );
|
|
143
|
+
* }
|
|
144
|
+
* ```
|
|
78
145
|
*/
|
|
79
146
|
export function useUpdateUser() {
|
|
80
147
|
const queryClient = useQueryClient();
|
|
@@ -103,7 +170,37 @@ interface CrudHooksConfig<T, CreateDTO, UpdateDTO> {
|
|
|
103
170
|
}
|
|
104
171
|
|
|
105
172
|
/**
|
|
106
|
-
* Factory to create CRUD hooks for any resource
|
|
173
|
+
* Factory to create CRUD hooks for any resource.
|
|
174
|
+
* Generates useList, useById, useCreate, useUpdate, and useDelete hooks
|
|
175
|
+
* with automatic cache management and toast notifications.
|
|
176
|
+
*
|
|
177
|
+
* @typeParam T - The entity type (must have an 'id' field)
|
|
178
|
+
* @typeParam CreateDTO - The type for create operations (defaults to Omit<T, 'id'>)
|
|
179
|
+
* @typeParam UpdateDTO - The type for update operations (defaults to Partial<T>)
|
|
180
|
+
* @param config - Configuration object with baseKey, endpoint, and entityName
|
|
181
|
+
* @returns Object containing all CRUD hooks
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* interface Product {
|
|
186
|
+
* id: string;
|
|
187
|
+
* name: string;
|
|
188
|
+
* price: number;
|
|
189
|
+
* }
|
|
190
|
+
*
|
|
191
|
+
* export const productsApi = createCrudHooks<Product>({
|
|
192
|
+
* baseKey: ['products'],
|
|
193
|
+
* endpoint: '/products',
|
|
194
|
+
* entityName: 'Product',
|
|
195
|
+
* });
|
|
196
|
+
*
|
|
197
|
+
* // Usage in components:
|
|
198
|
+
* const { data: products } = productsApi.useList();
|
|
199
|
+
* const { data: product } = productsApi.useById('123');
|
|
200
|
+
* const createProduct = productsApi.useCreate();
|
|
201
|
+
* const updateProduct = productsApi.useUpdate();
|
|
202
|
+
* const deleteProduct = productsApi.useDelete();
|
|
203
|
+
* ```
|
|
107
204
|
*/
|
|
108
205
|
export function createCrudHooks<
|
|
109
206
|
T extends { id: string },
|