@promoboxx/use-filter 1.11.2 → 2.0.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/cjs/_virtual/_rolldown/runtime.js +29 -0
- package/dist/cjs/lib/buildDefaultFilterInfo.d.ts +5 -0
- package/dist/cjs/lib/buildDefaultFilterInfo.js +27 -0
- package/dist/{lib → cjs/lib}/getOffsetFromPage.d.ts +2 -1
- package/dist/cjs/lib/getOffsetFromPage.js +8 -0
- package/dist/{lib → cjs/lib}/getPageFromOffset.d.ts +2 -1
- package/dist/cjs/lib/getPageFromOffset.js +8 -0
- package/dist/{lib → cjs/lib}/shallowEqual.d.ts +2 -1
- package/dist/cjs/lib/shallowEqual.js +24 -0
- package/dist/cjs/store/index.d.ts +14 -0
- package/dist/cjs/store/index.js +18 -0
- package/dist/cjs/store/localStorageStore.d.ts +5 -0
- package/dist/cjs/store/localStorageStore.js +33 -0
- package/dist/cjs/store/memoryStore.d.ts +5 -0
- package/dist/cjs/store/memoryStore.js +25 -0
- package/dist/cjs/store/reduxHelpers/createActions.d.ts +16 -0
- package/dist/cjs/store/reduxHelpers/createActions.js +16 -0
- package/dist/cjs/store/reduxHelpers/createReducer.d.ts +10 -0
- package/dist/cjs/store/reduxHelpers/createReducer.js +25 -0
- package/dist/cjs/store/reduxStore.d.ts +18 -0
- package/dist/cjs/store/reduxStore.js +63 -0
- package/dist/cjs/store/urlParamStore.d.ts +8 -0
- package/dist/cjs/store/urlParamStore.js +68 -0
- package/dist/cjs/useFilter.d.ts +106 -0
- package/dist/cjs/useFilter.js +251 -0
- package/dist/cjs/useSimpleFilter.d.ts +89 -0
- package/dist/cjs/useSimpleFilter.js +198 -0
- package/dist/esm/lib/buildDefaultFilterInfo.d.mts +6 -0
- package/dist/esm/lib/buildDefaultFilterInfo.mjs +27 -0
- package/dist/esm/lib/getOffsetFromPage.d.mts +4 -0
- package/dist/esm/lib/getOffsetFromPage.mjs +7 -0
- package/dist/esm/lib/getPageFromOffset.d.mts +4 -0
- package/dist/esm/lib/getPageFromOffset.mjs +7 -0
- package/dist/esm/lib/shallowEqual.d.mts +4 -0
- package/dist/esm/lib/shallowEqual.mjs +23 -0
- package/dist/esm/store/index.d.mts +14 -0
- package/dist/esm/store/index.mjs +15 -0
- package/dist/esm/store/localStorageStore.d.mts +6 -0
- package/dist/esm/store/localStorageStore.mjs +32 -0
- package/dist/esm/store/memoryStore.d.mts +6 -0
- package/dist/esm/store/memoryStore.mjs +24 -0
- package/dist/esm/store/reduxHelpers/createActions.d.mts +16 -0
- package/dist/esm/store/reduxHelpers/createActions.mjs +15 -0
- package/dist/esm/store/reduxHelpers/createReducer.d.mts +11 -0
- package/dist/esm/store/reduxHelpers/createReducer.mjs +24 -0
- package/dist/esm/store/reduxStore.d.mts +18 -0
- package/dist/esm/store/reduxStore.mjs +61 -0
- package/dist/esm/store/urlParamStore.d.mts +8 -0
- package/dist/esm/store/urlParamStore.mjs +63 -0
- package/dist/esm/useFilter.d.mts +106 -0
- package/dist/esm/useFilter.mjs +251 -0
- package/dist/esm/useSimpleFilter.d.mts +89 -0
- package/dist/esm/useSimpleFilter.mjs +198 -0
- package/package.json +33 -43
- package/dist/lib/buildDefaultFilterInfo.d.ts +0 -3
- package/dist/lib/buildDefaultFilterInfo.js +0 -35
- package/dist/lib/getOffsetFromPage.js +0 -6
- package/dist/lib/getPageFromOffset.js +0 -6
- package/dist/lib/shallowEqual.js +0 -23
- package/dist/store/index.d.ts +0 -10
- package/dist/store/index.js +0 -16
- package/dist/store/localStorageStore.d.ts +0 -3
- package/dist/store/localStorageStore.js +0 -31
- package/dist/store/memoryStore.d.ts +0 -3
- package/dist/store/memoryStore.js +0 -23
- package/dist/store/reduxHelpers/createActions.d.ts +0 -16
- package/dist/store/reduxHelpers/createActions.js +0 -27
- package/dist/store/reduxHelpers/createReducer.d.ts +0 -8
- package/dist/store/reduxHelpers/createReducer.js +0 -26
- package/dist/store/reduxStore.d.ts +0 -15
- package/dist/store/reduxStore.js +0 -67
- package/dist/store/urlParamStore.d.ts +0 -4
- package/dist/store/urlParamStore.js +0 -91
- package/dist/useFilter.d.ts +0 -103
- package/dist/useFilter.js +0 -254
- package/dist/useSimpleFilter.d.ts +0 -86
- package/dist/useSimpleFilter.js +0 -173
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
const require_lib_getOffsetFromPage = require('./lib/getOffsetFromPage.js');
|
|
2
|
+
const require_lib_getPageFromOffset = require('./lib/getPageFromOffset.js');
|
|
3
|
+
const require_lib_buildDefaultFilterInfo = require('./lib/buildDefaultFilterInfo.js');
|
|
4
|
+
const require_lib_shallowEqual = require('./lib/shallowEqual.js');
|
|
5
|
+
const require_store_index = require('./store/index.js');
|
|
6
|
+
let react = require("react");
|
|
7
|
+
|
|
8
|
+
//#region src/useFilter.ts
|
|
9
|
+
function useFilter(namespace, options) {
|
|
10
|
+
const ctxRefValue = {
|
|
11
|
+
namespace,
|
|
12
|
+
onChange: options.onChange,
|
|
13
|
+
debounceDuration: options.debounceDuration,
|
|
14
|
+
defaultFilterInfo: options.defaultFilterInfo,
|
|
15
|
+
onBeforeSaveFilter: options.onBeforeSaveFilter,
|
|
16
|
+
store: options.store
|
|
17
|
+
};
|
|
18
|
+
const ctxRef = (0, react.useRef)(ctxRefValue);
|
|
19
|
+
(0, react.useEffect)(() => {
|
|
20
|
+
ctxRef.current = ctxRefValue;
|
|
21
|
+
});
|
|
22
|
+
const [filterInfo, setFilterInfoState] = (0, react.useState)(() => {
|
|
23
|
+
const fromStore = require_store_index.getFilterStore(ctxRef.current.store).getFilter(namespace);
|
|
24
|
+
if (fromStore) {
|
|
25
|
+
const filterInfo = require_lib_buildDefaultFilterInfo({
|
|
26
|
+
...fromStore,
|
|
27
|
+
shouldRunImmediately: true,
|
|
28
|
+
filter: {
|
|
29
|
+
...options.defaultFilterInfo?.filter,
|
|
30
|
+
...fromStore.filter
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return filterInfo;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
const [data, setData] = (0, react.useState)(() => require_store_index.getFilterStore(ctxRef.current.store).getData(namespace));
|
|
37
|
+
const [isLoading, setIsLoading] = (0, react.useState)(!filterInfo);
|
|
38
|
+
const doesFilterExist = (0, react.useRef)(!!filterInfo);
|
|
39
|
+
const lastRefreshAtRef = (0, react.useRef)(options.shouldForceRunOnMount ? -1 : filterInfo ? filterInfo.lastRefreshAt : -1);
|
|
40
|
+
const updateReasonRef = (0, react.useRef)("initial");
|
|
41
|
+
(0, react.useEffect)(() => {
|
|
42
|
+
setIsLoading(true);
|
|
43
|
+
if (!filterInfo) {
|
|
44
|
+
setFilterInfoState({
|
|
45
|
+
...require_lib_buildDefaultFilterInfo(ctxRef.current.defaultFilterInfo),
|
|
46
|
+
shouldRunImmediately: true
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (lastRefreshAtRef.current === filterInfo.lastRefreshAt) {
|
|
51
|
+
setIsLoading(false);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const makeRequest = () => {
|
|
55
|
+
lastRefreshAtRef.current = filterInfo.lastRefreshAt;
|
|
56
|
+
const response = ctxRef.current.onChange(filterInfo, updateReasonRef.current);
|
|
57
|
+
require_store_index.getFilterStore(ctxRef.current.store).saveFilter(namespace, ctxRef.current.onBeforeSaveFilter ? ctxRef.current.onBeforeSaveFilter(filterInfo) : filterInfo);
|
|
58
|
+
if (!response) {
|
|
59
|
+
setIsLoading(false);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
function handleResponse(response) {
|
|
63
|
+
if (!response) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (response.filterInfo) {
|
|
67
|
+
setFilterInfoState((previous) => {
|
|
68
|
+
invariant(!!response.filterInfo, "");
|
|
69
|
+
invariant(previous != null, "handleResponse called without filterInfo");
|
|
70
|
+
const extra = {};
|
|
71
|
+
const { page, offset, totalResults, pageSize, nextCursor, ...filterInfoFromResponse } = response.filterInfo;
|
|
72
|
+
const pageSizeNumber = Number(pageSize || previous.pageSize);
|
|
73
|
+
if (page != null && offset == null) {
|
|
74
|
+
extra.offset = require_lib_getOffsetFromPage(page, pageSizeNumber);
|
|
75
|
+
extra.page = page;
|
|
76
|
+
} else if (page == null && offset != null) {
|
|
77
|
+
const offsetNumber = Number(offset);
|
|
78
|
+
extra.offset = offsetNumber;
|
|
79
|
+
extra.page = require_lib_getPageFromOffset(offsetNumber, pageSizeNumber);
|
|
80
|
+
}
|
|
81
|
+
if ("totalResults" in response.filterInfo) {
|
|
82
|
+
extra.totalResults = Number(totalResults || 0);
|
|
83
|
+
extra.totalPages = Math.ceil(extra.totalResults / pageSizeNumber);
|
|
84
|
+
}
|
|
85
|
+
if ("nextCursor" in response.filterInfo) {
|
|
86
|
+
extra.nextCursor = nextCursor;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
...previous,
|
|
90
|
+
...filterInfoFromResponse,
|
|
91
|
+
...extra
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (response.data) {
|
|
96
|
+
setData(response.data);
|
|
97
|
+
require_store_index.getFilterStore(ctxRef.current.store).saveData(namespace, response.data);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (isPromise(response)) {
|
|
101
|
+
response.then(handleResponse).finally(() => setIsLoading(false));
|
|
102
|
+
} else {
|
|
103
|
+
handleResponse(response);
|
|
104
|
+
setIsLoading(false);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
let timeout = undefined;
|
|
108
|
+
if (filterInfo.shouldRunImmediately) {
|
|
109
|
+
makeRequest();
|
|
110
|
+
} else {
|
|
111
|
+
timeout = setTimeout(makeRequest, ctxRef.current.debounceDuration != null ? ctxRef.current.debounceDuration : 500);
|
|
112
|
+
}
|
|
113
|
+
return () => {
|
|
114
|
+
if (timeout) {
|
|
115
|
+
clearTimeout(timeout);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}, [filterInfo, namespace]);
|
|
119
|
+
const api = {
|
|
120
|
+
isLoading,
|
|
121
|
+
data,
|
|
122
|
+
doesFilterExist: doesFilterExist.current,
|
|
123
|
+
filterInfo: filterInfo || require_lib_buildDefaultFilterInfo(options.defaultFilterInfo),
|
|
124
|
+
updateReason: updateReasonRef.current,
|
|
125
|
+
updateFilter: (0, react.useCallback)((filter, shouldRunImmediately = false) => {
|
|
126
|
+
updateReasonRef.current = "filter";
|
|
127
|
+
setFilterInfoState((previous) => {
|
|
128
|
+
invariant(previous != null, "updateFilter called without filterInfo");
|
|
129
|
+
const nextFilter = {
|
|
130
|
+
...previous.filter,
|
|
131
|
+
...filter
|
|
132
|
+
};
|
|
133
|
+
if (require_lib_shallowEqual(previous.filter, nextFilter)) {
|
|
134
|
+
return previous;
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
...previous,
|
|
138
|
+
offset: 0,
|
|
139
|
+
page: 1,
|
|
140
|
+
totalResults: 1,
|
|
141
|
+
totalPages: 1,
|
|
142
|
+
filter: nextFilter,
|
|
143
|
+
lastRefreshAt: new Date().getTime(),
|
|
144
|
+
cursor: undefined,
|
|
145
|
+
nextCursor: undefined,
|
|
146
|
+
shouldRunImmediately
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
}, []),
|
|
150
|
+
resetFilter: (0, react.useCallback)((shouldRunImmediately = false) => {
|
|
151
|
+
updateReasonRef.current = "filter";
|
|
152
|
+
setFilterInfoState({
|
|
153
|
+
...require_lib_buildDefaultFilterInfo(ctxRef.current.defaultFilterInfo),
|
|
154
|
+
lastRefreshAt: new Date().getTime(),
|
|
155
|
+
shouldRunImmediately
|
|
156
|
+
});
|
|
157
|
+
}, []),
|
|
158
|
+
setOffset: (0, react.useCallback)((offset, shouldRunImmediately = false) => {
|
|
159
|
+
updateReasonRef.current = "pagination";
|
|
160
|
+
setFilterInfoState((previous) => {
|
|
161
|
+
invariant(previous != null, "setOffset called without filterInfo");
|
|
162
|
+
const offsetNumber = Number(offset);
|
|
163
|
+
return {
|
|
164
|
+
...previous,
|
|
165
|
+
offset: offsetNumber,
|
|
166
|
+
page: require_lib_getPageFromOffset(offsetNumber, previous.pageSize),
|
|
167
|
+
lastRefreshAt: new Date().getTime(),
|
|
168
|
+
shouldRunImmediately
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
}, []),
|
|
172
|
+
setPage: (0, react.useCallback)((page, shouldRunImmediately = false) => {
|
|
173
|
+
updateReasonRef.current = "pagination";
|
|
174
|
+
setFilterInfoState((previous) => {
|
|
175
|
+
invariant(previous != null, "setPage called without filterInfo");
|
|
176
|
+
const pageNumber = Number(page);
|
|
177
|
+
return {
|
|
178
|
+
...previous,
|
|
179
|
+
offset: require_lib_getOffsetFromPage(pageNumber, previous.pageSize),
|
|
180
|
+
page: pageNumber,
|
|
181
|
+
lastRefreshAt: new Date().getTime(),
|
|
182
|
+
shouldRunImmediately
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
}, []),
|
|
186
|
+
setPageSize: (0, react.useCallback)((pageSize, shouldRunImmediately = false) => {
|
|
187
|
+
updateReasonRef.current = "pagination";
|
|
188
|
+
setFilterInfoState((previous) => {
|
|
189
|
+
invariant(previous != null, "setPageSize called without filterInfo");
|
|
190
|
+
const pageSizeNumber = Number(pageSize);
|
|
191
|
+
const page = require_lib_getPageFromOffset(previous.offset, pageSizeNumber);
|
|
192
|
+
const offset = require_lib_getOffsetFromPage(page, pageSizeNumber);
|
|
193
|
+
return {
|
|
194
|
+
...previous,
|
|
195
|
+
pageSize: pageSizeNumber,
|
|
196
|
+
offset,
|
|
197
|
+
page,
|
|
198
|
+
lastRefreshAt: new Date().getTime(),
|
|
199
|
+
shouldRunImmediately
|
|
200
|
+
};
|
|
201
|
+
});
|
|
202
|
+
}, []),
|
|
203
|
+
setSort: (0, react.useCallback)((sort, shouldRunImmediately = false) => {
|
|
204
|
+
updateReasonRef.current = "filter";
|
|
205
|
+
setFilterInfoState((previous) => {
|
|
206
|
+
invariant(previous != null, "setSort called without filterInfo");
|
|
207
|
+
return {
|
|
208
|
+
...previous,
|
|
209
|
+
sort,
|
|
210
|
+
lastRefreshAt: new Date().getTime(),
|
|
211
|
+
shouldRunImmediately
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
}, []),
|
|
215
|
+
setCursor: (0, react.useCallback)((cursor, shouldRunImmediately = false) => {
|
|
216
|
+
setFilterInfoState((previous) => {
|
|
217
|
+
updateReasonRef.current = "pagination";
|
|
218
|
+
invariant(previous != null, "setCursor called without filterInfo");
|
|
219
|
+
return {
|
|
220
|
+
...previous,
|
|
221
|
+
cursor,
|
|
222
|
+
lastRefreshAt: new Date().getTime(),
|
|
223
|
+
shouldRunImmediately
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
}, []),
|
|
227
|
+
forceRefresh: (0, react.useCallback)((shouldRunImmediately = false) => {
|
|
228
|
+
updateReasonRef.current = "filter";
|
|
229
|
+
setFilterInfoState((previous) => {
|
|
230
|
+
invariant(previous != null, "forceRefresh called without filterInfo");
|
|
231
|
+
return {
|
|
232
|
+
...previous,
|
|
233
|
+
lastRefreshAt: new Date().getTime(),
|
|
234
|
+
shouldRunImmediately
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
}, [])
|
|
238
|
+
};
|
|
239
|
+
return api;
|
|
240
|
+
}
|
|
241
|
+
function invariant(input, message) {
|
|
242
|
+
if (!input) {
|
|
243
|
+
throw new Error(`Invariant error: ${message}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function isPromise(t) {
|
|
247
|
+
return !!t?.then;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
module.exports = useFilter;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { FilterStore } from "./store/index.js";
|
|
2
|
+
import { UseFilterUpdateReason } from "./useFilter.js";
|
|
3
|
+
|
|
4
|
+
//#region src/useSimpleFilter.d.ts
|
|
5
|
+
interface UseSimpleFilterOptions<TFilter> {
|
|
6
|
+
/**
|
|
7
|
+
* Default values for your filter. When calling `.reset` your filter will be
|
|
8
|
+
* set to this.
|
|
9
|
+
* Changing these values does not cause a call to happen.
|
|
10
|
+
*/
|
|
11
|
+
defaultFilterInfo?: Partial<SimpleFilterInfo<TFilter>>;
|
|
12
|
+
/**
|
|
13
|
+
* In case you want to change the default debounce duration.
|
|
14
|
+
*/
|
|
15
|
+
debounceDuration?: number;
|
|
16
|
+
onBeforeSaveFilter?: (filterInfo: SimpleFilterInfo<TFilter>) => SimpleFilterInfo<TFilter>;
|
|
17
|
+
store?: FilterStore;
|
|
18
|
+
}
|
|
19
|
+
interface SimpleFilterApi<TFilter> {
|
|
20
|
+
/**
|
|
21
|
+
* Really more "is debouncing", since simple mode doesn't know when your code
|
|
22
|
+
* is doing anything.
|
|
23
|
+
*/
|
|
24
|
+
isLoading: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Access to the filter and its metadata.
|
|
27
|
+
*/
|
|
28
|
+
filterInfo: SimpleFilterInfo<TFilter>;
|
|
29
|
+
/**
|
|
30
|
+
* Same as the regular `filterInfo`, but updates in a debounced fashion.
|
|
31
|
+
*/
|
|
32
|
+
debouncedFilterInfo: SimpleFilterInfo<TFilter>;
|
|
33
|
+
/**
|
|
34
|
+
* Why the last update happened.
|
|
35
|
+
*/
|
|
36
|
+
updateReason: UseFilterUpdateReason;
|
|
37
|
+
/**
|
|
38
|
+
* Update one or more values in your filter.
|
|
39
|
+
*/
|
|
40
|
+
updateFilter: (filter: Partial<TFilter>, shouldRunImmediately?: boolean) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Does the boring math for you based on your `pageSize` and `totalResults`.
|
|
43
|
+
*/
|
|
44
|
+
pagingInfo: (total: string | number | null | undefined) => {
|
|
45
|
+
totalResults: number;
|
|
46
|
+
totalPages: number;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Resets the filter back to `defaultFilterInfo`.
|
|
50
|
+
*/
|
|
51
|
+
resetFilter: (shouldRunImmediately?: boolean) => void;
|
|
52
|
+
/**
|
|
53
|
+
* Changes the offset. Will update `page`.
|
|
54
|
+
*/
|
|
55
|
+
setOffset: (offset: number | string, shouldRunImmediately?: boolean) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Changes the page. Will update `offset`.
|
|
58
|
+
*/
|
|
59
|
+
setPage: (page: number | string, shouldRunImmediately?: boolean) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Changes the page size.
|
|
62
|
+
*/
|
|
63
|
+
setPageSize: (pageSize: number | string, shouldRunImmediately?: boolean) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Change the sort method.
|
|
66
|
+
*/
|
|
67
|
+
setSort: (sort: string, shouldRunImmediately?: boolean) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Changes the cursor.
|
|
70
|
+
*/
|
|
71
|
+
setCursor: (cursor: string | null | undefined, shouldRunImmediately?: boolean) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Forces a refresh of the filter.
|
|
74
|
+
*/
|
|
75
|
+
forceRefresh: (shouldRunImmediately?: boolean) => void;
|
|
76
|
+
}
|
|
77
|
+
interface SimpleFilterInfo<TFilter> {
|
|
78
|
+
filter: TFilter;
|
|
79
|
+
sort?: string;
|
|
80
|
+
offset: number;
|
|
81
|
+
page: number;
|
|
82
|
+
pageSize: number;
|
|
83
|
+
lastRefreshAt: number;
|
|
84
|
+
cursor?: string | null;
|
|
85
|
+
shouldRunImmediately: boolean;
|
|
86
|
+
}
|
|
87
|
+
declare function useSimpleFilter<TFilter extends Record<string, unknown>>(namespace: string, options: UseSimpleFilterOptions<TFilter>): SimpleFilterApi<TFilter>;
|
|
88
|
+
//#endregion
|
|
89
|
+
export { SimpleFilterApi, SimpleFilterInfo, useSimpleFilter as default };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
const require_lib_getOffsetFromPage = require('./lib/getOffsetFromPage.js');
|
|
2
|
+
const require_lib_getPageFromOffset = require('./lib/getPageFromOffset.js');
|
|
3
|
+
const require_lib_shallowEqual = require('./lib/shallowEqual.js');
|
|
4
|
+
const require_store_index = require('./store/index.js');
|
|
5
|
+
let react = require("react");
|
|
6
|
+
|
|
7
|
+
//#region src/useSimpleFilter.ts
|
|
8
|
+
function useSimpleFilter(namespace, options) {
|
|
9
|
+
const ctxRefValue = {
|
|
10
|
+
namespace,
|
|
11
|
+
debounceDuration: options.debounceDuration,
|
|
12
|
+
defaultFilterInfo: options.defaultFilterInfo,
|
|
13
|
+
onBeforeSaveFilter: options.onBeforeSaveFilter,
|
|
14
|
+
store: options.store
|
|
15
|
+
};
|
|
16
|
+
const ctxRef = (0, react.useRef)(ctxRefValue);
|
|
17
|
+
(0, react.useEffect)(() => {
|
|
18
|
+
ctxRef.current = ctxRefValue;
|
|
19
|
+
});
|
|
20
|
+
const [isLoading, setIsLoading] = (0, react.useState)(false);
|
|
21
|
+
const [filterInfo, setFilterInfoState] = (0, react.useState)(() => {
|
|
22
|
+
const fromStore = require_store_index.getFilterStore(ctxRef.current.store).getFilter(namespace);
|
|
23
|
+
if (fromStore) {
|
|
24
|
+
const filterInfo = buildDefaultFilterInfo({
|
|
25
|
+
...fromStore,
|
|
26
|
+
shouldRunImmediately: true,
|
|
27
|
+
filter: {
|
|
28
|
+
...options.defaultFilterInfo?.filter,
|
|
29
|
+
...fromStore.filter
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return filterInfo;
|
|
33
|
+
} else {
|
|
34
|
+
return buildDefaultFilterInfo({
|
|
35
|
+
...options.defaultFilterInfo,
|
|
36
|
+
shouldRunImmediately: true
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const [debouncedFilterInfo, setDebouncedFilterInfo] = (0, react.useState)(filterInfo);
|
|
41
|
+
const lastRefreshAtRef = (0, react.useRef)(-1);
|
|
42
|
+
const updateReasonRef = (0, react.useRef)("initial");
|
|
43
|
+
(0, react.useEffect)(() => {
|
|
44
|
+
setIsLoading(true);
|
|
45
|
+
if (lastRefreshAtRef.current === filterInfo.lastRefreshAt) {
|
|
46
|
+
setIsLoading(false);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
let timeout = undefined;
|
|
50
|
+
function makeRequest() {
|
|
51
|
+
lastRefreshAtRef.current = filterInfo.lastRefreshAt;
|
|
52
|
+
require_store_index.getFilterStore(ctxRef.current.store).saveFilter(ctxRef.current.namespace, ctxRef.current.onBeforeSaveFilter ? ctxRef.current.onBeforeSaveFilter(filterInfo) : filterInfo);
|
|
53
|
+
setDebouncedFilterInfo(filterInfo);
|
|
54
|
+
setIsLoading(false);
|
|
55
|
+
}
|
|
56
|
+
if (filterInfo.shouldRunImmediately) {
|
|
57
|
+
makeRequest();
|
|
58
|
+
} else {
|
|
59
|
+
timeout = setTimeout(makeRequest, ctxRef.current.debounceDuration ?? 500);
|
|
60
|
+
}
|
|
61
|
+
return () => {
|
|
62
|
+
if (timeout) {
|
|
63
|
+
clearTimeout(timeout);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}, [filterInfo]);
|
|
67
|
+
const previousTotalRef = (0, react.useRef)(0);
|
|
68
|
+
const api = {
|
|
69
|
+
isLoading,
|
|
70
|
+
filterInfo,
|
|
71
|
+
debouncedFilterInfo,
|
|
72
|
+
updateReason: updateReasonRef.current,
|
|
73
|
+
updateFilter: (0, react.useCallback)((filter, shouldRunImmediately = false) => {
|
|
74
|
+
updateReasonRef.current = "filter";
|
|
75
|
+
setFilterInfoState((previous) => {
|
|
76
|
+
const nextFilter = {
|
|
77
|
+
...previous.filter,
|
|
78
|
+
...filter
|
|
79
|
+
};
|
|
80
|
+
if (require_lib_shallowEqual(previous.filter, nextFilter)) {
|
|
81
|
+
return previous;
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
...previous,
|
|
85
|
+
shouldRunImmediately,
|
|
86
|
+
offset: 0,
|
|
87
|
+
page: 1,
|
|
88
|
+
totalResults: 1,
|
|
89
|
+
totalPages: 1,
|
|
90
|
+
filter: nextFilter,
|
|
91
|
+
cursor: undefined,
|
|
92
|
+
lastRefreshAt: new Date().getTime()
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}, []),
|
|
96
|
+
pagingInfo: (0, react.useCallback)((total) => {
|
|
97
|
+
const normalized = Number(total == null ? previousTotalRef.current : total);
|
|
98
|
+
previousTotalRef.current = normalized;
|
|
99
|
+
return {
|
|
100
|
+
totalResults: normalized,
|
|
101
|
+
totalPages: Math.ceil(normalized / filterInfo.pageSize)
|
|
102
|
+
};
|
|
103
|
+
}, [filterInfo.pageSize]),
|
|
104
|
+
resetFilter: (0, react.useCallback)((shouldRunImmediately = false) => {
|
|
105
|
+
updateReasonRef.current = "filter";
|
|
106
|
+
setFilterInfoState({
|
|
107
|
+
...buildDefaultFilterInfo(ctxRef.current.defaultFilterInfo),
|
|
108
|
+
shouldRunImmediately
|
|
109
|
+
});
|
|
110
|
+
}, []),
|
|
111
|
+
setOffset: (0, react.useCallback)((offset, shouldRunImmediately = false) => {
|
|
112
|
+
updateReasonRef.current = "pagination";
|
|
113
|
+
const offsetNumber = Number(offset);
|
|
114
|
+
setFilterInfoState((previous) => ({
|
|
115
|
+
...previous,
|
|
116
|
+
offset: offsetNumber,
|
|
117
|
+
page: require_lib_getPageFromOffset(offsetNumber, previous.pageSize),
|
|
118
|
+
lastRefreshAt: new Date().getTime(),
|
|
119
|
+
shouldRunImmediately
|
|
120
|
+
}));
|
|
121
|
+
}, []),
|
|
122
|
+
setPage: (0, react.useCallback)((page, shouldRunImmediately = false) => {
|
|
123
|
+
updateReasonRef.current = "pagination";
|
|
124
|
+
const pageNumber = Number(page);
|
|
125
|
+
setFilterInfoState((previous) => ({
|
|
126
|
+
...previous,
|
|
127
|
+
offset: require_lib_getOffsetFromPage(pageNumber, previous.pageSize),
|
|
128
|
+
page: pageNumber,
|
|
129
|
+
lastRefreshAt: new Date().getTime(),
|
|
130
|
+
shouldRunImmediately
|
|
131
|
+
}));
|
|
132
|
+
}, []),
|
|
133
|
+
setPageSize: (0, react.useCallback)((pageSize, shouldRunImmediately = false) => {
|
|
134
|
+
updateReasonRef.current = "pagination";
|
|
135
|
+
setFilterInfoState((previous) => {
|
|
136
|
+
const pageSizeNumber = Number(pageSize);
|
|
137
|
+
const page = require_lib_getPageFromOffset(previous.offset, pageSizeNumber);
|
|
138
|
+
const offset = require_lib_getOffsetFromPage(page, pageSizeNumber);
|
|
139
|
+
return {
|
|
140
|
+
...previous,
|
|
141
|
+
pageSize: pageSizeNumber,
|
|
142
|
+
offset,
|
|
143
|
+
page,
|
|
144
|
+
lastRefreshAt: new Date().getTime(),
|
|
145
|
+
shouldRunImmediately
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
}, []),
|
|
149
|
+
setSort: (0, react.useCallback)((sort, shouldRunImmediately = false) => {
|
|
150
|
+
updateReasonRef.current = "filter";
|
|
151
|
+
setFilterInfoState((previous) => ({
|
|
152
|
+
...previous,
|
|
153
|
+
sort,
|
|
154
|
+
lastRefreshAt: new Date().getTime(),
|
|
155
|
+
shouldRunImmediately
|
|
156
|
+
}));
|
|
157
|
+
}, []),
|
|
158
|
+
setCursor: (0, react.useCallback)((cursor, shouldRunImmediately = false) => {
|
|
159
|
+
updateReasonRef.current = "pagination";
|
|
160
|
+
setFilterInfoState((previous) => ({
|
|
161
|
+
...previous,
|
|
162
|
+
cursor,
|
|
163
|
+
lastRefreshAt: new Date().getTime(),
|
|
164
|
+
shouldRunImmediately
|
|
165
|
+
}));
|
|
166
|
+
}, []),
|
|
167
|
+
forceRefresh: (0, react.useCallback)((shouldRunImmediately = false) => {
|
|
168
|
+
updateReasonRef.current = "filter";
|
|
169
|
+
setFilterInfoState((previous) => ({
|
|
170
|
+
...previous,
|
|
171
|
+
lastRefreshAt: new Date().getTime(),
|
|
172
|
+
shouldRunImmediately
|
|
173
|
+
}));
|
|
174
|
+
}, [])
|
|
175
|
+
};
|
|
176
|
+
return api;
|
|
177
|
+
}
|
|
178
|
+
function buildDefaultFilterInfo(filterInfo = {}) {
|
|
179
|
+
const merged = {
|
|
180
|
+
filter: {},
|
|
181
|
+
sort: undefined,
|
|
182
|
+
pageSize: 20,
|
|
183
|
+
lastRefreshAt: new Date().getTime(),
|
|
184
|
+
offset: 0,
|
|
185
|
+
page: 1,
|
|
186
|
+
shouldRunImmediately: false,
|
|
187
|
+
...filterInfo
|
|
188
|
+
};
|
|
189
|
+
if (filterInfo.page != null && filterInfo.offset == null) {
|
|
190
|
+
merged.offset = require_lib_getOffsetFromPage(filterInfo.page, merged.pageSize);
|
|
191
|
+
} else if (filterInfo.page == null && filterInfo.offset != null) {
|
|
192
|
+
merged.page = require_lib_getPageFromOffset(filterInfo.offset, merged.pageSize);
|
|
193
|
+
}
|
|
194
|
+
return merged;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
module.exports = useSimpleFilter;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { FilterInfo } from "../useFilter.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/buildDefaultFilterInfo.d.ts
|
|
4
|
+
declare function buildDefaultFilterInfo<T extends Record<string, unknown>>(filterInfo?: Partial<FilterInfo<T>>): FilterInfo<T>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { buildDefaultFilterInfo as default };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import getOffsetFromPage from "./getOffsetFromPage.mjs";
|
|
2
|
+
import getPageFromOffset from "./getPageFromOffset.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/lib/buildDefaultFilterInfo.ts
|
|
5
|
+
function buildDefaultFilterInfo(filterInfo = {}) {
|
|
6
|
+
const merged = {
|
|
7
|
+
filter: {},
|
|
8
|
+
sort: undefined,
|
|
9
|
+
pageSize: 20,
|
|
10
|
+
lastRefreshAt: new Date().getTime(),
|
|
11
|
+
totalResults: 1,
|
|
12
|
+
totalPages: 1,
|
|
13
|
+
offset: 0,
|
|
14
|
+
page: 1,
|
|
15
|
+
shouldRunImmediately: false,
|
|
16
|
+
...filterInfo
|
|
17
|
+
};
|
|
18
|
+
if (filterInfo.page != null && filterInfo.offset == null) {
|
|
19
|
+
merged.offset = getOffsetFromPage(filterInfo.page, merged.pageSize);
|
|
20
|
+
} else if (filterInfo.page == null && filterInfo.offset != null) {
|
|
21
|
+
merged.page = getPageFromOffset(filterInfo.offset, merged.pageSize);
|
|
22
|
+
}
|
|
23
|
+
return merged;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { buildDefaultFilterInfo as default };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/lib/shallowEqual.ts
|
|
2
|
+
const shallowEqual = (objA, objB) => {
|
|
3
|
+
if (Object.is(objA, objB)) {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
if (typeof objA !== "object" || !objA || typeof objB !== "object" || !objB) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const keysA = Object.keys(objA);
|
|
10
|
+
const keysB = Object.keys(objB);
|
|
11
|
+
if (keysA.length !== keysB.length) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
for (const key of keysA) {
|
|
15
|
+
if (!Object.is(objA[key], objB[key])) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { shallowEqual as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FilterInfo } from "../useFilter.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/store/index.d.ts
|
|
4
|
+
interface FilterStore {
|
|
5
|
+
getFilter<TFilter extends Record<string, unknown>>(namespace: string): FilterInfo<TFilter> | null | undefined;
|
|
6
|
+
saveFilter<TFilter extends Record<string, unknown>>(namespace: string, filter: FilterInfo<TFilter>): void;
|
|
7
|
+
getData<TResult = any>(namespace: string): TResult | null | undefined;
|
|
8
|
+
saveData<TResult = any>(namespace: string, data: TResult): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
}
|
|
11
|
+
declare function setFilterStore(newStore: FilterStore): void;
|
|
12
|
+
declare function getFilterStore(optionalStore?: FilterStore): FilterStore;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { FilterStore, getFilterStore, setFilterStore };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/store/index.ts
|
|
2
|
+
let globalStore;
|
|
3
|
+
function setFilterStore(newStore) {
|
|
4
|
+
globalStore = newStore;
|
|
5
|
+
}
|
|
6
|
+
function getFilterStore(optionalStore) {
|
|
7
|
+
const resolvedStore = optionalStore || globalStore;
|
|
8
|
+
if (!resolvedStore) {
|
|
9
|
+
throw new Error("A store must be set with setFilterStore");
|
|
10
|
+
}
|
|
11
|
+
return resolvedStore;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { getFilterStore, setFilterStore };
|