@visns-studio/visns-components 4.10.33 → 4.10.34

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 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.33",
80
+ "version": "4.10.34",
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 = (formType, formId) => {
190
+ const modalOpen = (type, id) => {
187
191
  setModalShow(true);
188
- setFormType(formType);
189
- setFormId(formId);
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 = rowProps.data[linkKey];
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}
@@ -574,6 +574,10 @@ function Form({
574
574
  }
575
575
  };
576
576
 
577
+ useEffect(() => {
578
+ console.info('Form Settings', formSettings);
579
+ }, [formSettings]);
580
+
577
581
  const handleSubmit = async (e) => {
578
582
  try {
579
583
  if (e) {
@@ -1,42 +1,352 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { toast } from 'react-toastify';
3
- import CustomFetch from '../../crm/Fetch';
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
- const GenericDashboard = ({ userProfile }) => {
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="grid">
10
- <div className="grid__row">
11
- <div className="grid__three dashtopwidge">
12
- <div className="dashtopwidge__left">
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="grid__three dashtopwidge">
25
- <div className="dashtopwidge__left">
26
- <h2>
27
- Current{' '}
28
- <span>
29
- <strong>Enquiries</strong>
30
- </span>
31
- </h2>
32
- </div>
33
- <div className="dashtopwidge__right">
34
- <span>0</span>
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,