@visns-studio/visns-components 5.4.5 → 5.4.7
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 +14 -14
- package/src/components/crm/DataGrid.jsx +2 -0
- package/src/components/crm/README_DATAGRID.md +70 -0
- package/src/components/crm/auth/Login.jsx +30 -8
- package/src/components/crm/auth/TwoFactorAuth.jsx +184 -0
- package/src/components/crm/auth/styles/TwoFactorAuth.module.scss +29 -0
- package/src/components/crm/generic/GenericAuth.jsx +23 -0
- package/src/components/crm/generic/GenericIndex.jsx +2 -0
- package/src/components/crm/styles/DataGrid.module.scss +2 -2
- package/src/components/styles/global.css +2 -2
- package/src/examples/CustomHoverDataGrid.jsx +92 -0
package/package.json
CHANGED
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"akar-icons": "^1.9.31",
|
|
15
15
|
"array-move": "^4.0.0",
|
|
16
16
|
"awesome-debounce-promise": "^2.1.0",
|
|
17
|
-
"axios": "^1.8.
|
|
17
|
+
"axios": "^1.8.4",
|
|
18
18
|
"dayjs": "^1.11.13",
|
|
19
|
-
"fabric": "^6.
|
|
19
|
+
"fabric": "^6.6.2",
|
|
20
20
|
"file-saver": "^2.0.5",
|
|
21
21
|
"framer-motion": "^11.18.2",
|
|
22
22
|
"html-react-parser": "^5.2.3",
|
|
@@ -27,20 +27,20 @@
|
|
|
27
27
|
"numeral": "^2.0.6",
|
|
28
28
|
"pluralize": "^8.0.0",
|
|
29
29
|
"quill-image-uploader": "^1.3.0",
|
|
30
|
-
"react-big-calendar": "^1.
|
|
30
|
+
"react-big-calendar": "^1.18.0",
|
|
31
31
|
"react-color": "^2.19.3",
|
|
32
32
|
"react-confirm-alert": "^3.0.6",
|
|
33
33
|
"react-copy-to-clipboard": "^5.1.0",
|
|
34
34
|
"react-datepicker": "^7.6.0",
|
|
35
|
-
"react-dropzone": "^14.3.
|
|
35
|
+
"react-dropzone": "^14.3.8",
|
|
36
36
|
"react-grid-gallery": "^1.0.1",
|
|
37
37
|
"react-number-format": "^5.4.3",
|
|
38
38
|
"react-password-strength-bar": "^0.4.1",
|
|
39
39
|
"react-promise-tracker": "^2.1.1",
|
|
40
40
|
"react-quill": "^2.0.0",
|
|
41
41
|
"react-reveal": "^1.2.2",
|
|
42
|
-
"react-router-dom": "^6.
|
|
43
|
-
"react-select": "^5.
|
|
42
|
+
"react-router-dom": "^6.30.0",
|
|
43
|
+
"react-select": "^5.10.1",
|
|
44
44
|
"react-signature-pad-wrapper": "^4.1.0",
|
|
45
45
|
"react-slugify": "^4.0.1",
|
|
46
46
|
"react-sortable-hoc": "^2.0.0",
|
|
@@ -55,30 +55,30 @@
|
|
|
55
55
|
"truncate": "^3.0.0",
|
|
56
56
|
"uuid": "^10.0.0",
|
|
57
57
|
"validator": "^13.15.0",
|
|
58
|
-
"vite": "^5.4.
|
|
58
|
+
"vite": "^5.4.16",
|
|
59
59
|
"yarn": "^1.22.22"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@babel/core": "^7.26.
|
|
63
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
64
|
-
"@babel/preset-env": "^7.26.
|
|
62
|
+
"@babel/core": "^7.26.10",
|
|
63
|
+
"@babel/plugin-transform-runtime": "^7.26.10",
|
|
64
|
+
"@babel/preset-env": "^7.26.9",
|
|
65
65
|
"@babel/preset-react": "^7.26.3",
|
|
66
66
|
"babel-loader": "^9.2.1",
|
|
67
67
|
"copy-webpack-plugin": "^12.0.2",
|
|
68
68
|
"css-loader": "^7.1.2",
|
|
69
|
-
"css-minimizer-webpack-plugin": "^7.0.
|
|
69
|
+
"css-minimizer-webpack-plugin": "^7.0.2",
|
|
70
70
|
"mini-css-extract-plugin": "^2.9.2",
|
|
71
71
|
"react": "^18.3.1",
|
|
72
72
|
"react-dom": "^18.3.1",
|
|
73
|
-
"sass": "^1.
|
|
74
|
-
"sass-loader": "^16.0.
|
|
73
|
+
"sass": "^1.86.2",
|
|
74
|
+
"sass-loader": "^16.0.5"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"react": "^17.0.0 || ^18.0.0",
|
|
78
78
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
79
79
|
},
|
|
80
80
|
"name": "@visns-studio/visns-components",
|
|
81
|
-
"version": "5.4.
|
|
81
|
+
"version": "5.4.7",
|
|
82
82
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
83
83
|
"main": "src/index.js",
|
|
84
84
|
"files": [
|
|
@@ -133,6 +133,7 @@ const DataGrid = forwardRef(
|
|
|
133
133
|
columns,
|
|
134
134
|
form,
|
|
135
135
|
gridHeight,
|
|
136
|
+
hoverColor,
|
|
136
137
|
mapbox,
|
|
137
138
|
pageData,
|
|
138
139
|
pageSetting,
|
|
@@ -2856,6 +2857,7 @@ const DataGrid = forwardRef(
|
|
|
2856
2857
|
: 450
|
|
2857
2858
|
: 400,
|
|
2858
2859
|
boxShadow: 'none',
|
|
2860
|
+
...(hoverColor ? { '--hover-color': hoverColor } : {}),
|
|
2859
2861
|
});
|
|
2860
2862
|
const headerProps = {
|
|
2861
2863
|
style: style ? style : {},
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# DataGrid Component
|
|
2
|
+
|
|
3
|
+
## Customizing Hover Color
|
|
4
|
+
|
|
5
|
+
The DataGrid component now supports customizable hover colors. This allows you to set different hover colors for different instances of the DataGrid.
|
|
6
|
+
|
|
7
|
+
### Method 1: Using the hoverColor Prop (Recommended)
|
|
8
|
+
|
|
9
|
+
The simplest way to set a custom hover color is to use the `hoverColor` prop directly:
|
|
10
|
+
|
|
11
|
+
```jsx
|
|
12
|
+
import DataGrid from './components/crm/DataGrid';
|
|
13
|
+
|
|
14
|
+
// In your component
|
|
15
|
+
<DataGrid
|
|
16
|
+
hoverColor="rgb(255, 240, 230)" // Custom hover color
|
|
17
|
+
// other props...
|
|
18
|
+
/>;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Method 2: Using CSS Variables in Component Props
|
|
22
|
+
|
|
23
|
+
You can pass a custom style object to the DataGrid component with the `--hover-color` CSS variable:
|
|
24
|
+
|
|
25
|
+
```jsx
|
|
26
|
+
import DataGrid from './components/crm/DataGrid';
|
|
27
|
+
|
|
28
|
+
// Define custom styles with hover color
|
|
29
|
+
const customStyle = {
|
|
30
|
+
'--hover-color': 'rgb(255, 240, 230)', // Custom hover color
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// In your component
|
|
34
|
+
<DataGrid
|
|
35
|
+
style={customStyle}
|
|
36
|
+
// other props...
|
|
37
|
+
/>;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Method 3: Using CSS/SCSS
|
|
41
|
+
|
|
42
|
+
You can define the `--hover-color` CSS variable in your CSS or SCSS files:
|
|
43
|
+
|
|
44
|
+
```css
|
|
45
|
+
/* Global default hover color */
|
|
46
|
+
:root {
|
|
47
|
+
--hover-color: rgb(230, 240, 250);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* For specific containers */
|
|
51
|
+
.special-grid-container {
|
|
52
|
+
--hover-color: rgb(255, 240, 230);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then apply the class to your container:
|
|
57
|
+
|
|
58
|
+
```jsx
|
|
59
|
+
<div className="special-grid-container">
|
|
60
|
+
<DataGrid {...props} />
|
|
61
|
+
</div>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Default Value
|
|
65
|
+
|
|
66
|
+
If no hover color is specified (via prop or CSS variable), the DataGrid will use a default light blue color (`rgb(230, 240, 250)`).
|
|
67
|
+
|
|
68
|
+
### Example
|
|
69
|
+
|
|
70
|
+
See the `src/examples/CustomHoverDataGrid.jsx` file for a complete example of how to implement custom hover colors using all three methods.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '../../styles/global.css';
|
|
2
2
|
|
|
3
3
|
import React, { useEffect, useState } from 'react';
|
|
4
|
-
import { Link, useLocation } from 'react-router-dom';
|
|
4
|
+
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
|
5
5
|
import Reveal from 'react-reveal/Reveal';
|
|
6
6
|
import { toast } from 'react-toastify';
|
|
7
7
|
import { Person, LockOff } from 'akar-icons';
|
|
@@ -12,6 +12,8 @@ import styles from './styles/Login.module.scss';
|
|
|
12
12
|
|
|
13
13
|
const Login = ({ logo, providers, setSystemAuth, setUserProfile }) => {
|
|
14
14
|
const location = useLocation();
|
|
15
|
+
const navigate = useNavigate();
|
|
16
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
15
17
|
|
|
16
18
|
const [auth, setAuth] = useState({
|
|
17
19
|
email: '',
|
|
@@ -92,6 +94,9 @@ const Login = ({ logo, providers, setSystemAuth, setUserProfile }) => {
|
|
|
92
94
|
if (e) {
|
|
93
95
|
e.preventDefault();
|
|
94
96
|
|
|
97
|
+
setIsLoading(true);
|
|
98
|
+
toast.info('Logging in...', { autoClose: 2000 });
|
|
99
|
+
|
|
95
100
|
CustomFetch(
|
|
96
101
|
'/login/authenticate',
|
|
97
102
|
'POST',
|
|
@@ -103,13 +108,27 @@ const Login = ({ logo, providers, setSystemAuth, setUserProfile }) => {
|
|
|
103
108
|
: '',
|
|
104
109
|
},
|
|
105
110
|
(result) => {
|
|
111
|
+
setIsLoading(false);
|
|
106
112
|
if (result.error === '') {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
// Check if 2FA is required
|
|
114
|
+
if (result.requires_2fa) {
|
|
115
|
+
// Redirect to 2FA page with user data
|
|
116
|
+
navigate('/2fa', {
|
|
117
|
+
state: {
|
|
118
|
+
userData: result.user,
|
|
119
|
+
previousUrl:
|
|
120
|
+
location.state?.previousUrl || '',
|
|
121
|
+
},
|
|
122
|
+
});
|
|
111
123
|
} else {
|
|
112
|
-
|
|
124
|
+
// Normal login flow
|
|
125
|
+
setUserProfile(result.user);
|
|
126
|
+
|
|
127
|
+
if (result.previous && result.previous !== '') {
|
|
128
|
+
window.location.href = result.previous;
|
|
129
|
+
} else {
|
|
130
|
+
setSystemAuth(true);
|
|
131
|
+
}
|
|
113
132
|
}
|
|
114
133
|
} else {
|
|
115
134
|
setSystemAuth(false);
|
|
@@ -120,11 +139,13 @@ const Login = ({ logo, providers, setSystemAuth, setUserProfile }) => {
|
|
|
120
139
|
}));
|
|
121
140
|
|
|
122
141
|
toast.error(
|
|
123
|
-
|
|
142
|
+
result.error ||
|
|
143
|
+
'Could not log in with the supplied credentials, please try again.'
|
|
124
144
|
);
|
|
125
145
|
}
|
|
126
146
|
},
|
|
127
147
|
(error) => {
|
|
148
|
+
setIsLoading(false);
|
|
128
149
|
setAuthClass((prevState) => ({
|
|
129
150
|
...prevState,
|
|
130
151
|
username: 'inputError',
|
|
@@ -206,8 +227,9 @@ const Login = ({ logo, providers, setSystemAuth, setUserProfile }) => {
|
|
|
206
227
|
<button
|
|
207
228
|
className={styles.btn}
|
|
208
229
|
type="submit"
|
|
230
|
+
disabled={isLoading}
|
|
209
231
|
>
|
|
210
|
-
Login
|
|
232
|
+
{isLoading ? 'Logging in...' : 'Login'}
|
|
211
233
|
</button>
|
|
212
234
|
</div>
|
|
213
235
|
<div
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import '../../styles/global.css';
|
|
2
|
+
|
|
3
|
+
import React, { useState, useEffect } from 'react';
|
|
4
|
+
import { useNavigate, useLocation } from 'react-router-dom';
|
|
5
|
+
import Reveal from 'react-reveal/Reveal';
|
|
6
|
+
import { toast } from 'react-toastify';
|
|
7
|
+
import { LockOff } from 'akar-icons';
|
|
8
|
+
|
|
9
|
+
import CustomFetch from '../Fetch';
|
|
10
|
+
|
|
11
|
+
import styles from './styles/TwoFactorAuth.module.scss';
|
|
12
|
+
|
|
13
|
+
const TwoFactorAuth = ({ logo, setSystemAuth, setUserProfile }) => {
|
|
14
|
+
const navigate = useNavigate();
|
|
15
|
+
const location = useLocation();
|
|
16
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
17
|
+
|
|
18
|
+
// Get user data from location state
|
|
19
|
+
const userData = location.state?.userData || null;
|
|
20
|
+
const previousUrl = location.state?.previousUrl || '';
|
|
21
|
+
|
|
22
|
+
// If no userData, redirect to login
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (!userData) {
|
|
25
|
+
navigate('/login');
|
|
26
|
+
}
|
|
27
|
+
}, [userData, navigate]);
|
|
28
|
+
|
|
29
|
+
const [verificationCode, setVerificationCode] = useState('');
|
|
30
|
+
const [codeClass, setCodeClass] = useState('');
|
|
31
|
+
|
|
32
|
+
const handleChange = (e) => {
|
|
33
|
+
if (e) {
|
|
34
|
+
setVerificationCode(e.target.value);
|
|
35
|
+
setCodeClass('');
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleSubmit = (e) => {
|
|
40
|
+
if (e) {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
|
|
43
|
+
if (!verificationCode.trim()) {
|
|
44
|
+
setCodeClass('inputError');
|
|
45
|
+
toast.error('Please enter the verification code');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setIsLoading(true);
|
|
50
|
+
toast.info('Verifying code...', { autoClose: 2000 });
|
|
51
|
+
|
|
52
|
+
CustomFetch(
|
|
53
|
+
'/login/verify-2fa',
|
|
54
|
+
'POST',
|
|
55
|
+
{
|
|
56
|
+
user_id: userData?.id,
|
|
57
|
+
verification_code: verificationCode,
|
|
58
|
+
previous_url: previousUrl
|
|
59
|
+
},
|
|
60
|
+
(result) => {
|
|
61
|
+
setIsLoading(false);
|
|
62
|
+
if (result.error === '') {
|
|
63
|
+
toast.success('Two-factor authentication successful');
|
|
64
|
+
setUserProfile(result.user || userData);
|
|
65
|
+
|
|
66
|
+
if (result.previous && result.previous !== '') {
|
|
67
|
+
window.location.href = result.previous;
|
|
68
|
+
} else {
|
|
69
|
+
setSystemAuth(true);
|
|
70
|
+
navigate('/');
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
setCodeClass('inputError');
|
|
74
|
+
toast.error(result.error || 'Invalid verification code');
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
(error) => {
|
|
78
|
+
setIsLoading(false);
|
|
79
|
+
setCodeClass('inputError');
|
|
80
|
+
toast.error(String(error) || 'Failed to verify code');
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const handleResendCode = () => {
|
|
87
|
+
if (!userData?.id) {
|
|
88
|
+
toast.error('User information is missing. Please try logging in again.');
|
|
89
|
+
navigate('/login');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
toast.info('Requesting new verification code...', { autoClose: 2000 });
|
|
94
|
+
|
|
95
|
+
CustomFetch(
|
|
96
|
+
'/login/resend-2fa',
|
|
97
|
+
'POST',
|
|
98
|
+
{ user_id: userData.id },
|
|
99
|
+
(result) => {
|
|
100
|
+
if (result.error === '') {
|
|
101
|
+
toast.success('A new verification code has been sent');
|
|
102
|
+
} else {
|
|
103
|
+
toast.error(result.error || 'Failed to send new code');
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
(error) => {
|
|
107
|
+
toast.error(String(error) || 'Failed to send new code');
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div className={styles.lcontainer}>
|
|
114
|
+
<div className={styles.lwrap}>
|
|
115
|
+
<div className={styles.logincontainer}>
|
|
116
|
+
<form onSubmit={handleSubmit}>
|
|
117
|
+
<Reveal effect="fadeInUp">
|
|
118
|
+
<div className={styles.login}>
|
|
119
|
+
<img
|
|
120
|
+
src={logo}
|
|
121
|
+
alt="CRM"
|
|
122
|
+
className={styles.loginlogo}
|
|
123
|
+
/>
|
|
124
|
+
<div className={`${styles.formItem} ${styles.fwItem}`}>
|
|
125
|
+
<h2>Two-Factor Authentication</h2>
|
|
126
|
+
<p className={styles.instructions}>
|
|
127
|
+
Please enter the verification code that was sent to your device.
|
|
128
|
+
</p>
|
|
129
|
+
</div>
|
|
130
|
+
<div className={`${styles.formItem} ${styles.fwItem}`}>
|
|
131
|
+
<label className={styles.fi__label}>
|
|
132
|
+
<input
|
|
133
|
+
type="text"
|
|
134
|
+
name="verificationCode"
|
|
135
|
+
value={verificationCode}
|
|
136
|
+
onChange={handleChange}
|
|
137
|
+
tabIndex="1"
|
|
138
|
+
className={codeClass}
|
|
139
|
+
placeholder=" "
|
|
140
|
+
autoComplete="one-time-code"
|
|
141
|
+
maxLength="6"
|
|
142
|
+
/>
|
|
143
|
+
<span className={styles.fi__span}>
|
|
144
|
+
Verification Code
|
|
145
|
+
</span>
|
|
146
|
+
<small>
|
|
147
|
+
<LockOff strokeWidth={2} size={18} />
|
|
148
|
+
</small>
|
|
149
|
+
</label>
|
|
150
|
+
</div>
|
|
151
|
+
<div className={`${styles.formItem} ${styles.fwItem} ${styles.lastItem}`}>
|
|
152
|
+
<button
|
|
153
|
+
className={styles.btn}
|
|
154
|
+
type="submit"
|
|
155
|
+
disabled={isLoading}
|
|
156
|
+
>
|
|
157
|
+
{isLoading ? 'Verifying...' : 'Verify'}
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
<div className={`${styles.formItem} ${styles.fwItem} ${styles.lastItem} ${styles.forgotten}`}>
|
|
161
|
+
<span>
|
|
162
|
+
Didn't receive a code?{' '}
|
|
163
|
+
<a href="#" onClick={(e) => { e.preventDefault(); handleResendCode(); }}>
|
|
164
|
+
Resend Code
|
|
165
|
+
</a>
|
|
166
|
+
</span>
|
|
167
|
+
</div>
|
|
168
|
+
<div className={`${styles.formItem} ${styles.fwItem} ${styles.lastItem} ${styles.forgotten}`}>
|
|
169
|
+
<span>
|
|
170
|
+
<a href="#" onClick={(e) => { e.preventDefault(); navigate('/login'); }}>
|
|
171
|
+
Back to Login
|
|
172
|
+
</a>
|
|
173
|
+
</span>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</Reveal>
|
|
177
|
+
</form>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export default TwoFactorAuth;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Import the Login styles to maintain consistency
|
|
2
|
+
@import './Login.module.scss';
|
|
3
|
+
|
|
4
|
+
// Additional styles specific to the 2FA component
|
|
5
|
+
.instructions {
|
|
6
|
+
text-align: center;
|
|
7
|
+
margin: 0.5rem 0 1.5rem;
|
|
8
|
+
color: var(--paragraph-color);
|
|
9
|
+
font-size: 0.95rem;
|
|
10
|
+
line-height: 1.4;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.login {
|
|
14
|
+
h2 {
|
|
15
|
+
text-align: center;
|
|
16
|
+
margin: 0;
|
|
17
|
+
color: var(--heading-color);
|
|
18
|
+
font-weight: 500;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Style for the verification code input
|
|
23
|
+
.formItem {
|
|
24
|
+
input[name="verificationCode"] {
|
|
25
|
+
letter-spacing: 0.25rem;
|
|
26
|
+
font-size: 1.2rem;
|
|
27
|
+
text-align: center;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -17,6 +17,7 @@ import GenericMain from './GenericMain';
|
|
|
17
17
|
import Login from '../auth/Login';
|
|
18
18
|
import Reset from '../auth/Reset';
|
|
19
19
|
import Verify from '../auth/Verify';
|
|
20
|
+
import TwoFactorAuth from '../auth/TwoFactorAuth';
|
|
20
21
|
|
|
21
22
|
const ProtectedRoute = ({ user, loading, redirectPath = '/login' }) => {
|
|
22
23
|
const location = useLocation();
|
|
@@ -111,6 +112,17 @@ const GenericAuth = ({
|
|
|
111
112
|
/>
|
|
112
113
|
}
|
|
113
114
|
/>
|
|
115
|
+
<Route
|
|
116
|
+
path="2fa"
|
|
117
|
+
element={
|
|
118
|
+
<TwoFactorAuthComponent
|
|
119
|
+
loginBg={loginBg}
|
|
120
|
+
logo={logo}
|
|
121
|
+
setIsAuthenticated={setIsAuthenticated}
|
|
122
|
+
setUserProfile={setUserProfile}
|
|
123
|
+
/>
|
|
124
|
+
}
|
|
125
|
+
/>
|
|
114
126
|
<Route
|
|
115
127
|
element={
|
|
116
128
|
<ProtectedRoute
|
|
@@ -174,4 +186,15 @@ const VerifyComponent = React.memo(({ loginBg, logo, setIsAuthenticated }) => (
|
|
|
174
186
|
<Verify loginBg={loginBg} logo={logo} setSystemAuth={setIsAuthenticated} />
|
|
175
187
|
));
|
|
176
188
|
|
|
189
|
+
const TwoFactorAuthComponent = React.memo(
|
|
190
|
+
({ loginBg, logo, setIsAuthenticated, setUserProfile }) => (
|
|
191
|
+
<TwoFactorAuth
|
|
192
|
+
loginBg={loginBg}
|
|
193
|
+
logo={logo}
|
|
194
|
+
setSystemAuth={setIsAuthenticated}
|
|
195
|
+
setUserProfile={setUserProfile}
|
|
196
|
+
/>
|
|
197
|
+
)
|
|
198
|
+
);
|
|
199
|
+
|
|
177
200
|
export default GenericAuth;
|
|
@@ -40,6 +40,7 @@ function useConfig(setting, tabs, filters, setRowsSelected, tableSetting) {
|
|
|
40
40
|
columns: setting.columns,
|
|
41
41
|
setRowsSelected,
|
|
42
42
|
settings: setting.settings,
|
|
43
|
+
style: setting.style || {},
|
|
43
44
|
tableSetting,
|
|
44
45
|
type: setting.type ? setting.type : 'table',
|
|
45
46
|
});
|
|
@@ -340,6 +341,7 @@ function GenericIndex({
|
|
|
340
341
|
<Table
|
|
341
342
|
{...config}
|
|
342
343
|
ref={gridRef}
|
|
344
|
+
hoverColor={config.style.hoverColor}
|
|
343
345
|
gridHeight={windowHeight * 0.65}
|
|
344
346
|
setConfig={setConfig}
|
|
345
347
|
setTableData={setTableData}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
.vs-datagrid--row:hover {
|
|
25
25
|
.InovuaReactDataGrid__row-cell-wrap {
|
|
26
|
-
background: rgb(
|
|
26
|
+
background: var(--hover-color, rgb(230, 240, 250)) !important;
|
|
27
27
|
cursor: pointer;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
.InovuaReactDataGrid__row-hover-target:hover {
|
|
40
40
|
color: var(--primary-color) !important;
|
|
41
|
-
background: rgb(
|
|
41
|
+
background: var(--hover-color, rgb(230, 240, 250)) !important;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
.InovuaReactDataGrid__row:hover {
|
|
@@ -161,7 +161,7 @@ input[type]:not([type='search']):not([type='url']):not([type='hidden']):not(
|
|
|
161
161
|
|
|
162
162
|
.vs-datagrid--row:hover {
|
|
163
163
|
.InovuaReactDataGrid__row-cell-wrap {
|
|
164
|
-
background: rgb(
|
|
164
|
+
background: var(--hover-color, rgb(230, 240, 250)) !important;
|
|
165
165
|
cursor: pointer;
|
|
166
166
|
}
|
|
167
167
|
}
|
|
@@ -176,7 +176,7 @@ input[type]:not([type='search']):not([type='url']):not([type='hidden']):not(
|
|
|
176
176
|
|
|
177
177
|
.InovuaReactDataGrid__row-hover-target:hover {
|
|
178
178
|
color: var(--paragraph-color) !important;
|
|
179
|
-
background: rgb(
|
|
179
|
+
background: var(--hover-color, rgb(230, 240, 250)) !important;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
.InovuaReactDataGrid__row:hover {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import DataGrid from '../components/crm/DataGrid';
|
|
3
|
+
|
|
4
|
+
// Example of using custom hover color with DataGrid
|
|
5
|
+
const CustomHoverDataGrid = () => {
|
|
6
|
+
// Example DataGrid props with direct hoverColor prop
|
|
7
|
+
const exampleProps = {
|
|
8
|
+
// Your DataGrid props here
|
|
9
|
+
hoverColor: 'rgb(255, 240, 230)', // Peachy hover color
|
|
10
|
+
// Other props...
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Define custom styles with hover color (alternative method)
|
|
14
|
+
const customStyle = {
|
|
15
|
+
// You can define any CSS variables here
|
|
16
|
+
'--hover-color': 'rgb(230, 255, 230)', // Light green hover color
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div>
|
|
21
|
+
<h2>DataGrid with Custom Hover Color</h2>
|
|
22
|
+
<p>
|
|
23
|
+
This example shows how to customize the hover color of the
|
|
24
|
+
DataGrid.
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<h3>Method 1: Using the hoverColor prop (Recommended)</h3>
|
|
28
|
+
<div>
|
|
29
|
+
<DataGrid {...exampleProps} />
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<h3>Method 2: Using CSS Variables in style prop</h3>
|
|
33
|
+
<div>
|
|
34
|
+
<DataGrid style={customStyle} />
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<h3>Method 3: Using CSS/SCSS classes</h3>
|
|
38
|
+
<div className="custom-hover-grid">
|
|
39
|
+
<DataGrid />
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<h3>How to Use Custom Hover Colors</h3>
|
|
43
|
+
<p>You can set a custom hover color in three ways:</p>
|
|
44
|
+
<ol>
|
|
45
|
+
<li>
|
|
46
|
+
<strong>Using the hoverColor prop (Recommended):</strong>
|
|
47
|
+
<pre>
|
|
48
|
+
{`
|
|
49
|
+
// Direct prop approach
|
|
50
|
+
<DataGrid
|
|
51
|
+
hoverColor="rgb(255, 240, 230)"
|
|
52
|
+
{...otherProps}
|
|
53
|
+
/>
|
|
54
|
+
`}
|
|
55
|
+
</pre>
|
|
56
|
+
</li>
|
|
57
|
+
<li>
|
|
58
|
+
<strong>Using CSS Variables in style prop:</strong>
|
|
59
|
+
<pre>
|
|
60
|
+
{`
|
|
61
|
+
// Define in your component
|
|
62
|
+
const customStyle = {
|
|
63
|
+
'--hover-color': 'rgb(230, 255, 230)'
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Apply to DataGrid
|
|
67
|
+
<DataGrid style={customStyle} {...otherProps} />
|
|
68
|
+
`}
|
|
69
|
+
</pre>
|
|
70
|
+
</li>
|
|
71
|
+
<li>
|
|
72
|
+
<strong>Using CSS/SCSS:</strong>
|
|
73
|
+
<pre>
|
|
74
|
+
{`
|
|
75
|
+
/* In your CSS/SCSS file */
|
|
76
|
+
:root {
|
|
77
|
+
--hover-color: rgb(230, 240, 250);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* For specific containers */
|
|
81
|
+
.custom-hover-grid {
|
|
82
|
+
--hover-color: rgb(200, 220, 255);
|
|
83
|
+
}
|
|
84
|
+
`}
|
|
85
|
+
</pre>
|
|
86
|
+
</li>
|
|
87
|
+
</ol>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export default CustomHoverDataGrid;
|