@visns-studio/visns-components 1.8.5 → 2.0.0
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/.prettierrc.json +7 -0
- package/components/cms/{visns-data-grid.jsx → DataGrid.jsx} +2 -2
- package/components/cms/DropZone.jsx +161 -0
- package/components/cms/Field.jsx +747 -0
- package/components/cms/Form.jsx +475 -0
- package/components/cms/sorting/{list.jsx → List.jsx} +3 -3
- package/components/crm/{visns-async-select.jsx → AsyncSelect.jsx} +9 -9
- package/components/crm/Call.jsx +220 -0
- package/components/crm/{visns-data-grid.jsx → DataGrid.jsx} +263 -277
- package/components/crm/{visns-field.jsx → Field.jsx} +5 -5
- package/components/crm/{visns-form.jsx → Form.jsx} +302 -205
- package/components/crm/{visns-multi-select.jsx → MultiSelect.jsx} +1 -1
- package/components/crm/{visns-navigation.jsx → Navigation.jsx} +22 -18
- package/components/crm/{visns-notification.jsx → Notification.jsx} +1 -1
- package/components/crm/TableFilter.jsx +125 -0
- package/components/crm/auth/Login.jsx +158 -0
- package/components/crm/auth/Profile.jsx +163 -0
- package/components/crm/auth/Reset.jsx +87 -0
- package/components/crm/auth/Verify.jsx +162 -0
- package/components/crm/generic/GenericDetail.jsx +380 -0
- package/components/crm/generic/GenericIndex.jsx +112 -0
- package/components/crm/generic/NotificationList.jsx +64 -0
- package/index.js +37 -19
- package/package.json +6 -6
- package/components/cms/visns-dropzone.jsx +0 -161
- package/components/cms/visns-field.jsx +0 -747
- package/components/cms/visns-form.jsx +0 -475
- package/components/crm/visns-call.jsx +0 -220
- package/components/crm/visns-table-filter.jsx +0 -153
- /package/components/cms/sorting/{item.jsx → Item.jsx} +0 -0
- /package/components/crm/{visns-autocomplete.jsx → Autocomplete.jsx} +0 -0
- /package/components/crm/{visns-download.jsx → Download.jsx} +0 -0
- /package/components/crm/{visns-fetch.jsx → Fetch.jsx} +0 -0
- /package/components/crm/{visns-loader.jsx → Loader.jsx} +0 -0
- /package/components/crm/{visns-select.jsx → Select.jsx} +0 -0
- /package/components/crm/{visns-select-list.jsx → SelectList.jsx} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useEffect, useState } from
|
|
2
|
-
import { Link, useLocation, useNavigate } from
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
|
3
3
|
import {
|
|
4
4
|
ArrowCycle,
|
|
5
5
|
BookClose,
|
|
@@ -22,23 +22,23 @@ import {
|
|
|
22
22
|
StatisticUp,
|
|
23
23
|
Ticket,
|
|
24
24
|
Utensils,
|
|
25
|
-
} from
|
|
25
|
+
} from 'akar-icons';
|
|
26
26
|
|
|
27
|
-
import CustomFetch from
|
|
28
|
-
import Notification from
|
|
27
|
+
import CustomFetch from './Fetch';
|
|
28
|
+
import Notification from './Notification';
|
|
29
29
|
|
|
30
30
|
function Navigation({ logo, logout, navConfig, setSystemAuth, userProfile }) {
|
|
31
31
|
const location = useLocation();
|
|
32
32
|
const navigate = useNavigate();
|
|
33
|
-
const currentPage = location.pathname.substr(1) ||
|
|
33
|
+
const currentPage = location.pathname.substr(1) || 'dashboard';
|
|
34
34
|
const [navData, setNavData] = useState(navConfig);
|
|
35
35
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
36
|
-
const appNavClasses = `app-nav ${isScrolled ?
|
|
36
|
+
const appNavClasses = `app-nav ${isScrolled ? 'navscrolled' : ''}`;
|
|
37
37
|
|
|
38
38
|
const handleLogout = () => {
|
|
39
|
-
CustomFetch(
|
|
39
|
+
CustomFetch('/logout', 'GET', {}, () => {
|
|
40
40
|
setSystemAuth(false);
|
|
41
|
-
navigate(
|
|
41
|
+
navigate('/login');
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
44
|
|
|
@@ -51,13 +51,13 @@ function Navigation({ logo, logout, navConfig, setSystemAuth, userProfile }) {
|
|
|
51
51
|
signOut: SignOut,
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
if (n.id ===
|
|
54
|
+
if (n.id === 'notifications') {
|
|
55
55
|
return (
|
|
56
56
|
<li>
|
|
57
57
|
<Notification setSystemAuth={setSystemAuth} />
|
|
58
58
|
</li>
|
|
59
59
|
);
|
|
60
|
-
} else if (n.id ===
|
|
60
|
+
} else if (n.id === 'logout') {
|
|
61
61
|
const IconComponent = iconComponents[n.icon];
|
|
62
62
|
return (
|
|
63
63
|
<li>
|
|
@@ -81,7 +81,7 @@ function Navigation({ logo, logout, navConfig, setSystemAuth, userProfile }) {
|
|
|
81
81
|
data-tooltip-id="system-tooltip"
|
|
82
82
|
data-tooltip-content={n.label}
|
|
83
83
|
className="tooltip"
|
|
84
|
-
target={n.target ? n.target :
|
|
84
|
+
target={n.target ? n.target : '_self'}
|
|
85
85
|
>
|
|
86
86
|
<IconComponent size={19} strokeWidth={2} />
|
|
87
87
|
</Link>
|
|
@@ -225,7 +225,11 @@ function Navigation({ logo, logout, navConfig, setSystemAuth, userProfile }) {
|
|
|
225
225
|
setNavData((prevNavData) => {
|
|
226
226
|
const updateNavItems = (nav) => {
|
|
227
227
|
const cleanUrl = (url) => {
|
|
228
|
-
return url && url.startsWith(
|
|
228
|
+
return url && url.startsWith('/')
|
|
229
|
+
? url.substr(1).split('/')[0]
|
|
230
|
+
: url
|
|
231
|
+
? url.split('/')[0]
|
|
232
|
+
: '';
|
|
229
233
|
};
|
|
230
234
|
|
|
231
235
|
const currentUrl = cleanUrl(currentPage);
|
|
@@ -237,9 +241,9 @@ function Navigation({ logo, logout, navConfig, setSystemAuth, userProfile }) {
|
|
|
237
241
|
(child) => cleanUrl(child.url) === currentUrl
|
|
238
242
|
))
|
|
239
243
|
) {
|
|
240
|
-
return { ...nav, class:
|
|
244
|
+
return { ...nav, class: 'nav-item active' };
|
|
241
245
|
} else {
|
|
242
|
-
return { ...nav, class:
|
|
246
|
+
return { ...nav, class: 'nav-item' };
|
|
243
247
|
}
|
|
244
248
|
};
|
|
245
249
|
|
|
@@ -255,9 +259,9 @@ function Navigation({ logo, logout, navConfig, setSystemAuth, userProfile }) {
|
|
|
255
259
|
setIsScrolled(window.scrollY > 0);
|
|
256
260
|
}
|
|
257
261
|
|
|
258
|
-
window.addEventListener(
|
|
262
|
+
window.addEventListener('scroll', handleScroll);
|
|
259
263
|
return () => {
|
|
260
|
-
window.removeEventListener(
|
|
264
|
+
window.removeEventListener('scroll', handleScroll);
|
|
261
265
|
};
|
|
262
266
|
}, []);
|
|
263
267
|
|
|
@@ -273,7 +277,7 @@ function Navigation({ logo, logout, navConfig, setSystemAuth, userProfile }) {
|
|
|
273
277
|
<ul className={appNavClasses}>
|
|
274
278
|
{navData.navigations.map((nav, navKey) =>
|
|
275
279
|
nav.permission === true ||
|
|
276
|
-
nav.permissionKey ===
|
|
280
|
+
nav.permissionKey === '' ? (
|
|
277
281
|
<React.Fragment key={`nav-item-${navKey}`}>
|
|
278
282
|
{renderNav(nav)}
|
|
279
283
|
</React.Fragment>
|
|
@@ -6,7 +6,7 @@ import { TooltipWrapper } from "react-tooltip";
|
|
|
6
6
|
import { toast } from "react-toastify";
|
|
7
7
|
import { Bell, CircleX } from "akar-icons";
|
|
8
8
|
|
|
9
|
-
import CustomFetch from "./
|
|
9
|
+
import CustomFetch from "./Fetch";
|
|
10
10
|
|
|
11
11
|
function Notification(props) {
|
|
12
12
|
let interval;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
function TableFilter({ filters, setFilters, setSettings, type }) {
|
|
4
|
+
const filterTable = (e) => {
|
|
5
|
+
const { id, value, url } = e.target.dataset;
|
|
6
|
+
|
|
7
|
+
if (url && url !== '') {
|
|
8
|
+
window.open(url);
|
|
9
|
+
} else {
|
|
10
|
+
if (setSettings) {
|
|
11
|
+
setSettings((prevState) => {
|
|
12
|
+
if (prevState.ajaxSetting) {
|
|
13
|
+
let _where = prevState.ajaxSetting.where.reduce(
|
|
14
|
+
(acc, a) => {
|
|
15
|
+
if (
|
|
16
|
+
a.id === id &&
|
|
17
|
+
!acc.some((b) => b.id === id)
|
|
18
|
+
) {
|
|
19
|
+
acc.push({ id: id, value: value });
|
|
20
|
+
} else {
|
|
21
|
+
acc.push(a);
|
|
22
|
+
}
|
|
23
|
+
return acc;
|
|
24
|
+
},
|
|
25
|
+
[]
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
...prevState,
|
|
30
|
+
ajaxSetting: {
|
|
31
|
+
...prevState.ajaxSetting,
|
|
32
|
+
where: _where,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
} else {
|
|
36
|
+
let w = prevState.where.map((a) => {
|
|
37
|
+
if (id === a.id) {
|
|
38
|
+
return { ...a, value: value };
|
|
39
|
+
}
|
|
40
|
+
return a;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return { ...prevState, where: w };
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setFilters((prevFilters) => {
|
|
50
|
+
const tempFilters = prevFilters.map((item, index) => {
|
|
51
|
+
if (
|
|
52
|
+
e.target.dataset.hasOwnProperty('value') &&
|
|
53
|
+
parseInt(value) >= 0
|
|
54
|
+
) {
|
|
55
|
+
return {
|
|
56
|
+
...item,
|
|
57
|
+
class:
|
|
58
|
+
parseInt(value) === parseInt(item.value)
|
|
59
|
+
? type === 'simple'
|
|
60
|
+
? 'activetab'
|
|
61
|
+
: 'subactive'
|
|
62
|
+
: '',
|
|
63
|
+
show: parseInt(value) === parseInt(item.value),
|
|
64
|
+
};
|
|
65
|
+
} else {
|
|
66
|
+
return {
|
|
67
|
+
...item,
|
|
68
|
+
class:
|
|
69
|
+
id === item.id
|
|
70
|
+
? type === 'simple'
|
|
71
|
+
? 'activetab'
|
|
72
|
+
: 'subactive'
|
|
73
|
+
: '',
|
|
74
|
+
show: id === item.id,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return [...tempFilters];
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const renderContent = (d) => {
|
|
84
|
+
if (type === 'simple') {
|
|
85
|
+
return (
|
|
86
|
+
<li className={d.class}>
|
|
87
|
+
<button
|
|
88
|
+
data-id={d.id}
|
|
89
|
+
data-value={d.hasOwnProperty('value') ? d.value : ''}
|
|
90
|
+
data-url={d.url || ''}
|
|
91
|
+
onClick={filterTable}
|
|
92
|
+
>
|
|
93
|
+
{d.label}
|
|
94
|
+
</button>
|
|
95
|
+
</li>
|
|
96
|
+
);
|
|
97
|
+
} else {
|
|
98
|
+
return (
|
|
99
|
+
<li>
|
|
100
|
+
<a
|
|
101
|
+
data-id={d.id}
|
|
102
|
+
data-value={d.hasOwnProperty('value') ? d.value : ''}
|
|
103
|
+
data-url={d.url || ''}
|
|
104
|
+
onClick={filterTable}
|
|
105
|
+
className={d.class}
|
|
106
|
+
>
|
|
107
|
+
{d.label}
|
|
108
|
+
</a>
|
|
109
|
+
</li>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<ul>
|
|
116
|
+
{filters.map((item, key) => (
|
|
117
|
+
<React.Fragment key={'table-filter-' + key}>
|
|
118
|
+
{renderContent(item)}
|
|
119
|
+
</React.Fragment>
|
|
120
|
+
))}
|
|
121
|
+
</ul>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export default TableFilter;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Link, useNavigate, useLocation } from "react-router-dom";
|
|
3
|
+
import Reveal from "react-reveal/Reveal";
|
|
4
|
+
import { toast } from "react-toastify";
|
|
5
|
+
import { Person, LockOff } from "akar-icons";
|
|
6
|
+
|
|
7
|
+
import CustomFetch from "../Fetch";
|
|
8
|
+
|
|
9
|
+
const Login = ({ logo, setSystemAuth, setUserProfile }) => {
|
|
10
|
+
const location = useLocation();
|
|
11
|
+
const navigate = useNavigate();
|
|
12
|
+
|
|
13
|
+
const [auth, setAuth] = useState({
|
|
14
|
+
email: "",
|
|
15
|
+
password: "",
|
|
16
|
+
location: location,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const [authClass, setAuthClass] = useState({
|
|
20
|
+
username: "",
|
|
21
|
+
password: "",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const handleChange = (e) => {
|
|
25
|
+
if (e) {
|
|
26
|
+
setAuth((prevState) => ({
|
|
27
|
+
...prevState,
|
|
28
|
+
[e.target.name]: e.target.value,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handleSubmit = (e) => {
|
|
34
|
+
if (e) {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
|
|
37
|
+
CustomFetch(
|
|
38
|
+
"/login/authenticate",
|
|
39
|
+
"POST",
|
|
40
|
+
auth,
|
|
41
|
+
(result) => {
|
|
42
|
+
if (result.error === "") {
|
|
43
|
+
setUserProfile(result.user);
|
|
44
|
+
setSystemAuth(true);
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
result.previous?.state?.referrer &&
|
|
48
|
+
result.previous.state.referrer !== ""
|
|
49
|
+
) {
|
|
50
|
+
navigate(result.previous.state.referrer);
|
|
51
|
+
} else {
|
|
52
|
+
navigate("/");
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
setSystemAuth(false);
|
|
56
|
+
setAuthClass((prevState) => ({
|
|
57
|
+
...prevState,
|
|
58
|
+
username: "inputError",
|
|
59
|
+
password: "inputError",
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
toast.error(
|
|
63
|
+
"Could not log in with the supplied credentials, please try again."
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
(error) => {
|
|
68
|
+
setAuthClass((prevState) => ({
|
|
69
|
+
...prevState,
|
|
70
|
+
username: "inputError",
|
|
71
|
+
password: "inputError",
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
if (String(error) === "CSRF token mismatch.") {
|
|
75
|
+
toast.error(
|
|
76
|
+
"Auth token has timed out, please reload the page before attempting to log back in."
|
|
77
|
+
);
|
|
78
|
+
} else {
|
|
79
|
+
toast.error(String(error));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div className="lcontainer">
|
|
88
|
+
<div className="lwrap">
|
|
89
|
+
<aside className="aside"></aside>
|
|
90
|
+
<div className="logincontainer">
|
|
91
|
+
<form onSubmit={handleSubmit}>
|
|
92
|
+
<Reveal effect="fadeInUp">
|
|
93
|
+
<div className="login">
|
|
94
|
+
<img
|
|
95
|
+
src={logo}
|
|
96
|
+
alt="CRM"
|
|
97
|
+
className="loginlogo"
|
|
98
|
+
/>
|
|
99
|
+
<div className="formItem fwItem">
|
|
100
|
+
<label className="fi__label">
|
|
101
|
+
<input
|
|
102
|
+
type="email"
|
|
103
|
+
name="email"
|
|
104
|
+
value={auth.email}
|
|
105
|
+
onChange={handleChange}
|
|
106
|
+
tabIndex="1"
|
|
107
|
+
className={authClass.username}
|
|
108
|
+
placeholder=" "
|
|
109
|
+
/>
|
|
110
|
+
<span className="fi__span">Email</span>
|
|
111
|
+
<small>
|
|
112
|
+
<Person strokeWidth={2} size={18} />
|
|
113
|
+
</small>
|
|
114
|
+
</label>
|
|
115
|
+
</div>
|
|
116
|
+
<div className="formItem fwItem">
|
|
117
|
+
<label className="fi__label">
|
|
118
|
+
<input
|
|
119
|
+
type="password"
|
|
120
|
+
name="password"
|
|
121
|
+
value={auth.password}
|
|
122
|
+
onChange={handleChange}
|
|
123
|
+
tabIndex="2"
|
|
124
|
+
className={authClass.password}
|
|
125
|
+
placeholder=" "
|
|
126
|
+
/>
|
|
127
|
+
<span className="fi__span">
|
|
128
|
+
Password
|
|
129
|
+
</span>
|
|
130
|
+
<small>
|
|
131
|
+
<LockOff
|
|
132
|
+
strokeWidth={2}
|
|
133
|
+
size={18}
|
|
134
|
+
/>
|
|
135
|
+
</small>
|
|
136
|
+
</label>
|
|
137
|
+
</div>
|
|
138
|
+
<div className="formItem fwItem lastItem">
|
|
139
|
+
<button className="btn" type="submit">
|
|
140
|
+
Login
|
|
141
|
+
</button>
|
|
142
|
+
</div>
|
|
143
|
+
<div className="formItem fwItem lastItem forgotten">
|
|
144
|
+
<span>
|
|
145
|
+
Forgot your password?{" "}
|
|
146
|
+
<Link to="/reset">Click Here</Link>
|
|
147
|
+
</span>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</Reveal>
|
|
151
|
+
</form>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export default Login;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import PasswordStrengthBar from 'react-password-strength-bar';
|
|
3
|
+
import { toast } from 'react-toastify';
|
|
4
|
+
import CustomFetch from '../Fetch';
|
|
5
|
+
import TableFilter from '../TableFilter';
|
|
6
|
+
|
|
7
|
+
const Profile = ({ userProfile, setUserProfile }) => {
|
|
8
|
+
const [profile, setProfile] = useState({
|
|
9
|
+
name: '',
|
|
10
|
+
email: '',
|
|
11
|
+
password: '',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const [inputClasses, setInputClasses] = useState({
|
|
15
|
+
name: '',
|
|
16
|
+
email: '',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const [filters, setFilters] = useState([
|
|
20
|
+
{
|
|
21
|
+
id: 'overview',
|
|
22
|
+
show: true,
|
|
23
|
+
label: 'Overview',
|
|
24
|
+
class: 'subactive',
|
|
25
|
+
},
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
setProfile({
|
|
30
|
+
name: userProfile.name,
|
|
31
|
+
email: userProfile.email,
|
|
32
|
+
password: '',
|
|
33
|
+
});
|
|
34
|
+
}, [userProfile]);
|
|
35
|
+
|
|
36
|
+
const handleChangeProfile = (e) => {
|
|
37
|
+
const { name, value } = e.target;
|
|
38
|
+
setProfile((prevProfile) => ({
|
|
39
|
+
...prevProfile,
|
|
40
|
+
[name]: value,
|
|
41
|
+
}));
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleSubmitProfile = (e) => {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
|
|
47
|
+
if (profile.name.trim() === '' || profile.email.trim() === '') {
|
|
48
|
+
setInputClasses({
|
|
49
|
+
name: profile.name.trim() === '' ? 'inputError' : '',
|
|
50
|
+
email: profile.email.trim() === '' ? 'inputError' : '',
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
toast.error('Please fill in all the required fields.');
|
|
54
|
+
} else {
|
|
55
|
+
CustomFetch(
|
|
56
|
+
`/ajax/users/${userProfile.id}`,
|
|
57
|
+
'PUT',
|
|
58
|
+
profile,
|
|
59
|
+
function (result) {
|
|
60
|
+
setUserProfile(result.user);
|
|
61
|
+
toast.success(
|
|
62
|
+
'Your profile has been successfully updated.'
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const renderContent = (filter) => {
|
|
70
|
+
if (filter.show && filter.id === 'overview') {
|
|
71
|
+
return (
|
|
72
|
+
<div className="gridtxt" key={filter.id}>
|
|
73
|
+
<div className="gridtxt__header">
|
|
74
|
+
<span>Overview</span>
|
|
75
|
+
</div>
|
|
76
|
+
<div className="formcontainer">
|
|
77
|
+
<form
|
|
78
|
+
className="modalForm"
|
|
79
|
+
onSubmit={handleSubmitProfile}
|
|
80
|
+
>
|
|
81
|
+
<div className="formItem">
|
|
82
|
+
<label className="fi__label">
|
|
83
|
+
<input
|
|
84
|
+
type="text"
|
|
85
|
+
name="name"
|
|
86
|
+
onChange={handleChangeProfile}
|
|
87
|
+
className={inputClasses.name}
|
|
88
|
+
value={profile.name}
|
|
89
|
+
/>
|
|
90
|
+
<span className="fi__span">Name *</span>
|
|
91
|
+
</label>
|
|
92
|
+
</div>
|
|
93
|
+
<div className="formItem">
|
|
94
|
+
<label className="fi__label">
|
|
95
|
+
<input
|
|
96
|
+
type="text"
|
|
97
|
+
name="email"
|
|
98
|
+
onChange={handleChangeProfile}
|
|
99
|
+
className={inputClasses.email}
|
|
100
|
+
value={profile.email}
|
|
101
|
+
/>
|
|
102
|
+
<span className="fi__span">Email *</span>
|
|
103
|
+
</label>
|
|
104
|
+
</div>
|
|
105
|
+
<div className="formItem">
|
|
106
|
+
<label className="fi__label">
|
|
107
|
+
<span className="fi__span prefocus">
|
|
108
|
+
Password
|
|
109
|
+
</span>
|
|
110
|
+
<input
|
|
111
|
+
type="password"
|
|
112
|
+
name="password"
|
|
113
|
+
onChange={handleChangeProfile}
|
|
114
|
+
/>
|
|
115
|
+
<PasswordStrengthBar
|
|
116
|
+
password={profile.password}
|
|
117
|
+
/>
|
|
118
|
+
</label>
|
|
119
|
+
</div>
|
|
120
|
+
<div className="formItem fwItem lastItem">
|
|
121
|
+
<button className="btn modalsave" type="submit">
|
|
122
|
+
Update
|
|
123
|
+
</button>
|
|
124
|
+
</div>
|
|
125
|
+
</form>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div>
|
|
135
|
+
<div className="grid">
|
|
136
|
+
<div className="grid__row">
|
|
137
|
+
<div className="grid__full crmtitle">
|
|
138
|
+
<h1>My Profile</h1>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
<div className="grid">
|
|
143
|
+
<div className="grid__subrow">
|
|
144
|
+
<div className="grid__subnav">
|
|
145
|
+
<TableFilter
|
|
146
|
+
filters={filters}
|
|
147
|
+
setFilters={setFilters}
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
<div className="grid__subcontent">
|
|
151
|
+
{filters.map((filter) => (
|
|
152
|
+
<React.Fragment key={`filter-${filter.id}`}>
|
|
153
|
+
{renderContent(filter)}
|
|
154
|
+
</React.Fragment>
|
|
155
|
+
))}
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export default Profile;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import Reveal from "react-reveal/Reveal";
|
|
3
|
+
import { toast } from "react-toastify";
|
|
4
|
+
import parse from "html-react-parser";
|
|
5
|
+
import { Person } from "akar-icons";
|
|
6
|
+
|
|
7
|
+
import CustomFetch from "../Fetch";
|
|
8
|
+
|
|
9
|
+
const Reset = () => {
|
|
10
|
+
const [email, setEmail] = useState("");
|
|
11
|
+
const [emailClass, setEmailClass] = useState("");
|
|
12
|
+
|
|
13
|
+
const handleSubmit = (e) => {
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
|
|
16
|
+
if (email === "") {
|
|
17
|
+
const error = "Please type in your email address.";
|
|
18
|
+
setEmailClass("inputError");
|
|
19
|
+
toast.error(<div>{parse(error)}</div>);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
CustomFetch(
|
|
24
|
+
"/password/forgot",
|
|
25
|
+
"POST",
|
|
26
|
+
{ email: email },
|
|
27
|
+
function (result) {
|
|
28
|
+
if (result.error === "") {
|
|
29
|
+
setEmail(
|
|
30
|
+
"You have successfully requested to reset your password, an email will be sent shortly. Please follow the instruction on the email."
|
|
31
|
+
);
|
|
32
|
+
} else {
|
|
33
|
+
toast.error(result.error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className="lcontainer">
|
|
41
|
+
<div className="lwrap">
|
|
42
|
+
<aside className="aside"></aside>
|
|
43
|
+
<div className="logincontainer">
|
|
44
|
+
<form onSubmit={handleSubmit}>
|
|
45
|
+
<Reveal effect="fadeInUp">
|
|
46
|
+
<div className="login">
|
|
47
|
+
<div className="formItem fwItem">
|
|
48
|
+
<h1>Forgot your password?</h1>
|
|
49
|
+
</div>
|
|
50
|
+
<div className="formItem fwItem">
|
|
51
|
+
<label className="fi__label">
|
|
52
|
+
<input
|
|
53
|
+
type="email"
|
|
54
|
+
name="email"
|
|
55
|
+
value={email}
|
|
56
|
+
onChange={(e) => {
|
|
57
|
+
setEmail(e.target.value);
|
|
58
|
+
setEmailClass("");
|
|
59
|
+
}}
|
|
60
|
+
tabIndex="1"
|
|
61
|
+
className={emailClass}
|
|
62
|
+
/>
|
|
63
|
+
<span className="fi__span">Email</span>
|
|
64
|
+
<small>
|
|
65
|
+
<Person strokeWidth={2} size={18} />
|
|
66
|
+
</small>
|
|
67
|
+
</label>
|
|
68
|
+
</div>
|
|
69
|
+
<div className="formItem fwItem lastItem">
|
|
70
|
+
<button
|
|
71
|
+
className="btn"
|
|
72
|
+
type="submit"
|
|
73
|
+
tabIndex="2"
|
|
74
|
+
>
|
|
75
|
+
Reset Password
|
|
76
|
+
</button>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</Reveal>
|
|
80
|
+
</form>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export default Reset;
|