@umituz/react-native-design-system 4.23.67 → 4.23.69

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 (68) hide show
  1. package/package.json +1 -1
  2. package/src/atoms/EmptyState.tsx +2 -2
  3. package/src/atoms/icon/AtomicIcon.tsx +41 -112
  4. package/src/atoms/icon/components/iconRenderer.tsx +118 -0
  5. package/src/atoms/icon/utils/iconUtils.ts +94 -0
  6. package/src/exception/infrastructure/services/ExceptionService.ts +29 -17
  7. package/src/exception/presentation/components/ExceptionEmptyState.tsx +1 -1
  8. package/src/exception/presentation/components/ExceptionErrorState.tsx +1 -1
  9. package/src/image/infrastructure/services/ImageBatchService.ts +1 -7
  10. package/src/image/infrastructure/types/BatchTypes.ts +11 -0
  11. package/src/image/infrastructure/utils/BatchProcessor.ts +1 -1
  12. package/src/image/infrastructure/utils/ImageErrorHandler.ts +1 -0
  13. package/src/infinite-scroll/presentation/components/infinite-scroll-list.tsx +2 -2
  14. package/src/layouts/ScreenHeader/ScreenHeader.tsx +3 -3
  15. package/src/media/presentation/hooks/useCardMediaGeneration.ts +4 -4
  16. package/src/media/presentation/hooks/useCardMediaUpload.ts +4 -4
  17. package/src/media/presentation/hooks/useCardMediaValidation.ts +4 -4
  18. package/src/media/presentation/hooks/useCardMultimediaFlashcard.ts +5 -5
  19. package/src/media/presentation/hooks/useMediaGeneration.ts +4 -4
  20. package/src/media/presentation/hooks/useMediaUpload.ts +4 -4
  21. package/src/media/presentation/hooks/useMediaValidation.ts +4 -4
  22. package/src/media/presentation/hooks/useMultimediaFlashcard.ts +5 -5
  23. package/src/molecules/BaseModal.tsx +1 -1
  24. package/src/molecules/ConfirmationModalContent.tsx +2 -2
  25. package/src/molecules/ConfirmationModalMain.tsx +2 -2
  26. package/src/molecules/alerts/AlertToast.tsx +163 -192
  27. package/src/molecules/alerts/utils/alertToastHelpers.ts +70 -0
  28. package/src/molecules/bottom-sheet/components/filter/FilterBottomSheet.tsx +2 -2
  29. package/src/molecules/calendar/presentation/components/AtomicCalendar.tsx +1 -1
  30. package/src/molecules/calendar/presentation/components/CalendarDayCell.tsx +2 -1
  31. package/src/molecules/calendar/presentation/components/CalendarWeekdayHeader.tsx +1 -1
  32. package/src/molecules/confirmation-modal/useConfirmationModal.ts +6 -6
  33. package/src/molecules/countdown/components/Countdown.tsx +2 -2
  34. package/src/molecules/splash/components/SplashScreen.tsx +9 -23
  35. package/src/molecules/swipe-actions/domain/entities/SwipeAction.ts +1 -1
  36. package/src/molecules/swipe-actions/presentation/components/SwipeActionButton.tsx +2 -2
  37. package/src/organisms/FormContainer.tsx +2 -2
  38. package/src/responsive/validation.ts +1 -0
  39. package/src/services/api/ApiClient.ts +242 -0
  40. package/src/services/api/index.ts +9 -0
  41. package/src/services/api/types/ApiTypes.ts +50 -0
  42. package/src/services/api/utils/requestBuilder.ts +92 -0
  43. package/src/services/api/utils/responseHandler.ts +130 -0
  44. package/src/storage/cache/domain/ErrorHandler.ts +1 -0
  45. package/src/storage/domain/errors/StorageError.ts +6 -0
  46. package/src/storage/infrastructure/repositories/AsyncStorageRepository.ts +31 -16
  47. package/src/tanstack/domain/repositories/BaseRepository.ts +16 -72
  48. package/src/tanstack/domain/repositories/IBaseRepository.ts +34 -0
  49. package/src/tanstack/domain/repositories/helpers/repositoryHelpers.ts +58 -0
  50. package/src/tanstack/domain/repositories/mixins/repositoryInvalidationMethods.ts +101 -0
  51. package/src/tanstack/domain/repositories/mixins/repositoryQueryMethods.ts +102 -0
  52. package/src/tanstack/infrastructure/providers/TanstackProvider.tsx +3 -3
  53. package/src/tanstack/presentation/hooks/types/prefetchTypes.ts +33 -0
  54. package/src/tanstack/presentation/hooks/usePrefetch.ts +8 -28
  55. package/src/tanstack/presentation/hooks/utils/prefetchLogger.ts +27 -0
  56. package/src/theme/index.ts +0 -3
  57. package/src/theme/infrastructure/providers/DesignSystemProvider.tsx +15 -4
  58. package/src/utils/colorMapper.ts +193 -0
  59. package/src/utils/formatHelper.ts +16 -0
  60. package/src/utils/formatters/dateFormatter.ts +64 -0
  61. package/src/utils/formatters/numberFormatter.ts +130 -0
  62. package/src/utils/formatters/stringFormatter.ts +190 -0
  63. package/src/utils/index.ts +15 -0
  64. package/src/utils/styleComposer.ts +94 -0
  65. package/src/utils/validationHelper.ts +16 -0
  66. package/src/utils/validators/dataValidators.ts +111 -0
  67. package/src/utils/validators/numericValidators.ts +106 -0
  68. package/src/utils/validators/stringValidators.ts +85 -0
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Response Handler Utility
3
+ * Handles API responses and errors
4
+ */
5
+
6
+ import type { ApiResponse, ApiError } from '../types/ApiTypes';
7
+
8
+ /**
9
+ * Parses fetch response to ApiResponse
10
+ *
11
+ * @param response - Fetch response
12
+ * @returns Parsed API response
13
+ */
14
+ export async function parseResponse<T>(response: Response): Promise<ApiResponse<T>> {
15
+ const data = await parseResponseBody<T>(response);
16
+
17
+ return {
18
+ data,
19
+ status: response.status,
20
+ statusText: response.statusText,
21
+ headers: Object.fromEntries(response.headers.entries()),
22
+ };
23
+ }
24
+
25
+ /**
26
+ * Parses response body based on content type
27
+ *
28
+ * @param response - Fetch response
29
+ * @returns Parsed body data
30
+ */
31
+ async function parseResponseBody<T>(response: Response): Promise<T> {
32
+ const contentType = response.headers.get('Content-Type');
33
+
34
+ if (contentType?.includes('application/json')) {
35
+ const data = await response.json();
36
+ return data as T;
37
+ }
38
+
39
+ if (contentType?.includes('text/')) {
40
+ const text = await response.text();
41
+ return text as unknown as T;
42
+ }
43
+
44
+ const blob = await response.blob();
45
+ return blob as unknown as T;
46
+ }
47
+
48
+ /**
49
+ * Handles HTTP error and converts to ApiError
50
+ *
51
+ * @param response - Fetch response
52
+ * @returns ApiError object
53
+ */
54
+ export async function handleHttpError(response: Response): Promise<ApiError> {
55
+ let details: any;
56
+
57
+ try {
58
+ details = await response.json();
59
+ } catch {
60
+ details = await response.text();
61
+ }
62
+
63
+ return {
64
+ message: details?.message || response.statusText || 'Request failed',
65
+ status: response.status,
66
+ code: details?.code,
67
+ details,
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Handles network error
73
+ *
74
+ * @param error - Error object
75
+ * @returns ApiError object
76
+ */
77
+ export function handleNetworkError(error: unknown): ApiError {
78
+ if (error instanceof Error) {
79
+ return {
80
+ message: error.message || 'Network error',
81
+ details: error,
82
+ };
83
+ }
84
+
85
+ return {
86
+ message: 'Unknown network error',
87
+ details: error,
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Checks if response is successful
93
+ *
94
+ * @param response - Fetch response
95
+ * @returns True if response is OK
96
+ */
97
+ export function isSuccessfulResponse(response: Response): boolean {
98
+ return response.ok && response.status >= 200 && response.status < 300;
99
+ }
100
+
101
+ /**
102
+ * Creates timeout promise
103
+ *
104
+ * @param ms - Timeout in milliseconds
105
+ * @returns Promise that rejects after timeout
106
+ */
107
+ export function createTimeoutPromise(ms: number): Promise<never> {
108
+ return new Promise((_, reject) => {
109
+ setTimeout(() => reject(new Error(`Request timeout after ${ms}ms`)), ms);
110
+ });
111
+ }
112
+
113
+ /**
114
+ * Wraps fetch with timeout
115
+ *
116
+ * @param url - Request URL
117
+ * @param options - Fetch options
118
+ * @param timeout - Timeout in milliseconds
119
+ * @returns Fetch result with timeout
120
+ */
121
+ export async function fetchWithTimeout(
122
+ url: string,
123
+ options: RequestInit,
124
+ timeout: number
125
+ ): Promise<Response> {
126
+ return Promise.race([
127
+ fetch(url, options),
128
+ createTimeoutPromise(timeout),
129
+ ]) as Promise<Response>;
130
+ }
@@ -6,6 +6,7 @@ export class CacheError extends Error {
6
6
  constructor(message: string, public readonly code: string) {
7
7
  super(message);
8
8
  this.name = 'CacheError';
9
+ Object.setPrototypeOf(this, CacheError.prototype);
9
10
  }
10
11
  }
11
12
 
@@ -12,6 +12,7 @@ export class StorageError extends Error {
12
12
  constructor(message: string, public readonly key?: string) {
13
13
  super(message);
14
14
  this.name = 'StorageError';
15
+ Object.setPrototypeOf(this, StorageError.prototype);
15
16
  }
16
17
  }
17
18
 
@@ -25,6 +26,7 @@ export class StorageReadError extends StorageError {
25
26
  super(`Failed to read from storage: ${key}`, key);
26
27
  this.name = 'StorageReadError';
27
28
  this.cause = cause;
29
+ Object.setPrototypeOf(this, StorageReadError.prototype);
28
30
  }
29
31
  }
30
32
 
@@ -38,6 +40,7 @@ export class StorageWriteError extends StorageError {
38
40
  super(`Failed to write to storage: ${key}`, key);
39
41
  this.name = 'StorageWriteError';
40
42
  this.cause = cause;
43
+ Object.setPrototypeOf(this, StorageWriteError.prototype);
41
44
  }
42
45
  }
43
46
 
@@ -51,6 +54,7 @@ export class StorageDeleteError extends StorageError {
51
54
  super(`Failed to delete from storage: ${key}`, key);
52
55
  this.name = 'StorageDeleteError';
53
56
  this.cause = cause;
57
+ Object.setPrototypeOf(this, StorageDeleteError.prototype);
54
58
  }
55
59
  }
56
60
 
@@ -64,6 +68,7 @@ export class StorageSerializationError extends StorageError {
64
68
  super(`Failed to serialize data for key: ${key}`, key);
65
69
  this.name = 'StorageSerializationError';
66
70
  this.cause = cause;
71
+ Object.setPrototypeOf(this, StorageSerializationError.prototype);
67
72
  }
68
73
  }
69
74
 
@@ -77,5 +82,6 @@ export class StorageDeserializationError extends StorageError {
77
82
  super(`Failed to deserialize data for key: ${key}`, key);
78
83
  this.name = 'StorageDeserializationError';
79
84
  this.cause = cause;
85
+ Object.setPrototypeOf(this, StorageDeserializationError.prototype);
80
86
  }
81
87
  }
@@ -16,63 +16,76 @@ import { BatchStorageOperations } from './BatchStorageOperations';
16
16
  * Uses composition to follow Single Responsibility Principle
17
17
  */
18
18
  export class AsyncStorageRepository implements IStorageRepository {
19
- private baseOps: BaseStorageOperations;
20
- private stringOps: StringStorageOperations;
21
- private batchOps: BatchStorageOperations;
19
+ private baseOps: BaseStorageOperations | null = null;
20
+ private stringOps: StringStorageOperations | null = null;
21
+ private batchOps: BatchStorageOperations | null = null;
22
22
 
23
23
  constructor() {
24
- this.baseOps = new BaseStorageOperations();
25
- this.stringOps = new StringStorageOperations();
26
- this.batchOps = new BatchStorageOperations();
24
+ // Lazy initialization - defer object creation
25
+ }
26
+
27
+ private ensureInitialized() {
28
+ if (!this.baseOps) {
29
+ this.baseOps = new BaseStorageOperations();
30
+ this.stringOps = new StringStorageOperations();
31
+ this.batchOps = new BatchStorageOperations();
32
+ }
27
33
  }
28
34
 
29
35
  /**
30
36
  * Get item from AsyncStorage with type safety
31
37
  */
32
38
  async getItem<T>(key: string, defaultValue: T): Promise<StorageResult<T>> {
33
- return this.baseOps.getItem(key, defaultValue);
39
+ this.ensureInitialized();
40
+ return this.baseOps!.getItem(key, defaultValue);
34
41
  }
35
42
 
36
43
  /**
37
44
  * Set item in AsyncStorage with automatic JSON serialization
38
45
  */
39
46
  async setItem<T>(key: string, value: T): Promise<StorageResult<T>> {
40
- return this.baseOps.setItem(key, value);
47
+ this.ensureInitialized();
48
+ return this.baseOps!.setItem(key, value);
41
49
  }
42
50
 
43
51
  /**
44
52
  * Get string value (no JSON parsing)
45
53
  */
46
54
  async getString(key: string, defaultValue: string): Promise<StorageResult<string>> {
47
- return this.stringOps.getString(key, defaultValue);
55
+ this.ensureInitialized();
56
+ return this.stringOps!.getString(key, defaultValue);
48
57
  }
49
58
 
50
59
  /**
51
60
  * Set string value (no JSON serialization)
52
61
  */
53
62
  async setString(key: string, value: string): Promise<StorageResult<string>> {
54
- return this.stringOps.setString(key, value);
63
+ this.ensureInitialized();
64
+ return this.stringOps!.setString(key, value);
55
65
  }
56
66
 
57
67
  /**
58
68
  * Remove item from AsyncStorage
59
69
  */
60
70
  async removeItem(key: string): Promise<StorageResult<void>> {
61
- return this.baseOps.removeItem(key);
71
+ this.ensureInitialized();
72
+ return this.baseOps!.removeItem(key);
62
73
  }
63
74
 
64
75
  /**
65
76
  * Check if key exists in storage
66
77
  */
67
78
  async hasItem(key: string): Promise<boolean> {
68
- return this.baseOps.hasItem(key);
79
+ this.ensureInitialized();
80
+ return this.baseOps!.hasItem(key);
69
81
  }
70
82
 
71
83
  /**
72
84
  * Clear all AsyncStorage data
73
85
  */
74
86
  async clearAll(): Promise<StorageResult<void>> {
75
- return this.baseOps.clearAll();
87
+ this.ensureInitialized();
88
+ return this.baseOps!.clearAll();
76
89
  }
77
90
 
78
91
  /**
@@ -81,18 +94,20 @@ export class AsyncStorageRepository implements IStorageRepository {
81
94
  async getMultiple(
82
95
  keys: string[]
83
96
  ): Promise<StorageResult<Record<string, string | null>>> {
84
- return this.batchOps.getMultiple(keys);
97
+ this.ensureInitialized();
98
+ return this.batchOps!.getMultiple(keys);
85
99
  }
86
100
 
87
101
  /**
88
102
  * Get all keys from storage
89
103
  */
90
104
  async getAllKeys(): Promise<StorageResult<string[]>> {
91
- return this.batchOps.getAllKeys();
105
+ this.ensureInitialized();
106
+ return this.batchOps!.getAllKeys();
92
107
  }
93
108
  }
94
109
 
95
110
  /**
96
- * Singleton instance
111
+ * Singleton instance - lazy initialization
97
112
  */
98
113
  export const storageRepository = new AsyncStorageRepository();
@@ -35,9 +35,8 @@
35
35
  * ```
36
36
  */
37
37
 
38
- import type { QueryClient, QueryKey } from '@tanstack/react-query';
38
+ import type { QueryClient } from '@tanstack/react-query';
39
39
  import { getGlobalQueryClient } from '../config/QueryClientAccessor';
40
- import { CacheStrategies } from '../../infrastructure/config/QueryClientConfig';
41
40
  import { createQueryKeyFactory } from '../utils/QueryKeyFactory';
42
41
  import type {
43
42
  CreateParams,
@@ -45,6 +44,9 @@ import type {
45
44
  ListParams,
46
45
  RepositoryOptions,
47
46
  } from './RepositoryTypes';
47
+ import { mergeRepositoryOptions, getCacheOptions } from './helpers/repositoryHelpers';
48
+ import * as queryMethods from './mixins/repositoryQueryMethods';
49
+ import * as invalidationMethods from './mixins/repositoryInvalidationMethods';
48
50
 
49
51
  /**
50
52
  * Base repository for CRUD operations
@@ -68,11 +70,7 @@ export abstract class BaseRepository<
68
70
 
69
71
  constructor(resource: string, options: RepositoryOptions = {}) {
70
72
  this.resource = resource;
71
- this.options = {
72
- cacheStrategy: options.cacheStrategy ?? CacheStrategies.PUBLIC_DATA,
73
- ...options,
74
- };
75
-
73
+ this.options = mergeRepositoryOptions(options);
76
74
  this.keys = createQueryKeyFactory(this.resource);
77
75
  }
78
76
 
@@ -87,10 +85,7 @@ export abstract class BaseRepository<
87
85
  * Get cache options for queries
88
86
  */
89
87
  protected getCacheOptions(): { staleTime: number; gcTime: number } {
90
- return {
91
- staleTime: this.options.staleTime ?? (this.options.cacheStrategy?.staleTime ?? CacheStrategies.PUBLIC_DATA.staleTime),
92
- gcTime: this.options.gcTime ?? (this.options.cacheStrategy?.gcTime ?? CacheStrategies.PUBLIC_DATA.gcTime),
93
- };
88
+ return getCacheOptions(this.options);
94
89
  }
95
90
 
96
91
  /**
@@ -122,120 +117,69 @@ export abstract class BaseRepository<
122
117
  * Query all items with caching
123
118
  */
124
119
  async queryAll(params?: ListParams): Promise<TData[]> {
125
- const client = this.getClient();
126
- const queryKey = params ? this.keys.list(params as Record<string, unknown>) : this.keys.lists();
127
- const cacheOptions = this.getCacheOptions();
128
-
129
- return client.fetchQuery({
130
- queryKey: queryKey as QueryKey,
131
- queryFn: () => this.fetchAll(params),
132
- ...cacheOptions,
133
- });
120
+ return queryMethods.queryAll(this, params);
134
121
  }
135
122
 
136
123
  /**
137
124
  * Query item by ID with caching
138
125
  */
139
126
  async queryById(id: string | number): Promise<TData | undefined> {
140
- const client = this.getClient();
141
- const queryKey = this.keys.detail(id);
142
- const cacheOptions = this.getCacheOptions();
143
-
144
- try {
145
- return client.fetchQuery({
146
- queryKey: queryKey as QueryKey,
147
- queryFn: () => this.fetchById(id),
148
- ...cacheOptions,
149
- });
150
- } catch {
151
- return undefined;
152
- }
127
+ return queryMethods.queryById(this, id);
153
128
  }
154
129
 
155
130
  /**
156
131
  * Prefetch all items
157
132
  */
158
133
  async prefetchAll(params?: ListParams): Promise<void> {
159
- const client = this.getClient();
160
- const queryKey = params ? this.keys.list(params as Record<string, unknown>) : this.keys.lists();
161
- const cacheOptions = this.getCacheOptions();
162
-
163
- await client.prefetchQuery({
164
- queryKey: queryKey as QueryKey,
165
- queryFn: () => this.fetchAll(params),
166
- ...cacheOptions,
167
- });
134
+ return queryMethods.prefetchAll(this, params);
168
135
  }
169
136
 
170
137
  /**
171
138
  * Prefetch item by ID
172
139
  */
173
140
  async prefetchById(id: string | number): Promise<void> {
174
- const client = this.getClient();
175
- const queryKey = this.keys.detail(id);
176
- const cacheOptions = this.getCacheOptions();
177
-
178
- await client.prefetchQuery({
179
- queryKey: queryKey as QueryKey,
180
- queryFn: () => this.fetchById(id),
181
- ...cacheOptions,
182
- });
141
+ return queryMethods.prefetchById(this, id);
183
142
  }
184
143
 
185
144
  /**
186
145
  * Invalidate all queries for this resource
187
146
  */
188
147
  invalidateAll(): Promise<void> {
189
- const client = this.getClient();
190
- return client.invalidateQueries({
191
- predicate: (query: { queryKey: readonly unknown[] }) => {
192
- const key = query.queryKey[0] as string;
193
- return key === this.resource;
194
- },
195
- });
148
+ return invalidationMethods.invalidateAll(this);
196
149
  }
197
150
 
198
151
  /**
199
152
  * Invalidate list queries
200
153
  */
201
154
  invalidateLists(): Promise<void> {
202
- const client = this.getClient();
203
- return client.invalidateQueries({
204
- queryKey: this.keys.lists(),
205
- });
155
+ return invalidationMethods.invalidateLists(this);
206
156
  }
207
157
 
208
158
  /**
209
159
  * Invalidate detail query
210
160
  */
211
161
  invalidateDetail(id: string | number): Promise<void> {
212
- const client = this.getClient();
213
- return client.invalidateQueries({
214
- queryKey: this.keys.detail(id),
215
- });
162
+ return invalidationMethods.invalidateDetail(this, id);
216
163
  }
217
164
 
218
165
  /**
219
166
  * Set query data (optimistic update)
220
167
  */
221
168
  setData(id: string | number, data: TData): void {
222
- const client = this.getClient();
223
- client.setQueryData(this.keys.detail(id), data);
169
+ invalidationMethods.setData(this, id, data);
224
170
  }
225
171
 
226
172
  /**
227
173
  * Get query data from cache
228
174
  */
229
175
  getData(id: string | number): TData | undefined {
230
- const client = this.getClient();
231
- return client.getQueryData<TData>(this.keys.detail(id));
176
+ return invalidationMethods.getData(this, id);
232
177
  }
233
178
 
234
179
  /**
235
180
  * Remove query data from cache
236
181
  */
237
182
  clearData(id: string | number): void {
238
- const client = this.getClient();
239
- client.setQueryData(this.keys.detail(id), undefined);
183
+ invalidationMethods.clearData(this, id);
240
184
  }
241
185
  }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Base Repository Interface
3
+ * Defines the contract for repository implementations
4
+ */
5
+
6
+ import type { QueryClient } from '@tanstack/react-query';
7
+ import type { QueryKeyFactory } from '../utils/QueryKeyFactory';
8
+ import type {
9
+ CreateParams,
10
+ UpdateParams,
11
+ ListParams,
12
+ RepositoryOptions,
13
+ } from './RepositoryTypes';
14
+
15
+ export interface IBaseRepository<TData, TCreateVariables, TUpdateVariables> {
16
+ /** Query client instance */
17
+ getClient(): QueryClient;
18
+
19
+ /** Resource name */
20
+ readonly resource: string;
21
+
22
+ /** Query key factory */
23
+ readonly keys: QueryKeyFactory;
24
+
25
+ /** Cache options */
26
+ getCacheOptions(): RepositoryOptions;
27
+
28
+ /** Abstract methods to be implemented by subclasses */
29
+ fetchAll(params?: ListParams): Promise<TData[]>;
30
+ fetchById(id: string | number): Promise<TData>;
31
+ create(data: CreateParams<TCreateVariables>): Promise<TData>;
32
+ update(id: string | number, data: UpdateParams<TUpdateVariables>): Promise<TData>;
33
+ remove(id: string | number): Promise<void>;
34
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Repository Helper Functions
3
+ * Common helper functions for repository operations
4
+ */
5
+
6
+ import type { RepositoryOptions } from '../RepositoryTypes';
7
+ import { CacheStrategies } from '../../../infrastructure/config/QueryClientConfig';
8
+
9
+ /**
10
+ * Gets cache options for repository queries
11
+ *
12
+ * @param options - Repository options
13
+ * @returns Cache options with staleTime and gcTime
14
+ */
15
+ export function getCacheOptions(
16
+ options: RepositoryOptions
17
+ ): { staleTime: number; gcTime: number } {
18
+ return {
19
+ staleTime:
20
+ options.staleTime ??
21
+ options.cacheStrategy?.staleTime ??
22
+ CacheStrategies.PUBLIC_DATA.staleTime,
23
+ gcTime:
24
+ options.gcTime ??
25
+ options.cacheStrategy?.gcTime ??
26
+ CacheStrategies.PUBLIC_DATA.gcTime,
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Merges repository options with defaults
32
+ *
33
+ * @param options - User provided options
34
+ * @returns Merged options
35
+ */
36
+ export function mergeRepositoryOptions(
37
+ options: RepositoryOptions = {}
38
+ ): Required<Pick<RepositoryOptions, 'cacheStrategy'>> & RepositoryOptions {
39
+ return {
40
+ cacheStrategy: options.cacheStrategy ?? CacheStrategies.PUBLIC_DATA,
41
+ ...options,
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Checks if a query key matches a resource
47
+ *
48
+ * @param queryKey - Query key to check
49
+ * @param resource - Resource name to match
50
+ * @returns True if query key matches resource
51
+ */
52
+ export function matchesResource(
53
+ queryKey: readonly unknown[],
54
+ resource: string
55
+ ): boolean {
56
+ const key = queryKey[0] as string;
57
+ return key === resource;
58
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Repository Invalidation Methods
3
+ * Cache invalidation methods for repository operations
4
+ */
5
+
6
+ import type { QueryClient } from '@tanstack/react-query';
7
+ import type { IBaseRepository } from '../IBaseRepository';
8
+ import { matchesResource } from '../helpers/repositoryHelpers';
9
+
10
+ /**
11
+ * Invalidate all queries for this resource
12
+ *
13
+ * @param repository - Repository instance
14
+ */
15
+ export function invalidateAll<TData>(
16
+ repository: IBaseRepository<TData, unknown, unknown>
17
+ ): Promise<void> {
18
+ const client = (repository as any).getClient() as QueryClient;
19
+ const resource = (repository as any).resource;
20
+
21
+ return client.invalidateQueries({
22
+ predicate: (query: { queryKey: readonly unknown[] }) => {
23
+ return matchesResource(query.queryKey, resource);
24
+ },
25
+ });
26
+ }
27
+
28
+ /**
29
+ * Invalidate list queries
30
+ *
31
+ * @param repository - Repository instance
32
+ */
33
+ export function invalidateLists<TData>(
34
+ repository: IBaseRepository<TData, unknown, unknown>
35
+ ): Promise<void> {
36
+ const client = (repository as any).getClient() as QueryClient;
37
+ return client.invalidateQueries({
38
+ queryKey: repository.keys.lists(),
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Invalidate detail query
44
+ *
45
+ * @param repository - Repository instance
46
+ * @param id - Item ID
47
+ */
48
+ export function invalidateDetail<TData>(
49
+ repository: IBaseRepository<TData, unknown, unknown>,
50
+ id: string | number
51
+ ): Promise<void> {
52
+ const client = (repository as any).getClient() as QueryClient;
53
+ return client.invalidateQueries({
54
+ queryKey: repository.keys.detail(id),
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Set query data (optimistic update)
60
+ *
61
+ * @param repository - Repository instance
62
+ * @param id - Item ID
63
+ * @param data - Data to set
64
+ */
65
+ export function setData<TData>(
66
+ repository: BaseRepository<TData, unknown, unknown>,
67
+ id: string | number,
68
+ data: TData
69
+ ): void {
70
+ const client = (repository as any).getClient() as QueryClient;
71
+ client.setQueryData(repository.keys.detail(id), data);
72
+ }
73
+
74
+ /**
75
+ * Get query data from cache
76
+ *
77
+ * @param repository - Repository instance
78
+ * @param id - Item ID
79
+ * @returns Cached data or undefined
80
+ */
81
+ export function getData<TData>(
82
+ repository: BaseRepository<TData, unknown, unknown>,
83
+ id: string | number
84
+ ): TData | undefined {
85
+ const client = (repository as any).getClient() as QueryClient;
86
+ return client.getQueryData<TData>(repository.keys.detail(id));
87
+ }
88
+
89
+ /**
90
+ * Remove query data from cache
91
+ *
92
+ * @param repository - Repository instance
93
+ * @param id - Item ID
94
+ */
95
+ export function clearData<TData>(
96
+ repository: BaseRepository<TData, unknown, unknown>,
97
+ id: string | number
98
+ ): void {
99
+ const client = (repository as any).getClient() as QueryClient;
100
+ client.setQueryData(repository.keys.detail(id), undefined);
101
+ }