@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.
@@ -1,7 +1,9 @@
1
- import type { QueryKey, UseQueryOptions } from '@tanstack/react-query';
2
- import { useQuery } from '@tanstack/react-query';
3
- import { useEffect, useState } from 'react';
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
- // const { middleware: middlewares } = useStore(bootStore);
16
- // const [middleware] = middlewares as unknown as MiddlewareFunction[];
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 isFutureQueriesPaused = usePauseFutureRequests((state) => state.isFutureQueriesPaused);
18
+ const isFutureMutationsPaused = usePauseFutureRequests((state) => state.isFutureMutationsPaused);
20
19
 
21
20
  const { API_URL, TIMEOUT } = useEnvironmentVariables();
22
21
 
23
- const globalHeaders = useHeaderStore((state) => state.headers);
22
+ const storeHeaders = useHeaderStore((state) => state.headers);
24
23
 
25
- const sendRequest = async (res: (value: any) => void, rej: (reason?: any) => void, queryKey: QueryKey) => {
26
- const [url] = queryKey;
27
- const requestUrl = (url ?? requestPath) as string;
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: requestUrl,
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
- res(deleteResponse as IRequestSuccess<TResponse>);
42
+ return deleteResponse as IRequestSuccess<TResponse>;
56
43
  } else {
57
- rej(deleteResponse);
44
+ throw deleteResponse;
58
45
  }
59
46
  };
60
47
 
61
- const query = useQuery<any, any, IRequestSuccess<TResponse>>({
62
- queryKey: [requestPath, {}],
63
- queryFn: ({ queryKey }) =>
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
- const updatedPathAsync = async (link: string) => {
70
- return setRequestPath(link);
71
- };
72
-
73
- const setOptionsAsync = async (fetchOptions: any) => {
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
- link: string,
79
- internalDeleteOptions?: UseQueryOptions<
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 (!isFutureQueriesPaused) {
87
- // set enabled to be true for every delete
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({ link, internalDeleteOptions });
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 (!isFutureQueriesPaused && requestPayload) {
104
- destroy(requestPayload.link, requestPayload.internalDeleteOptions);
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
- }, [isFutureQueriesPaused]);
109
-
110
- return { destroy, ...query, isLoading: (query.isLoading as boolean) || isFutureQueriesPaused };
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 globalHeaders = useHeaderStore((state) => state.headers);
37
- const [requestPath, setRequestPath] = useState<string>(path);
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 { QueryKey, useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
2
- import { startTransition, useEffect, useMemo, useState } from 'react';
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 globalHeaders = useHeaderStore((state) => state.headers);
41
+ const storeHeaders = useHeaderStore((state) => state.headers);
43
42
 
44
- const [requestPayload, setRequestPayload] = useState<Record<any, any>>();
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
- let queryClient = useQueryClient();
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
- const sendRequest = async (
63
- res: (
64
- value: IRequestError | IRequestSuccess<TResponse> | PromiseLike<IRequestError | IRequestSuccess<TResponse>>
65
- ) => void,
66
- rej: (reason?: any) => void,
67
- queryKey: QueryKey
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
- options: requestOptions,
71
+ headers: { ...globalHeaders, ...headers },
72
+ baseURL: baseUrl ?? API_URL,
73
+ timeout: TIMEOUT,
93
74
  };
94
75
 
95
- getResponse = await executeMiddlewareChain<TResponse>(middleware, context, finalHandler);
96
- } else {
97
- // Otherwise, just make the request directly
98
- getResponse = await makeRequest<TResponse>(requestOptions);
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
- if (getResponse.status) {
102
- res(getResponse as IRequestSuccess<TResponse>);
103
- } else {
104
- rej(getResponse);
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
- const query = useQuery<any, any, IRequestSuccess<TResponse>>({
109
- queryKey: [requestPath, {}],
110
- queryFn: ({ queryKey }) =>
111
- new Promise<IRequestSuccess<TResponse> | IRequestError>((res, rej) => sendRequest(res, rej, queryKey)),
112
- enabled: load && !isFutureQueriesPaused,
113
- ...options,
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 = (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
- });
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
- return extractPagination(response);
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
- // 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);
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
- setRequestPath(constructPaginationLink(requestPath, paginationData.next_page));
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
- // 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);
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
- setRequestPath(constructPaginationLink(requestPath, paginationData.previous_page));
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
- * Construct a pagination URL using the configured builder
217
+ * Navigate to a specific page
186
218
  */
187
- const constructPaginationLink = (link: string, pageNumber: number) => {
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';
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
- * Navigate to a specific page
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 gotoPage = (pageNumber: number) => {
216
- setRequestPath(constructPaginationLink(requestPath, pageNumber));
217
- };
218
-
219
- const updatedPathAsync = async (link: string) => {
220
- startTransition(() => {
221
- setRequestPath(link);
222
- });
223
- };
224
-
225
- const setOptionsAsync = async (fetchOptions: any) => {
226
- startTransition(() => {
227
- setOptions(fetchOptions);
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
- const get = async (
232
- link: string,
233
- fetchOptions?: UseQueryOptions<
234
- IRequestSuccess<TResponse | undefined>,
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
- useEffect(() => {
252
- if (!isFutureQueriesPaused && requestPayload) {
253
- get(requestPayload.link, requestPayload.fetchOptions);
254
- setRequestPayload(undefined);
255
- }
256
- // eslint-disable-next-line react-hooks/exhaustive-deps
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: (query.isLoading as boolean) || isFutureQueriesPaused,
270
+ isLoading: query.isLoading || isFutureQueriesPaused,
262
271
  setRequestPath,
263
272
  nextPage,
264
273
  prevPage,
265
274
  get,
266
275
  gotoPage,
267
276
  page,
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;
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 globalHeaders = useHeaderStore((state) => state.headers);
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
  };