@ventlio/tanstack-query 0.5.11 → 0.5.13
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/README.md +178 -150
- package/dist/config/bootstrapQueryRequest.d.ts +7 -1
- package/dist/config/useEnvironmentVariables.d.ts +4 -0
- package/dist/index.mjs +307 -90
- package/dist/index.mjs.map +1 -1
- package/dist/node_modules/@tanstack/react-store/dist/esm/index.js +1 -1
- package/dist/node_modules/{@tanstack/react-store/node_modules/use-sync-external-store → use-sync-external-store}/cjs/use-sync-external-store-shim/with-selector.development.js +1 -1
- package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js.map +1 -0
- package/dist/node_modules/{@tanstack/react-store/node_modules/use-sync-external-store → use-sync-external-store}/cjs/use-sync-external-store-shim/with-selector.production.js +1 -1
- package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.production.js.map +1 -0
- package/dist/node_modules/{@tanstack/react-store/node_modules/use-sync-external-store → use-sync-external-store}/cjs/use-sync-external-store-shim.development.js +1 -1
- package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js.map +1 -0
- package/dist/node_modules/{@tanstack/react-store/node_modules/use-sync-external-store → use-sync-external-store}/cjs/use-sync-external-store-shim.production.js +1 -1
- package/dist/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js.map +1 -0
- package/dist/node_modules/{@tanstack/react-store/node_modules/use-sync-external-store → use-sync-external-store}/shim/index.js +1 -1
- package/dist/node_modules/use-sync-external-store/shim/index.js.map +1 -0
- package/dist/node_modules/{@tanstack/react-store/node_modules/use-sync-external-store → use-sync-external-store}/shim/with-selector.js +1 -1
- package/dist/node_modules/use-sync-external-store/shim/with-selector.js.map +1 -0
- package/dist/queries/useGetRequest.d.ts +12 -2
- package/dist/request/make-request.d.ts +12 -1
- package/dist/src/config/bootstrapQueryRequest.js +42 -2
- package/dist/src/config/bootstrapQueryRequest.js.map +1 -1
- package/dist/src/config/useEnvironmentVariables.js +34 -3
- package/dist/src/config/useEnvironmentVariables.js.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/queries/useDeleteRequest.js +19 -14
- package/dist/src/queries/useDeleteRequest.js.map +1 -1
- package/dist/src/queries/useGetInfiniteRequest.js +17 -12
- package/dist/src/queries/useGetInfiniteRequest.js.map +1 -1
- package/dist/src/queries/useGetRequest.js +86 -28
- package/dist/src/queries/useGetRequest.js.map +1 -1
- package/dist/src/queries/usePatchRequest.js +19 -14
- package/dist/src/queries/usePatchRequest.js.map +1 -1
- package/dist/src/queries/usePostRequest.js +18 -13
- package/dist/src/queries/usePostRequest.js.map +1 -1
- package/dist/src/request/make-request.js +75 -6
- package/dist/src/request/make-request.js.map +1 -1
- package/dist/types/index.d.ts +24 -5
- package/package.json +2 -2
- package/src/config/bootstrapQueryRequest.ts +48 -3
- package/src/config/useEnvironmentVariables.ts +41 -3
- package/src/queries/useDeleteRequest.ts +18 -20
- package/src/queries/useGetInfiniteRequest.ts +17 -17
- package/src/queries/useGetRequest.ts +109 -33
- package/src/queries/usePatchRequest.ts +19 -16
- package/src/queries/usePostRequest.ts +18 -15
- package/src/queries/usePutRequest.ts +16 -15
- package/src/request/make-request.ts +112 -15
- package/src/types/index.ts +38 -4
- package/dist/node_modules/@tanstack/react-store/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js.map +0 -1
- package/dist/node_modules/@tanstack/react-store/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.production.js.map +0 -1
- package/dist/node_modules/@tanstack/react-store/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js.map +0 -1
- package/dist/node_modules/@tanstack/react-store/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js.map +0 -1
- package/dist/node_modules/@tanstack/react-store/node_modules/use-sync-external-store/shim/index.js.map +0 -1
- package/dist/node_modules/@tanstack/react-store/node_modules/use-sync-external-store/shim/with-selector.js.map +0 -1
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { QueryKey, UseQueryOptions } from '@tanstack/react-query';
|
|
2
2
|
import { useQuery } from '@tanstack/react-query';
|
|
3
|
-
import { useStore } from '@tanstack/react-store';
|
|
4
3
|
import { useEffect, useState } from 'react';
|
|
5
4
|
import { useEnvironmentVariables } from '../config';
|
|
6
|
-
import { bootStore } from '../config/bootStore';
|
|
7
5
|
import type { IRequestError, IRequestSuccess } from '../request';
|
|
8
6
|
import { HttpMethod, makeRequest } from '../request';
|
|
9
7
|
import { useHeaderStore, usePauseFutureRequests } from '../stores';
|
|
@@ -14,8 +12,8 @@ export const useDeleteRequest = <TResponse>(deleteOptions?: DefaultRequestOption
|
|
|
14
12
|
const [requestPath, setRequestPath] = useState<string>('');
|
|
15
13
|
const [options, setOptions] = useState<any>();
|
|
16
14
|
|
|
17
|
-
const { middleware } = useStore(bootStore);
|
|
18
|
-
|
|
15
|
+
// const { middleware: middlewares } = useStore(bootStore);
|
|
16
|
+
// const [middleware] = middlewares as unknown as MiddlewareFunction[];
|
|
19
17
|
const [requestPayload, setRequestPayload] = useState<Record<any, any>>();
|
|
20
18
|
|
|
21
19
|
const isFutureQueriesPaused = usePauseFutureRequests((state) => state.isFutureQueriesPaused);
|
|
@@ -36,22 +34,22 @@ export const useDeleteRequest = <TResponse>(deleteOptions?: DefaultRequestOption
|
|
|
36
34
|
timeout: TIMEOUT,
|
|
37
35
|
};
|
|
38
36
|
|
|
39
|
-
let deleteResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
40
|
-
if (middleware) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} else {
|
|
53
|
-
|
|
54
|
-
}
|
|
37
|
+
// let deleteResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
38
|
+
// if (middleware) {
|
|
39
|
+
// // perform global middleware
|
|
40
|
+
// deleteResponse = await middleware(
|
|
41
|
+
// async (middlewareOptions) =>
|
|
42
|
+
// await makeRequest<TResponse>(
|
|
43
|
+
// middlewareOptions ? { ...requestOptions, ...middlewareOptions } : requestOptions
|
|
44
|
+
// ),
|
|
45
|
+
// {
|
|
46
|
+
// path: requestUrl,
|
|
47
|
+
// baseUrl: baseUrl ?? API_URL,
|
|
48
|
+
// }
|
|
49
|
+
// );
|
|
50
|
+
// } else {
|
|
51
|
+
const deleteResponse = await makeRequest<TResponse>(requestOptions);
|
|
52
|
+
// }
|
|
55
53
|
|
|
56
54
|
if (deleteResponse.status) {
|
|
57
55
|
res(deleteResponse as IRequestSuccess<TResponse>);
|
|
@@ -37,7 +37,7 @@ export const useGetInfiniteRequest = <TResponse extends Record<string, any>>({
|
|
|
37
37
|
const [requestPath, setRequestPath] = useState<string>(path);
|
|
38
38
|
|
|
39
39
|
const [options, setOptions] = useState<any>(queryOptions);
|
|
40
|
-
|
|
40
|
+
useStore(bootStore);
|
|
41
41
|
|
|
42
42
|
const [requestPayload, setRequestPayload] = useState<Record<any, any>>();
|
|
43
43
|
|
|
@@ -68,22 +68,22 @@ export const useGetInfiniteRequest = <TResponse extends Record<string, any>>({
|
|
|
68
68
|
timeout: TIMEOUT,
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
-
let getResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
72
|
-
if (middleware) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
} else {
|
|
85
|
-
|
|
86
|
-
}
|
|
71
|
+
// let getResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
72
|
+
// if (middleware) {
|
|
73
|
+
// // perform global middleware
|
|
74
|
+
// getResponse = await middleware(
|
|
75
|
+
// async (middlewareOptions) =>
|
|
76
|
+
// await makeRequest<TResponse>(
|
|
77
|
+
// middlewareOptions ? { ...requestOptions, ...middlewareOptions } : requestOptions
|
|
78
|
+
// ),
|
|
79
|
+
// {
|
|
80
|
+
// path,
|
|
81
|
+
// baseUrl: baseUrl ?? API_URL,
|
|
82
|
+
// }
|
|
83
|
+
// );
|
|
84
|
+
// } else {
|
|
85
|
+
const getResponse = await makeRequest<TResponse>(requestOptions);
|
|
86
|
+
// }
|
|
87
87
|
|
|
88
88
|
if (getResponse.status) {
|
|
89
89
|
res(getResponse as IRequestSuccess<TResponse & { pagination: Pagination }>);
|
|
@@ -5,9 +5,14 @@ import { useEnvironmentVariables } from '../config';
|
|
|
5
5
|
import { useStore } from '@tanstack/react-store';
|
|
6
6
|
import { bootStore } from '../config/bootStore';
|
|
7
7
|
import { IRequestError, IRequestSuccess, makeRequest } from '../request';
|
|
8
|
+
import { executeMiddlewareChain } from '../request/make-request';
|
|
8
9
|
import { useHeaderStore, usePauseFutureRequests } from '../stores';
|
|
10
|
+
import type { MiddlewareContext, MiddlewareNext } from '../types';
|
|
9
11
|
import { DefaultRequestOptions, IPagination, TanstackQueryOption } from './queries.interface';
|
|
10
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Hook for making GET requests with pagination support
|
|
15
|
+
*/
|
|
11
16
|
export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
12
17
|
path,
|
|
13
18
|
load = false,
|
|
@@ -15,18 +20,24 @@ export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
|
15
20
|
keyTracker,
|
|
16
21
|
baseUrl,
|
|
17
22
|
headers,
|
|
23
|
+
paginationConfig,
|
|
18
24
|
}: {
|
|
19
25
|
path: string;
|
|
20
26
|
load?: boolean;
|
|
21
27
|
queryOptions?: TanstackQueryOption<TResponse>;
|
|
22
28
|
keyTracker?: string;
|
|
29
|
+
paginationConfig?: {
|
|
30
|
+
extractPagination?: (response: IRequestSuccess<TResponse>) => IPagination | undefined;
|
|
31
|
+
buildPaginationUrl?: (url: string, page: number) => string;
|
|
32
|
+
pageParamName?: string;
|
|
33
|
+
};
|
|
23
34
|
} & DefaultRequestOptions) => {
|
|
24
35
|
const [requestPath, setRequestPath] = useState<string>(path);
|
|
25
36
|
const [options, setOptions] = useState<any>(queryOptions);
|
|
26
37
|
const [page, setPage] = useState<number>(1);
|
|
27
38
|
|
|
28
39
|
const { API_URL, TIMEOUT } = useEnvironmentVariables();
|
|
29
|
-
const { middleware } = useStore(bootStore);
|
|
40
|
+
const { middleware, pagination: globalPaginationConfig } = useStore(bootStore);
|
|
30
41
|
|
|
31
42
|
const globalHeaders = useHeaderStore((state) => state.headers);
|
|
32
43
|
|
|
@@ -39,6 +50,15 @@ export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
|
39
50
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
51
|
queryClient = useMemo(() => queryClient, []);
|
|
41
52
|
|
|
53
|
+
// Merge global and local pagination config
|
|
54
|
+
const pagination = useMemo(
|
|
55
|
+
() => ({
|
|
56
|
+
...globalPaginationConfig,
|
|
57
|
+
...paginationConfig,
|
|
58
|
+
}),
|
|
59
|
+
[globalPaginationConfig, paginationConfig]
|
|
60
|
+
);
|
|
61
|
+
|
|
42
62
|
const sendRequest = async (
|
|
43
63
|
res: (
|
|
44
64
|
value: IRequestError | IRequestSuccess<TResponse> | PromiseLike<IRequestError | IRequestSuccess<TResponse>>
|
|
@@ -56,20 +76,25 @@ export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
|
56
76
|
timeout: TIMEOUT,
|
|
57
77
|
};
|
|
58
78
|
|
|
79
|
+
// Create the final handler that makes the actual request
|
|
80
|
+
const finalHandler: MiddlewareNext<TResponse> = async (options) => {
|
|
81
|
+
const finalOptions = options ? { ...requestOptions, ...options } : requestOptions;
|
|
82
|
+
return await makeRequest<TResponse>(finalOptions);
|
|
83
|
+
};
|
|
84
|
+
|
|
59
85
|
let getResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
);
|
|
86
|
+
|
|
87
|
+
// If middleware is available, execute the middleware chain
|
|
88
|
+
if (middleware && Array.isArray(middleware) && middleware.length > 0) {
|
|
89
|
+
const context: MiddlewareContext<TResponse> = {
|
|
90
|
+
baseUrl: baseUrl ?? API_URL,
|
|
91
|
+
path: requestUrl,
|
|
92
|
+
options: requestOptions,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
getResponse = await executeMiddlewareChain<TResponse>(middleware, context, finalHandler);
|
|
72
96
|
} else {
|
|
97
|
+
// Otherwise, just make the request directly
|
|
73
98
|
getResponse = await makeRequest<TResponse>(requestOptions);
|
|
74
99
|
}
|
|
75
100
|
|
|
@@ -105,41 +130,88 @@ export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
|
105
130
|
}
|
|
106
131
|
}, [keyTracker, requestPath, queryClient, queryOptions?.staleTime]);
|
|
107
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Extract pagination data from response using configured extractor
|
|
135
|
+
*/
|
|
136
|
+
const getPaginationData = (response: IRequestSuccess<TResponse>): IPagination | undefined => {
|
|
137
|
+
// Use the configured pagination extractor or fall back to default
|
|
138
|
+
const extractPagination =
|
|
139
|
+
pagination.extractPagination ||
|
|
140
|
+
((res) => {
|
|
141
|
+
if ('pagination' in res.data) {
|
|
142
|
+
return res.data.pagination as IPagination;
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
return extractPagination(response);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Navigate to the next page if available
|
|
152
|
+
*/
|
|
108
153
|
const nextPage = () => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
154
|
+
// The linter thinks query.data is always falsy, but we know it can be defined after a successful query
|
|
155
|
+
// Let's restructure to avoid the conditional
|
|
156
|
+
const paginationData = (query as any).data && getPaginationData(query.data);
|
|
157
|
+
if (!paginationData) return;
|
|
158
|
+
|
|
159
|
+
if (
|
|
160
|
+
paginationData.next_page !== paginationData.current_page &&
|
|
161
|
+
paginationData.next_page > paginationData.current_page
|
|
162
|
+
) {
|
|
163
|
+
setRequestPath(constructPaginationLink(requestPath, paginationData.next_page));
|
|
114
164
|
}
|
|
115
165
|
};
|
|
116
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Navigate to the previous page if available
|
|
169
|
+
*/
|
|
117
170
|
const prevPage = () => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
171
|
+
// The linter thinks query.data is always falsy, but we know it can be defined after a successful query
|
|
172
|
+
// Let's restructure to avoid the conditional
|
|
173
|
+
const paginationData = (query as any).data && getPaginationData(query.data);
|
|
174
|
+
if (!paginationData) return;
|
|
175
|
+
|
|
176
|
+
if (
|
|
177
|
+
paginationData.previous_page !== paginationData.current_page &&
|
|
178
|
+
paginationData.previous_page < paginationData.current_page
|
|
179
|
+
) {
|
|
180
|
+
setRequestPath(constructPaginationLink(requestPath, paginationData.previous_page));
|
|
123
181
|
}
|
|
124
182
|
};
|
|
125
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Construct a pagination URL using the configured builder
|
|
186
|
+
*/
|
|
126
187
|
const constructPaginationLink = (link: string, pageNumber: number) => {
|
|
127
|
-
|
|
128
|
-
const
|
|
188
|
+
// Use the configured pagination URL builder or fall back to default
|
|
189
|
+
const buildPaginationUrl =
|
|
190
|
+
pagination.buildPaginationUrl ||
|
|
191
|
+
((url, page) => {
|
|
192
|
+
const [pathname, queryString] = url.split('?');
|
|
193
|
+
const queryParams = new URLSearchParams(queryString || '');
|
|
194
|
+
const pageParamName = pagination.pageParamName || 'page';
|
|
129
195
|
|
|
130
|
-
|
|
196
|
+
const oldPage = Number(queryParams.get(pageParamName));
|
|
197
|
+
queryParams.set(pageParamName, String(page));
|
|
131
198
|
|
|
132
|
-
|
|
199
|
+
const newUrl = pathname + '?' + queryParams.toString();
|
|
133
200
|
|
|
134
|
-
|
|
201
|
+
// only update page when pagination number changed
|
|
202
|
+
if (oldPage !== pageNumber) {
|
|
203
|
+
setPage(pageNumber);
|
|
204
|
+
}
|
|
135
205
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return link;
|
|
206
|
+
return newUrl;
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
return buildPaginationUrl(link, pageNumber);
|
|
141
210
|
};
|
|
142
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Navigate to a specific page
|
|
214
|
+
*/
|
|
143
215
|
const gotoPage = (pageNumber: number) => {
|
|
144
216
|
setRequestPath(constructPaginationLink(requestPath, pageNumber));
|
|
145
217
|
};
|
|
@@ -194,5 +266,9 @@ export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
|
194
266
|
gotoPage,
|
|
195
267
|
page,
|
|
196
268
|
queryKey: [requestPath, {}],
|
|
269
|
+
// Add pagination data accessor - restructured to avoid linter error
|
|
270
|
+
getPaginationData: function () {
|
|
271
|
+
return (query as any).data ? getPaginationData(query.data) : undefined;
|
|
272
|
+
},
|
|
197
273
|
};
|
|
198
274
|
};
|
|
@@ -19,7 +19,7 @@ export const usePatchRequest = <TResponse>({ path, baseUrl, headers }: { path: s
|
|
|
19
19
|
const [requestPayload, setRequestPayload] = useState<Record<any, any>>();
|
|
20
20
|
|
|
21
21
|
const isFutureMutationsPaused = usePauseFutureRequests((state) => state.isFutureMutationsPaused);
|
|
22
|
-
const {
|
|
22
|
+
const { context } = useStore(bootStore);
|
|
23
23
|
|
|
24
24
|
const sendRequest = async (res: (value: any) => void, rej: (reason?: any) => void, data: any) => {
|
|
25
25
|
// get request headers
|
|
@@ -34,22 +34,25 @@ export const usePatchRequest = <TResponse>({ path, baseUrl, headers }: { path: s
|
|
|
34
34
|
onUploadProgress,
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
let patchResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
38
|
-
if (middleware) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
// let patchResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
38
|
+
// if (middleware) {
|
|
39
|
+
// // perform global middleware
|
|
40
|
+
// const middlewareResponse = await middleware(
|
|
41
|
+
// async (options) =>
|
|
42
|
+
// await makeRequest<TResponse>(
|
|
43
|
+
// options ? { ...requestOptions, ...options } : requestOptions
|
|
44
|
+
// ),
|
|
45
|
+
// {
|
|
46
|
+
// path,
|
|
47
|
+
// baseUrl: baseUrl ?? API_URL,
|
|
48
|
+
// body: data,
|
|
49
|
+
// }
|
|
50
|
+
// );
|
|
48
51
|
|
|
49
|
-
|
|
50
|
-
} else {
|
|
51
|
-
|
|
52
|
-
}
|
|
52
|
+
// patchResponse = middlewareResponse;
|
|
53
|
+
// } else {
|
|
54
|
+
const patchResponse = await makeRequest<TResponse>(requestOptions);
|
|
55
|
+
// }
|
|
53
56
|
if (patchResponse.status) {
|
|
54
57
|
// scroll to top after success
|
|
55
58
|
if (context !== 'app') {
|
|
@@ -25,7 +25,7 @@ export const usePostRequest = <TResponse>({
|
|
|
25
25
|
} & DefaultRequestOptions) => {
|
|
26
26
|
const { API_URL, TIMEOUT } = useEnvironmentVariables();
|
|
27
27
|
|
|
28
|
-
const {
|
|
28
|
+
const { context } = useStore(bootStore);
|
|
29
29
|
|
|
30
30
|
const globalHeaders = useHeaderStore((state) => state.headers);
|
|
31
31
|
const { isApp } = useReactNativeEnv();
|
|
@@ -61,20 +61,23 @@ export const usePostRequest = <TResponse>({
|
|
|
61
61
|
...requestConfig,
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
let postResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
65
|
-
if (middleware) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
64
|
+
// let postResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
65
|
+
// if (middleware) {
|
|
66
|
+
// // perform global middleware
|
|
67
|
+
// postResponse = await middleware(
|
|
68
|
+
// async (options) =>
|
|
69
|
+
// await makeRequest<TResponse>(
|
|
70
|
+
// options ? { ...requestOptions, ...options } : requestOptions
|
|
71
|
+
// ),
|
|
72
|
+
// {
|
|
73
|
+
// path,
|
|
74
|
+
// baseUrl: baseUrl ?? API_URL,
|
|
75
|
+
// body: data,
|
|
76
|
+
// }
|
|
77
|
+
// );
|
|
78
|
+
// } else {
|
|
79
|
+
const postResponse = await makeRequest<TResponse>(requestOptions);
|
|
80
|
+
// }
|
|
78
81
|
|
|
79
82
|
if (postResponse.status) {
|
|
80
83
|
// scroll to top after success
|
|
@@ -20,7 +20,7 @@ export const usePutRequest = <TResponse>({ path, baseUrl, headers }: { path: str
|
|
|
20
20
|
|
|
21
21
|
const isFutureMutationsPaused = usePauseFutureRequests((state) => state.isFutureMutationsPaused);
|
|
22
22
|
|
|
23
|
-
const {
|
|
23
|
+
const { context } = useStore(bootStore);
|
|
24
24
|
|
|
25
25
|
const sendRequest = async (res: (value: any) => void, rej: (reason?: any) => void, data: any) => {
|
|
26
26
|
// get request headers
|
|
@@ -35,20 +35,21 @@ export const usePutRequest = <TResponse>({ path, baseUrl, headers }: { path: str
|
|
|
35
35
|
onUploadProgress,
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
let putResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
39
|
-
if (middleware) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
// let putResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
39
|
+
// if (middleware) {
|
|
40
|
+
// // perform global middleware
|
|
41
|
+
// putResponse = await middleware(
|
|
42
|
+
// async (options) =>
|
|
43
|
+
// await makeRequest<TResponse>(options ? { ...requestOptions, ...options } : requestOptions),
|
|
44
|
+
// {
|
|
45
|
+
// path,
|
|
46
|
+
// baseUrl: baseUrl ?? API_URL,
|
|
47
|
+
// body: data,
|
|
48
|
+
// }
|
|
49
|
+
// );
|
|
50
|
+
// } else {
|
|
51
|
+
const putResponse = await makeRequest<TResponse>(requestOptions);
|
|
52
|
+
// }
|
|
52
53
|
if (putResponse.status) {
|
|
53
54
|
// scroll to top after success
|
|
54
55
|
if (context !== 'app') {
|
|
@@ -2,34 +2,126 @@ import type { AxiosRequestConfig, RawAxiosRequestHeaders } from 'axios';
|
|
|
2
2
|
import axios from 'axios';
|
|
3
3
|
import { axiosInstance } from './axios-instance';
|
|
4
4
|
|
|
5
|
+
import type { MiddlewareContext, MiddlewareFunction, MiddlewareNext } from '../types';
|
|
5
6
|
import { ContentType, HttpMethod } from './request.enum';
|
|
6
7
|
import type { IMakeRequest, IRequestError, IRequestSuccess } from './request.interface';
|
|
7
8
|
import { errorTransformer, successTransformer } from './transformer';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Execute a chain of middleware functions
|
|
12
|
+
*/
|
|
13
|
+
export async function executeMiddlewareChain<T>(
|
|
14
|
+
middlewares: MiddlewareFunction[],
|
|
15
|
+
context: MiddlewareContext<T>,
|
|
16
|
+
finalHandler: MiddlewareNext<T>
|
|
17
|
+
): Promise<IRequestSuccess<T> | IRequestError> {
|
|
18
|
+
// Create a chain of middleware functions
|
|
19
|
+
const chain = middlewares.reduceRight((next: MiddlewareNext<T>, middleware: MiddlewareFunction<T>) => {
|
|
20
|
+
return (options) => {
|
|
21
|
+
// Update context with new options if provided
|
|
22
|
+
const updatedContext = options ? { ...context, options: { ...context.options, ...options } } : context;
|
|
23
|
+
return middleware(updatedContext, next);
|
|
24
|
+
};
|
|
25
|
+
}, finalHandler);
|
|
26
|
+
|
|
27
|
+
// Execute the middleware chain
|
|
28
|
+
return await chain(undefined);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Make an HTTP request with middleware support
|
|
33
|
+
*
|
|
34
|
+
* @param requestOptions - Request options
|
|
35
|
+
* @param middlewares - Optional array of middleware functions
|
|
36
|
+
*/
|
|
37
|
+
export async function makeRequest<TResponse>(
|
|
38
|
+
requestOptions: IMakeRequest,
|
|
39
|
+
middlewares?: MiddlewareFunction[]
|
|
40
|
+
): Promise<IRequestSuccess<TResponse> | IRequestError> {
|
|
41
|
+
const {
|
|
42
|
+
body = {},
|
|
43
|
+
method = HttpMethod.GET,
|
|
44
|
+
path,
|
|
45
|
+
isFormData,
|
|
46
|
+
headers = {},
|
|
47
|
+
baseURL,
|
|
48
|
+
timeout,
|
|
49
|
+
appFileConfig,
|
|
50
|
+
onUploadProgress,
|
|
51
|
+
} = requestOptions;
|
|
52
|
+
|
|
20
53
|
// check if file is included in mobile app environment and extract all file input to avoid
|
|
21
54
|
// it being formatted to object using axios formData builder
|
|
22
55
|
const isApp = appFileConfig?.isApp;
|
|
23
56
|
const appFiles: Record<string, string> = isApp ? getAppFiles(body, appFileConfig.fileSelectors) : {};
|
|
24
57
|
|
|
25
58
|
// configure body
|
|
26
|
-
|
|
59
|
+
const processedBody = (isFormData ? axios.toFormData(body as FormData) : body) as FormData;
|
|
60
|
+
|
|
61
|
+
// configure request header
|
|
62
|
+
configureRequestHeader(isFormData, headers, isApp, appFiles, processedBody);
|
|
63
|
+
|
|
64
|
+
// Create the final handler that makes the actual request
|
|
65
|
+
const finalHandler: MiddlewareNext<TResponse> = async (options) => {
|
|
66
|
+
const finalRequestOptions = options
|
|
67
|
+
? {
|
|
68
|
+
...requestOptions,
|
|
69
|
+
body: processedBody,
|
|
70
|
+
...options,
|
|
71
|
+
}
|
|
72
|
+
: {
|
|
73
|
+
...requestOptions,
|
|
74
|
+
body: processedBody,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return await performRequest<TResponse>(finalRequestOptions);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// If middleware is available, execute the middleware chain
|
|
81
|
+
if (middlewares && middlewares.length > 0) {
|
|
82
|
+
const context: MiddlewareContext<TResponse> = {
|
|
83
|
+
baseUrl: baseURL,
|
|
84
|
+
path,
|
|
85
|
+
body: body as Record<string, any>,
|
|
86
|
+
method,
|
|
87
|
+
headers,
|
|
88
|
+
options: {
|
|
89
|
+
baseURL,
|
|
90
|
+
timeout,
|
|
91
|
+
path,
|
|
92
|
+
body: processedBody,
|
|
93
|
+
method,
|
|
94
|
+
isFormData,
|
|
95
|
+
headers,
|
|
96
|
+
appFileConfig,
|
|
97
|
+
onUploadProgress,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return await executeMiddlewareChain<TResponse>(middlewares, context, finalHandler);
|
|
102
|
+
}
|
|
27
103
|
|
|
28
|
-
//
|
|
29
|
-
|
|
104
|
+
// Otherwise, just make the request directly
|
|
105
|
+
return await finalHandler(undefined);
|
|
106
|
+
}
|
|
30
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Perform the actual HTTP request
|
|
110
|
+
*/
|
|
111
|
+
async function performRequest<TResponse>({
|
|
112
|
+
body,
|
|
113
|
+
method,
|
|
114
|
+
path,
|
|
115
|
+
isFormData,
|
|
116
|
+
headers,
|
|
117
|
+
baseURL,
|
|
118
|
+
timeout,
|
|
119
|
+
appFileConfig,
|
|
120
|
+
onUploadProgress,
|
|
121
|
+
}: IMakeRequest): Promise<IRequestSuccess<TResponse> | IRequestError> {
|
|
31
122
|
try {
|
|
32
123
|
const axiosRequest = axiosInstance({ baseURL, headers, timeout });
|
|
124
|
+
const isApp = appFileConfig?.isApp;
|
|
33
125
|
|
|
34
126
|
const axiosRequestConfig: AxiosRequestConfig<Record<string, any>> = {
|
|
35
127
|
url: path,
|
|
@@ -37,7 +129,12 @@ export async function makeRequest<TResponse>({
|
|
|
37
129
|
onUploadProgress,
|
|
38
130
|
};
|
|
39
131
|
|
|
40
|
-
if
|
|
132
|
+
// Check if body exists and is not null
|
|
133
|
+
if (
|
|
134
|
+
body &&
|
|
135
|
+
((typeof body === 'object' && Object.keys(body).length > 0) ||
|
|
136
|
+
(isFormData && !isApp && body instanceof FormData && Array.from(body.keys()).length > 0))
|
|
137
|
+
) {
|
|
41
138
|
axiosRequestConfig.data = body;
|
|
42
139
|
}
|
|
43
140
|
|