@visns-studio/visns-components 4.10.33 → 4.10.35
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/package.json +1 -1
- package/src/components/crm/DataGrid.jsx +74 -6
- package/src/components/crm/Field.jsx +7 -1
- package/src/components/crm/Form.jsx +4 -0
- package/src/components/crm/generic/GenericDashboard.jsx +340 -30
- package/src/components/crm/generic/styles/GenericDashboard.module.scss +325 -0
- package/src/index.js +2 -0
package/package.json
CHANGED
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
78
78
|
},
|
|
79
79
|
"name": "@visns-studio/visns-components",
|
|
80
|
-
"version": "4.10.
|
|
80
|
+
"version": "4.10.35",
|
|
81
81
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
82
82
|
"main": "src/index.js",
|
|
83
83
|
"files": [
|
|
@@ -59,8 +59,7 @@ import 'react-confirm-alert/src/react-confirm-alert.css';
|
|
|
59
59
|
import CustomFetch from './Fetch';
|
|
60
60
|
import Download from './Download';
|
|
61
61
|
import Form from './Form';
|
|
62
|
-
import _ from 'lodash';
|
|
63
|
-
import { distance2D } from 'framer-motion';
|
|
62
|
+
import _, { set } from 'lodash';
|
|
64
63
|
|
|
65
64
|
const loadData = async (
|
|
66
65
|
{ skip, limit, sortInfo, filterValue },
|
|
@@ -182,17 +181,32 @@ const DataGrid = forwardRef(
|
|
|
182
181
|
const [formId, setFormId] = useState(0);
|
|
183
182
|
const [modalShow, setModalShow] = useState(false);
|
|
184
183
|
|
|
184
|
+
const [formSettingData, setFormSettingData] = useState({});
|
|
185
|
+
const [formSettingType, setFormSettingType] = useState('');
|
|
186
|
+
const [formSettingId, setFormSettingId] = useState(0);
|
|
187
|
+
const [modalSettingShow, setModalSettingShow] = useState(false);
|
|
188
|
+
|
|
185
189
|
/** Modal Functions */
|
|
186
|
-
const modalOpen = (
|
|
190
|
+
const modalOpen = (type, id) => {
|
|
187
191
|
setModalShow(true);
|
|
188
|
-
setFormType(
|
|
189
|
-
setFormId(
|
|
192
|
+
setFormType(type);
|
|
193
|
+
setFormId(id);
|
|
190
194
|
};
|
|
191
195
|
|
|
192
196
|
const modalClose = () => {
|
|
193
197
|
setModalShow(false);
|
|
194
198
|
};
|
|
195
199
|
|
|
200
|
+
const modalSettingOpen = (type, id) => {
|
|
201
|
+
setModalSettingShow(true);
|
|
202
|
+
setFormSettingType(type);
|
|
203
|
+
setFormSettingId(id);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const modalSettingClose = () => {
|
|
207
|
+
setModalSettingShow(false);
|
|
208
|
+
};
|
|
209
|
+
|
|
196
210
|
useEffect(() => {
|
|
197
211
|
setFormData(form);
|
|
198
212
|
}, [form]);
|
|
@@ -555,6 +569,22 @@ const DataGrid = forwardRef(
|
|
|
555
569
|
],
|
|
556
570
|
});
|
|
557
571
|
break;
|
|
572
|
+
case 'form':
|
|
573
|
+
if (s.key) {
|
|
574
|
+
let fsd = formSettingData;
|
|
575
|
+
|
|
576
|
+
if (fsd.fields && fsd.fields.length > 0) {
|
|
577
|
+
fsd.fields.forEach((fItem, fKey) => {
|
|
578
|
+
if (fItem.id === s.key) {
|
|
579
|
+
fsd.fields[fKey].value = d.id;
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
setFormSettingData(fsd);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
modalSettingOpen('create', 0);
|
|
587
|
+
break;
|
|
558
588
|
case 'envelope':
|
|
559
589
|
CustomFetch(s.url, 'POST', { id: d[s.key] }, (result) => {
|
|
560
590
|
toast.success(result.message);
|
|
@@ -731,7 +761,17 @@ const DataGrid = forwardRef(
|
|
|
731
761
|
const linkUrl = column.link.url;
|
|
732
762
|
const linkKey =
|
|
733
763
|
rowProps.columns[columnIndex].link.key;
|
|
734
|
-
const rowData =
|
|
764
|
+
const rowData = linkKey.includes('.')
|
|
765
|
+
? linkKey
|
|
766
|
+
.split('.')
|
|
767
|
+
.reduce(
|
|
768
|
+
(obj, key) =>
|
|
769
|
+
obj && obj[key]
|
|
770
|
+
? obj[key]
|
|
771
|
+
: null,
|
|
772
|
+
rowProps.data
|
|
773
|
+
)
|
|
774
|
+
: rowProps.data[linkKey];
|
|
735
775
|
|
|
736
776
|
if (column.link.hasOwnProperty('folder')) {
|
|
737
777
|
const linkFolder =
|
|
@@ -1157,6 +1197,10 @@ const DataGrid = forwardRef(
|
|
|
1157
1197
|
}
|
|
1158
1198
|
}
|
|
1159
1199
|
|
|
1200
|
+
if (s.form) {
|
|
1201
|
+
setFormSettingData(s.form);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1160
1204
|
if (allow) {
|
|
1161
1205
|
switch (s.id) {
|
|
1162
1206
|
case 'activate':
|
|
@@ -1179,6 +1223,7 @@ const DataGrid = forwardRef(
|
|
|
1179
1223
|
return getIconComponent(Network);
|
|
1180
1224
|
case 'gallery':
|
|
1181
1225
|
return getIconComponent(Image);
|
|
1226
|
+
case 'form':
|
|
1182
1227
|
case 'link':
|
|
1183
1228
|
return getIconComponent(LinkOut);
|
|
1184
1229
|
case 'primary':
|
|
@@ -2833,6 +2878,29 @@ const DataGrid = forwardRef(
|
|
|
2833
2878
|
userProfile={userProfile}
|
|
2834
2879
|
/>
|
|
2835
2880
|
</Popup>
|
|
2881
|
+
<Popup
|
|
2882
|
+
open={modalSettingShow}
|
|
2883
|
+
onClose={modalSettingClose}
|
|
2884
|
+
closeOnDocumentClick={false}
|
|
2885
|
+
nested
|
|
2886
|
+
>
|
|
2887
|
+
<Form
|
|
2888
|
+
ajaxSetting={ajaxSetting}
|
|
2889
|
+
api={api}
|
|
2890
|
+
closeModal={modalSettingClose}
|
|
2891
|
+
columnId={formSettingId}
|
|
2892
|
+
fetchTable={handleReload}
|
|
2893
|
+
formSettings={formSettingData}
|
|
2894
|
+
formType={formSettingType}
|
|
2895
|
+
gridRef={gridRef}
|
|
2896
|
+
mapbox={mapbox}
|
|
2897
|
+
modalOpen={modalSettingOpen}
|
|
2898
|
+
paramValue={paramValue}
|
|
2899
|
+
style={style}
|
|
2900
|
+
updateForm={setFormSettingData}
|
|
2901
|
+
userProfile={userProfile}
|
|
2902
|
+
/>
|
|
2903
|
+
</Popup>
|
|
2836
2904
|
<Popup
|
|
2837
2905
|
open={modalGalleryShow}
|
|
2838
2906
|
onClose={modalGalleryClose}
|
|
@@ -2,7 +2,7 @@ import '../styles/global.css';
|
|
|
2
2
|
|
|
3
3
|
import React, { useEffect, useRef, useState } from 'react';
|
|
4
4
|
import DatePicker from 'react-datepicker';
|
|
5
|
-
import _ from 'lodash';
|
|
5
|
+
import _, { forEach } from 'lodash';
|
|
6
6
|
import Toggle from 'react-toggle';
|
|
7
7
|
import moment from 'moment';
|
|
8
8
|
import parse from 'html-react-parser';
|
|
@@ -227,6 +227,12 @@ function Field({
|
|
|
227
227
|
filter.orderBy = a.orderBy;
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
if (a.where) {
|
|
231
|
+
forEach(a.where, (w) => {
|
|
232
|
+
filter.where.push(w);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
230
236
|
CustomFetch(a.url, 'POST', filter, function (result) {
|
|
231
237
|
childDropdownCallback({
|
|
232
238
|
id: a.id,
|
|
@@ -1,42 +1,352 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { ResponsiveBar } from '@nivo/bar';
|
|
3
|
+
import Select from 'react-select';
|
|
4
|
+
import styles from './styles/GenericDashboard.module.scss';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
import CustomFetch from '../Fetch';
|
|
7
|
+
|
|
8
|
+
function GenericDashboard({ setting, userProfile }) {
|
|
6
9
|
const [data, setData] = useState([]);
|
|
10
|
+
const [dropdown, setDropdown] = useState({ filters: [] });
|
|
11
|
+
const [selectedFilters, setSelectedFilters] = useState({});
|
|
12
|
+
const [filterValues, setFilterValues] = useState({});
|
|
13
|
+
const [errorMessage, setErrorMessage] = useState('');
|
|
14
|
+
|
|
15
|
+
const customStyles = {
|
|
16
|
+
control: (base) => ({
|
|
17
|
+
...base,
|
|
18
|
+
height: '51px',
|
|
19
|
+
minHeight: '51px',
|
|
20
|
+
padding: '0',
|
|
21
|
+
borderColor: '#ced4da',
|
|
22
|
+
borderRadius: '5px',
|
|
23
|
+
boxShadow: 'none',
|
|
24
|
+
'&:hover': {
|
|
25
|
+
borderColor: '#80bdff',
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
valueContainer: (base) => ({
|
|
29
|
+
...base,
|
|
30
|
+
height: '51px',
|
|
31
|
+
padding: '0 8px',
|
|
32
|
+
display: 'flex',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const fetchDropdownData = async () => {
|
|
38
|
+
try {
|
|
39
|
+
const response = await CustomFetch(
|
|
40
|
+
setting.api.dropdownUrl,
|
|
41
|
+
'POST',
|
|
42
|
+
{}
|
|
43
|
+
);
|
|
44
|
+
setDropdown((prevState) => ({
|
|
45
|
+
...prevState,
|
|
46
|
+
filters: response?.data?.data || [],
|
|
47
|
+
}));
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('Error fetching dropdown data:', error);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const fetchData = async () => {
|
|
54
|
+
try {
|
|
55
|
+
const filters = Object.keys(filterValues).reduce((acc, key) => {
|
|
56
|
+
if (filterValues[key]) {
|
|
57
|
+
acc[key] = filterValues[key];
|
|
58
|
+
}
|
|
59
|
+
return acc;
|
|
60
|
+
}, {});
|
|
61
|
+
|
|
62
|
+
const response = await CustomFetch(
|
|
63
|
+
setting.api.fetchDataUrl,
|
|
64
|
+
'POST',
|
|
65
|
+
filters
|
|
66
|
+
);
|
|
67
|
+
setData(response?.data?.data || []);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Error fetching data:', error);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const handleFilterChange = (filterId, value) => {
|
|
74
|
+
setFilterValues((prevValues) => ({
|
|
75
|
+
...prevValues,
|
|
76
|
+
[filterId]: value,
|
|
77
|
+
}));
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
fetchDropdownData();
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
fetchData();
|
|
86
|
+
}, [filterValues]);
|
|
7
87
|
|
|
8
88
|
return (
|
|
9
|
-
<div className=
|
|
10
|
-
<div className=
|
|
11
|
-
<div className=
|
|
12
|
-
<
|
|
13
|
-
<h2>
|
|
14
|
-
Current
|
|
15
|
-
<span>
|
|
16
|
-
<strong>Enquiries</strong>
|
|
17
|
-
</span>
|
|
18
|
-
</h2>
|
|
19
|
-
</div>
|
|
20
|
-
<div className="dashtopwidge__right">
|
|
21
|
-
<span>0</span>
|
|
22
|
-
</div>
|
|
89
|
+
<div className={styles.grid}>
|
|
90
|
+
<div className={styles.filterContainer}>
|
|
91
|
+
<div className={styles.filterHeader}>
|
|
92
|
+
<h3>{setting.filters?.title || 'Filters'}</h3>
|
|
23
93
|
</div>
|
|
24
|
-
<div className=
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
94
|
+
<div className={styles.filterFields}>
|
|
95
|
+
{setting.filters?.filters?.map((filter, index) => {
|
|
96
|
+
switch (filter.type) {
|
|
97
|
+
case 'dateRange':
|
|
98
|
+
return (
|
|
99
|
+
<div
|
|
100
|
+
key={index}
|
|
101
|
+
className={styles.filterField}
|
|
102
|
+
>
|
|
103
|
+
<label htmlFor={filter.startDateId}>
|
|
104
|
+
{filter.startDateLabel ||
|
|
105
|
+
'Start Date'}
|
|
106
|
+
</label>
|
|
107
|
+
<input
|
|
108
|
+
id={filter.startDateId}
|
|
109
|
+
type="date"
|
|
110
|
+
value={
|
|
111
|
+
filterValues[
|
|
112
|
+
filter.startDateId
|
|
113
|
+
] || ''
|
|
114
|
+
}
|
|
115
|
+
onChange={(e) =>
|
|
116
|
+
handleFilterChange(
|
|
117
|
+
filter.startDateId,
|
|
118
|
+
e.target.value
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
/>
|
|
122
|
+
<label htmlFor={filter.endDateId}>
|
|
123
|
+
{filter.endDateLabel || 'End Date'}
|
|
124
|
+
</label>
|
|
125
|
+
<input
|
|
126
|
+
id={filter.endDateId}
|
|
127
|
+
type="date"
|
|
128
|
+
value={
|
|
129
|
+
filterValues[
|
|
130
|
+
filter.endDateId
|
|
131
|
+
] || ''
|
|
132
|
+
}
|
|
133
|
+
onChange={(e) =>
|
|
134
|
+
handleFilterChange(
|
|
135
|
+
filter.endDateId,
|
|
136
|
+
e.target.value
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
/>
|
|
140
|
+
</div>
|
|
141
|
+
);
|
|
142
|
+
case 'dropdown':
|
|
143
|
+
return (
|
|
144
|
+
<div
|
|
145
|
+
key={index}
|
|
146
|
+
className={styles.filterField}
|
|
147
|
+
>
|
|
148
|
+
<label htmlFor={filter.id}>
|
|
149
|
+
{filter.label || 'Select Option'}
|
|
150
|
+
</label>
|
|
151
|
+
<Select
|
|
152
|
+
id={filter.id}
|
|
153
|
+
isMulti={filter.isMulti}
|
|
154
|
+
options={dropdown.filters.map(
|
|
155
|
+
(option) => ({
|
|
156
|
+
value: option.id,
|
|
157
|
+
label: option.label,
|
|
158
|
+
})
|
|
159
|
+
)}
|
|
160
|
+
styles={customStyles}
|
|
161
|
+
value={selectedFilters[filter.id]}
|
|
162
|
+
onChange={(value) =>
|
|
163
|
+
handleFilterChange(
|
|
164
|
+
filter.id,
|
|
165
|
+
value
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
default:
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
})}
|
|
175
|
+
<div className={styles.filterActions}>
|
|
176
|
+
<button onClick={fetchData} className="btn btn-primary">
|
|
177
|
+
{setting.filters?.applyButtonLabel ||
|
|
178
|
+
'Apply Filters'}
|
|
179
|
+
</button>
|
|
180
|
+
<button
|
|
181
|
+
onClick={() => {
|
|
182
|
+
setFilterValues({});
|
|
183
|
+
setErrorMessage('');
|
|
184
|
+
}}
|
|
185
|
+
className="btn btn-secondary"
|
|
186
|
+
>
|
|
187
|
+
{setting.filters?.clearButtonLabel ||
|
|
188
|
+
'Clear Filters'}
|
|
189
|
+
</button>
|
|
35
190
|
</div>
|
|
36
191
|
</div>
|
|
192
|
+
{errorMessage && (
|
|
193
|
+
<div className={styles.errorMessage}>
|
|
194
|
+
<p>{errorMessage}</p>
|
|
195
|
+
</div>
|
|
196
|
+
)}
|
|
37
197
|
</div>
|
|
198
|
+
|
|
199
|
+
{setting.widgets?.map((widget, index) => {
|
|
200
|
+
switch (widget.type) {
|
|
201
|
+
case 'chart':
|
|
202
|
+
return (
|
|
203
|
+
<div key={index} className={styles.grid__row}>
|
|
204
|
+
<div className={styles.grid__dashfull}>
|
|
205
|
+
<div className={styles.widgetTitle}>
|
|
206
|
+
<h2>
|
|
207
|
+
{widget.title || 'Chart Widget'}
|
|
208
|
+
</h2>
|
|
209
|
+
</div>
|
|
210
|
+
<div style={{ height: 600 }}>
|
|
211
|
+
{data.length > 0 ? (
|
|
212
|
+
<ResponsiveBar
|
|
213
|
+
data={data}
|
|
214
|
+
keys={widget.keys || []}
|
|
215
|
+
indexBy={
|
|
216
|
+
widget.indexBy ||
|
|
217
|
+
'supervisor'
|
|
218
|
+
}
|
|
219
|
+
margin={
|
|
220
|
+
widget.margin || {
|
|
221
|
+
top: 20,
|
|
222
|
+
right: 200,
|
|
223
|
+
bottom: 110,
|
|
224
|
+
left: 80,
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
padding={0.2}
|
|
228
|
+
valueScale={{ type: 'linear' }}
|
|
229
|
+
indexScale={{
|
|
230
|
+
type: 'band',
|
|
231
|
+
round: true,
|
|
232
|
+
}}
|
|
233
|
+
colors={{
|
|
234
|
+
scheme:
|
|
235
|
+
widget.colorScheme ||
|
|
236
|
+
'set3',
|
|
237
|
+
}}
|
|
238
|
+
borderColor={{
|
|
239
|
+
from: 'color',
|
|
240
|
+
modifiers: [
|
|
241
|
+
['darker', 1.6],
|
|
242
|
+
],
|
|
243
|
+
}}
|
|
244
|
+
axisBottom={
|
|
245
|
+
widget.axisBottom || {
|
|
246
|
+
tickSize: 5,
|
|
247
|
+
tickPadding: 5,
|
|
248
|
+
tickRotation: 45,
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
axisLeft={
|
|
252
|
+
widget.axisLeft || {
|
|
253
|
+
tickSize: 5,
|
|
254
|
+
tickPadding: 5,
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
legends={widget.legends || []}
|
|
258
|
+
/>
|
|
259
|
+
) : (
|
|
260
|
+
<div>Loading chart...</div>
|
|
261
|
+
)}
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
case 'table':
|
|
267
|
+
return (
|
|
268
|
+
<div key={index} className={styles.grid__row}>
|
|
269
|
+
<div className={styles.grid__dashfull}>
|
|
270
|
+
<div className={styles.widgetTitle}>
|
|
271
|
+
<h2>
|
|
272
|
+
{widget.title || 'Table Widget'}
|
|
273
|
+
</h2>
|
|
274
|
+
</div>
|
|
275
|
+
<div className={styles.tableContainer}>
|
|
276
|
+
{data.length > 0 ? (
|
|
277
|
+
<table>
|
|
278
|
+
<thead>
|
|
279
|
+
<tr>
|
|
280
|
+
<th>
|
|
281
|
+
{widget.tableHeader ||
|
|
282
|
+
'Data'}
|
|
283
|
+
</th>
|
|
284
|
+
{data.map(
|
|
285
|
+
(row, index) => (
|
|
286
|
+
<th key={index}>
|
|
287
|
+
{
|
|
288
|
+
row.supervisor
|
|
289
|
+
}
|
|
290
|
+
</th>
|
|
291
|
+
)
|
|
292
|
+
)}
|
|
293
|
+
</tr>
|
|
294
|
+
</thead>
|
|
295
|
+
<tbody>
|
|
296
|
+
{widget.keys?.map(
|
|
297
|
+
(key, index) => {
|
|
298
|
+
let total = 0;
|
|
299
|
+
return (
|
|
300
|
+
<tr key={index}>
|
|
301
|
+
<td>
|
|
302
|
+
{key}
|
|
303
|
+
</td>
|
|
304
|
+
{data.map(
|
|
305
|
+
(
|
|
306
|
+
row
|
|
307
|
+
) => {
|
|
308
|
+
const count =
|
|
309
|
+
row[
|
|
310
|
+
key
|
|
311
|
+
] ||
|
|
312
|
+
0;
|
|
313
|
+
total +=
|
|
314
|
+
count;
|
|
315
|
+
return (
|
|
316
|
+
<td
|
|
317
|
+
key={
|
|
318
|
+
row.supervisor
|
|
319
|
+
}
|
|
320
|
+
>
|
|
321
|
+
{
|
|
322
|
+
count
|
|
323
|
+
}
|
|
324
|
+
</td>
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
)}
|
|
328
|
+
<td>
|
|
329
|
+
{total}
|
|
330
|
+
</td>
|
|
331
|
+
</tr>
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
)}
|
|
335
|
+
</tbody>
|
|
336
|
+
</table>
|
|
337
|
+
) : (
|
|
338
|
+
<div>No data available</div>
|
|
339
|
+
)}
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
</div>
|
|
343
|
+
);
|
|
344
|
+
default:
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
})}
|
|
38
348
|
</div>
|
|
39
349
|
);
|
|
40
|
-
}
|
|
350
|
+
}
|
|
41
351
|
|
|
42
352
|
export default GenericDashboard;
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
body {
|
|
2
|
+
min-height: 100vh;
|
|
3
|
+
background: var(--bg);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.grid {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: 2rem;
|
|
10
|
+
padding: 2rem;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.filterContainer {
|
|
14
|
+
background: #ffffff; // White background for contrast
|
|
15
|
+
border: 1px solid #dadce0; // Subtle border for separation
|
|
16
|
+
border-radius: 8px; // Rounded corners
|
|
17
|
+
padding: 1.5rem;
|
|
18
|
+
margin-bottom: 1.5rem; // Spacing below the filter section
|
|
19
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); // Subtle shadow for depth
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.filterHeader {
|
|
23
|
+
text-align: left;
|
|
24
|
+
margin-bottom: 1rem;
|
|
25
|
+
|
|
26
|
+
h3 {
|
|
27
|
+
font-size: 1.25rem;
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
color: #333;
|
|
30
|
+
margin: 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.filterFields {
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-wrap: wrap;
|
|
37
|
+
gap: 1rem; // Gap between fields
|
|
38
|
+
align-items: flex-end; // Align fields vertically
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.filterField {
|
|
42
|
+
flex: 1; // Ensures equal spacing for each field
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
min-width: 200px; // Sets a minimum width for smaller screens
|
|
46
|
+
|
|
47
|
+
label {
|
|
48
|
+
font-size: 0.875rem;
|
|
49
|
+
font-weight: 600;
|
|
50
|
+
margin-bottom: 0.5rem;
|
|
51
|
+
color: #555;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
input,
|
|
55
|
+
select {
|
|
56
|
+
border: 1px solid #dadce0;
|
|
57
|
+
border-radius: 5px;
|
|
58
|
+
padding: 0.5rem 0.75rem;
|
|
59
|
+
font-size: 0.875rem;
|
|
60
|
+
color: #333;
|
|
61
|
+
outline: none;
|
|
62
|
+
background-color: #f9f9f9;
|
|
63
|
+
width: 100%; // Ensures full width within the container
|
|
64
|
+
height: 51px;
|
|
65
|
+
|
|
66
|
+
&:focus {
|
|
67
|
+
border-color: #007bff;
|
|
68
|
+
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); // Focus effect
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.filterActions {
|
|
74
|
+
display: flex;
|
|
75
|
+
gap: 0.75rem; // Gap between buttons
|
|
76
|
+
|
|
77
|
+
.btn {
|
|
78
|
+
padding: 0.5rem 1rem;
|
|
79
|
+
border-radius: 5px;
|
|
80
|
+
font-size: 0.875rem;
|
|
81
|
+
font-weight: 600;
|
|
82
|
+
text-transform: uppercase;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
transition: background-color 0.2s;
|
|
85
|
+
height: 51px;
|
|
86
|
+
|
|
87
|
+
&.btn-primary {
|
|
88
|
+
background-color: #007bff;
|
|
89
|
+
color: #fff;
|
|
90
|
+
border: none;
|
|
91
|
+
|
|
92
|
+
&:hover {
|
|
93
|
+
background-color: #0056b3;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&.btn-secondary {
|
|
98
|
+
background-color: #f8f9fa;
|
|
99
|
+
color: #333;
|
|
100
|
+
border: 1px solid #ccc;
|
|
101
|
+
|
|
102
|
+
&:hover {
|
|
103
|
+
background-color: #e2e6ea;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.widgetTitle {
|
|
110
|
+
width: 100%;
|
|
111
|
+
height: auto;
|
|
112
|
+
padding: 0 0 1em 0;
|
|
113
|
+
margin-bottom: 1em;
|
|
114
|
+
border-bottom: 1px dashed #dadce0;
|
|
115
|
+
|
|
116
|
+
h2 {
|
|
117
|
+
font-size: 1.375em;
|
|
118
|
+
font-weight: 700;
|
|
119
|
+
margin: 0;
|
|
120
|
+
padding: 0;
|
|
121
|
+
line-height: 1;
|
|
122
|
+
text-transform: capitalize;
|
|
123
|
+
text-align: left;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.dashList {
|
|
128
|
+
width: 100%;
|
|
129
|
+
display: flex;
|
|
130
|
+
flex-wrap: wrap;
|
|
131
|
+
list-style: none;
|
|
132
|
+
padding: 0;
|
|
133
|
+
margin: 0;
|
|
134
|
+
|
|
135
|
+
li {
|
|
136
|
+
width: 100%;
|
|
137
|
+
padding: 0;
|
|
138
|
+
margin: 0;
|
|
139
|
+
|
|
140
|
+
&:first-child {
|
|
141
|
+
button {
|
|
142
|
+
border-top-left-radius: var(--br);
|
|
143
|
+
border-top-right-radius: var(--br);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
&:last-child {
|
|
148
|
+
margin-bottom: 0;
|
|
149
|
+
|
|
150
|
+
button {
|
|
151
|
+
border-bottom-left-radius: var(--br);
|
|
152
|
+
border-bottom-right-radius: var(--br);
|
|
153
|
+
border-bottom: 1px solid #dadce0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
a {
|
|
158
|
+
text-decoration: none;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
button {
|
|
162
|
+
width: 100%;
|
|
163
|
+
display: block;
|
|
164
|
+
background: white;
|
|
165
|
+
border: 1px solid #dadce0;
|
|
166
|
+
border-bottom: none;
|
|
167
|
+
outline: none;
|
|
168
|
+
padding: 0.5rem 1rem;
|
|
169
|
+
color: var(--paragraph-color);
|
|
170
|
+
text-align: left;
|
|
171
|
+
transition: all 0.25s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
172
|
+
letter-spacing: 0.018em;
|
|
173
|
+
|
|
174
|
+
&:hover {
|
|
175
|
+
background: rgba(var(--secondary-color), 0.05);
|
|
176
|
+
transition: all 0.25s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
strong {
|
|
180
|
+
color: var(--paragraph-color);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
span {
|
|
184
|
+
color: rgba(var(--secondary-color-rgb), 1.1);
|
|
185
|
+
float: right;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.grid__row {
|
|
192
|
+
width: 100%;
|
|
193
|
+
display: flex;
|
|
194
|
+
align-items: flex-start;
|
|
195
|
+
flex-wrap: nowrap;
|
|
196
|
+
height: auto;
|
|
197
|
+
gap: 1rem;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.grid__dashfull {
|
|
201
|
+
width: 100%;
|
|
202
|
+
background: var(--item-color);
|
|
203
|
+
border-radius: var(--br);
|
|
204
|
+
border: 1px solid rgba(var(--item-color-rgb), 1.15);
|
|
205
|
+
box-sizing: border-box;
|
|
206
|
+
padding: 20px;
|
|
207
|
+
margin: 8px 0;
|
|
208
|
+
box-shadow: 0 4px 0 rgba(var(--primary-color-rgb), 0.05);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.tableContainer {
|
|
212
|
+
margin-top: 20px;
|
|
213
|
+
border: 1px solid #dadce0;
|
|
214
|
+
border-radius: 8px;
|
|
215
|
+
overflow: hidden;
|
|
216
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.tableContainer table {
|
|
220
|
+
width: 100%;
|
|
221
|
+
border-collapse: collapse;
|
|
222
|
+
text-align: left;
|
|
223
|
+
background-color: #ffffff;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.tableContainer th {
|
|
227
|
+
background-color: #f6f8fa;
|
|
228
|
+
color: #333;
|
|
229
|
+
font-weight: bold;
|
|
230
|
+
padding: 12px 15px;
|
|
231
|
+
border-bottom: 1px solid #dadce0;
|
|
232
|
+
text-transform: capitalize;
|
|
233
|
+
font-size: 14px;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.tableContainer td {
|
|
237
|
+
padding: 10px 15px;
|
|
238
|
+
border-bottom: 1px solid #eaeaea;
|
|
239
|
+
font-size: 13px;
|
|
240
|
+
color: #555;
|
|
241
|
+
text-align: center;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.tableContainer tbody tr:hover {
|
|
245
|
+
background-color: #f9f9f9;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.tableContainer tbody tr:nth-child(even) {
|
|
249
|
+
background-color: #f7f7f7;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.tableContainer th:first-child,
|
|
253
|
+
.tableContainer td:first-child {
|
|
254
|
+
text-align: left;
|
|
255
|
+
font-weight: bold;
|
|
256
|
+
padding-left: 20px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.tableContainer td:last-child {
|
|
260
|
+
border-right: none;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.tableContainer th:last-child {
|
|
264
|
+
border-right: none;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.dashwidget {
|
|
268
|
+
background: var(--primary-color) !important;
|
|
269
|
+
border-top: 1px solid transparent !important;
|
|
270
|
+
border-left: 1px solid transparent !important;
|
|
271
|
+
border-right: 1px solid transparent !important;
|
|
272
|
+
border-bottom: 4px solid rgba(var(--primary-color-rgb), 0.9) !important;
|
|
273
|
+
|
|
274
|
+
h2 {
|
|
275
|
+
color: var(--highlight-color) !important;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.widgetTitle {
|
|
279
|
+
border-bottom: 1px dashed rgba(#dadce0, 0.15);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.grid__contentlist {
|
|
284
|
+
li {
|
|
285
|
+
position: relative;
|
|
286
|
+
|
|
287
|
+
&:hover {
|
|
288
|
+
.edititem {
|
|
289
|
+
opacity: 1;
|
|
290
|
+
transition: opacity 0.15s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.edititem {
|
|
295
|
+
position: absolute;
|
|
296
|
+
right: 0;
|
|
297
|
+
text-decoration: none;
|
|
298
|
+
opacity: 0;
|
|
299
|
+
transition: opacity 0.15s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.react-datepicker__month-select,
|
|
305
|
+
.react-datepicker__year-select {
|
|
306
|
+
padding: 0.5em 0.85em;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.react-confirm-alert-overlay {
|
|
310
|
+
z-index: 999 !important;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.polActions {
|
|
314
|
+
position: fixed;
|
|
315
|
+
bottom: 15px;
|
|
316
|
+
right: 20px;
|
|
317
|
+
width: auto;
|
|
318
|
+
|
|
319
|
+
button {
|
|
320
|
+
display: block;
|
|
321
|
+
float: left;
|
|
322
|
+
padding: 0.35em 1em;
|
|
323
|
+
margin: 0 0.15em;
|
|
324
|
+
}
|
|
325
|
+
}
|
package/src/index.js
CHANGED
|
@@ -37,6 +37,7 @@ import CmsSort from './components/cms/generic/CmsSort';
|
|
|
37
37
|
import AuditLog from './components/crm/generic/AuditLog';
|
|
38
38
|
import AuditLogs from './components/crm/generic/AuditLogs';
|
|
39
39
|
import GenericAuth from './components/crm/generic/GenericAuth';
|
|
40
|
+
import GenericDashboard from './components/crm/generic/GenericDashboard';
|
|
40
41
|
import GenericDetail from './components/crm/generic/GenericDetail';
|
|
41
42
|
import GenericDynamic from './components/crm/generic/GenericDynamic';
|
|
42
43
|
import GenericFormBuilder from './components/crm/generic/GenericFormBuilder';
|
|
@@ -67,6 +68,7 @@ export {
|
|
|
67
68
|
Field,
|
|
68
69
|
Form,
|
|
69
70
|
GenericAuth,
|
|
71
|
+
GenericDashboard,
|
|
70
72
|
GenericDetail,
|
|
71
73
|
GenericDynamic,
|
|
72
74
|
GenericFormBuilder,
|