ui-soxo-bootstrap-core 2.6.20 → 2.6.22

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.
@@ -9,142 +9,150 @@ import React from 'react';
9
9
 
10
10
  import Base from '../base/base';
11
11
 
12
- import { ApiUtils } from './../../lib/'
13
-
12
+ import { ApiUtils } from './../../lib/';
14
13
 
15
14
  class CoreScript extends Base {
15
+ constructor() {
16
+ super();
16
17
 
17
- constructor() {
18
- super();
19
-
20
- this.fields = [
21
- {
22
- field: 'name',
23
- caption: 'Name'
24
- },
25
- {
26
- field: 'amount',
27
- caption: 'Amount'
28
- }
29
- ];
30
-
31
- // this.columns = ;
32
- }
33
-
34
- get id() {
35
- return 'id';
36
- }
37
-
38
- get getEndpoint() {
39
- return 'core-scripts';
40
- }
41
-
42
-
43
- get modelName() {
44
- return `core-scripts`;
45
- }
46
-
47
- get columns() {
48
- return [
49
- {
50
- caption: 'Staff',
51
- field: 'staff.name',
52
- key: 'staff'
53
- },
54
- {
55
- caption: 'Weight',
56
- field: 'weight',
57
- key: 'weight'
58
- },
59
- {
60
- caption: 'Date',
61
- field: 'created_at',
62
- key: 'created_at'
63
- }
64
- ];
65
- }
66
-
67
-
68
- /**
69
- *Getting core_script data
70
- * @returns
71
- */
72
- getReportingLisitng = (id, formBody, dbPtr = null) => {
73
-
74
- // Settings db pointer
75
- if (!dbPtr) dbPtr = localStorage.db_ptr;
76
- return ApiUtils.post({
77
- url: `core-scripts/dashboardquery/${id}`,
78
- formBody,
79
- headers: {
80
- 'Content-Type': 'application/json',
81
- Authorization: 'Bearer ' + localStorage.access_token,
82
- db_ptr: dbPtr
18
+ this.fields = [
19
+ {
20
+ field: 'name',
21
+ caption: 'Name',
83
22
  },
84
- });
85
- };
86
-
23
+ {
24
+ field: 'amount',
25
+ caption: 'Amount',
26
+ },
27
+ ];
87
28
 
88
- /**
89
- *Updating user details
90
- * @returns
91
- */
92
- getUserDetailsLisitng = (id, formBody) => {
29
+ // this.columns = ;
30
+ }
93
31
 
94
- return ApiUtils.post({
95
- url: `core-scripts/update-user-deatils/${id}`,
96
- formBody,
97
- });
98
- };
32
+ get id() {
33
+ return 'id';
34
+ }
99
35
 
36
+ get getEndpoint() {
37
+ return 'core-scripts';
38
+ }
100
39
 
101
- /**
102
- *
103
- */
104
- getReportMenu = async ({ id }) => {
105
-
106
- const result = await this.getRecord({ id });
107
-
108
- const report = result.result
109
-
110
- return {
111
- ...report,
112
- caption: report.caption,
113
- path: '/reports/' + report.id,
114
- is_visible: true
115
- }
116
- }
117
-
118
- /**
119
- * To get extra script data corresponding to mode
120
- *
121
- * @param {*} mode
122
- * @returns
123
- */
124
- getExtraInfo = (mode) => {
125
- return ApiUtils.get({
126
- url: `core-scripts/get-script-data?mode=${mode}`,
127
- });
128
- };
40
+ get modelName() {
41
+ return `core-scripts`;
42
+ }
129
43
 
130
-
131
- /**
132
- * To get executed data
133
- *
134
- * @param {*} mode
135
- * @returns
136
- */
137
-
138
- getSelectedExtraInfo = (formBody) => {
139
- return ApiUtils.post({
140
- url: `core-scripts/get-selected-script-data`,
141
- formBody,
142
- headers: {
143
- 'Content-Type': 'application/json',
144
- Authorization: 'Bearer ' + localStorage.access_token,
145
- },
146
- });
44
+ get columns() {
45
+ return [
46
+ {
47
+ caption: 'Staff',
48
+ field: 'staff.name',
49
+ key: 'staff',
50
+ },
51
+ {
52
+ caption: 'Weight',
53
+ field: 'weight',
54
+ key: 'weight',
55
+ },
56
+ {
57
+ caption: 'Date',
58
+ field: 'created_at',
59
+ key: 'created_at',
60
+ },
61
+ ];
62
+ }
63
+
64
+ /**
65
+ *Getting core_script data
66
+ * @returns
67
+ */
68
+ getReportingLisitng = (id, formBody, dbPtr = null) => {
69
+ // Settings db pointer
70
+ if (!dbPtr) dbPtr = localStorage.db_ptr;
71
+ return ApiUtils.post({
72
+ // baseUrl: 'http://localhost:8002/dev/',
73
+ url: `core-scripts/dashboardquery/${id}`,
74
+ formBody,
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ Authorization: 'Bearer ' + localStorage.access_token,
78
+ db_ptr: dbPtr,
79
+ },
80
+ });
81
+ };
82
+
83
+ /**
84
+ *Updating user details
85
+ * @returns
86
+ */
87
+ getUserDetailsLisitng = (id, formBody) => {
88
+ return ApiUtils.post({
89
+ url: `core-scripts/update-user-deatils/${id}`,
90
+ formBody,
91
+ });
92
+ };
93
+
94
+ getQuery = (formBody) => {
95
+ return ApiUtils.post({
96
+ url: `core-scripts/execute-script-api`,
97
+ formBody,
98
+ });
99
+ };
100
+ /**
101
+ *
102
+ */
103
+ getQuerySeacch = (formBody) => {
104
+ return ApiUtils.post({
105
+ // baseUrl: 'http://localhost:8002/dev/',
106
+ url: `core-scripts/execute-script-by-search`,
107
+ formBody,
108
+ });
109
+ };
110
+
111
+ /**
112
+ *
113
+ */
114
+ getReportMenu = async ({ id }) => {
115
+ const result = await this.getRecord({ id });
116
+
117
+ const report = result.result;
118
+
119
+ return {
120
+ ...report,
121
+ caption: report.caption,
122
+ path: '/reports/' + report.id,
123
+ is_visible: true,
147
124
  };
125
+ };
126
+
127
+ /**
128
+ * To get extra script data corresponding to mode
129
+ *
130
+ * @param {*} mode
131
+ * @returns
132
+ */
133
+ getExtraInfo = (mode) => {
134
+ return ApiUtils.get({
135
+ url: `core-scripts/get-script-data?mode=${mode}`,
136
+ });
137
+ };
138
+
139
+ /**
140
+ * To get executed data
141
+ *
142
+ * @param {*} mode
143
+ * @returns
144
+ */
145
+
146
+ getSelectedExtraInfo = (formBody) => {
147
+ return ApiUtils.post({
148
+ url: `core-scripts/get-selected-script-data`,
149
+ formBody,
150
+ headers: {
151
+ 'Content-Type': 'application/json',
152
+ Authorization: 'Bearer ' + localStorage.access_token,
153
+ },
154
+ });
155
+ };
148
156
  }
149
157
 
150
158
  export default CoreScript;
@@ -0,0 +1,174 @@
1
+
2
+ import React, { useState, useEffect, useRef } from "react";
3
+ import { Select, Checkbox, Input, Spin } from "antd";
4
+ import { CoreScripts } from "../../../../../models";
5
+ import "./advance-search.scss";
6
+
7
+ const { Search } = Input;
8
+
9
+ export default function AdvancedSearchSelect({ reportId, onReset, field, value, onChange, style, ...rest }) {
10
+ // Normalize the configuration.
11
+ // If 'field' is an object, we are in "legacy" mode. If it's a string, we are using the spread props from rest.
12
+ const isObjectMode = typeof field === "object";
13
+ const config = isObjectMode ? field : { ...rest, field };
14
+
15
+ const finalReportId = reportId || config.reportId;
16
+ const finalOnReset = onReset || config.onReset;
17
+ const isSearchQuery = !!config.search_query;
18
+ const fieldName = isObjectMode ? field.field : field;
19
+ const caption = config.caption;
20
+
21
+ const safeValue = Array.isArray(value) ? value : [];
22
+
23
+ const [searchResults, setSearchResults] = useState([]);
24
+ const [displayOptions, setDisplayOptions] = useState([]);
25
+ const [loading, setLoading] = useState(false);
26
+ const debounceRef = useRef(null);
27
+
28
+ const loadOptions = async (searchText = "") => {
29
+ try {
30
+ setLoading(true);
31
+
32
+ const formBody = {
33
+ script_id: finalReportId,
34
+ search_field: fieldName,
35
+ search_condition: searchText,
36
+ };
37
+
38
+ const res = await CoreScripts.getQuerySeacch(formBody);
39
+ const data = Array.isArray(res.data) ? res.data : [];
40
+ const apiValues = data?.map((r) => r[fieldName]) || [];
41
+
42
+ setSearchResults(apiValues);
43
+ // Refresh display options only when new search results arrive to keep the list stable during interaction
44
+ setDisplayOptions([
45
+ ...safeValue,
46
+ ...apiValues.filter((item) => !safeValue.includes(item)),
47
+ ]);
48
+ } catch (error) {
49
+ console.error("Search API error", error);
50
+ } finally {
51
+ setLoading(false);
52
+ }
53
+ };
54
+
55
+ useEffect(() => {
56
+ // Clear search results when the field or report context changes,
57
+ // but do not load automatically on mount.
58
+ setSearchResults([]);
59
+ }, [fieldName, finalReportId]);
60
+
61
+ const handleSearch = (text) => {
62
+ if (debounceRef.current) clearTimeout(debounceRef.current);
63
+ debounceRef.current = setTimeout(() => loadOptions(text), 400);
64
+ };
65
+
66
+ const toggleValue = (checked, item) => {
67
+ let newValues;
68
+
69
+ if (checked) newValues = [...safeValue, item];
70
+ else newValues = safeValue.filter((v) => v !== item);
71
+
72
+ onChange(newValues);
73
+ };
74
+
75
+ const handleReset = () => {
76
+ onChange([]);
77
+ if (finalOnReset) {
78
+ finalOnReset(); // 🔥 trigger dashboard refresh
79
+ }
80
+ };
81
+
82
+ const isActive = safeValue.length > 0;
83
+
84
+ // -------- INPUT MODE --------
85
+ if (!isSearchQuery) {
86
+ return (
87
+ <Input
88
+ allowClear
89
+ className={`advanced-search-input ${isActive ? "advanced-search-active" : ""}`}
90
+ placeholder={`Search ${caption}`}
91
+ style={style}
92
+ // The parent provides an array for `value`.
93
+ // We take the first element for the input's display value.
94
+ value={safeValue[0] || ""}
95
+ onChange={(e) => {
96
+ const text = e?.target?.value;
97
+ // Always pass an array back to the parent to be consistent with the Select mode.
98
+ onChange(text ? [text] : []);
99
+ if (!text && finalOnReset) {
100
+ finalOnReset();
101
+ }
102
+ }}
103
+ />
104
+ );
105
+ }
106
+
107
+ // -------- SELECT MODE --------
108
+ return (
109
+ <Select
110
+ className={`advanced-search-select ${isActive ? "advanced-search-active" : ""}`}
111
+ style={style}
112
+ mode="multiple"
113
+ value={safeValue}
114
+ placeholder={caption}
115
+ onDropdownVisibleChange={(open) => {
116
+ if (open) {
117
+ loadOptions("");
118
+ } else {
119
+ // When closing, re-sort selected items to the top so they are visible next time it opens
120
+ const currentResults = searchResults.length > 0 ? searchResults : displayOptions;
121
+ setDisplayOptions([
122
+ ...safeValue,
123
+ ...currentResults.filter((item) => !safeValue.includes(item)),
124
+ ]);
125
+ }
126
+ }}
127
+ allowClear
128
+ maxTagCount={1}
129
+ onChange={onChange}
130
+ maxTagPlaceholder={(omittedValues) => (
131
+ <span className="tag-placeholder-count">
132
+ +{omittedValues.length}
133
+ </span>
134
+ )}
135
+ dropdownRender={() => (
136
+ <div className="dropdown-content">
137
+ <Search
138
+ placeholder={`Search ${caption}`}
139
+ onChange={(e) => handleSearch(e.target.value)}
140
+ />
141
+
142
+ <div className="dropdown-options-list">
143
+ {loading ? (
144
+ <Spin />
145
+ ) : (
146
+ displayOptions.map((item, idx) => (
147
+ <div
148
+ key={`${item}-${idx}`}
149
+ className="dropdown-option-item"
150
+ onClick={() => toggleValue(!safeValue.includes(item), item)}
151
+ style={{ cursor: 'pointer' }}
152
+ >
153
+ <Checkbox
154
+ checked={safeValue.includes(item)}
155
+ onClick={(e) => e.stopPropagation()} // Prevent double trigger when clicking the checkbox box specifically
156
+ onChange={(e) => toggleValue(e.target.checked, item)}
157
+ >
158
+ {item}
159
+ </Checkbox>
160
+ </div>
161
+ ))
162
+ )}
163
+ </div>
164
+
165
+ <div className="dropdown-footer">
166
+ <span className="dropdown-reset-button" onClick={handleReset}>
167
+ Reset
168
+ </span>
169
+ </div>
170
+ </div>
171
+ )}
172
+ />
173
+ );
174
+ }
@@ -0,0 +1,76 @@
1
+ // .advanced-search-select,
2
+ /* Base select width */
3
+ .advanced-search-select {
4
+ width: 160px;
5
+ // width: 100%;
6
+ }
7
+ .advanced-search-input {
8
+ width: 160px;
9
+ }
10
+ /* Active state (when value selected) */
11
+ .advanced-search-select.advanced-search-active .ant-select-selector {
12
+ border-color: #1677ff !important;
13
+ box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2) !important;
14
+ border-radius: 6px !important;
15
+ }
16
+
17
+ /* Input active state */
18
+ .advanced-search-input.advanced-search-active {
19
+ border-color: #1677ff !important;
20
+ box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2);
21
+ border-radius: 6px;
22
+ }
23
+ // .advanced-search-input {
24
+ // width: 250px;
25
+
26
+ // &.advanced-search-active {
27
+ // // Antd Select and Input don't share the same border-radius property,
28
+ // // so we apply a wrapper style that works for both.
29
+ // // For more specific control, you might need to target internal antd classes.
30
+ // border: 1px solid #91caff !important;
31
+ // box-shadow: 0 0 0 1px #91caff;
32
+ // border-radius: 6px;
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
+ }