react-hook-core 0.1.22 → 0.1.24
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/lib/components.js +2 -2
- package/lib/index.js +43 -15
- package/lib/useSearch.js +2 -2
- package/package.json +1 -1
- package/src/components.ts +2 -2
- package/src/core.ts +1 -1
- package/src/index.ts +73 -3
- package/src/useEdit.ts +539 -539
- package/src/useSearch.ts +523 -523
package/src/useSearch.ts
CHANGED
|
@@ -1,523 +1,523 @@
|
|
|
1
|
-
import {useEffect, useState} from 'react';
|
|
2
|
-
import {error, getName, getRemoveError, getValidateForm, handleToggle, hideLoading, initForm, Locale, PageChange, pageSizes, removeFormError, ResourceService, SearchParameter, SearchResult, SearchService, showLoading} from './core';
|
|
3
|
-
import {DispatchWithCallback, useMergeState} from './merge';
|
|
4
|
-
import {clone} from './reflect';
|
|
5
|
-
import {buildFromUrl} from './route';
|
|
6
|
-
import {addParametersIntoUrl, append, buildMessage, formatResults, getFieldsFromForm, getModel, handleAppend, handleSort, initFilter, mergeFilter as mergeFilter2, Pagination, removeSortStatus, showPaging, Sortable, validate} from './search';
|
|
7
|
-
import {enLocale} from './state';
|
|
8
|
-
import {useUpdate} from './update';
|
|
9
|
-
|
|
10
|
-
export interface Searchable extends Pagination, Sortable {
|
|
11
|
-
nextPageToken?: string;
|
|
12
|
-
excluding?: string[]|number[];
|
|
13
|
-
}
|
|
14
|
-
interface Filter {
|
|
15
|
-
page?: number;
|
|
16
|
-
limit?: number;
|
|
17
|
-
firstLimit?: number;
|
|
18
|
-
fields?: string[];
|
|
19
|
-
sort?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const callSearch = <T, S extends Filter>(se: S, search3: (s: S, limit?: number, offset?: number|string, fields?: string[]) => Promise<SearchResult<T>>, showResults3: (s: S, sr: SearchResult<T>, lc: Locale) => void, searchError3: (err: any) => void, lc: Locale, nextPageToken?: string) => {
|
|
23
|
-
const s = clone(se);
|
|
24
|
-
let page = se.page;
|
|
25
|
-
if (!page || page < 1) {
|
|
26
|
-
page = 1;
|
|
27
|
-
}
|
|
28
|
-
let offset: number;
|
|
29
|
-
if (!se.limit || se.limit <= 0) {
|
|
30
|
-
se.limit = 24;
|
|
31
|
-
}
|
|
32
|
-
if (se.firstLimit && se.firstLimit > 0) {
|
|
33
|
-
offset = se.limit * (page - 2) + se.firstLimit;
|
|
34
|
-
} else {
|
|
35
|
-
offset = se.limit * (page - 1);
|
|
36
|
-
}
|
|
37
|
-
const limit = (page <= 1 && se.firstLimit && se.firstLimit > 0 ? se.firstLimit : se.limit);
|
|
38
|
-
const next = (nextPageToken && nextPageToken.length > 0 ? nextPageToken : offset);
|
|
39
|
-
const fields = se.fields;
|
|
40
|
-
delete se['page'];
|
|
41
|
-
delete se['fields'];
|
|
42
|
-
delete se['limit'];
|
|
43
|
-
delete se['firstLimit'];
|
|
44
|
-
search3(s, limit, next, fields).then(sr => {
|
|
45
|
-
showResults3(s, sr, lc);
|
|
46
|
-
}).catch(err => err && searchError3(err));
|
|
47
|
-
};
|
|
48
|
-
const appendListOfState = <T, S extends Filter>(results: T[], list: T[]|undefined, setState2: DispatchWithCallback<Partial<SearchComponentState<T, S>>>) => {
|
|
49
|
-
const arr = append(list, results);
|
|
50
|
-
setState2({ list: arr } as any);
|
|
51
|
-
};
|
|
52
|
-
const setListOfState = <T, S extends Filter>(list: T[], setState2: DispatchWithCallback<Partial<SearchComponentState<T, S>>>) => {
|
|
53
|
-
setState2({ list } as any);
|
|
54
|
-
};
|
|
55
|
-
export interface InitSearchComponentParam<T, M extends Filter, S> extends SearchComponentParam<T, M> {
|
|
56
|
-
createFilter?: () => M;
|
|
57
|
-
initialize?: (ld: (s: M, auto?: boolean) => void, setState2: DispatchWithCallback<Partial<S>>, com?: SearchComponentState<T, M>) => void;
|
|
58
|
-
}
|
|
59
|
-
export interface HookPropsSearchParameter<T, S extends Filter, ST extends SearchComponentState<T, S>, P> extends HookPropsBaseSearchParameter<T, S, ST, P> {
|
|
60
|
-
createFilter?: () => S;
|
|
61
|
-
initialize?: (ld: (s: S, auto?: boolean) => void, setState2: DispatchWithCallback<Partial<ST>>, com?: SearchComponentState<T, S>) => void;
|
|
62
|
-
}
|
|
63
|
-
export interface SearchComponentParam<T, M extends Filter> {
|
|
64
|
-
addable?: boolean;
|
|
65
|
-
editable?: boolean;
|
|
66
|
-
approvable?: boolean;
|
|
67
|
-
deletable?: boolean;
|
|
68
|
-
|
|
69
|
-
keys?: string[];
|
|
70
|
-
sequenceNo?: string;
|
|
71
|
-
hideFilter?: boolean;
|
|
72
|
-
name?: string;
|
|
73
|
-
fields?: string[];
|
|
74
|
-
appendMode?: boolean;
|
|
75
|
-
pageSizes?: number[];
|
|
76
|
-
pageIndex?: number;
|
|
77
|
-
pageSize?: number;
|
|
78
|
-
initPageSize?: number;
|
|
79
|
-
pageMaxSize?: number;
|
|
80
|
-
ignoreUrlParam?: boolean;
|
|
81
|
-
|
|
82
|
-
load?: (s: M, auto?: boolean) => void;
|
|
83
|
-
getModelName?: () => string;
|
|
84
|
-
getCurrencyCode?: () => string;
|
|
85
|
-
setFilter?: (s: M) => void;
|
|
86
|
-
getFilter?: (se?: Searchable) => M;
|
|
87
|
-
getFields?: () => string[]|undefined;
|
|
88
|
-
validateSearch?: (se: M, callback: () => void) => void;
|
|
89
|
-
// prepareCustomData?: (data: any) => void;
|
|
90
|
-
format?(obj: T, locale?: Locale): T;
|
|
91
|
-
showResults?(s: M, sr: SearchResult<T>, lc: Locale): void;
|
|
92
|
-
appendList?(results: T[], list: T[]|undefined, s: DispatchWithCallback<Partial<SearchComponentState<T, M>>>): void;
|
|
93
|
-
setList?(list: T[], s: DispatchWithCallback<Partial<SearchComponentState<T, M>>>): void;
|
|
94
|
-
/*
|
|
95
|
-
showLoading?(firstTime?: boolean): void;
|
|
96
|
-
hideLoading?(): void;
|
|
97
|
-
decodeFromForm?(form: HTMLFormElement, locale?: Locale, currencyCode?: string): any;
|
|
98
|
-
registerEvents?(form: HTMLFormElement): void;
|
|
99
|
-
validateForm?(form: HTMLFormElement, locale?: Locale, focusFirst?: boolean, scroll?: boolean): boolean;
|
|
100
|
-
removeFormError?(form: HTMLFormElement): void;
|
|
101
|
-
removeError?(el: HTMLInputElement): void;
|
|
102
|
-
*/
|
|
103
|
-
}
|
|
104
|
-
export interface HookBaseSearchParameter<T, S extends Filter, ST extends SearchComponentState<T, S>> extends SearchComponentParam<T, S> {
|
|
105
|
-
refForm: any;
|
|
106
|
-
initialState: ST;
|
|
107
|
-
service: ((s: S, limit?: number, offset?: number|string, fields?: string[]) => Promise<SearchResult<T>>) | SearchService<T, S>;
|
|
108
|
-
resource: ResourceService;
|
|
109
|
-
showMessage: (msg: string) => void;
|
|
110
|
-
showError: (m: string, header?: string, detail?: string, callback?: () => void) => void;
|
|
111
|
-
getLocale?: () => Locale;
|
|
112
|
-
autoSearch?: boolean;
|
|
113
|
-
}
|
|
114
|
-
export interface HookPropsBaseSearchParameter<T, S extends Filter, ST extends SearchComponentState<T, S>, P> extends HookBaseSearchParameter<T, S, ST> {
|
|
115
|
-
props?: P;
|
|
116
|
-
// prepareCustomData?: (data: any) => void;
|
|
117
|
-
}
|
|
118
|
-
export interface SearchComponentState<T, S> extends Pagination, Sortable {
|
|
119
|
-
view?: string;
|
|
120
|
-
nextPageToken?: string;
|
|
121
|
-
keys?: string[];
|
|
122
|
-
filter?: S;
|
|
123
|
-
list?: T[];
|
|
124
|
-
|
|
125
|
-
format?: (obj: T, locale: Locale) => T;
|
|
126
|
-
fields?: string[];
|
|
127
|
-
initFields?: boolean;
|
|
128
|
-
triggerSearch?: boolean;
|
|
129
|
-
tmpPageIndex?: number;
|
|
130
|
-
|
|
131
|
-
pageMaxSize?: number;
|
|
132
|
-
pageSizes?: number[];
|
|
133
|
-
excluding?: string[]|number[];
|
|
134
|
-
hideFilter?: boolean;
|
|
135
|
-
|
|
136
|
-
ignoreUrlParam?: boolean;
|
|
137
|
-
viewable?: boolean;
|
|
138
|
-
addable?: boolean;
|
|
139
|
-
editable?: boolean;
|
|
140
|
-
approvable?: boolean;
|
|
141
|
-
deletable?: boolean;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function mergeParam<T, S extends Filter>(p?: SearchComponentParam<T, S>): SearchComponentParam<T, S> {
|
|
145
|
-
if (p) {
|
|
146
|
-
if (!p.sequenceNo) {
|
|
147
|
-
p.sequenceNo = 'sequenceNo';
|
|
148
|
-
}
|
|
149
|
-
if (!p.pageSize) {
|
|
150
|
-
p.pageSize = 24;
|
|
151
|
-
}
|
|
152
|
-
if (!p.pageSizes) {
|
|
153
|
-
p.pageSizes = pageSizes;
|
|
154
|
-
}
|
|
155
|
-
if (!p.pageMaxSize || p.pageMaxSize <= 0) {
|
|
156
|
-
p.pageMaxSize = 7;
|
|
157
|
-
}
|
|
158
|
-
if (p.hideFilter === undefined) {
|
|
159
|
-
p.hideFilter = true;
|
|
160
|
-
}
|
|
161
|
-
if (p.addable === undefined) {
|
|
162
|
-
p.addable = true;
|
|
163
|
-
}
|
|
164
|
-
if (p.editable === undefined) {
|
|
165
|
-
p.editable = true;
|
|
166
|
-
}
|
|
167
|
-
if (p.approvable === undefined) {
|
|
168
|
-
p.approvable = true;
|
|
169
|
-
}
|
|
170
|
-
if (p.deletable === undefined) {
|
|
171
|
-
p.deletable = true;
|
|
172
|
-
}
|
|
173
|
-
return p;
|
|
174
|
-
} else {
|
|
175
|
-
return {
|
|
176
|
-
sequenceNo: 'sequenceNo',
|
|
177
|
-
pageSize: 24,
|
|
178
|
-
pageSizes,
|
|
179
|
-
pageMaxSize: 7,
|
|
180
|
-
hideFilter: true,
|
|
181
|
-
addable: true,
|
|
182
|
-
editable: true,
|
|
183
|
-
approvable: true,
|
|
184
|
-
deletable: true
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
export const useSearch = <T, S extends Filter, ST extends SearchComponentState<T, S>>(
|
|
189
|
-
refForm: any,
|
|
190
|
-
initialState: ST,
|
|
191
|
-
service: ((s: S, limit?: number, offset?: number|string, fields?: string[]) => Promise<SearchResult<T>>) | SearchService<T, S>,
|
|
192
|
-
p2: SearchParameter,
|
|
193
|
-
p?: InitSearchComponentParam<T, S, ST>,
|
|
194
|
-
) => {
|
|
195
|
-
const baseProps = useCoreSearch(refForm, initialState, service, p2, p);
|
|
196
|
-
|
|
197
|
-
useEffect(() => {
|
|
198
|
-
const { load, setState, component, searchError } = baseProps;
|
|
199
|
-
if (refForm) {
|
|
200
|
-
const registerEvents = (p2.ui ? p2.ui.registerEvents : undefined);
|
|
201
|
-
initForm(refForm.current, registerEvents);
|
|
202
|
-
}
|
|
203
|
-
if (p && p.initialize) {
|
|
204
|
-
p.initialize(load, setState, component);
|
|
205
|
-
} else {
|
|
206
|
-
const se: S|undefined = (p && p.createFilter ? p.createFilter() : undefined);
|
|
207
|
-
try {
|
|
208
|
-
const s: any = mergeFilter2(buildFromUrl<S>(se), se, component.pageSizes);
|
|
209
|
-
load(s, p2.auto);
|
|
210
|
-
} catch (error) {
|
|
211
|
-
searchError(error);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
215
|
-
}, []);
|
|
216
|
-
return { ...baseProps };
|
|
217
|
-
};
|
|
218
|
-
export const useSearchOneProps = <T, S extends Filter, ST extends SearchComponentState<T, S>, P>(p: HookPropsSearchParameter<T, S, ST, P>) => {
|
|
219
|
-
return useSearch(p.refForm, p.initialState, p.service, p, p);
|
|
220
|
-
};
|
|
221
|
-
export const useSearchOne = <T, S extends Filter, ST extends SearchComponentState<T, S>>(p: HookBaseSearchParameter<T, S, ST>) => {
|
|
222
|
-
return useCoreSearch(p.refForm, p.initialState, p.service, p, p);
|
|
223
|
-
};
|
|
224
|
-
export const useCoreSearch = <T, S extends Filter, ST>(
|
|
225
|
-
refForm: any,
|
|
226
|
-
initialState: ST,
|
|
227
|
-
service: ((s: S, limit?: number, offset?: number|string, fields?: string[]) => Promise<SearchResult<T>>) | SearchService<T, S>,
|
|
228
|
-
p1: SearchParameter,
|
|
229
|
-
p2?: SearchComponentParam<T, S>
|
|
230
|
-
) => {
|
|
231
|
-
const p = mergeParam(p2);
|
|
232
|
-
const [running, setRunning] = useState<boolean>();
|
|
233
|
-
|
|
234
|
-
const _getModelName = (): string => {
|
|
235
|
-
return getName('filter', p && p.name ? p.name : undefined);
|
|
236
|
-
};
|
|
237
|
-
const getModelName = (p && p.getModelName ? p.getModelName : _getModelName);
|
|
238
|
-
|
|
239
|
-
// const setState2: <K extends keyof S, P>(st: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null), cb?: () => void) => void;
|
|
240
|
-
const baseProps = useUpdate<ST>(initialState, getModelName, p1.getLocale, getRemoveError(p1));
|
|
241
|
-
const { state, setState } = baseProps;
|
|
242
|
-
const [rerender, setRerender] = useState(false);
|
|
243
|
-
|
|
244
|
-
// trigger re-render page when change state in useSearch
|
|
245
|
-
useEffect(() => {
|
|
246
|
-
setRerender(!rerender);
|
|
247
|
-
}, [state]);
|
|
248
|
-
|
|
249
|
-
const _getCurrencyCode = (): string => {
|
|
250
|
-
return refForm && refForm.current ? refForm.current.getAttribute('currency-code') : null;
|
|
251
|
-
};
|
|
252
|
-
const getCurrencyCode = p && p.getCurrencyCode ? p.getCurrencyCode : _getCurrencyCode;
|
|
253
|
-
|
|
254
|
-
// const p = createSearchComponentState<T, S>(p1);
|
|
255
|
-
const [component, setComponent] = useMergeState<SearchComponentState<T, S>>(p);
|
|
256
|
-
|
|
257
|
-
const toggleFilter = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
|
|
258
|
-
const x = !component.hideFilter;
|
|
259
|
-
handleToggle(event.target as HTMLInputElement, !x);
|
|
260
|
-
setComponent({ hideFilter: x });
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const _getFields = (): string[]|undefined => {
|
|
264
|
-
const { fields, initFields } = component;
|
|
265
|
-
const fs = getFieldsFromForm(fields, initFields, refForm.current);
|
|
266
|
-
setComponent({ fields: fs, initFields: true });
|
|
267
|
-
return fs;
|
|
268
|
-
};
|
|
269
|
-
const getFields = p && p.getFields ? p.getFields : _getFields;
|
|
270
|
-
|
|
271
|
-
const _getFilter = (se?: Searchable): S => {
|
|
272
|
-
if (!se) {
|
|
273
|
-
se = component;
|
|
274
|
-
}
|
|
275
|
-
let keys = p && p.keys ? p.keys : undefined;
|
|
276
|
-
if (!keys && typeof service !== 'function' && service.keys) {
|
|
277
|
-
keys = service.keys();
|
|
278
|
-
}
|
|
279
|
-
const n = getModelName();
|
|
280
|
-
let fs = p && p.fields;
|
|
281
|
-
if (!fs || fs.length <= 0) {
|
|
282
|
-
fs = getFields();
|
|
283
|
-
}
|
|
284
|
-
const obj3 = getModel<S>(state, n, se, fs, se.excluding);
|
|
285
|
-
return obj3;
|
|
286
|
-
};
|
|
287
|
-
const getFilter = p && p.getFilter ? p.getFilter : _getFilter;
|
|
288
|
-
const _setFilter = (s: S): void => {
|
|
289
|
-
const objSet: any = {};
|
|
290
|
-
const n = getModelName();
|
|
291
|
-
objSet[n] = s;
|
|
292
|
-
setState(objSet);
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
const setFilter = p && p.setFilter ? p.setFilter : _setFilter;
|
|
296
|
-
|
|
297
|
-
const _load = (s: S, auto?: boolean): void => {
|
|
298
|
-
const com = Object.assign({}, component);
|
|
299
|
-
const obj2 = initFilter(s, com);
|
|
300
|
-
setComponent(com);
|
|
301
|
-
setFilter(obj2);
|
|
302
|
-
const runSearch = doSearch;
|
|
303
|
-
if (auto) {
|
|
304
|
-
setTimeout(() => {
|
|
305
|
-
runSearch((obj2 as Searchable), true);
|
|
306
|
-
}, 0);
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
const load = p && p.load ? p.load : _load;
|
|
310
|
-
|
|
311
|
-
const doSearch = (se: Searchable, isFirstLoad?: boolean) => {
|
|
312
|
-
removeFormError(p1, refForm.current);
|
|
313
|
-
const s = getFilter(se);
|
|
314
|
-
|
|
315
|
-
if (isFirstLoad){
|
|
316
|
-
setState(state); // force update state if we refresh again page
|
|
317
|
-
}
|
|
318
|
-
const isStillRunning = running;
|
|
319
|
-
validateSearch(s, () => {
|
|
320
|
-
if (isStillRunning === true) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
setRunning(true);
|
|
324
|
-
showLoading(p1.loading);
|
|
325
|
-
if (p && !p.ignoreUrlParam) {
|
|
326
|
-
addParametersIntoUrl(s, isFirstLoad);
|
|
327
|
-
}
|
|
328
|
-
const lc = p1.getLocale ? p1.getLocale() : enLocale;
|
|
329
|
-
if (typeof service === 'function') {
|
|
330
|
-
callSearch<T, S>(s, service, showResults, searchError, lc, se.nextPageToken);
|
|
331
|
-
} else {
|
|
332
|
-
callSearch<T, S>(s, service.search, showResults, searchError, lc, se.nextPageToken);
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
const _validateSearch = (se: S, callback: () => void) => {
|
|
338
|
-
validate(se, callback, refForm.current, (p1.getLocale ? p1.getLocale() : undefined), getValidateForm(p1));
|
|
339
|
-
};
|
|
340
|
-
const validateSearch = p && p.validateSearch ? p.validateSearch : _validateSearch;
|
|
341
|
-
|
|
342
|
-
const pageSizeChanged = (event: any) => {
|
|
343
|
-
const size = parseInt(event.currentTarget.value, 10);
|
|
344
|
-
component.pageSize = size;
|
|
345
|
-
component.pageIndex = 1;
|
|
346
|
-
component.tmpPageIndex = 1;
|
|
347
|
-
setComponent({
|
|
348
|
-
pageSize: size,
|
|
349
|
-
pageIndex: 1,
|
|
350
|
-
tmpPageIndex: 1
|
|
351
|
-
});
|
|
352
|
-
doSearch(component);
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
const clearQ = (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
356
|
-
if (e) {
|
|
357
|
-
e.preventDefault();
|
|
358
|
-
}
|
|
359
|
-
const n = getModelName();
|
|
360
|
-
if (n && n.length > 0) {
|
|
361
|
-
const m = (state as any)[n];
|
|
362
|
-
if (m) {
|
|
363
|
-
m.q = '';
|
|
364
|
-
const setObj: any = {};
|
|
365
|
-
setObj[n] = m;
|
|
366
|
-
setState(setObj);
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const search = (event?: React.MouseEvent<HTMLButtonElement, MouseEvent> | React.MouseEvent<HTMLElement, MouseEvent>): void => {
|
|
373
|
-
if (event) {
|
|
374
|
-
event.preventDefault();
|
|
375
|
-
}
|
|
376
|
-
resetAndSearch();
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
const sort = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
380
|
-
event.preventDefault();
|
|
381
|
-
if (event && event.target) {
|
|
382
|
-
const target = event.target as any;
|
|
383
|
-
const s = handleSort(target, component.sortTarget, component.sortField, component.sortType);
|
|
384
|
-
setComponent({
|
|
385
|
-
sortField: s.field,
|
|
386
|
-
sortType: s.type,
|
|
387
|
-
sortTarget: target
|
|
388
|
-
});
|
|
389
|
-
component.sortField = s.field;
|
|
390
|
-
component.sortType = s.type;
|
|
391
|
-
component.sortTarget = target;
|
|
392
|
-
}
|
|
393
|
-
if (!component.appendMode) {
|
|
394
|
-
doSearch(component);
|
|
395
|
-
} else {
|
|
396
|
-
resetAndSearch();
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
const changeView = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, view?: string) => {
|
|
400
|
-
if (view && view.length > 0) {
|
|
401
|
-
setComponent({view});
|
|
402
|
-
} else if (event && event.target) {
|
|
403
|
-
const target = event.target as any;
|
|
404
|
-
const v: string = target.getAttribute('data-view');
|
|
405
|
-
if (v && v.length > 0) {
|
|
406
|
-
setComponent({view: v});
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
const resetAndSearch = () => {
|
|
412
|
-
if (running === true) {
|
|
413
|
-
setComponent({ pageIndex: 1, triggerSearch: true });
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
setComponent({ pageIndex: 1, tmpPageIndex: 1 });
|
|
417
|
-
removeSortStatus(component.sortTarget);
|
|
418
|
-
setComponent({
|
|
419
|
-
sortTarget: undefined,
|
|
420
|
-
sortField: undefined,
|
|
421
|
-
append: false,
|
|
422
|
-
pageIndex: 1
|
|
423
|
-
});
|
|
424
|
-
component.sortTarget = undefined;
|
|
425
|
-
component.sortField = undefined;
|
|
426
|
-
component.append = false;
|
|
427
|
-
component.pageIndex = 1;
|
|
428
|
-
doSearch(component);
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
const searchError = (err: any): void => {
|
|
432
|
-
setComponent({ pageIndex: component.tmpPageIndex });
|
|
433
|
-
error(err, p1.resource.value, p1.showError);
|
|
434
|
-
hideLoading(p1.loading)
|
|
435
|
-
};
|
|
436
|
-
const appendList = (p && p.appendList ? p.appendList : appendListOfState);
|
|
437
|
-
const setList = (p && p.setList ? p.setList : setListOfState);
|
|
438
|
-
const _showResults = (s: S, sr: SearchResult<T>, lc: Locale) => {
|
|
439
|
-
if (sr === undefined) {
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
const results = sr?.list || [];
|
|
443
|
-
if (results && results.length > 0) {
|
|
444
|
-
formatResults(results, component.pageIndex, component.pageSize, component.pageSize, p ? p.sequenceNo : undefined, p ? p.format : undefined, lc);
|
|
445
|
-
}
|
|
446
|
-
const am = component.appendMode;
|
|
447
|
-
const pi = (s.page && s.page >= 1 ? s.page : 1);
|
|
448
|
-
setComponent({ total: sr.total, pageIndex: pi, nextPageToken: sr.
|
|
449
|
-
if (am) {
|
|
450
|
-
let limit = s.limit;
|
|
451
|
-
if ((!s.page || s.page <= 1) && s.firstLimit && s.firstLimit > 0) {
|
|
452
|
-
limit = s.firstLimit;
|
|
453
|
-
}
|
|
454
|
-
handleAppend(component, sr.list, limit, sr.
|
|
455
|
-
if (component.append && (s.page && s.page > 1)) {
|
|
456
|
-
appendList(results, component.list, setState as any);
|
|
457
|
-
} else {
|
|
458
|
-
setList(results, setState as any);
|
|
459
|
-
}
|
|
460
|
-
} else {
|
|
461
|
-
showPaging(component, sr.list, s.limit, sr.total);
|
|
462
|
-
setList(results, setState as any);
|
|
463
|
-
setComponent({ tmpPageIndex: s.page });
|
|
464
|
-
if (s.limit) {
|
|
465
|
-
const m1 = buildMessage(p1.resource, s.page, s.limit, sr.list, sr.total);
|
|
466
|
-
p1.showMessage(m1);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
setRunning(false);
|
|
470
|
-
hideLoading(p1.loading);
|
|
471
|
-
if (component.triggerSearch) {
|
|
472
|
-
setComponent({ triggerSearch: false });
|
|
473
|
-
resetAndSearch();
|
|
474
|
-
}
|
|
475
|
-
};
|
|
476
|
-
const showResults = (p && p.showResults ? p.showResults : _showResults);
|
|
477
|
-
|
|
478
|
-
const showMore = (event: any) => {
|
|
479
|
-
event.preventDefault();
|
|
480
|
-
const n = component.pageIndex ? component.pageIndex + 1 : 2;
|
|
481
|
-
const m = component.pageIndex;
|
|
482
|
-
setComponent({ tmpPageIndex: m, pageIndex: n, append: true });
|
|
483
|
-
component.tmpPageIndex = m;
|
|
484
|
-
component.pageIndex = n;
|
|
485
|
-
component.append = true;
|
|
486
|
-
doSearch(component);
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
const pageChanged = (data: PageChange) => {
|
|
490
|
-
const { page, size } = data;
|
|
491
|
-
setComponent({ pageIndex: page, pageSize: size, append: false });
|
|
492
|
-
component.pageIndex = page;
|
|
493
|
-
component.pageSize = size;
|
|
494
|
-
component.append = false;
|
|
495
|
-
doSearch(component);
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
return {
|
|
499
|
-
...baseProps,
|
|
500
|
-
running,
|
|
501
|
-
setRunning,
|
|
502
|
-
getCurrencyCode,
|
|
503
|
-
resource: p1.resource.resource(),
|
|
504
|
-
setComponent,
|
|
505
|
-
component,
|
|
506
|
-
showMessage: p1.showMessage,
|
|
507
|
-
load,
|
|
508
|
-
search,
|
|
509
|
-
sort,
|
|
510
|
-
changeView,
|
|
511
|
-
showMore,
|
|
512
|
-
toggleFilter,
|
|
513
|
-
doSearch,
|
|
514
|
-
pageChanged,
|
|
515
|
-
pageSizeChanged,
|
|
516
|
-
clearQ,
|
|
517
|
-
showResults,
|
|
518
|
-
getFields,
|
|
519
|
-
getModelName,
|
|
520
|
-
format: p ? p.format : undefined,
|
|
521
|
-
searchError
|
|
522
|
-
};
|
|
523
|
-
};
|
|
1
|
+
import {useEffect, useState} from 'react';
|
|
2
|
+
import {error, getName, getRemoveError, getValidateForm, handleToggle, hideLoading, initForm, Locale, PageChange, pageSizes, removeFormError, ResourceService, SearchParameter, SearchResult, SearchService, showLoading} from './core';
|
|
3
|
+
import {DispatchWithCallback, useMergeState} from './merge';
|
|
4
|
+
import {clone} from './reflect';
|
|
5
|
+
import {buildFromUrl} from './route';
|
|
6
|
+
import {addParametersIntoUrl, append, buildMessage, formatResults, getFieldsFromForm, getModel, handleAppend, handleSort, initFilter, mergeFilter as mergeFilter2, Pagination, removeSortStatus, showPaging, Sortable, validate} from './search';
|
|
7
|
+
import {enLocale} from './state';
|
|
8
|
+
import {useUpdate} from './update';
|
|
9
|
+
|
|
10
|
+
export interface Searchable extends Pagination, Sortable {
|
|
11
|
+
nextPageToken?: string;
|
|
12
|
+
excluding?: string[]|number[];
|
|
13
|
+
}
|
|
14
|
+
interface Filter {
|
|
15
|
+
page?: number;
|
|
16
|
+
limit?: number;
|
|
17
|
+
firstLimit?: number;
|
|
18
|
+
fields?: string[];
|
|
19
|
+
sort?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const callSearch = <T, S extends Filter>(se: S, search3: (s: S, limit?: number, offset?: number|string, fields?: string[]) => Promise<SearchResult<T>>, showResults3: (s: S, sr: SearchResult<T>, lc: Locale) => void, searchError3: (err: any) => void, lc: Locale, nextPageToken?: string) => {
|
|
23
|
+
const s = clone(se);
|
|
24
|
+
let page = se.page;
|
|
25
|
+
if (!page || page < 1) {
|
|
26
|
+
page = 1;
|
|
27
|
+
}
|
|
28
|
+
let offset: number;
|
|
29
|
+
if (!se.limit || se.limit <= 0) {
|
|
30
|
+
se.limit = 24;
|
|
31
|
+
}
|
|
32
|
+
if (se.firstLimit && se.firstLimit > 0) {
|
|
33
|
+
offset = se.limit * (page - 2) + se.firstLimit;
|
|
34
|
+
} else {
|
|
35
|
+
offset = se.limit * (page - 1);
|
|
36
|
+
}
|
|
37
|
+
const limit = (page <= 1 && se.firstLimit && se.firstLimit > 0 ? se.firstLimit : se.limit);
|
|
38
|
+
const next = (nextPageToken && nextPageToken.length > 0 ? nextPageToken : offset);
|
|
39
|
+
const fields = se.fields;
|
|
40
|
+
delete se['page'];
|
|
41
|
+
delete se['fields'];
|
|
42
|
+
delete se['limit'];
|
|
43
|
+
delete se['firstLimit'];
|
|
44
|
+
search3(s, limit, next, fields).then(sr => {
|
|
45
|
+
showResults3(s, sr, lc);
|
|
46
|
+
}).catch(err => err && searchError3(err));
|
|
47
|
+
};
|
|
48
|
+
const appendListOfState = <T, S extends Filter>(results: T[], list: T[]|undefined, setState2: DispatchWithCallback<Partial<SearchComponentState<T, S>>>) => {
|
|
49
|
+
const arr = append(list, results);
|
|
50
|
+
setState2({ list: arr } as any);
|
|
51
|
+
};
|
|
52
|
+
const setListOfState = <T, S extends Filter>(list: T[], setState2: DispatchWithCallback<Partial<SearchComponentState<T, S>>>) => {
|
|
53
|
+
setState2({ list } as any);
|
|
54
|
+
};
|
|
55
|
+
export interface InitSearchComponentParam<T, M extends Filter, S> extends SearchComponentParam<T, M> {
|
|
56
|
+
createFilter?: () => M;
|
|
57
|
+
initialize?: (ld: (s: M, auto?: boolean) => void, setState2: DispatchWithCallback<Partial<S>>, com?: SearchComponentState<T, M>) => void;
|
|
58
|
+
}
|
|
59
|
+
export interface HookPropsSearchParameter<T, S extends Filter, ST extends SearchComponentState<T, S>, P> extends HookPropsBaseSearchParameter<T, S, ST, P> {
|
|
60
|
+
createFilter?: () => S;
|
|
61
|
+
initialize?: (ld: (s: S, auto?: boolean) => void, setState2: DispatchWithCallback<Partial<ST>>, com?: SearchComponentState<T, S>) => void;
|
|
62
|
+
}
|
|
63
|
+
export interface SearchComponentParam<T, M extends Filter> {
|
|
64
|
+
addable?: boolean;
|
|
65
|
+
editable?: boolean;
|
|
66
|
+
approvable?: boolean;
|
|
67
|
+
deletable?: boolean;
|
|
68
|
+
|
|
69
|
+
keys?: string[];
|
|
70
|
+
sequenceNo?: string;
|
|
71
|
+
hideFilter?: boolean;
|
|
72
|
+
name?: string;
|
|
73
|
+
fields?: string[];
|
|
74
|
+
appendMode?: boolean;
|
|
75
|
+
pageSizes?: number[];
|
|
76
|
+
pageIndex?: number;
|
|
77
|
+
pageSize?: number;
|
|
78
|
+
initPageSize?: number;
|
|
79
|
+
pageMaxSize?: number;
|
|
80
|
+
ignoreUrlParam?: boolean;
|
|
81
|
+
|
|
82
|
+
load?: (s: M, auto?: boolean) => void;
|
|
83
|
+
getModelName?: () => string;
|
|
84
|
+
getCurrencyCode?: () => string;
|
|
85
|
+
setFilter?: (s: M) => void;
|
|
86
|
+
getFilter?: (se?: Searchable) => M;
|
|
87
|
+
getFields?: () => string[]|undefined;
|
|
88
|
+
validateSearch?: (se: M, callback: () => void) => void;
|
|
89
|
+
// prepareCustomData?: (data: any) => void;
|
|
90
|
+
format?(obj: T, locale?: Locale): T;
|
|
91
|
+
showResults?(s: M, sr: SearchResult<T>, lc: Locale): void;
|
|
92
|
+
appendList?(results: T[], list: T[]|undefined, s: DispatchWithCallback<Partial<SearchComponentState<T, M>>>): void;
|
|
93
|
+
setList?(list: T[], s: DispatchWithCallback<Partial<SearchComponentState<T, M>>>): void;
|
|
94
|
+
/*
|
|
95
|
+
showLoading?(firstTime?: boolean): void;
|
|
96
|
+
hideLoading?(): void;
|
|
97
|
+
decodeFromForm?(form: HTMLFormElement, locale?: Locale, currencyCode?: string): any;
|
|
98
|
+
registerEvents?(form: HTMLFormElement): void;
|
|
99
|
+
validateForm?(form: HTMLFormElement, locale?: Locale, focusFirst?: boolean, scroll?: boolean): boolean;
|
|
100
|
+
removeFormError?(form: HTMLFormElement): void;
|
|
101
|
+
removeError?(el: HTMLInputElement): void;
|
|
102
|
+
*/
|
|
103
|
+
}
|
|
104
|
+
export interface HookBaseSearchParameter<T, S extends Filter, ST extends SearchComponentState<T, S>> extends SearchComponentParam<T, S> {
|
|
105
|
+
refForm: any;
|
|
106
|
+
initialState: ST;
|
|
107
|
+
service: ((s: S, limit?: number, offset?: number|string, fields?: string[]) => Promise<SearchResult<T>>) | SearchService<T, S>;
|
|
108
|
+
resource: ResourceService;
|
|
109
|
+
showMessage: (msg: string) => void;
|
|
110
|
+
showError: (m: string, header?: string, detail?: string, callback?: () => void) => void;
|
|
111
|
+
getLocale?: () => Locale;
|
|
112
|
+
autoSearch?: boolean;
|
|
113
|
+
}
|
|
114
|
+
export interface HookPropsBaseSearchParameter<T, S extends Filter, ST extends SearchComponentState<T, S>, P> extends HookBaseSearchParameter<T, S, ST> {
|
|
115
|
+
props?: P;
|
|
116
|
+
// prepareCustomData?: (data: any) => void;
|
|
117
|
+
}
|
|
118
|
+
export interface SearchComponentState<T, S> extends Pagination, Sortable {
|
|
119
|
+
view?: string;
|
|
120
|
+
nextPageToken?: string;
|
|
121
|
+
keys?: string[];
|
|
122
|
+
filter?: S;
|
|
123
|
+
list?: T[];
|
|
124
|
+
|
|
125
|
+
format?: (obj: T, locale: Locale) => T;
|
|
126
|
+
fields?: string[];
|
|
127
|
+
initFields?: boolean;
|
|
128
|
+
triggerSearch?: boolean;
|
|
129
|
+
tmpPageIndex?: number;
|
|
130
|
+
|
|
131
|
+
pageMaxSize?: number;
|
|
132
|
+
pageSizes?: number[];
|
|
133
|
+
excluding?: string[]|number[];
|
|
134
|
+
hideFilter?: boolean;
|
|
135
|
+
|
|
136
|
+
ignoreUrlParam?: boolean;
|
|
137
|
+
viewable?: boolean;
|
|
138
|
+
addable?: boolean;
|
|
139
|
+
editable?: boolean;
|
|
140
|
+
approvable?: boolean;
|
|
141
|
+
deletable?: boolean;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function mergeParam<T, S extends Filter>(p?: SearchComponentParam<T, S>): SearchComponentParam<T, S> {
|
|
145
|
+
if (p) {
|
|
146
|
+
if (!p.sequenceNo) {
|
|
147
|
+
p.sequenceNo = 'sequenceNo';
|
|
148
|
+
}
|
|
149
|
+
if (!p.pageSize) {
|
|
150
|
+
p.pageSize = 24;
|
|
151
|
+
}
|
|
152
|
+
if (!p.pageSizes) {
|
|
153
|
+
p.pageSizes = pageSizes;
|
|
154
|
+
}
|
|
155
|
+
if (!p.pageMaxSize || p.pageMaxSize <= 0) {
|
|
156
|
+
p.pageMaxSize = 7;
|
|
157
|
+
}
|
|
158
|
+
if (p.hideFilter === undefined) {
|
|
159
|
+
p.hideFilter = true;
|
|
160
|
+
}
|
|
161
|
+
if (p.addable === undefined) {
|
|
162
|
+
p.addable = true;
|
|
163
|
+
}
|
|
164
|
+
if (p.editable === undefined) {
|
|
165
|
+
p.editable = true;
|
|
166
|
+
}
|
|
167
|
+
if (p.approvable === undefined) {
|
|
168
|
+
p.approvable = true;
|
|
169
|
+
}
|
|
170
|
+
if (p.deletable === undefined) {
|
|
171
|
+
p.deletable = true;
|
|
172
|
+
}
|
|
173
|
+
return p;
|
|
174
|
+
} else {
|
|
175
|
+
return {
|
|
176
|
+
sequenceNo: 'sequenceNo',
|
|
177
|
+
pageSize: 24,
|
|
178
|
+
pageSizes,
|
|
179
|
+
pageMaxSize: 7,
|
|
180
|
+
hideFilter: true,
|
|
181
|
+
addable: true,
|
|
182
|
+
editable: true,
|
|
183
|
+
approvable: true,
|
|
184
|
+
deletable: true
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export const useSearch = <T, S extends Filter, ST extends SearchComponentState<T, S>>(
|
|
189
|
+
refForm: any,
|
|
190
|
+
initialState: ST,
|
|
191
|
+
service: ((s: S, limit?: number, offset?: number|string, fields?: string[]) => Promise<SearchResult<T>>) | SearchService<T, S>,
|
|
192
|
+
p2: SearchParameter,
|
|
193
|
+
p?: InitSearchComponentParam<T, S, ST>,
|
|
194
|
+
) => {
|
|
195
|
+
const baseProps = useCoreSearch(refForm, initialState, service, p2, p);
|
|
196
|
+
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
const { load, setState, component, searchError } = baseProps;
|
|
199
|
+
if (refForm) {
|
|
200
|
+
const registerEvents = (p2.ui ? p2.ui.registerEvents : undefined);
|
|
201
|
+
initForm(refForm.current, registerEvents);
|
|
202
|
+
}
|
|
203
|
+
if (p && p.initialize) {
|
|
204
|
+
p.initialize(load, setState, component);
|
|
205
|
+
} else {
|
|
206
|
+
const se: S|undefined = (p && p.createFilter ? p.createFilter() : undefined);
|
|
207
|
+
try {
|
|
208
|
+
const s: any = mergeFilter2(buildFromUrl<S>(se), se, component.pageSizes);
|
|
209
|
+
load(s, p2.auto);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
searchError(error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
215
|
+
}, []);
|
|
216
|
+
return { ...baseProps };
|
|
217
|
+
};
|
|
218
|
+
export const useSearchOneProps = <T, S extends Filter, ST extends SearchComponentState<T, S>, P>(p: HookPropsSearchParameter<T, S, ST, P>) => {
|
|
219
|
+
return useSearch(p.refForm, p.initialState, p.service, p, p);
|
|
220
|
+
};
|
|
221
|
+
export const useSearchOne = <T, S extends Filter, ST extends SearchComponentState<T, S>>(p: HookBaseSearchParameter<T, S, ST>) => {
|
|
222
|
+
return useCoreSearch(p.refForm, p.initialState, p.service, p, p);
|
|
223
|
+
};
|
|
224
|
+
export const useCoreSearch = <T, S extends Filter, ST>(
|
|
225
|
+
refForm: any,
|
|
226
|
+
initialState: ST,
|
|
227
|
+
service: ((s: S, limit?: number, offset?: number|string, fields?: string[]) => Promise<SearchResult<T>>) | SearchService<T, S>,
|
|
228
|
+
p1: SearchParameter,
|
|
229
|
+
p2?: SearchComponentParam<T, S>
|
|
230
|
+
) => {
|
|
231
|
+
const p = mergeParam(p2);
|
|
232
|
+
const [running, setRunning] = useState<boolean>();
|
|
233
|
+
|
|
234
|
+
const _getModelName = (): string => {
|
|
235
|
+
return getName('filter', p && p.name ? p.name : undefined);
|
|
236
|
+
};
|
|
237
|
+
const getModelName = (p && p.getModelName ? p.getModelName : _getModelName);
|
|
238
|
+
|
|
239
|
+
// const setState2: <K extends keyof S, P>(st: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null), cb?: () => void) => void;
|
|
240
|
+
const baseProps = useUpdate<ST>(initialState, getModelName, p1.getLocale, getRemoveError(p1));
|
|
241
|
+
const { state, setState } = baseProps;
|
|
242
|
+
const [rerender, setRerender] = useState(false);
|
|
243
|
+
|
|
244
|
+
// trigger re-render page when change state in useSearch
|
|
245
|
+
useEffect(() => {
|
|
246
|
+
setRerender(!rerender);
|
|
247
|
+
}, [state]);
|
|
248
|
+
|
|
249
|
+
const _getCurrencyCode = (): string => {
|
|
250
|
+
return refForm && refForm.current ? refForm.current.getAttribute('currency-code') : null;
|
|
251
|
+
};
|
|
252
|
+
const getCurrencyCode = p && p.getCurrencyCode ? p.getCurrencyCode : _getCurrencyCode;
|
|
253
|
+
|
|
254
|
+
// const p = createSearchComponentState<T, S>(p1);
|
|
255
|
+
const [component, setComponent] = useMergeState<SearchComponentState<T, S>>(p);
|
|
256
|
+
|
|
257
|
+
const toggleFilter = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
|
|
258
|
+
const x = !component.hideFilter;
|
|
259
|
+
handleToggle(event.target as HTMLInputElement, !x);
|
|
260
|
+
setComponent({ hideFilter: x });
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const _getFields = (): string[]|undefined => {
|
|
264
|
+
const { fields, initFields } = component;
|
|
265
|
+
const fs = getFieldsFromForm(fields, initFields, refForm.current);
|
|
266
|
+
setComponent({ fields: fs, initFields: true });
|
|
267
|
+
return fs;
|
|
268
|
+
};
|
|
269
|
+
const getFields = p && p.getFields ? p.getFields : _getFields;
|
|
270
|
+
|
|
271
|
+
const _getFilter = (se?: Searchable): S => {
|
|
272
|
+
if (!se) {
|
|
273
|
+
se = component;
|
|
274
|
+
}
|
|
275
|
+
let keys = p && p.keys ? p.keys : undefined;
|
|
276
|
+
if (!keys && typeof service !== 'function' && service.keys) {
|
|
277
|
+
keys = service.keys();
|
|
278
|
+
}
|
|
279
|
+
const n = getModelName();
|
|
280
|
+
let fs = p && p.fields;
|
|
281
|
+
if (!fs || fs.length <= 0) {
|
|
282
|
+
fs = getFields();
|
|
283
|
+
}
|
|
284
|
+
const obj3 = getModel<S>(state, n, se, fs, se.excluding);
|
|
285
|
+
return obj3;
|
|
286
|
+
};
|
|
287
|
+
const getFilter = p && p.getFilter ? p.getFilter : _getFilter;
|
|
288
|
+
const _setFilter = (s: S): void => {
|
|
289
|
+
const objSet: any = {};
|
|
290
|
+
const n = getModelName();
|
|
291
|
+
objSet[n] = s;
|
|
292
|
+
setState(objSet);
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const setFilter = p && p.setFilter ? p.setFilter : _setFilter;
|
|
296
|
+
|
|
297
|
+
const _load = (s: S, auto?: boolean): void => {
|
|
298
|
+
const com = Object.assign({}, component);
|
|
299
|
+
const obj2 = initFilter(s, com);
|
|
300
|
+
setComponent(com);
|
|
301
|
+
setFilter(obj2);
|
|
302
|
+
const runSearch = doSearch;
|
|
303
|
+
if (auto) {
|
|
304
|
+
setTimeout(() => {
|
|
305
|
+
runSearch((obj2 as Searchable), true);
|
|
306
|
+
}, 0);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
const load = p && p.load ? p.load : _load;
|
|
310
|
+
|
|
311
|
+
const doSearch = (se: Searchable, isFirstLoad?: boolean) => {
|
|
312
|
+
removeFormError(p1, refForm.current);
|
|
313
|
+
const s = getFilter(se);
|
|
314
|
+
|
|
315
|
+
if (isFirstLoad){
|
|
316
|
+
setState(state); // force update state if we refresh again page
|
|
317
|
+
}
|
|
318
|
+
const isStillRunning = running;
|
|
319
|
+
validateSearch(s, () => {
|
|
320
|
+
if (isStillRunning === true) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
setRunning(true);
|
|
324
|
+
showLoading(p1.loading);
|
|
325
|
+
if (p && !p.ignoreUrlParam) {
|
|
326
|
+
addParametersIntoUrl(s, isFirstLoad);
|
|
327
|
+
}
|
|
328
|
+
const lc = p1.getLocale ? p1.getLocale() : enLocale;
|
|
329
|
+
if (typeof service === 'function') {
|
|
330
|
+
callSearch<T, S>(s, service, showResults, searchError, lc, se.nextPageToken);
|
|
331
|
+
} else {
|
|
332
|
+
callSearch<T, S>(s, service.search, showResults, searchError, lc, se.nextPageToken);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const _validateSearch = (se: S, callback: () => void) => {
|
|
338
|
+
validate(se, callback, refForm.current, (p1.getLocale ? p1.getLocale() : undefined), getValidateForm(p1));
|
|
339
|
+
};
|
|
340
|
+
const validateSearch = p && p.validateSearch ? p.validateSearch : _validateSearch;
|
|
341
|
+
|
|
342
|
+
const pageSizeChanged = (event: any) => {
|
|
343
|
+
const size = parseInt(event.currentTarget.value, 10);
|
|
344
|
+
component.pageSize = size;
|
|
345
|
+
component.pageIndex = 1;
|
|
346
|
+
component.tmpPageIndex = 1;
|
|
347
|
+
setComponent({
|
|
348
|
+
pageSize: size,
|
|
349
|
+
pageIndex: 1,
|
|
350
|
+
tmpPageIndex: 1
|
|
351
|
+
});
|
|
352
|
+
doSearch(component);
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const clearQ = (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
356
|
+
if (e) {
|
|
357
|
+
e.preventDefault();
|
|
358
|
+
}
|
|
359
|
+
const n = getModelName();
|
|
360
|
+
if (n && n.length > 0) {
|
|
361
|
+
const m = (state as any)[n];
|
|
362
|
+
if (m) {
|
|
363
|
+
m.q = '';
|
|
364
|
+
const setObj: any = {};
|
|
365
|
+
setObj[n] = m;
|
|
366
|
+
setState(setObj);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const search = (event?: React.MouseEvent<HTMLButtonElement, MouseEvent> | React.MouseEvent<HTMLElement, MouseEvent>): void => {
|
|
373
|
+
if (event) {
|
|
374
|
+
event.preventDefault();
|
|
375
|
+
}
|
|
376
|
+
resetAndSearch();
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const sort = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
380
|
+
event.preventDefault();
|
|
381
|
+
if (event && event.target) {
|
|
382
|
+
const target = event.target as any;
|
|
383
|
+
const s = handleSort(target, component.sortTarget, component.sortField, component.sortType);
|
|
384
|
+
setComponent({
|
|
385
|
+
sortField: s.field,
|
|
386
|
+
sortType: s.type,
|
|
387
|
+
sortTarget: target
|
|
388
|
+
});
|
|
389
|
+
component.sortField = s.field;
|
|
390
|
+
component.sortType = s.type;
|
|
391
|
+
component.sortTarget = target;
|
|
392
|
+
}
|
|
393
|
+
if (!component.appendMode) {
|
|
394
|
+
doSearch(component);
|
|
395
|
+
} else {
|
|
396
|
+
resetAndSearch();
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
const changeView = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, view?: string) => {
|
|
400
|
+
if (view && view.length > 0) {
|
|
401
|
+
setComponent({view});
|
|
402
|
+
} else if (event && event.target) {
|
|
403
|
+
const target = event.target as any;
|
|
404
|
+
const v: string = target.getAttribute('data-view');
|
|
405
|
+
if (v && v.length > 0) {
|
|
406
|
+
setComponent({view: v});
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
const resetAndSearch = () => {
|
|
412
|
+
if (running === true) {
|
|
413
|
+
setComponent({ pageIndex: 1, triggerSearch: true });
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
setComponent({ pageIndex: 1, tmpPageIndex: 1 });
|
|
417
|
+
removeSortStatus(component.sortTarget);
|
|
418
|
+
setComponent({
|
|
419
|
+
sortTarget: undefined,
|
|
420
|
+
sortField: undefined,
|
|
421
|
+
append: false,
|
|
422
|
+
pageIndex: 1
|
|
423
|
+
});
|
|
424
|
+
component.sortTarget = undefined;
|
|
425
|
+
component.sortField = undefined;
|
|
426
|
+
component.append = false;
|
|
427
|
+
component.pageIndex = 1;
|
|
428
|
+
doSearch(component);
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
const searchError = (err: any): void => {
|
|
432
|
+
setComponent({ pageIndex: component.tmpPageIndex });
|
|
433
|
+
error(err, p1.resource.value, p1.showError);
|
|
434
|
+
hideLoading(p1.loading)
|
|
435
|
+
};
|
|
436
|
+
const appendList = (p && p.appendList ? p.appendList : appendListOfState);
|
|
437
|
+
const setList = (p && p.setList ? p.setList : setListOfState);
|
|
438
|
+
const _showResults = (s: S, sr: SearchResult<T>, lc: Locale) => {
|
|
439
|
+
if (sr === undefined) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const results = sr?.list || [];
|
|
443
|
+
if (results && results.length > 0) {
|
|
444
|
+
formatResults(results, component.pageIndex, component.pageSize, component.pageSize, p ? p.sequenceNo : undefined, p ? p.format : undefined, lc);
|
|
445
|
+
}
|
|
446
|
+
const am = component.appendMode;
|
|
447
|
+
const pi = (s.page && s.page >= 1 ? s.page : 1);
|
|
448
|
+
setComponent({ total: sr.total, pageIndex: pi, nextPageToken: sr.next });
|
|
449
|
+
if (am) {
|
|
450
|
+
let limit = s.limit;
|
|
451
|
+
if ((!s.page || s.page <= 1) && s.firstLimit && s.firstLimit > 0) {
|
|
452
|
+
limit = s.firstLimit;
|
|
453
|
+
}
|
|
454
|
+
handleAppend(component, sr.list, limit, sr.next);
|
|
455
|
+
if (component.append && (s.page && s.page > 1)) {
|
|
456
|
+
appendList(results, component.list, setState as any);
|
|
457
|
+
} else {
|
|
458
|
+
setList(results, setState as any);
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
showPaging(component, sr.list, s.limit, sr.total);
|
|
462
|
+
setList(results, setState as any);
|
|
463
|
+
setComponent({ tmpPageIndex: s.page });
|
|
464
|
+
if (s.limit) {
|
|
465
|
+
const m1 = buildMessage(p1.resource, s.page, s.limit, sr.list, sr.total);
|
|
466
|
+
p1.showMessage(m1);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
setRunning(false);
|
|
470
|
+
hideLoading(p1.loading);
|
|
471
|
+
if (component.triggerSearch) {
|
|
472
|
+
setComponent({ triggerSearch: false });
|
|
473
|
+
resetAndSearch();
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
const showResults = (p && p.showResults ? p.showResults : _showResults);
|
|
477
|
+
|
|
478
|
+
const showMore = (event: any) => {
|
|
479
|
+
event.preventDefault();
|
|
480
|
+
const n = component.pageIndex ? component.pageIndex + 1 : 2;
|
|
481
|
+
const m = component.pageIndex;
|
|
482
|
+
setComponent({ tmpPageIndex: m, pageIndex: n, append: true });
|
|
483
|
+
component.tmpPageIndex = m;
|
|
484
|
+
component.pageIndex = n;
|
|
485
|
+
component.append = true;
|
|
486
|
+
doSearch(component);
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
const pageChanged = (data: PageChange) => {
|
|
490
|
+
const { page, size } = data;
|
|
491
|
+
setComponent({ pageIndex: page, pageSize: size, append: false });
|
|
492
|
+
component.pageIndex = page;
|
|
493
|
+
component.pageSize = size;
|
|
494
|
+
component.append = false;
|
|
495
|
+
doSearch(component);
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
return {
|
|
499
|
+
...baseProps,
|
|
500
|
+
running,
|
|
501
|
+
setRunning,
|
|
502
|
+
getCurrencyCode,
|
|
503
|
+
resource: p1.resource.resource(),
|
|
504
|
+
setComponent,
|
|
505
|
+
component,
|
|
506
|
+
showMessage: p1.showMessage,
|
|
507
|
+
load,
|
|
508
|
+
search,
|
|
509
|
+
sort,
|
|
510
|
+
changeView,
|
|
511
|
+
showMore,
|
|
512
|
+
toggleFilter,
|
|
513
|
+
doSearch,
|
|
514
|
+
pageChanged,
|
|
515
|
+
pageSizeChanged,
|
|
516
|
+
clearQ,
|
|
517
|
+
showResults,
|
|
518
|
+
getFields,
|
|
519
|
+
getModelName,
|
|
520
|
+
format: p ? p.format : undefined,
|
|
521
|
+
searchError
|
|
522
|
+
};
|
|
523
|
+
};
|