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

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,137 +1,20 @@
1
1
 
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
-
122
2
  import React, { useState, useEffect, useRef } from "react";
123
3
  import { Select, Checkbox, Input, Spin } from "antd";
124
4
  import { CoreScripts } from "../../../../../models";
5
+ import "./advance-search.scss";
125
6
 
126
7
  const { Search } = Input;
127
8
 
128
- export default function AdvancedSearchSelect({ field, value = [], onChange }) {
129
- const [searchResults, setSearchResults] = useState([]); // only API results
130
- const [selectedItems, setSelectedItems] = useState(value); // persisted selections
9
+ export default function AdvancedSearchSelect({ reportId, field, value = [], onChange ,onReset}) {
10
+
11
+ const isSearchQuery = !!field.search_query;
12
+
13
+ const [searchResults, setSearchResults] = useState([]);
14
+ const [selectedItems, setSelectedItems] = useState(value);
131
15
  const [loading, setLoading] = useState(false);
132
16
  const debounceRef = useRef(null);
133
17
 
134
- // Sync selectedItems if parent value changes externally
135
18
  useEffect(() => {
136
19
  setSelectedItems(value);
137
20
  }, [value]);
@@ -140,11 +23,14 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
140
23
  try {
141
24
  setLoading(true);
142
25
 
143
- let query = field?.search_query || "";
144
- query = query.replace("@search_text;", searchText || "");
26
+ const formBody = {
27
+ script_id: reportId,
28
+ search_field: field.field,
29
+ search_condition: searchText,
30
+ };
145
31
 
146
- const res = await CoreScripts.getQuery({ script: query });
147
- const data = Array.isArray(res) ? res[0] : [];
32
+ const res = await CoreScripts.getQuerySeacch(formBody);
33
+ const data = Array.isArray(res.data) ? res.data : [];
148
34
  const apiValues = data?.map((r) => r[field.field]) || [];
149
35
 
150
36
  setSearchResults(apiValues);
@@ -156,7 +42,7 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
156
42
  };
157
43
 
158
44
  useEffect(() => {
159
- loadOptions("");
45
+ if (isSearchQuery) loadOptions("");
160
46
  }, [field]);
161
47
 
162
48
  const handleSearch = (text) => {
@@ -167,11 +53,8 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
167
53
  const toggleValue = (checked, item) => {
168
54
  let newValues;
169
55
 
170
- if (checked) {
171
- newValues = [...selectedItems, item];
172
- } else {
173
- newValues = selectedItems.filter((v) => v !== item);
174
- }
56
+ if (checked) newValues = [...selectedItems, item];
57
+ else newValues = selectedItems.filter((v) => v !== item);
175
58
 
176
59
  setSelectedItems(newValues);
177
60
  onChange(newValues);
@@ -180,53 +63,67 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
180
63
  const handleReset = () => {
181
64
  setSelectedItems([]);
182
65
  onChange([]);
66
+ // if (onReset) {
67
+ onReset(); // 🔥 trigger dashboard refresh
68
+ // }
183
69
  };
184
70
 
185
- // Merge: selected items always on top, then search results
186
71
  const displayOptions = [
187
72
  ...selectedItems,
188
73
  ...searchResults.filter((item) => !selectedItems.includes(item)),
189
74
  ];
190
75
 
76
+ const isActive = value && value.length > 0;
77
+
78
+ // -------- INPUT MODE --------
79
+ if (!isSearchQuery) {
80
+ return (
81
+ <Input
82
+ className={`advanced-search-input ${isActive ? "advanced-search-active" : ""}`}
83
+ placeholder={`Search ${field.caption}`}
84
+ // The parent provides an array for `value`.
85
+ // We take the first element for the input's display value.
86
+ value={value[0] || ""}
87
+ onChange={(e) => {
88
+ const text = e.target.value;
89
+ // Always pass an array back to the parent to be consistent with the Select mode.
90
+ onChange(text ? [text] : []);
91
+ }}
92
+ />
93
+ );
94
+ }
95
+
96
+ // -------- SELECT MODE --------
191
97
  return (
192
98
  <Select
99
+ className={`advanced-search-select ${isActive ? "advanced-search-active" : ""}`}
193
100
  mode="multiple"
194
101
  value={value}
195
- style={{ width: 250 }}
196
102
  placeholder={field.caption}
197
103
  allowClear
198
104
  maxTagCount={0}
199
105
  onChange={onChange}
200
106
  maxTagPlaceholder={() => (
201
- <span style={{ display: "flex", alignItems: "center", gap: 8 }}>
107
+ <span className="tag-placeholder">
202
108
  {field.caption}
203
- <span
204
- style={{
205
- background: "#e6f0ff",
206
- color: "#1677ff",
207
- borderRadius: "10px",
208
- padding: "0 8px",
209
- fontWeight: 600,
210
- fontSize: 12,
211
- }}
212
- >
109
+ <span className="tag-placeholder-count">
213
110
  {value?.length || 0}
214
111
  </span>
215
112
  </span>
216
113
  )}
217
114
  dropdownRender={() => (
218
- <div style={{ padding: 10 }}>
115
+ <div className="dropdown-content">
219
116
  <Search
220
117
  placeholder={`Search ${field.caption}`}
221
118
  onChange={(e) => handleSearch(e.target.value)}
222
119
  />
223
120
 
224
- <div style={{ maxHeight: 200, overflowY: "auto", marginTop: 10 }}>
121
+ <div className="dropdown-options-list">
225
122
  {loading ? (
226
123
  <Spin />
227
124
  ) : (
228
125
  displayOptions.map((item) => (
229
- <div key={item} style={{ marginBottom: 6 }}>
126
+ <div key={item} className="dropdown-option-item">
230
127
  <Checkbox
231
128
  checked={selectedItems.includes(item)}
232
129
  onChange={(e) => toggleValue(e.target.checked, item)}
@@ -238,24 +135,8 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
238
135
  )}
239
136
  </div>
240
137
 
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
- >
138
+ <div className="dropdown-footer">
139
+ <span className="dropdown-reset-button" onClick={handleReset}>
259
140
  Reset
260
141
  </span>
261
142
  </div>
@@ -0,0 +1,76 @@
1
+ // .advanced-search-select,
2
+ /* Base select width */
3
+ .advanced-search-select {
4
+ width: 160px;
5
+ }
6
+ .advanced-search-input {
7
+ width: 160px;
8
+ }
9
+ /* Active state (when value selected) */
10
+ .advanced-search-select.advanced-search-active .ant-select-selector {
11
+ border-color: #1677ff !important;
12
+ box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2) !important;
13
+ border-radius: 6px !important;
14
+ }
15
+
16
+ /* Input active state */
17
+ .advanced-search-input.advanced-search-active {
18
+ border-color: #1677ff !important;
19
+ box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2);
20
+ border-radius: 6px;
21
+ }
22
+ // .advanced-search-input {
23
+ // width: 250px;
24
+
25
+ // &.advanced-search-active {
26
+ // // Antd Select and Input don't share the same border-radius property,
27
+ // // so we apply a wrapper style that works for both.
28
+ // // For more specific control, you might need to target internal antd classes.
29
+ // border: 1px solid #91caff !important;
30
+ // box-shadow: 0 0 0 1px #91caff;
31
+ // border-radius: 6px;
32
+ // }
33
+ // }
34
+
35
+ .tag-placeholder {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: 8px;
39
+
40
+ .tag-placeholder-count {
41
+ background: #e6f0ff;
42
+ color: #1677ff;
43
+ border-radius: 10px;
44
+ padding: 0 8px;
45
+ font-weight: 600;
46
+ font-size: 12px;
47
+ }
48
+ }
49
+
50
+ .dropdown-content {
51
+ padding: 10px;
52
+
53
+ .dropdown-options-list {
54
+ max-height: 200px;
55
+ overflow-y: auto;
56
+ margin-top: 10px;
57
+
58
+ .dropdown-option-item {
59
+ margin-bottom: 6px;
60
+ }
61
+ }
62
+
63
+ .dropdown-footer {
64
+ display: flex;
65
+ justify-content: flex-end;
66
+ margin-top: 10px;
67
+ border-top: 1px solid #f0f0f0;
68
+ padding-top: 8px;
69
+
70
+ .dropdown-reset-button {
71
+ color: #1677ff;
72
+ cursor: pointer;
73
+ font-weight: 500;
74
+ }
75
+ }
76
+ }
@@ -344,144 +344,6 @@ export default function ReportingDashboard({
344
344
  }
345
345
  };
346
346
 
347
- /**
348
- *
349
- * @param {*} searchValues
350
- * @param {*} searchParameters
351
- * @returns
352
- */
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.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
-
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
347
  const handleSubmit = (values) => {
486
348
  const hasSearchValues = Object.values(searchValues).some((v) => Array.isArray(v) && v.length > 0);
487
349
 
@@ -511,11 +373,9 @@ export default function ReportingDashboard({
511
373
 
512
374
  onOk() {
513
375
  // YES → send form values + search condition
514
- const searchCondition = buildSearchCondition(searchValues, searchParameters);
515
-
516
376
  const finalValues = {
517
377
  ...values,
518
- search_condition: searchCondition,
378
+ search_values: searchValues,
519
379
  };
520
380
 
521
381
  runSubmit(finalValues);
@@ -523,8 +383,6 @@ export default function ReportingDashboard({
523
383
 
524
384
  onCancel() {
525
385
  // NO → reset form values
526
- const searchCondition = buildSearchCondition(searchValues, searchParameters);
527
-
528
386
  const resetValues = {};
529
387
  Object.keys(values).forEach((key) => {
530
388
  resetValues[key] = null;
@@ -532,7 +390,7 @@ export default function ReportingDashboard({
532
390
 
533
391
  const finalValues = {
534
392
  ...resetValues,
535
- search_condition: searchCondition,
393
+ search_values: searchValues,
536
394
  };
537
395
 
538
396
  runSubmit(finalValues);
@@ -540,8 +398,6 @@ export default function ReportingDashboard({
540
398
  });
541
399
  } else {
542
400
  // no form change
543
- const searchCondition = buildSearchCondition(searchValues, searchParameters);
544
-
545
401
  const resetValues = {};
546
402
  Object.keys(values).forEach((key) => {
547
403
  resetValues[key] = null;
@@ -549,7 +405,7 @@ export default function ReportingDashboard({
549
405
 
550
406
  const finalValues = {
551
407
  ...resetValues,
552
- search_condition: searchCondition,
408
+ search_values: searchValues,
553
409
  };
554
410
 
555
411
  runSubmit(finalValues);
@@ -562,7 +418,7 @@ export default function ReportingDashboard({
562
418
 
563
419
  scriptId.current = null;
564
420
 
565
- const hasSearchValues = finalValues.search_condition;
421
+ const hasSearchValues = finalValues.search_values && Object.values(finalValues.search_values).some((v) => Array.isArray(v) && v.length > 0);
566
422
 
567
423
  if (!hasSearchValues) {
568
424
  const currentUrlParams = Location.search();
@@ -746,6 +602,7 @@ export default function ReportingDashboard({
746
602
  key={param.field}
747
603
  parameter={param}
748
604
  field={param}
605
+ reportId={reportId}
749
606
  value={searchValues[param.field] || []}
750
607
  onChange={(value) => {
751
608
  setSearchValues((prev) => ({
@@ -753,6 +610,32 @@ export default function ReportingDashboard({
753
610
  [param.field]: value,
754
611
  }));
755
612
  }}
613
+ onReset={() => {
614
+ setSearchValues((prev) => {
615
+ const updated = {
616
+ ...prev,
617
+ [param.field]: [],
618
+ };
619
+
620
+ // const finalValues = {
621
+ // ...formContents,
622
+ // search_values: updated,
623
+ // };
624
+ // console.log(finalValues);
625
+ // runSubmit(finalValues); // 🔥 refresh report correctly
626
+ getPatientDetails();
627
+
628
+ return updated;
629
+ });
630
+ }}
631
+ // onReset={() => {
632
+ // setSearchValues((prev) => ({
633
+ // ...prev,
634
+ // [param.field]: [],
635
+ // }));
636
+
637
+ // handleSubmit(formContents); // 🔥 refresh report
638
+ // }}
756
639
  />
757
640
  ))
758
641
  : null}
@@ -13,6 +13,8 @@ export default function ActionButtons({
13
13
  steps,
14
14
  activeStep,
15
15
  isStepCompleted,
16
+ isFullscreen,
17
+ onToggleFullscreen,
16
18
  renderDynamicComponent,
17
19
  handlePrevious,
18
20
  handleNext,
@@ -37,6 +39,10 @@ export default function ActionButtons({
37
39
  Back
38
40
  </Button>
39
41
 
42
+ <Button type="default" onClick={onToggleFullscreen}>
43
+ {isFullscreen ? 'Exit Full Screen' : 'Switch to Full Screen'}
44
+ </Button>
45
+
40
46
  {/* Skip button */}
41
47
  {steps.length > 0 && steps[activeStep]?.allow_skip === 'Y' && (
42
48
  <Button type="default" onClick={handleSkip} disabled={activeStep === steps.length - 1}>
@@ -11,6 +11,7 @@
11
11
  overflow-y: auto;
12
12
  overflow-x: hidden;
13
13
  overscroll-behavior: contain;
14
+
14
15
  padding-bottom: 8px;
15
16
  }
16
17
 
@@ -27,7 +28,6 @@
27
28
  border-top: 1px solid #f0f0f0;
28
29
  box-shadow: 0 -2px 10px rgba(15, 23, 42, 0.04);
29
30
 
30
-
31
31
  width: 61%;
32
32
  padding: 10px;
33
33
  position: fixed;
@@ -37,9 +37,15 @@
37
37
  display: flex;
38
38
  border-radius: 4px;
39
39
  box-shadow: -1px -4px 10px 2px #f7f7f76e;
40
-
40
+ flex-wrap: wrap;
41
41
 
42
42
  .ant-btn {
43
43
  border-radius: 4px;
44
44
  }
45
- }
45
+ }
46
+
47
+ .process-steps-page.is-fullscreen .action-buttons-container {
48
+ width: calc(100% - 24px);
49
+ left: 12px;
50
+ right: 12px;
51
+ }