@ventlio/tanstack-query 0.5.14 → 0.6.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/dist/helpers/index.d.ts +0 -1
- package/dist/index.mjs +158 -171
- package/dist/index.mjs.map +1 -1
- package/dist/queries/useDeleteRequest.d.ts +93 -39
- package/dist/queries/useGetRequest.d.ts +125 -12
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/queries/useDeleteRequest.js +39 -55
- package/dist/src/queries/useDeleteRequest.js.map +1 -1
- package/dist/src/queries/useGetInfiniteRequest.js +8 -3
- package/dist/src/queries/useGetInfiniteRequest.js.map +1 -1
- package/dist/src/queries/useGetRequest.js +98 -88
- package/dist/src/queries/useGetRequest.js.map +1 -1
- package/dist/src/queries/usePatchRequest.js +8 -12
- package/dist/src/queries/usePatchRequest.js.map +1 -1
- package/dist/src/queries/usePostRequest.js +10 -12
- package/dist/src/queries/usePostRequest.js.map +1 -1
- package/dist/types/index.d.ts +17 -1
- package/package.json +1 -1
- package/src/helpers/index.ts +0 -1
- package/src/queries/useDeleteRequest.ts +43 -68
- package/src/queries/useGetInfiniteRequest.ts +9 -3
- package/src/queries/useGetRequest.ts +167 -157
- package/src/queries/usePatchRequest.ts +10 -12
- package/src/queries/usePostRequest.ts +11 -13
- package/src/queries/usePutRequest.ts +10 -13
- package/src/types/index.ts +17 -1
- package/dist/helpers/scrollToTop.d.ts +0 -1
- package/dist/src/helpers/scrollToTop.js +0 -9
- package/dist/src/helpers/scrollToTop.js.map +0 -1
- package/src/helpers/scrollToTop.ts +0 -6
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import type { MutateOptions } from '@tanstack/react-query';
|
|
2
|
+
import { useMutation } from '@tanstack/react-query';
|
|
3
|
+
import { useStore } from '@tanstack/react-store';
|
|
4
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
5
|
import { useEnvironmentVariables } from '../config';
|
|
6
|
+
import { bootStore } from '../config/bootStore';
|
|
5
7
|
import type { IRequestError, IRequestSuccess } from '../request';
|
|
6
8
|
import { HttpMethod, makeRequest } from '../request';
|
|
7
9
|
import { useHeaderStore, usePauseFutureRequests } from '../stores';
|
|
@@ -9,103 +11,76 @@ import type { DefaultRequestOptions } from './queries.interface';
|
|
|
9
11
|
|
|
10
12
|
export const useDeleteRequest = <TResponse>(deleteOptions?: DefaultRequestOptions) => {
|
|
11
13
|
const { baseUrl, headers } = deleteOptions ?? {};
|
|
12
|
-
const [requestPath, setRequestPath] = useState<string>('');
|
|
13
|
-
const [options, setOptions] = useState<any>();
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const [requestPayload, setRequestPayload] = useState<Record<any, any>>();
|
|
15
|
+
const { headerProvider } = useStore(bootStore);
|
|
16
|
+
const [requestPayload, setRequestPayload] = useState<{ path: string; options?: any }>();
|
|
18
17
|
|
|
19
|
-
const
|
|
18
|
+
const isFutureMutationsPaused = usePauseFutureRequests((state) => state.isFutureMutationsPaused);
|
|
20
19
|
|
|
21
20
|
const { API_URL, TIMEOUT } = useEnvironmentVariables();
|
|
22
21
|
|
|
23
|
-
const
|
|
22
|
+
const storeHeaders = useHeaderStore((state) => state.headers);
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
24
|
+
// Get headers from both the store and the headerProvider (if configured)
|
|
25
|
+
const globalHeaders = useMemo(() => {
|
|
26
|
+
const providerHeaders = headerProvider ? headerProvider() : undefined;
|
|
27
|
+
return { ...providerHeaders, ...storeHeaders };
|
|
28
|
+
}, [storeHeaders, headerProvider]);
|
|
28
29
|
|
|
30
|
+
const sendRequest = async (path: string): Promise<IRequestSuccess<TResponse>> => {
|
|
29
31
|
const requestOptions = {
|
|
30
|
-
path
|
|
32
|
+
path,
|
|
31
33
|
headers: { ...globalHeaders, ...headers },
|
|
32
34
|
baseURL: baseUrl ?? API_URL,
|
|
33
35
|
method: HttpMethod.DELETE,
|
|
34
36
|
timeout: TIMEOUT,
|
|
35
37
|
};
|
|
36
38
|
|
|
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
39
|
const deleteResponse = await makeRequest<TResponse>(requestOptions);
|
|
52
|
-
// }
|
|
53
40
|
|
|
54
41
|
if (deleteResponse.status) {
|
|
55
|
-
|
|
42
|
+
return deleteResponse as IRequestSuccess<TResponse>;
|
|
56
43
|
} else {
|
|
57
|
-
|
|
44
|
+
throw deleteResponse;
|
|
58
45
|
}
|
|
59
46
|
};
|
|
60
47
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
new Promise<IRequestSuccess<TResponse> | IRequestError>((res, rej) => sendRequest(res, rej, queryKey)),
|
|
65
|
-
enabled: false,
|
|
66
|
-
...options,
|
|
48
|
+
// Use mutation instead of query for DELETE operations
|
|
49
|
+
const mutation = useMutation<IRequestSuccess<TResponse>, IRequestError, { path: string }>({
|
|
50
|
+
mutationFn: async ({ path }) => sendRequest(path),
|
|
67
51
|
});
|
|
68
52
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return setOptions(fetchOptions);
|
|
75
|
-
};
|
|
76
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Perform a DELETE request to the specified path
|
|
55
|
+
* @param path - The API path to send the DELETE request to
|
|
56
|
+
* @param options - Optional mutation options (onSuccess, onError, etc.)
|
|
57
|
+
*/
|
|
77
58
|
const destroy = async (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
IRequestSuccess<TResponse | undefined>,
|
|
81
|
-
IRequestError,
|
|
82
|
-
IRequestSuccess<TResponse | undefined>,
|
|
83
|
-
Array<any>
|
|
84
|
-
> & { cached?: boolean }
|
|
59
|
+
path: string,
|
|
60
|
+
options?: MutateOptions<IRequestSuccess<TResponse>, IRequestError, { path: string }, unknown>
|
|
85
61
|
): Promise<IRequestSuccess<TResponse> | undefined> => {
|
|
86
|
-
if (!
|
|
87
|
-
|
|
88
|
-
internalDeleteOptions = internalDeleteOptions
|
|
89
|
-
? { ...internalDeleteOptions, queryKey: [link, {}], enabled: true }
|
|
90
|
-
: { queryKey: [link, {}], enabled: true };
|
|
91
|
-
|
|
92
|
-
await setOptionsAsync(internalDeleteOptions);
|
|
93
|
-
await updatedPathAsync(link);
|
|
94
|
-
|
|
95
|
-
return query.data;
|
|
62
|
+
if (!isFutureMutationsPaused) {
|
|
63
|
+
return mutation.mutateAsync({ path }, options);
|
|
96
64
|
} else {
|
|
97
|
-
setRequestPayload({
|
|
65
|
+
setRequestPayload({ path, options });
|
|
98
66
|
return undefined;
|
|
99
67
|
}
|
|
100
68
|
};
|
|
101
69
|
|
|
70
|
+
// Resume paused requests when mutations are unpaused
|
|
102
71
|
useEffect(() => {
|
|
103
|
-
if (!
|
|
104
|
-
destroy(requestPayload.
|
|
72
|
+
if (!isFutureMutationsPaused && requestPayload) {
|
|
73
|
+
destroy(requestPayload.path, requestPayload.options);
|
|
105
74
|
setRequestPayload(undefined);
|
|
106
75
|
}
|
|
107
76
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
108
|
-
}, [
|
|
109
|
-
|
|
110
|
-
return {
|
|
77
|
+
}, [isFutureMutationsPaused]);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
destroy,
|
|
81
|
+
...mutation,
|
|
82
|
+
isLoading: mutation.isPending || isFutureMutationsPaused,
|
|
83
|
+
// For backward compatibility - mutations don't have initial loading state
|
|
84
|
+
isInitialLoading: false,
|
|
85
|
+
};
|
|
111
86
|
};
|
|
@@ -33,11 +33,17 @@ export const useGetInfiniteRequest = <TResponse extends Record<string, any>>({
|
|
|
33
33
|
keyTracker?: string;
|
|
34
34
|
} & DefaultRequestOptions) => {
|
|
35
35
|
const { API_URL, TIMEOUT } = useEnvironmentVariables();
|
|
36
|
-
const
|
|
37
|
-
const
|
|
36
|
+
const { headerProvider } = useStore(bootStore);
|
|
37
|
+
const storeHeaders = useHeaderStore((state) => state.headers);
|
|
38
|
+
|
|
39
|
+
// Get headers from both the store and the headerProvider (if configured)
|
|
40
|
+
const globalHeaders = useMemo(() => {
|
|
41
|
+
const providerHeaders = headerProvider ? headerProvider() : undefined;
|
|
42
|
+
return { ...providerHeaders, ...storeHeaders };
|
|
43
|
+
}, [storeHeaders, headerProvider]);
|
|
38
44
|
|
|
45
|
+
const [requestPath, setRequestPath] = useState<string>(path);
|
|
39
46
|
const [options, setOptions] = useState<any>(queryOptions);
|
|
40
|
-
useStore(bootStore);
|
|
41
47
|
|
|
42
48
|
const [requestPayload, setRequestPayload] = useState<Record<any, any>>();
|
|
43
49
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import { useEnvironmentVariables } from '../config';
|
|
4
4
|
|
|
5
5
|
import { useStore } from '@tanstack/react-store';
|
|
@@ -33,22 +33,24 @@ export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
|
33
33
|
};
|
|
34
34
|
} & DefaultRequestOptions) => {
|
|
35
35
|
const [requestPath, setRequestPath] = useState<string>(path);
|
|
36
|
-
const [options, setOptions] = useState<any>(queryOptions);
|
|
37
36
|
const [page, setPage] = useState<number>(1);
|
|
38
37
|
|
|
39
38
|
const { API_URL, TIMEOUT } = useEnvironmentVariables();
|
|
40
|
-
const { middleware, pagination: globalPaginationConfig } = useStore(bootStore);
|
|
39
|
+
const { middleware, pagination: globalPaginationConfig, headerProvider } = useStore(bootStore);
|
|
41
40
|
|
|
42
|
-
const
|
|
41
|
+
const storeHeaders = useHeaderStore((state) => state.headers);
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
// Get headers from both the store and the headerProvider (if configured)
|
|
44
|
+
// headerProvider allows reading from cookies/localStorage synchronously
|
|
45
|
+
const globalHeaders = useMemo(() => {
|
|
46
|
+
const providerHeaders = headerProvider ? headerProvider() : undefined;
|
|
47
|
+
// Merge: store headers take precedence over provider headers
|
|
48
|
+
return { ...providerHeaders, ...storeHeaders };
|
|
49
|
+
}, [storeHeaders, headerProvider]);
|
|
45
50
|
|
|
46
51
|
const isFutureQueriesPaused = usePauseFutureRequests((state) => state.isFutureQueriesPaused);
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
51
|
-
queryClient = useMemo(() => queryClient, []);
|
|
53
|
+
const queryClient = useQueryClient();
|
|
52
54
|
|
|
53
55
|
// Merge global and local pagination config
|
|
54
56
|
const pagination = useMemo(
|
|
@@ -59,73 +61,74 @@ export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
|
59
61
|
[globalPaginationConfig, paginationConfig]
|
|
60
62
|
);
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
) => {
|
|
69
|
-
const [url] = queryKey;
|
|
70
|
-
const requestUrl = (url ?? requestPath) as string;
|
|
71
|
-
|
|
72
|
-
const requestOptions = {
|
|
73
|
-
path: requestUrl,
|
|
74
|
-
headers: { ...globalHeaders, ...headers },
|
|
75
|
-
baseURL: baseUrl ?? API_URL,
|
|
76
|
-
timeout: TIMEOUT,
|
|
77
|
-
};
|
|
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
|
-
|
|
85
|
-
let getResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
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,
|
|
64
|
+
/**
|
|
65
|
+
* Core request function that makes the actual HTTP request
|
|
66
|
+
*/
|
|
67
|
+
const executeRequest = useCallback(
|
|
68
|
+
async (requestUrl: string): Promise<IRequestSuccess<TResponse>> => {
|
|
69
|
+
const requestOptions = {
|
|
91
70
|
path: requestUrl,
|
|
92
|
-
|
|
71
|
+
headers: { ...globalHeaders, ...headers },
|
|
72
|
+
baseURL: baseUrl ?? API_URL,
|
|
73
|
+
timeout: TIMEOUT,
|
|
93
74
|
};
|
|
94
75
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
76
|
+
// Create the final handler that makes the actual request
|
|
77
|
+
const finalHandler: MiddlewareNext<TResponse> = async (options) => {
|
|
78
|
+
const finalOptions = options ? { ...requestOptions, ...options } : requestOptions;
|
|
79
|
+
return await makeRequest<TResponse>(finalOptions);
|
|
80
|
+
};
|
|
100
81
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
82
|
+
let getResponse: IRequestError | IRequestSuccess<TResponse>;
|
|
83
|
+
|
|
84
|
+
// If middleware is available, execute the middleware chain
|
|
85
|
+
if (middleware && Array.isArray(middleware) && middleware.length > 0) {
|
|
86
|
+
const context: MiddlewareContext<TResponse> = {
|
|
87
|
+
baseUrl: baseUrl ?? API_URL,
|
|
88
|
+
path: requestUrl,
|
|
89
|
+
options: requestOptions,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
getResponse = await executeMiddlewareChain<TResponse>(middleware, context, finalHandler);
|
|
93
|
+
} else {
|
|
94
|
+
// Otherwise, just make the request directly
|
|
95
|
+
getResponse = await makeRequest<TResponse>(requestOptions);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (getResponse.status) {
|
|
99
|
+
return getResponse as IRequestSuccess<TResponse>;
|
|
100
|
+
} else {
|
|
101
|
+
throw getResponse;
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
[globalHeaders, headers, baseUrl, API_URL, TIMEOUT, middleware]
|
|
105
|
+
);
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
107
|
+
// The declarative query - only runs when load is true
|
|
108
|
+
const query = useQuery({
|
|
109
|
+
queryKey: [requestPath, {}] as const,
|
|
110
|
+
queryFn: async ({ queryKey }) => {
|
|
111
|
+
const [url] = queryKey;
|
|
112
|
+
return executeRequest(url);
|
|
113
|
+
},
|
|
114
|
+
// Only enable when load is explicitly true AND queries aren't paused
|
|
115
|
+
enabled: load === true && !isFutureQueriesPaused,
|
|
116
|
+
...queryOptions,
|
|
114
117
|
});
|
|
115
118
|
|
|
119
|
+
// Update request path when prop changes
|
|
116
120
|
useEffect(() => {
|
|
117
|
-
if (path) {
|
|
121
|
+
if (path && path !== requestPath) {
|
|
118
122
|
setRequestPath(path);
|
|
119
123
|
}
|
|
120
|
-
}, [path]);
|
|
124
|
+
}, [path, requestPath]);
|
|
121
125
|
|
|
126
|
+
// Track query key for external reference
|
|
122
127
|
useEffect(() => {
|
|
123
128
|
if (keyTracker) {
|
|
124
|
-
// set expiration time for the tracker
|
|
125
129
|
queryClient.setQueryDefaults([keyTracker], {
|
|
126
130
|
staleTime: Infinity,
|
|
127
131
|
});
|
|
128
|
-
|
|
129
132
|
queryClient.setQueryData([keyTracker], [requestPath, {}]);
|
|
130
133
|
}
|
|
131
134
|
}, [keyTracker, requestPath, queryClient, queryOptions?.staleTime]);
|
|
@@ -133,142 +136,149 @@ export const useGetRequest = <TResponse extends Record<string, any>>({
|
|
|
133
136
|
/**
|
|
134
137
|
* Extract pagination data from response using configured extractor
|
|
135
138
|
*/
|
|
136
|
-
const getPaginationData = (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
139
|
+
const getPaginationData = useCallback(
|
|
140
|
+
(response: IRequestSuccess<TResponse>): IPagination | undefined => {
|
|
141
|
+
const extractPagination =
|
|
142
|
+
pagination.extractPagination ||
|
|
143
|
+
((res) => {
|
|
144
|
+
if ('pagination' in res.data) {
|
|
145
|
+
return res.data.pagination as IPagination;
|
|
146
|
+
}
|
|
147
|
+
return undefined;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return extractPagination(response);
|
|
151
|
+
},
|
|
152
|
+
[pagination.extractPagination]
|
|
153
|
+
);
|
|
146
154
|
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Construct a pagination URL using the configured builder
|
|
157
|
+
*/
|
|
158
|
+
const constructPaginationLink = useCallback(
|
|
159
|
+
(link: string, pageNumber: number) => {
|
|
160
|
+
const buildPaginationUrl =
|
|
161
|
+
pagination.buildPaginationUrl ||
|
|
162
|
+
((url, targetPage) => {
|
|
163
|
+
const [pathname, queryString] = url.split('?');
|
|
164
|
+
const queryParams = new URLSearchParams(queryString || '');
|
|
165
|
+
const pageParamName = pagination.pageParamName || 'page';
|
|
166
|
+
|
|
167
|
+
queryParams.set(pageParamName, String(targetPage));
|
|
168
|
+
return pathname + '?' + queryParams.toString();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
return buildPaginationUrl(link, pageNumber);
|
|
172
|
+
},
|
|
173
|
+
[pagination.buildPaginationUrl, pagination.pageParamName]
|
|
174
|
+
);
|
|
149
175
|
|
|
150
176
|
/**
|
|
151
177
|
* Navigate to the next page if available
|
|
152
178
|
*/
|
|
153
|
-
const nextPage = () => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
179
|
+
const nextPage = useCallback(() => {
|
|
180
|
+
const data = query.data as IRequestSuccess<TResponse> | undefined;
|
|
181
|
+
if (!data) return;
|
|
182
|
+
|
|
183
|
+
const paginationData = getPaginationData(data);
|
|
157
184
|
if (!paginationData) return;
|
|
158
185
|
|
|
159
186
|
if (
|
|
160
187
|
paginationData.next_page !== paginationData.current_page &&
|
|
161
188
|
paginationData.next_page > paginationData.current_page
|
|
162
189
|
) {
|
|
163
|
-
|
|
190
|
+
const newPath = constructPaginationLink(requestPath, paginationData.next_page);
|
|
191
|
+
setRequestPath(newPath);
|
|
192
|
+
setPage(paginationData.next_page);
|
|
164
193
|
}
|
|
165
|
-
};
|
|
194
|
+
}, [query.data, getPaginationData, constructPaginationLink, requestPath]);
|
|
166
195
|
|
|
167
196
|
/**
|
|
168
197
|
* Navigate to the previous page if available
|
|
169
198
|
*/
|
|
170
|
-
const prevPage = () => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
199
|
+
const prevPage = useCallback(() => {
|
|
200
|
+
const data = query.data as IRequestSuccess<TResponse> | undefined;
|
|
201
|
+
if (!data) return;
|
|
202
|
+
|
|
203
|
+
const paginationData = getPaginationData(data);
|
|
174
204
|
if (!paginationData) return;
|
|
175
205
|
|
|
176
206
|
if (
|
|
177
207
|
paginationData.previous_page !== paginationData.current_page &&
|
|
178
208
|
paginationData.previous_page < paginationData.current_page
|
|
179
209
|
) {
|
|
180
|
-
|
|
210
|
+
const newPath = constructPaginationLink(requestPath, paginationData.previous_page);
|
|
211
|
+
setRequestPath(newPath);
|
|
212
|
+
setPage(paginationData.previous_page);
|
|
181
213
|
}
|
|
182
|
-
};
|
|
214
|
+
}, [query.data, getPaginationData, constructPaginationLink, requestPath]);
|
|
183
215
|
|
|
184
216
|
/**
|
|
185
|
-
*
|
|
217
|
+
* Navigate to a specific page
|
|
186
218
|
*/
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const oldPage = Number(queryParams.get(pageParamName));
|
|
197
|
-
queryParams.set(pageParamName, String(page));
|
|
198
|
-
|
|
199
|
-
const newUrl = pathname + '?' + queryParams.toString();
|
|
200
|
-
|
|
201
|
-
// only update page when pagination number changed
|
|
202
|
-
if (oldPage !== pageNumber) {
|
|
203
|
-
setPage(pageNumber);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return newUrl;
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
return buildPaginationUrl(link, pageNumber);
|
|
210
|
-
};
|
|
219
|
+
const gotoPage = useCallback(
|
|
220
|
+
(pageNumber: number) => {
|
|
221
|
+
const newPath = constructPaginationLink(requestPath, pageNumber);
|
|
222
|
+
setRequestPath(newPath);
|
|
223
|
+
setPage(pageNumber);
|
|
224
|
+
},
|
|
225
|
+
[constructPaginationLink, requestPath]
|
|
226
|
+
);
|
|
211
227
|
|
|
212
228
|
/**
|
|
213
|
-
*
|
|
229
|
+
* Imperative GET request - fetches data from a dynamic URL
|
|
230
|
+
* Uses queryClient.fetchQuery for proper caching and deduplication
|
|
231
|
+
*
|
|
232
|
+
* @param url - The URL to fetch from
|
|
233
|
+
* @param fetchOptions - Optional query options (staleTime, gcTime, etc.)
|
|
234
|
+
* @returns Promise resolving to the response data
|
|
214
235
|
*/
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
236
|
+
const get = useCallback(
|
|
237
|
+
async (
|
|
238
|
+
url: string,
|
|
239
|
+
fetchOptions?: {
|
|
240
|
+
staleTime?: number;
|
|
241
|
+
gcTime?: number;
|
|
242
|
+
}
|
|
243
|
+
): Promise<IRequestSuccess<TResponse>> => {
|
|
244
|
+
if (isFutureQueriesPaused) {
|
|
245
|
+
throw new Error('Queries are currently paused');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Use fetchQuery for imperative fetching - this properly handles caching
|
|
249
|
+
const result = await queryClient.fetchQuery({
|
|
250
|
+
queryKey: [url, {}] as const,
|
|
251
|
+
queryFn: () => executeRequest(url),
|
|
252
|
+
staleTime: fetchOptions?.staleTime,
|
|
253
|
+
gcTime: fetchOptions?.gcTime,
|
|
254
|
+
});
|
|
230
255
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
IRequestError,
|
|
236
|
-
IRequestSuccess<TResponse | undefined>,
|
|
237
|
-
Array<any>
|
|
238
|
-
>
|
|
239
|
-
): Promise<IRequestSuccess<TResponse> | undefined> => {
|
|
240
|
-
if (!isFutureQueriesPaused) {
|
|
241
|
-
await setOptionsAsync(fetchOptions);
|
|
242
|
-
await updatedPathAsync(link);
|
|
243
|
-
|
|
244
|
-
return query.data;
|
|
245
|
-
} else {
|
|
246
|
-
setRequestPayload({ link, fetchOptions });
|
|
247
|
-
return undefined;
|
|
248
|
-
}
|
|
249
|
-
};
|
|
256
|
+
return result;
|
|
257
|
+
},
|
|
258
|
+
[queryClient, executeRequest, isFutureQueriesPaused]
|
|
259
|
+
);
|
|
250
260
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}, [isFutureQueriesPaused]);
|
|
261
|
+
/**
|
|
262
|
+
* Refetch the current query with the existing path
|
|
263
|
+
*/
|
|
264
|
+
const refetch = useCallback(() => {
|
|
265
|
+
return query.refetch();
|
|
266
|
+
}, [query]);
|
|
258
267
|
|
|
259
268
|
return {
|
|
260
269
|
...query,
|
|
261
|
-
isLoading:
|
|
270
|
+
isLoading: query.isLoading || isFutureQueriesPaused,
|
|
262
271
|
setRequestPath,
|
|
263
272
|
nextPage,
|
|
264
273
|
prevPage,
|
|
265
274
|
get,
|
|
266
275
|
gotoPage,
|
|
267
276
|
page,
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
getPaginationData:
|
|
271
|
-
|
|
277
|
+
refetch,
|
|
278
|
+
queryKey: [requestPath, {}] as const,
|
|
279
|
+
getPaginationData: () => {
|
|
280
|
+
const data = query.data as IRequestSuccess<TResponse> | undefined;
|
|
281
|
+
return data ? getPaginationData(data) : undefined;
|
|
272
282
|
},
|
|
273
283
|
};
|
|
274
284
|
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { MutateOptions } from '@tanstack/react-query';
|
|
2
2
|
import { useMutation } from '@tanstack/react-query';
|
|
3
3
|
import { useStore } from '@tanstack/react-store';
|
|
4
|
-
import { useEffect, useState } from 'react';
|
|
4
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
5
5
|
import { useEnvironmentVariables } from '../config';
|
|
6
6
|
import { bootStore } from '../config/bootStore';
|
|
7
|
-
import { scrollToTop } from '../helpers';
|
|
8
7
|
import { useUploadProgress } from '../hooks';
|
|
9
8
|
import { HttpMethod, makeRequest } from '../request';
|
|
10
9
|
import type { IRequestError, IRequestSuccess } from '../request/request.interface';
|
|
@@ -14,12 +13,19 @@ import type { DefaultRequestOptions } from './queries.interface';
|
|
|
14
13
|
export const usePatchRequest = <TResponse>({ path, baseUrl, headers }: { path: string } & DefaultRequestOptions) => {
|
|
15
14
|
const { API_URL, TIMEOUT } = useEnvironmentVariables();
|
|
16
15
|
const { uploadProgressPercent, onUploadProgress } = useUploadProgress();
|
|
17
|
-
const
|
|
16
|
+
const { headerProvider } = useStore(bootStore);
|
|
17
|
+
|
|
18
|
+
const storeHeaders = useHeaderStore((state) => state.headers);
|
|
19
|
+
|
|
20
|
+
// Get headers from both the store and the headerProvider (if configured)
|
|
21
|
+
const globalHeaders = useMemo(() => {
|
|
22
|
+
const providerHeaders = headerProvider ? headerProvider() : undefined;
|
|
23
|
+
return { ...providerHeaders, ...storeHeaders };
|
|
24
|
+
}, [storeHeaders, headerProvider]);
|
|
18
25
|
|
|
19
26
|
const [requestPayload, setRequestPayload] = useState<Record<any, any>>();
|
|
20
27
|
|
|
21
28
|
const isFutureMutationsPaused = usePauseFutureRequests((state) => state.isFutureMutationsPaused);
|
|
22
|
-
const { context } = useStore(bootStore);
|
|
23
29
|
|
|
24
30
|
const sendRequest = async (res: (value: any) => void, rej: (reason?: any) => void, data: any) => {
|
|
25
31
|
// get request headers
|
|
@@ -54,16 +60,8 @@ export const usePatchRequest = <TResponse>({ path, baseUrl, headers }: { path: s
|
|
|
54
60
|
const patchResponse = await makeRequest<TResponse>(requestOptions);
|
|
55
61
|
// }
|
|
56
62
|
if (patchResponse.status) {
|
|
57
|
-
// scroll to top after success
|
|
58
|
-
if (context !== 'app') {
|
|
59
|
-
scrollToTop();
|
|
60
|
-
}
|
|
61
63
|
res(patchResponse as IRequestSuccess<TResponse>);
|
|
62
64
|
} else {
|
|
63
|
-
// scroll to top after error
|
|
64
|
-
if (context !== 'app') {
|
|
65
|
-
scrollToTop();
|
|
66
|
-
}
|
|
67
65
|
rej(patchResponse);
|
|
68
66
|
}
|
|
69
67
|
};
|