api-core-lib 3.3.2 → 3.3.3
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/dist/index.d.mts +62 -24
- package/dist/index.d.ts +62 -24
- package/dist/index.js +37 -14
- package/dist/index.mjs +37 -14
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
@@ -75,19 +75,6 @@ interface PaginateQueryOptions {
|
|
75
75
|
}[];
|
76
76
|
filter?: Record<string, any>;
|
77
77
|
}
|
78
|
-
/**
|
79
|
-
* واجهة لتهيئة الهوك `useApi`.
|
80
|
-
* @template T نوع البيانات التي يتعامل معها الهوك.
|
81
|
-
*/
|
82
|
-
interface UseApiConfig<T> {
|
83
|
-
endpoint: string;
|
84
|
-
initialData?: T | T[];
|
85
|
-
initialQuery?: PaginateQueryOptions;
|
86
|
-
enabled?: boolean;
|
87
|
-
refetchAfterChange?: boolean;
|
88
|
-
onSuccess?: (message: string, data?: T) => void;
|
89
|
-
onError?: (message: string, error?: ApiError) => void;
|
90
|
-
}
|
91
78
|
/**
|
92
79
|
* واجهة لتخصيص عملية تجديد التوكن بشكل كامل.
|
93
80
|
*/
|
@@ -174,6 +161,49 @@ interface StandardResponse<T> {
|
|
174
161
|
message?: string;
|
175
162
|
validationErrors?: ValidationError[];
|
176
163
|
}
|
164
|
+
/**
|
165
|
+
* NEW: واجهة استعلام مرنة تسمح بالبارامترات القياسية (للفلترة والترقيم)
|
166
|
+
* بالإضافة إلى أي بارامترات مخصصة أخرى عبر الـ index signature.
|
167
|
+
* @example
|
168
|
+
* { page: 1, limit: 10, search: 'term', status: 'published', authorId: 123 }
|
169
|
+
*/
|
170
|
+
interface QueryOptions {
|
171
|
+
page?: number;
|
172
|
+
limit?: number;
|
173
|
+
search?: string;
|
174
|
+
sortBy?: {
|
175
|
+
key: string;
|
176
|
+
direction: 'asc' | 'desc';
|
177
|
+
}[];
|
178
|
+
filter?: Record<string, any>;
|
179
|
+
[key: string]: any;
|
180
|
+
}
|
181
|
+
/**
|
182
|
+
* NEW: واجهة لتمرير خيارات إضافية لدوال الأكشن (create, update, remove).
|
183
|
+
*/
|
184
|
+
interface ActionOptions {
|
185
|
+
/**
|
186
|
+
* يسمح لك بتجاوز الـ endpoint الافتراضي المحدد في الهوك.
|
187
|
+
* مفيد لإرسال طلبات لنقاط نهاية متخصصة.
|
188
|
+
* @example
|
189
|
+
* // لتحديث عنصر وتغيير حالته عبر مسار مختلف
|
190
|
+
* update('123', { status: 'active' }, { endpoint: '/items/123/activate' })
|
191
|
+
*/
|
192
|
+
endpoint?: string;
|
193
|
+
}
|
194
|
+
/**
|
195
|
+
* واجهة لتهيئة الهوك `useApi`.
|
196
|
+
* @template T نوع البيانات التي يتعامل معها الهوك.
|
197
|
+
*/
|
198
|
+
interface UseApiConfig<T> {
|
199
|
+
endpoint: string;
|
200
|
+
initialData?: T | T[];
|
201
|
+
initialQuery?: QueryOptions;
|
202
|
+
enabled?: boolean;
|
203
|
+
refetchAfterChange?: boolean;
|
204
|
+
onSuccess?: (message: string, data?: T) => void;
|
205
|
+
onError?: (message: string, error?: ApiError) => void;
|
206
|
+
}
|
177
207
|
|
178
208
|
/**
|
179
209
|
* @file src/core/client.ts
|
@@ -185,12 +215,13 @@ interface StandardResponse<T> {
|
|
185
215
|
|
186
216
|
declare function createApiClient(config: ApiClientConfig): AxiosInstance;
|
187
217
|
|
218
|
+
type CrudRequestConfig = RequestConfig & ActionOptions;
|
188
219
|
declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: string): {
|
189
220
|
get: (id?: string, config?: RequestConfig) => Promise<StandardResponse<T | T[]>>;
|
190
221
|
getWithQuery: (query: string, config?: RequestConfig) => Promise<StandardResponse<T[]>>;
|
191
|
-
post: (data: Partial<T>, config?:
|
192
|
-
patch: (id: string, data: Partial<T>, config?:
|
193
|
-
remove: (id: string, config?:
|
222
|
+
post: (data: Partial<T>, config?: CrudRequestConfig) => Promise<StandardResponse<T>>;
|
223
|
+
patch: (id: string, data: Partial<T>, config?: CrudRequestConfig) => Promise<StandardResponse<T>>;
|
224
|
+
remove: (id: string, config?: CrudRequestConfig) => Promise<StandardResponse<any>>;
|
194
225
|
};
|
195
226
|
|
196
227
|
/**
|
@@ -201,7 +232,13 @@ declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: st
|
|
201
232
|
* بالإضافة إلى دوال التحقق من الأنواع (type guards).
|
202
233
|
*/
|
203
234
|
|
204
|
-
|
235
|
+
/**
|
236
|
+
* يبني سلسلة استعلام (query string) من كائن خيارات مرن.
|
237
|
+
* يتعامل مع البارامترات القياسية والمخصصة.
|
238
|
+
* @param query - كائن من نوع QueryOptions.
|
239
|
+
* @returns سلسلة استعلام جاهزة للإضافة للرابط.
|
240
|
+
*/
|
241
|
+
declare function buildPaginateQuery(query: QueryOptions): string;
|
205
242
|
|
206
243
|
/**
|
207
244
|
* Defines a single custom API action.
|
@@ -263,14 +300,14 @@ declare function useApi<T extends {
|
|
263
300
|
state: StandardResponse<T | T[]>;
|
264
301
|
setState: react.Dispatch<react.SetStateAction<StandardResponse<T | T[]>>>;
|
265
302
|
actions: {
|
266
|
-
fetch: () => Promise<void>;
|
267
|
-
create: (newItem: Partial<T
|
268
|
-
update: (id: string, updatedItem: Partial<T
|
269
|
-
remove: (id: string) => Promise<StandardResponse<any>>;
|
303
|
+
fetch: (options?: QueryOptions) => Promise<void>;
|
304
|
+
create: (newItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
|
305
|
+
update: (id: string, updatedItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
|
306
|
+
remove: (id: string, options?: ActionOptions) => Promise<StandardResponse<any>>;
|
270
307
|
};
|
271
308
|
query: {
|
272
|
-
options:
|
273
|
-
setOptions: react.Dispatch<react.SetStateAction<
|
309
|
+
options: QueryOptions;
|
310
|
+
setOptions: react.Dispatch<react.SetStateAction<QueryOptions>>;
|
274
311
|
setPage: (page: number) => void;
|
275
312
|
setLimit: (limit: number) => void;
|
276
313
|
setSearchTerm: (search: string) => void;
|
@@ -279,8 +316,9 @@ declare function useApi<T extends {
|
|
279
316
|
direction: "asc" | "desc";
|
280
317
|
}[]) => void;
|
281
318
|
setFilters: (filter: Record<string, any>) => void;
|
319
|
+
setQueryParam: (key: string, value: any) => void;
|
282
320
|
reset: () => void;
|
283
321
|
};
|
284
322
|
};
|
285
323
|
|
286
|
-
export { type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type RefreshTokenConfig, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiActions, createApiClient, createApiServices, processResponse, useApi };
|
324
|
+
export { type ActionOptions, type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type QueryOptions, type RefreshTokenConfig, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiActions, createApiClient, createApiServices, processResponse, useApi };
|
package/dist/index.d.ts
CHANGED
@@ -75,19 +75,6 @@ interface PaginateQueryOptions {
|
|
75
75
|
}[];
|
76
76
|
filter?: Record<string, any>;
|
77
77
|
}
|
78
|
-
/**
|
79
|
-
* واجهة لتهيئة الهوك `useApi`.
|
80
|
-
* @template T نوع البيانات التي يتعامل معها الهوك.
|
81
|
-
*/
|
82
|
-
interface UseApiConfig<T> {
|
83
|
-
endpoint: string;
|
84
|
-
initialData?: T | T[];
|
85
|
-
initialQuery?: PaginateQueryOptions;
|
86
|
-
enabled?: boolean;
|
87
|
-
refetchAfterChange?: boolean;
|
88
|
-
onSuccess?: (message: string, data?: T) => void;
|
89
|
-
onError?: (message: string, error?: ApiError) => void;
|
90
|
-
}
|
91
78
|
/**
|
92
79
|
* واجهة لتخصيص عملية تجديد التوكن بشكل كامل.
|
93
80
|
*/
|
@@ -174,6 +161,49 @@ interface StandardResponse<T> {
|
|
174
161
|
message?: string;
|
175
162
|
validationErrors?: ValidationError[];
|
176
163
|
}
|
164
|
+
/**
|
165
|
+
* NEW: واجهة استعلام مرنة تسمح بالبارامترات القياسية (للفلترة والترقيم)
|
166
|
+
* بالإضافة إلى أي بارامترات مخصصة أخرى عبر الـ index signature.
|
167
|
+
* @example
|
168
|
+
* { page: 1, limit: 10, search: 'term', status: 'published', authorId: 123 }
|
169
|
+
*/
|
170
|
+
interface QueryOptions {
|
171
|
+
page?: number;
|
172
|
+
limit?: number;
|
173
|
+
search?: string;
|
174
|
+
sortBy?: {
|
175
|
+
key: string;
|
176
|
+
direction: 'asc' | 'desc';
|
177
|
+
}[];
|
178
|
+
filter?: Record<string, any>;
|
179
|
+
[key: string]: any;
|
180
|
+
}
|
181
|
+
/**
|
182
|
+
* NEW: واجهة لتمرير خيارات إضافية لدوال الأكشن (create, update, remove).
|
183
|
+
*/
|
184
|
+
interface ActionOptions {
|
185
|
+
/**
|
186
|
+
* يسمح لك بتجاوز الـ endpoint الافتراضي المحدد في الهوك.
|
187
|
+
* مفيد لإرسال طلبات لنقاط نهاية متخصصة.
|
188
|
+
* @example
|
189
|
+
* // لتحديث عنصر وتغيير حالته عبر مسار مختلف
|
190
|
+
* update('123', { status: 'active' }, { endpoint: '/items/123/activate' })
|
191
|
+
*/
|
192
|
+
endpoint?: string;
|
193
|
+
}
|
194
|
+
/**
|
195
|
+
* واجهة لتهيئة الهوك `useApi`.
|
196
|
+
* @template T نوع البيانات التي يتعامل معها الهوك.
|
197
|
+
*/
|
198
|
+
interface UseApiConfig<T> {
|
199
|
+
endpoint: string;
|
200
|
+
initialData?: T | T[];
|
201
|
+
initialQuery?: QueryOptions;
|
202
|
+
enabled?: boolean;
|
203
|
+
refetchAfterChange?: boolean;
|
204
|
+
onSuccess?: (message: string, data?: T) => void;
|
205
|
+
onError?: (message: string, error?: ApiError) => void;
|
206
|
+
}
|
177
207
|
|
178
208
|
/**
|
179
209
|
* @file src/core/client.ts
|
@@ -185,12 +215,13 @@ interface StandardResponse<T> {
|
|
185
215
|
|
186
216
|
declare function createApiClient(config: ApiClientConfig): AxiosInstance;
|
187
217
|
|
218
|
+
type CrudRequestConfig = RequestConfig & ActionOptions;
|
188
219
|
declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: string): {
|
189
220
|
get: (id?: string, config?: RequestConfig) => Promise<StandardResponse<T | T[]>>;
|
190
221
|
getWithQuery: (query: string, config?: RequestConfig) => Promise<StandardResponse<T[]>>;
|
191
|
-
post: (data: Partial<T>, config?:
|
192
|
-
patch: (id: string, data: Partial<T>, config?:
|
193
|
-
remove: (id: string, config?:
|
222
|
+
post: (data: Partial<T>, config?: CrudRequestConfig) => Promise<StandardResponse<T>>;
|
223
|
+
patch: (id: string, data: Partial<T>, config?: CrudRequestConfig) => Promise<StandardResponse<T>>;
|
224
|
+
remove: (id: string, config?: CrudRequestConfig) => Promise<StandardResponse<any>>;
|
194
225
|
};
|
195
226
|
|
196
227
|
/**
|
@@ -201,7 +232,13 @@ declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: st
|
|
201
232
|
* بالإضافة إلى دوال التحقق من الأنواع (type guards).
|
202
233
|
*/
|
203
234
|
|
204
|
-
|
235
|
+
/**
|
236
|
+
* يبني سلسلة استعلام (query string) من كائن خيارات مرن.
|
237
|
+
* يتعامل مع البارامترات القياسية والمخصصة.
|
238
|
+
* @param query - كائن من نوع QueryOptions.
|
239
|
+
* @returns سلسلة استعلام جاهزة للإضافة للرابط.
|
240
|
+
*/
|
241
|
+
declare function buildPaginateQuery(query: QueryOptions): string;
|
205
242
|
|
206
243
|
/**
|
207
244
|
* Defines a single custom API action.
|
@@ -263,14 +300,14 @@ declare function useApi<T extends {
|
|
263
300
|
state: StandardResponse<T | T[]>;
|
264
301
|
setState: react.Dispatch<react.SetStateAction<StandardResponse<T | T[]>>>;
|
265
302
|
actions: {
|
266
|
-
fetch: () => Promise<void>;
|
267
|
-
create: (newItem: Partial<T
|
268
|
-
update: (id: string, updatedItem: Partial<T
|
269
|
-
remove: (id: string) => Promise<StandardResponse<any>>;
|
303
|
+
fetch: (options?: QueryOptions) => Promise<void>;
|
304
|
+
create: (newItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
|
305
|
+
update: (id: string, updatedItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
|
306
|
+
remove: (id: string, options?: ActionOptions) => Promise<StandardResponse<any>>;
|
270
307
|
};
|
271
308
|
query: {
|
272
|
-
options:
|
273
|
-
setOptions: react.Dispatch<react.SetStateAction<
|
309
|
+
options: QueryOptions;
|
310
|
+
setOptions: react.Dispatch<react.SetStateAction<QueryOptions>>;
|
274
311
|
setPage: (page: number) => void;
|
275
312
|
setLimit: (limit: number) => void;
|
276
313
|
setSearchTerm: (search: string) => void;
|
@@ -279,8 +316,9 @@ declare function useApi<T extends {
|
|
279
316
|
direction: "asc" | "desc";
|
280
317
|
}[]) => void;
|
281
318
|
setFilters: (filter: Record<string, any>) => void;
|
319
|
+
setQueryParam: (key: string, value: any) => void;
|
282
320
|
reset: () => void;
|
283
321
|
};
|
284
322
|
};
|
285
323
|
|
286
|
-
export { type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type RefreshTokenConfig, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiActions, createApiClient, createApiServices, processResponse, useApi };
|
324
|
+
export { type ActionOptions, type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type QueryOptions, type RefreshTokenConfig, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiActions, createApiClient, createApiServices, processResponse, useApi };
|
package/dist/index.js
CHANGED
@@ -164,6 +164,7 @@ var import_axios2 = __toESM(require("axios"));
|
|
164
164
|
function buildPaginateQuery(query) {
|
165
165
|
if (!query) return "";
|
166
166
|
const params = new URLSearchParams();
|
167
|
+
const standardKeys = /* @__PURE__ */ new Set(["page", "limit", "search", "sortBy", "filter"]);
|
167
168
|
if (query.page) params.append("page", query.page.toString());
|
168
169
|
if (query.limit) params.append("limit", query.limit.toString());
|
169
170
|
if (query.search) params.append("search", query.search);
|
@@ -175,6 +176,14 @@ function buildPaginateQuery(query) {
|
|
175
176
|
params.append(`filter.${field}`, String(value));
|
176
177
|
});
|
177
178
|
}
|
179
|
+
for (const key in query) {
|
180
|
+
if (Object.prototype.hasOwnProperty.call(query, key) && !standardKeys.has(key)) {
|
181
|
+
const value = query[key];
|
182
|
+
if (value !== void 0 && value !== null) {
|
183
|
+
params.append(key, String(value));
|
184
|
+
}
|
185
|
+
}
|
186
|
+
}
|
178
187
|
const queryString = params.toString();
|
179
188
|
return queryString ? `?${queryString}` : "";
|
180
189
|
}
|
@@ -244,24 +253,27 @@ function createApiServices(axiosInstance, endpoint) {
|
|
244
253
|
}
|
245
254
|
};
|
246
255
|
const post = async (data, config) => {
|
256
|
+
const finalUrl = config?.endpoint || endpoint;
|
247
257
|
try {
|
248
|
-
const response = await axiosInstance.post(
|
258
|
+
const response = await axiosInstance.post(finalUrl, data, config);
|
249
259
|
return processResponse(response);
|
250
260
|
} catch (error) {
|
251
261
|
return processResponse(error);
|
252
262
|
}
|
253
263
|
};
|
254
264
|
const patch = async (id, data, config) => {
|
265
|
+
const finalUrl = config?.endpoint || `${endpoint}/${id}`;
|
255
266
|
try {
|
256
|
-
const response = await axiosInstance.patch(
|
267
|
+
const response = await axiosInstance.patch(finalUrl, data, config);
|
257
268
|
return processResponse(response);
|
258
269
|
} catch (error) {
|
259
270
|
return processResponse(error);
|
260
271
|
}
|
261
272
|
};
|
262
273
|
const remove = async (id, config) => {
|
274
|
+
const finalUrl = config?.endpoint || `${endpoint}/${id}`;
|
263
275
|
try {
|
264
|
-
const response = await axiosInstance.delete(
|
276
|
+
const response = await axiosInstance.delete(finalUrl, config);
|
265
277
|
return processResponse(response);
|
266
278
|
} catch (error) {
|
267
279
|
return processResponse(error);
|
@@ -335,15 +347,15 @@ function useApi(axiosInstance, config) {
|
|
335
347
|
const {
|
336
348
|
endpoint,
|
337
349
|
initialData,
|
338
|
-
initialQuery = {
|
350
|
+
initialQuery = { limit: 10 },
|
339
351
|
enabled = true,
|
340
352
|
refetchAfterChange = true,
|
353
|
+
// تم تعديل القيمة الافتراضية لتكون أكثر شيوعًا
|
341
354
|
onSuccess,
|
342
355
|
onError
|
343
356
|
} = config;
|
344
357
|
const [state, setState] = (0, import_react.useState)({
|
345
358
|
data: initialData || null,
|
346
|
-
// <--- التغيير هنا
|
347
359
|
rawResponse: null,
|
348
360
|
loading: enabled,
|
349
361
|
error: null,
|
@@ -351,9 +363,10 @@ function useApi(axiosInstance, config) {
|
|
351
363
|
});
|
352
364
|
const [queryOptions, setQueryOptions] = (0, import_react.useState)(initialQuery);
|
353
365
|
const apiServices = (0, import_react.useRef)(createApiServices(axiosInstance, endpoint)).current;
|
354
|
-
const fetchData = (0, import_react.useCallback)(async () => {
|
366
|
+
const fetchData = (0, import_react.useCallback)(async (options) => {
|
367
|
+
const currentQuery = options || queryOptions;
|
355
368
|
setState((prev) => ({ ...prev, data: null, loading: true, error: null }));
|
356
|
-
const queryString = buildPaginateQuery(
|
369
|
+
const queryString = buildPaginateQuery(currentQuery);
|
357
370
|
const result = await apiServices.getWithQuery(queryString, { cancelTokenKey: endpoint });
|
358
371
|
setState(result);
|
359
372
|
if (!result.success && onError) {
|
@@ -365,9 +378,9 @@ function useApi(axiosInstance, config) {
|
|
365
378
|
fetchData();
|
366
379
|
}
|
367
380
|
}, [enabled, queryOptions]);
|
368
|
-
const createItem = async (newItem) => {
|
381
|
+
const createItem = async (newItem, options) => {
|
369
382
|
setState((prev) => ({ ...prev, loading: true }));
|
370
|
-
const result = await apiServices.post(newItem);
|
383
|
+
const result = await apiServices.post(newItem, options);
|
371
384
|
if (result.success) {
|
372
385
|
if (refetchAfterChange) await fetchData();
|
373
386
|
else setState((prev) => ({ ...prev, loading: false }));
|
@@ -378,9 +391,9 @@ function useApi(axiosInstance, config) {
|
|
378
391
|
}
|
379
392
|
return result;
|
380
393
|
};
|
381
|
-
const updateItem = async (id, updatedItem) => {
|
394
|
+
const updateItem = async (id, updatedItem, options) => {
|
382
395
|
setState((prev) => ({ ...prev, loading: true }));
|
383
|
-
const result = await apiServices.patch(id, updatedItem);
|
396
|
+
const result = await apiServices.patch(id, updatedItem, options);
|
384
397
|
if (result.success) {
|
385
398
|
if (refetchAfterChange) await fetchData();
|
386
399
|
else setState((prev) => ({ ...prev, loading: false }));
|
@@ -391,9 +404,9 @@ function useApi(axiosInstance, config) {
|
|
391
404
|
}
|
392
405
|
return result;
|
393
406
|
};
|
394
|
-
const deleteItem = async (id) => {
|
407
|
+
const deleteItem = async (id, options) => {
|
395
408
|
setState((prev) => ({ ...prev, loading: true }));
|
396
|
-
const result = await apiServices.remove(id);
|
409
|
+
const result = await apiServices.remove(id, options);
|
397
410
|
if (result.success) {
|
398
411
|
if (refetchAfterChange) await fetchData();
|
399
412
|
else setState((prev) => ({ ...prev, loading: false }));
|
@@ -409,11 +422,19 @@ function useApi(axiosInstance, config) {
|
|
409
422
|
const setSearchTerm = (search) => setQueryOptions((prev) => ({ ...prev, search, page: 1 }));
|
410
423
|
const setSorting = (sortBy) => setQueryOptions((prev) => ({ ...prev, sortBy }));
|
411
424
|
const setFilters = (filter) => setQueryOptions((prev) => ({ ...prev, filter, page: 1 }));
|
425
|
+
const setQueryParam = (key, value) => {
|
426
|
+
setQueryOptions((prev) => {
|
427
|
+
const newQuery = { ...prev, [key]: value };
|
428
|
+
if (key !== "page") {
|
429
|
+
newQuery.page = 1;
|
430
|
+
}
|
431
|
+
return newQuery;
|
432
|
+
});
|
433
|
+
};
|
412
434
|
const resetQuery = () => setQueryOptions(initialQuery);
|
413
435
|
return {
|
414
436
|
state,
|
415
437
|
setState,
|
416
|
-
// Exposing setState for direct manipulation or connection to Redux
|
417
438
|
actions: {
|
418
439
|
fetch: fetchData,
|
419
440
|
create: createItem,
|
@@ -428,6 +449,8 @@ function useApi(axiosInstance, config) {
|
|
428
449
|
setSearchTerm,
|
429
450
|
setSorting,
|
430
451
|
setFilters,
|
452
|
+
setQueryParam,
|
453
|
+
// <-- NEW
|
431
454
|
reset: resetQuery
|
432
455
|
}
|
433
456
|
};
|
package/dist/index.mjs
CHANGED
@@ -122,6 +122,7 @@ import axios2 from "axios";
|
|
122
122
|
function buildPaginateQuery(query) {
|
123
123
|
if (!query) return "";
|
124
124
|
const params = new URLSearchParams();
|
125
|
+
const standardKeys = /* @__PURE__ */ new Set(["page", "limit", "search", "sortBy", "filter"]);
|
125
126
|
if (query.page) params.append("page", query.page.toString());
|
126
127
|
if (query.limit) params.append("limit", query.limit.toString());
|
127
128
|
if (query.search) params.append("search", query.search);
|
@@ -133,6 +134,14 @@ function buildPaginateQuery(query) {
|
|
133
134
|
params.append(`filter.${field}`, String(value));
|
134
135
|
});
|
135
136
|
}
|
137
|
+
for (const key in query) {
|
138
|
+
if (Object.prototype.hasOwnProperty.call(query, key) && !standardKeys.has(key)) {
|
139
|
+
const value = query[key];
|
140
|
+
if (value !== void 0 && value !== null) {
|
141
|
+
params.append(key, String(value));
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
136
145
|
const queryString = params.toString();
|
137
146
|
return queryString ? `?${queryString}` : "";
|
138
147
|
}
|
@@ -202,24 +211,27 @@ function createApiServices(axiosInstance, endpoint) {
|
|
202
211
|
}
|
203
212
|
};
|
204
213
|
const post = async (data, config) => {
|
214
|
+
const finalUrl = config?.endpoint || endpoint;
|
205
215
|
try {
|
206
|
-
const response = await axiosInstance.post(
|
216
|
+
const response = await axiosInstance.post(finalUrl, data, config);
|
207
217
|
return processResponse(response);
|
208
218
|
} catch (error) {
|
209
219
|
return processResponse(error);
|
210
220
|
}
|
211
221
|
};
|
212
222
|
const patch = async (id, data, config) => {
|
223
|
+
const finalUrl = config?.endpoint || `${endpoint}/${id}`;
|
213
224
|
try {
|
214
|
-
const response = await axiosInstance.patch(
|
225
|
+
const response = await axiosInstance.patch(finalUrl, data, config);
|
215
226
|
return processResponse(response);
|
216
227
|
} catch (error) {
|
217
228
|
return processResponse(error);
|
218
229
|
}
|
219
230
|
};
|
220
231
|
const remove = async (id, config) => {
|
232
|
+
const finalUrl = config?.endpoint || `${endpoint}/${id}`;
|
221
233
|
try {
|
222
|
-
const response = await axiosInstance.delete(
|
234
|
+
const response = await axiosInstance.delete(finalUrl, config);
|
223
235
|
return processResponse(response);
|
224
236
|
} catch (error) {
|
225
237
|
return processResponse(error);
|
@@ -293,15 +305,15 @@ function useApi(axiosInstance, config) {
|
|
293
305
|
const {
|
294
306
|
endpoint,
|
295
307
|
initialData,
|
296
|
-
initialQuery = {
|
308
|
+
initialQuery = { limit: 10 },
|
297
309
|
enabled = true,
|
298
310
|
refetchAfterChange = true,
|
311
|
+
// تم تعديل القيمة الافتراضية لتكون أكثر شيوعًا
|
299
312
|
onSuccess,
|
300
313
|
onError
|
301
314
|
} = config;
|
302
315
|
const [state, setState] = useState({
|
303
316
|
data: initialData || null,
|
304
|
-
// <--- التغيير هنا
|
305
317
|
rawResponse: null,
|
306
318
|
loading: enabled,
|
307
319
|
error: null,
|
@@ -309,9 +321,10 @@ function useApi(axiosInstance, config) {
|
|
309
321
|
});
|
310
322
|
const [queryOptions, setQueryOptions] = useState(initialQuery);
|
311
323
|
const apiServices = useRef(createApiServices(axiosInstance, endpoint)).current;
|
312
|
-
const fetchData = useCallback(async () => {
|
324
|
+
const fetchData = useCallback(async (options) => {
|
325
|
+
const currentQuery = options || queryOptions;
|
313
326
|
setState((prev) => ({ ...prev, data: null, loading: true, error: null }));
|
314
|
-
const queryString = buildPaginateQuery(
|
327
|
+
const queryString = buildPaginateQuery(currentQuery);
|
315
328
|
const result = await apiServices.getWithQuery(queryString, { cancelTokenKey: endpoint });
|
316
329
|
setState(result);
|
317
330
|
if (!result.success && onError) {
|
@@ -323,9 +336,9 @@ function useApi(axiosInstance, config) {
|
|
323
336
|
fetchData();
|
324
337
|
}
|
325
338
|
}, [enabled, queryOptions]);
|
326
|
-
const createItem = async (newItem) => {
|
339
|
+
const createItem = async (newItem, options) => {
|
327
340
|
setState((prev) => ({ ...prev, loading: true }));
|
328
|
-
const result = await apiServices.post(newItem);
|
341
|
+
const result = await apiServices.post(newItem, options);
|
329
342
|
if (result.success) {
|
330
343
|
if (refetchAfterChange) await fetchData();
|
331
344
|
else setState((prev) => ({ ...prev, loading: false }));
|
@@ -336,9 +349,9 @@ function useApi(axiosInstance, config) {
|
|
336
349
|
}
|
337
350
|
return result;
|
338
351
|
};
|
339
|
-
const updateItem = async (id, updatedItem) => {
|
352
|
+
const updateItem = async (id, updatedItem, options) => {
|
340
353
|
setState((prev) => ({ ...prev, loading: true }));
|
341
|
-
const result = await apiServices.patch(id, updatedItem);
|
354
|
+
const result = await apiServices.patch(id, updatedItem, options);
|
342
355
|
if (result.success) {
|
343
356
|
if (refetchAfterChange) await fetchData();
|
344
357
|
else setState((prev) => ({ ...prev, loading: false }));
|
@@ -349,9 +362,9 @@ function useApi(axiosInstance, config) {
|
|
349
362
|
}
|
350
363
|
return result;
|
351
364
|
};
|
352
|
-
const deleteItem = async (id) => {
|
365
|
+
const deleteItem = async (id, options) => {
|
353
366
|
setState((prev) => ({ ...prev, loading: true }));
|
354
|
-
const result = await apiServices.remove(id);
|
367
|
+
const result = await apiServices.remove(id, options);
|
355
368
|
if (result.success) {
|
356
369
|
if (refetchAfterChange) await fetchData();
|
357
370
|
else setState((prev) => ({ ...prev, loading: false }));
|
@@ -367,11 +380,19 @@ function useApi(axiosInstance, config) {
|
|
367
380
|
const setSearchTerm = (search) => setQueryOptions((prev) => ({ ...prev, search, page: 1 }));
|
368
381
|
const setSorting = (sortBy) => setQueryOptions((prev) => ({ ...prev, sortBy }));
|
369
382
|
const setFilters = (filter) => setQueryOptions((prev) => ({ ...prev, filter, page: 1 }));
|
383
|
+
const setQueryParam = (key, value) => {
|
384
|
+
setQueryOptions((prev) => {
|
385
|
+
const newQuery = { ...prev, [key]: value };
|
386
|
+
if (key !== "page") {
|
387
|
+
newQuery.page = 1;
|
388
|
+
}
|
389
|
+
return newQuery;
|
390
|
+
});
|
391
|
+
};
|
370
392
|
const resetQuery = () => setQueryOptions(initialQuery);
|
371
393
|
return {
|
372
394
|
state,
|
373
395
|
setState,
|
374
|
-
// Exposing setState for direct manipulation or connection to Redux
|
375
396
|
actions: {
|
376
397
|
fetch: fetchData,
|
377
398
|
create: createItem,
|
@@ -386,6 +407,8 @@ function useApi(axiosInstance, config) {
|
|
386
407
|
setSearchTerm,
|
387
408
|
setSorting,
|
388
409
|
setFilters,
|
410
|
+
setQueryParam,
|
411
|
+
// <-- NEW
|
389
412
|
reset: resetQuery
|
390
413
|
}
|
391
414
|
};
|