ui-soxo-bootstrap-core 2.6.1-dev.10 → 2.6.1-dev.11

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,5 +1,124 @@
1
1
 
2
2
 
3
+ // import React, { useState, useEffect, useRef } from "react";
4
+ // import { Select, Checkbox, Input, Spin } from "antd";
5
+ // import { CoreScripts } from "../../../../../models";
6
+
7
+ // const { Search } = Input;
8
+
9
+ // export default function AdvancedSearchSelect({ field, value = [], onChange }) {
10
+ // const [searchResults, setSearchResults] = useState([]); // only API results
11
+ // const [selectedItems, setSelectedItems] = useState(value); // persisted selections
12
+ // const [loading, setLoading] = useState(false);
13
+ // const debounceRef = useRef(null);
14
+
15
+ // // Sync selectedItems if parent value changes externally
16
+ // useEffect(() => {
17
+ // setSelectedItems(value);
18
+ // }, [value]);
19
+
20
+ // const loadOptions = async (searchText = "") => {
21
+ // try {
22
+ // setLoading(true);
23
+
24
+ // let query = field?.search_query || "";
25
+ // query = query.replace("@search_text;", searchText || "");
26
+
27
+ // const res = await CoreScripts.getQuery({ script: query });
28
+ // const data = Array.isArray(res) ? res[0] : [];
29
+ // const apiValues = data?.map((r) => r[field.field]) || [];
30
+
31
+ // setSearchResults(apiValues);
32
+ // } catch (error) {
33
+ // console.error("Search API error", error);
34
+ // } finally {
35
+ // setLoading(false);
36
+ // }
37
+ // };
38
+
39
+ // useEffect(() => {
40
+ // loadOptions("");
41
+ // }, [field]);
42
+
43
+ // const handleSearch = (text) => {
44
+ // if (debounceRef.current) clearTimeout(debounceRef.current);
45
+ // debounceRef.current = setTimeout(() => loadOptions(text), 400);
46
+ // };
47
+
48
+ // const toggleValue = (checked, item) => {
49
+ // let newValues;
50
+
51
+ // if (checked) {
52
+ // newValues = [...selectedItems, item];
53
+ // } else {
54
+ // newValues = selectedItems.filter((v) => v !== item);
55
+ // }
56
+
57
+ // setSelectedItems(newValues); // update local persisted state immediately
58
+ // onChange(newValues);
59
+ // };
60
+
61
+ // // Merge: selected items always on top, then search results (excluding already selected)
62
+ // const displayOptions = [
63
+ // ...selectedItems,
64
+ // ...searchResults.filter((item) => !selectedItems.includes(item)),
65
+ // ];
66
+
67
+ // return (
68
+ // <Select
69
+ // mode="multiple"
70
+ // value={value}
71
+ // style={{ width: 250 }}
72
+ // placeholder={field.caption}
73
+ // allowClear
74
+ // maxTagCount={0}
75
+ // onChange={onChange}
76
+ // maxTagPlaceholder={() => (
77
+ // <span style={{ display: "flex", alignItems: "center", gap: 8 }}>
78
+ // {field.caption}
79
+ // <span
80
+ // style={{
81
+ // background: "#e6f0ff",
82
+ // color: "#1677ff",
83
+ // borderRadius: "10px",
84
+ // padding: "0 8px",
85
+ // fontWeight: 600,
86
+ // fontSize: 12,
87
+ // }}
88
+ // >
89
+ // {value?.length || 0}
90
+ // </span>
91
+ // </span>
92
+ // )}
93
+ // dropdownRender={() => (
94
+ // <div style={{ padding: 10 }}>
95
+ // <Search
96
+ // placeholder={`Search ${field.caption}`}
97
+ // onChange={(e) => handleSearch(e.target.value)}
98
+ // />
99
+
100
+ // <div style={{ maxHeight: 200, overflowY: "auto", marginTop: 10 }}>
101
+ // {loading ? (
102
+ // <Spin />
103
+ // ) : (
104
+ // displayOptions.map((item) => (
105
+ // <div key={item} style={{ marginBottom: 6 }}>
106
+ // <Checkbox
107
+ // checked={selectedItems.includes(item)}
108
+ // onChange={(e) => toggleValue(e.target.checked, item)}
109
+ // >
110
+ // {item}
111
+ // </Checkbox>
112
+ // </div>
113
+ // ))
114
+ // )}
115
+ // </div>
116
+ // </div>
117
+ // )}
118
+ // />
119
+ // );
120
+ // }
121
+
3
122
  import React, { useState, useEffect, useRef } from "react";
4
123
  import { Select, Checkbox, Input, Spin } from "antd";
5
124
  import { CoreScripts } from "../../../../../models";
@@ -54,11 +173,16 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
54
173
  newValues = selectedItems.filter((v) => v !== item);
55
174
  }
56
175
 
57
- setSelectedItems(newValues); // update local persisted state immediately
176
+ setSelectedItems(newValues);
58
177
  onChange(newValues);
59
178
  };
60
179
 
61
- // Merge: selected items always on top, then search results (excluding already selected)
180
+ const handleReset = () => {
181
+ setSelectedItems([]);
182
+ onChange([]);
183
+ };
184
+
185
+ // Merge: selected items always on top, then search results
62
186
  const displayOptions = [
63
187
  ...selectedItems,
64
188
  ...searchResults.filter((item) => !selectedItems.includes(item)),
@@ -113,6 +237,28 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
113
237
  ))
114
238
  )}
115
239
  </div>
240
+
241
+ {/* Reset Button */}
242
+ <div
243
+ style={{
244
+ display: "flex",
245
+ justifyContent: "flex-end",
246
+ marginTop: 10,
247
+ borderTop: "1px solid #f0f0f0",
248
+ paddingTop: 8,
249
+ }}
250
+ >
251
+ <span
252
+ style={{
253
+ color: "#1677ff",
254
+ cursor: "pointer",
255
+ fontWeight: 500,
256
+ }}
257
+ onClick={handleReset}
258
+ >
259
+ Reset
260
+ </span>
261
+ </div>
116
262
  </div>
117
263
  )}
118
264
  />
@@ -173,7 +173,7 @@ export default function ReportingDashboard({
173
173
  parameters = record.input_parameters ? JSON.parse(record.input_parameters) : null;
174
174
 
175
175
  let formContent = {};
176
- const searchFields = parameters.filter((p) => p.type === 'search');
176
+ const searchFields = parameters.filter((p) => p.type === 'search' && p.search_enabled === 'yes');
177
177
  setSearchParameters([...searchFields]);
178
178
 
179
179
  parameters = await parameters?.map((record) => {
@@ -345,170 +345,241 @@ export default function ReportingDashboard({
345
345
  };
346
346
 
347
347
  /**
348
- *
349
- * @param {*} searchValues
350
- * @param {*} searchParameters
351
- * @returns
348
+ *
349
+ * @param {*} searchValues
350
+ * @param {*} searchParameters
351
+ * @returns
352
352
  */
353
353
  const buildSearchCondition = (searchValues, searchParameters) => {
354
- let searchCondition = "";
355
-
356
- Object.keys(searchValues).forEach((key) => {
357
- const arr = searchValues[key];
358
- if (!Array.isArray(arr) || arr.length === 0) return;
359
-
360
- const param = searchParameters.find((p) => p.field === key);
361
- if (!param) return;
362
-
363
- const operator = (param.search_operator || "").trim().toUpperCase();
364
- const column = param.db_column || key;
365
-
366
- if (operator === "LIKE") {
367
- const likeConditions = arr
368
- .map((v) => `${column} LIKE '${v}'`)
369
- .join(" OR ");
370
- searchCondition += ` AND (${likeConditions})`;
371
- }
372
-
373
- else if (operator === "IN") {
374
- const valueList = arr.map((v) => `'${v}'`).join(",");
375
- searchCondition += ` AND ${column} IN (${valueList})`;
376
- }
377
-
378
- else if (operator === "=") {
379
- const eqConditions = arr
380
- .map((v) => `${column} = '${v}'`)
381
- .join(" OR ");
382
- searchCondition += ` AND (${eqConditions})`;
383
- }
354
+ let searchCondition = '';
355
+
356
+ Object.keys(searchValues).forEach((key) => {
357
+ const arr = searchValues[key];
358
+ if (!Array.isArray(arr) || arr.length === 0) return;
359
+
360
+ const param = searchParameters.find((p) => p.field === key);
361
+ if (!param) return;
362
+
363
+ const operator = (param.search_operator || '').trim().toUpperCase();
364
+ const column = param.db_column || key;
365
+
366
+ if (operator === 'LIKE') {
367
+ const likeConditions = arr.map((v) => `${column} LIKE '${v}'`).join(' OR ');
368
+ searchCondition += ` AND (${likeConditions})`;
369
+ } else if (operator === 'IN') {
370
+ const valueList = arr.map((v) => `'${v}'`).join(',');
371
+ searchCondition += ` AND ${column} IN (${valueList})`;
372
+ } else if (operator === '=') {
373
+ const eqConditions = arr.map((v) => `${column} = '${v}'`).join(' OR ');
374
+ searchCondition += ` AND (${eqConditions})`;
375
+ } else if (operator === '!=') {
376
+ const neqConditions = arr.map((v) => `${column} != '${v}'`).join(' AND ');
377
+ searchCondition += ` AND (${neqConditions})`;
378
+ } else {
379
+ // fallback for other operators like > < >= <=
380
+ const conditions = arr.map((v) => `${column} ${operator} '${v}'`).join(' OR ');
381
+ searchCondition += ` AND (${conditions})`;
382
+ }
383
+ });
384
384
 
385
- else if (operator === "!=") {
386
- const neqConditions = arr
387
- .map((v) => `${column} != '${v}'`)
388
- .join(" AND ");
389
- searchCondition += ` AND (${neqConditions})`;
385
+ return searchCondition;
386
+ };
387
+ // const handleSubmit = (values) => {
388
+ // const hasSearchValues = Object.values(searchValues).some((v) => Array.isArray(v) && v.length > 0);
389
+
390
+ // // Check if regular form values have changed since the last submission.
391
+ // const regularValuesChanged = (() => {
392
+ // const newKeys = Object.keys(values);
393
+ // const oldKeys = Object.keys(formContents);
394
+
395
+ // if (newKeys.length !== oldKeys.length) return true;
396
+
397
+ // for (const key of newKeys) {
398
+ // const newValue = values[key];
399
+ // const oldValue = formContents[key];
400
+
401
+ // if (moment.isMoment(newValue) && moment.isMoment(oldValue)) {
402
+ // if (!newValue.isSame(oldValue)) {
403
+ // return true;
404
+ // }
405
+ // } else if (newValue !== oldValue) {
406
+ // // This is a shallow comparison, but should work for primitives and new array/object references.
407
+ // return true;
408
+ // }
409
+ // }
410
+ // return false;
411
+ // })();
412
+
413
+ // if (hasSearchValues && regularValuesChanged) {
414
+ // Modal.confirm({
415
+ // title: 'Combine Filters',
416
+ // content: 'You have applied both standard and advanced filters. Do you want to combine them?',
417
+ // okText: 'Yes, Apply Both',
418
+ // cancelText: 'No, Use Advanced Only',
419
+ // onOk: () => {
420
+ // // User chose to combine filters.
421
+ // const searchCondition = buildSearchCondition(searchValues, searchParameters);
422
+ // const finalValues = {
423
+ // ...values,
424
+ // search_condition: searchCondition,
425
+ // };
426
+ // onFinish(finalValues, 1);
427
+ // },
428
+ // onCancel: () => {
429
+ // // User chose to use only advanced search.
430
+ // const searchCondition = buildSearchCondition(searchValues, searchParameters);
431
+ // const resetValues = {};
432
+ // Object.keys(values).forEach((key) => {
433
+ // resetValues[key] = null;
434
+ // });
435
+ // const finalValues = {
436
+ // ...resetValues,
437
+ // search_condition: searchCondition,
438
+ // };
439
+ // onFinish(finalValues, 1);
440
+ // },
441
+ // });
442
+ // return; // Stop further execution, wait for modal response.
443
+ // }
444
+
445
+ // // --- Default behavior if the condition for the modal is not met ---
446
+
447
+ // let finalValues = values;
448
+ // if (hasSearchValues) {
449
+ // // If only advanced search has values (or regular filters haven't changed), reset regular filters.
450
+ // const searchCondition = buildSearchCondition(searchValues, searchParameters);
451
+ // const resetValues = {};
452
+ // Object.keys(values).forEach((key) => {
453
+ // resetValues[key] = null;
454
+ // });
455
+ // finalValues = {
456
+ // ...resetValues,
457
+ // search_condition: searchCondition,
458
+ // };
459
+ // }
460
+
461
+ // const { pageSize } = pagination;
462
+ // const resetPage = 1;
463
+
464
+ // scriptId.current = null;
465
+
466
+ // // Update URL only when NOT using advanced search
467
+ // if (!hasSearchValues) {
468
+ // const currentUrlParams = Location.search();
469
+ // const { script_id, selected_card, ...cleanParams } = currentUrlParams;
470
+
471
+ // const newParams = new URLSearchParams({
472
+ // ...cleanParams,
473
+ // current: resetPage,
474
+ // pageSize,
475
+ // });
476
+
477
+ // const newUrl = `${window.location.pathname}?${newParams.toString()}`;
478
+ // window.history.replaceState({}, '', newUrl);
479
+ // }
480
+
481
+ // // Call report API
482
+ // onFinish(finalValues, resetPage);
483
+ // };
484
+
485
+ const handleSubmit = (values) => {
486
+ const hasSearchValues = Object.values(searchValues).some((v) => Array.isArray(v) && v.length > 0);
487
+
488
+ if (!hasSearchValues) {
489
+ runSubmit(values);
490
+ return;
390
491
  }
391
492
 
392
- else {
393
- // fallback for other operators like > < >= <=
394
- const conditions = arr
395
- .map((v) => `${column} ${operator} '${v}'`)
396
- .join(" OR ");
397
- searchCondition += ` AND (${conditions})`;
398
- }
399
- });
493
+ // Check if form values changed (date or others)
494
+ const formChanged = Object.keys(values).some((key) => {
495
+ const newVal = values[key];
496
+ const oldVal = formContents[key];
400
497
 
401
- return searchCondition;
402
- };
403
- const handleSubmit = (values) => {
498
+ if (moment.isMoment(newVal) && moment.isMoment(oldVal)) {
499
+ return !newVal.isSame(oldVal, 'day');
500
+ }
404
501
 
405
- const hasSearchValues = Object.values(searchValues).some(
406
- (v) => Array.isArray(v) && v.length > 0
407
- );
502
+ return newVal !== oldVal;
503
+ });
408
504
 
409
- let finalValues = values;
505
+ if (formChanged) {
506
+ Modal.confirm({
507
+ title: 'Filters changed',
508
+ content: 'You changed some filters. Do you want to search using these filters also?',
509
+ okText: 'Yes',
510
+ cancelText: 'No',
410
511
 
411
- if (hasSearchValues) {
512
+ onOk() {
513
+ // YES → send form values + search condition
514
+ const searchCondition = buildSearchCondition(searchValues, searchParameters);
412
515
 
413
- const searchCondition = buildSearchCondition(
414
- searchValues,
415
- searchParameters
416
- );
516
+ const finalValues = {
517
+ ...values,
518
+ search_condition: searchCondition,
519
+ };
417
520
 
418
- const resetValues = {};
419
- Object.keys(values).forEach((key) => {
420
- resetValues[key] = null;
421
- });
521
+ runSubmit(finalValues);
522
+ },
422
523
 
423
- finalValues = {
424
- ...resetValues,
425
- search_condition: searchCondition,
426
- };
427
- }
524
+ onCancel() {
525
+ // NO → reset form values
526
+ const searchCondition = buildSearchCondition(searchValues, searchParameters);
428
527
 
429
- const { pageSize } = pagination;
430
- const resetPage = 1;
528
+ const resetValues = {};
529
+ Object.keys(values).forEach((key) => {
530
+ resetValues[key] = null;
531
+ });
431
532
 
432
- scriptId.current = null;
533
+ const finalValues = {
534
+ ...resetValues,
535
+ search_condition: searchCondition,
536
+ };
433
537
 
434
- if (!hasSearchValues) {
435
- const currentUrlParams = Location.search();
436
- const { script_id, selected_card, ...cleanParams } = currentUrlParams;
538
+ runSubmit(finalValues);
539
+ },
540
+ });
541
+ } else {
542
+ // no form change
543
+ const searchCondition = buildSearchCondition(searchValues, searchParameters);
437
544
 
438
- const newParams = new URLSearchParams({
439
- ...cleanParams,
440
- current: resetPage,
441
- pageSize,
442
- });
545
+ const resetValues = {};
546
+ Object.keys(values).forEach((key) => {
547
+ resetValues[key] = null;
548
+ });
443
549
 
444
- const newUrl = `${window.location.pathname}?${newParams.toString()}`;
445
- window.history.replaceState({}, "", newUrl);
446
- }
550
+ const finalValues = {
551
+ ...resetValues,
552
+ search_condition: searchCondition,
553
+ };
447
554
 
448
- onFinish(finalValues, resetPage);
449
- };
450
- // const handleSubmit = (values) => {
555
+ runSubmit(finalValues);
556
+ }
557
+ };
451
558
 
452
- // // Check if any advanced search value exists
453
- // const hasSearchValues = Object.values(searchValues).some((v) => Array.isArray(v) && v.length > 0);
454
-
455
- // let finalValues = values;
456
- // let searchCondition = '';
457
- // if (hasSearchValues) {
458
- // Object.keys(searchValues).forEach((key) => {
459
- // const arr = searchValues[key];
460
- // if (!Array.isArray(arr) || arr.length === 0) return;
461
-
462
- // // Find input parameter configuration
463
- // const param = searchParameters.find((p) => p.field === key);
464
- // if (!param) return;
465
-
466
- // const operator = (param.search_operator || '').trim(); // LIKE / IN / =
467
- // const column = param.db_column || key; // DB column mapping if available
468
-
469
- // // Build value list
470
- // const valueList = arr.map((v) => `'${v}'`).join(',');
471
-
472
- // // Build SQL condition dynamically
473
- // searchCondition += ` AND ${column} ${operator} (${valueList})`;
474
- // });
475
-
476
- // // Reset normal form parameters
477
- // const resetValues = {};
478
- // Object.keys(values).forEach((key) => {
479
- // resetValues[key] = null;
480
- // });
481
-
482
- // // Final values sent to API
483
- // finalValues = {
484
- // ...resetValues,
485
- // search_condition: searchCondition,
486
- // };
487
- // }
559
+ const runSubmit = (finalValues) => {
560
+ const { pageSize } = pagination;
561
+ const resetPage = 1;
488
562
 
489
- // const { pageSize } = pagination;
490
- // const resetPage = 1;
563
+ scriptId.current = null;
491
564
 
492
- // scriptId.current = null;
565
+ const hasSearchValues = finalValues.search_condition;
493
566
 
494
- // // Update URL only when NOT using advanced search
495
- // if (!hasSearchValues) {
496
- // const currentUrlParams = Location.search();
497
- // const { script_id, selected_card, ...cleanParams } = currentUrlParams;
567
+ if (!hasSearchValues) {
568
+ const currentUrlParams = Location.search();
569
+ const { script_id, selected_card, ...cleanParams } = currentUrlParams;
498
570
 
499
- // const newParams = new URLSearchParams({
500
- // ...cleanParams,
501
- // current: resetPage,
502
- // pageSize,
503
- // });
571
+ const newParams = new URLSearchParams({
572
+ ...cleanParams,
573
+ current: resetPage,
574
+ pageSize,
575
+ });
504
576
 
505
- // const newUrl = `${window.location.pathname}?${newParams.toString()}`;
506
- // window.history.replaceState({}, '', newUrl);
507
- // }
577
+ const newUrl = `${window.location.pathname}?${newParams.toString()}`;
578
+ window.history.replaceState({}, '', newUrl);
579
+ }
508
580
 
509
- // // Call report API
510
- // onFinish(finalValues, resetPage);
511
- // };
581
+ onFinish(finalValues, resetPage);
582
+ };
512
583
  /**
513
584
  *
514
585
  * @param {*} values
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui-soxo-bootstrap-core",
3
- "version": "2.6.1-dev.10",
3
+ "version": "2.6.1-dev.11",
4
4
  "description": "All the Core Components for you to start",
5
5
  "keywords": [
6
6
  "all in one"