@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.
Files changed (36) hide show
  1. package/.prettierrc.json +7 -0
  2. package/components/cms/{visns-data-grid.jsx → DataGrid.jsx} +2 -2
  3. package/components/cms/DropZone.jsx +161 -0
  4. package/components/cms/Field.jsx +747 -0
  5. package/components/cms/Form.jsx +475 -0
  6. package/components/cms/sorting/{list.jsx → List.jsx} +3 -3
  7. package/components/crm/{visns-async-select.jsx → AsyncSelect.jsx} +9 -9
  8. package/components/crm/Call.jsx +220 -0
  9. package/components/crm/{visns-data-grid.jsx → DataGrid.jsx} +263 -277
  10. package/components/crm/{visns-field.jsx → Field.jsx} +5 -5
  11. package/components/crm/{visns-form.jsx → Form.jsx} +302 -205
  12. package/components/crm/{visns-multi-select.jsx → MultiSelect.jsx} +1 -1
  13. package/components/crm/{visns-navigation.jsx → Navigation.jsx} +22 -18
  14. package/components/crm/{visns-notification.jsx → Notification.jsx} +1 -1
  15. package/components/crm/TableFilter.jsx +125 -0
  16. package/components/crm/auth/Login.jsx +158 -0
  17. package/components/crm/auth/Profile.jsx +163 -0
  18. package/components/crm/auth/Reset.jsx +87 -0
  19. package/components/crm/auth/Verify.jsx +162 -0
  20. package/components/crm/generic/GenericDetail.jsx +380 -0
  21. package/components/crm/generic/GenericIndex.jsx +112 -0
  22. package/components/crm/generic/NotificationList.jsx +64 -0
  23. package/index.js +37 -19
  24. package/package.json +6 -6
  25. package/components/cms/visns-dropzone.jsx +0 -161
  26. package/components/cms/visns-field.jsx +0 -747
  27. package/components/cms/visns-form.jsx +0 -475
  28. package/components/crm/visns-call.jsx +0 -220
  29. package/components/crm/visns-table-filter.jsx +0 -153
  30. /package/components/cms/sorting/{item.jsx → Item.jsx} +0 -0
  31. /package/components/crm/{visns-autocomplete.jsx → Autocomplete.jsx} +0 -0
  32. /package/components/crm/{visns-download.jsx → Download.jsx} +0 -0
  33. /package/components/crm/{visns-fetch.jsx → Fetch.jsx} +0 -0
  34. /package/components/crm/{visns-loader.jsx → Loader.jsx} +0 -0
  35. /package/components/crm/{visns-select.jsx → Select.jsx} +0 -0
  36. /package/components/crm/{visns-select-list.jsx → SelectList.jsx} +0 -0
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState } from "react";
2
- import SelectList from "./visns-select-list";
2
+ import SelectList from "./SelectList";
3
3
  import Select, { createFilter } from "react-select";
4
4
 
5
5
  function MultiSelect(props) {
@@ -1,5 +1,5 @@
1
- import React, { useEffect, useState } from "react";
2
- import { Link, useLocation, useNavigate } from "react-router-dom";
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 "akar-icons";
25
+ } from 'akar-icons';
26
26
 
27
- import CustomFetch from "./visns-fetch";
28
- import Notification from "./visns-notification";
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) || "dashboard";
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 ? "navscrolled" : ""}`;
36
+ const appNavClasses = `app-nav ${isScrolled ? 'navscrolled' : ''}`;
37
37
 
38
38
  const handleLogout = () => {
39
- CustomFetch("/logout", "GET", {}, () => {
39
+ CustomFetch('/logout', 'GET', {}, () => {
40
40
  setSystemAuth(false);
41
- navigate("/login");
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 === "notifications") {
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 === "logout") {
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 : "_self"}
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("/") ? url.substr(1) : url;
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: "nav-item active" };
244
+ return { ...nav, class: 'nav-item active' };
241
245
  } else {
242
- return { ...nav, class: "nav-item" };
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("scroll", handleScroll);
262
+ window.addEventListener('scroll', handleScroll);
259
263
  return () => {
260
- window.removeEventListener("scroll", handleScroll);
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 "./visns-fetch";
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;