@visns-studio/visns-components 4.0.6 → 4.0.8

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.
@@ -255,6 +255,14 @@ function Form({
255
255
  }
256
256
  };
257
257
 
258
+ const handleChangeSignature = (e) => {
259
+ if (e) {
260
+ e.preventDefault();
261
+ }
262
+
263
+ console.info(userProfile, 'aaa');
264
+ };
265
+
258
266
  const handleChangeToggle = (e) => {
259
267
  if (!e) {
260
268
  return;
@@ -1197,6 +1205,9 @@ function Form({
1197
1205
  handleChangeRicheditor
1198
1206
  }
1199
1207
  onChangeSelect={handleChangeSelect}
1208
+ onChangeSignature={
1209
+ handleChangeSignature
1210
+ }
1200
1211
  onChangeToggle={handleChangeToggle}
1201
1212
  settings={item}
1202
1213
  setFormData={setFormData}
@@ -1318,6 +1329,9 @@ function Form({
1318
1329
  onChangeRicheditor={
1319
1330
  handleChangeRicheditor
1320
1331
  }
1332
+ onChangeSignature={
1333
+ handleChangeSignature
1334
+ }
1321
1335
  onChangeSelect={handleChangeSelect}
1322
1336
  onChangeToggle={handleChangeToggle}
1323
1337
  onFileDownload={handleFileDownload}
@@ -138,7 +138,6 @@ function TableFilter({
138
138
  </li>
139
139
  );
140
140
  } else {
141
- console.info(d.class);
142
141
  return (
143
142
  <li>
144
143
  <a
@@ -161,7 +160,6 @@ function TableFilter({
161
160
  >
162
161
  {d.children.map((child, key) => (
163
162
  <li key={`table-filter-child-${d.id}-${key}`}>
164
- {console.info(child.class)}
165
163
  <a
166
164
  className={childClass(child)}
167
165
  data-id={child.id}
@@ -1,19 +1,27 @@
1
- import React, { useState, useEffect } from 'react';
1
+ // src/components/Profile.jsx
2
+
3
+ import React, { useState, useEffect, useRef } from 'react';
2
4
  import PasswordStrengthBar from 'react-password-strength-bar';
3
5
  import { toast } from 'react-toastify';
6
+ import SignaturePad from 'react-signature-pad-wrapper';
4
7
  import CustomFetch from '../Fetch';
5
8
  import TableFilter from '../TableFilter';
9
+ import styles from './styles/Profile.module.css';
6
10
 
7
11
  const Profile = ({ userProfile, setUserProfile }) => {
12
+ const signatureRef = useRef(null);
8
13
  const [profile, setProfile] = useState({
9
14
  name: '',
10
15
  email: '',
11
16
  password: '',
17
+ password_confirmation: '',
12
18
  });
13
19
 
14
20
  const [inputClasses, setInputClasses] = useState({
15
21
  name: '',
16
22
  email: '',
23
+ password: '',
24
+ password_confirmation: '',
17
25
  });
18
26
 
19
27
  const [filters, setFilters] = useState([
@@ -25,13 +33,12 @@ const Profile = ({ userProfile, setUserProfile }) => {
25
33
  },
26
34
  ]);
27
35
 
28
- useEffect(() => {
29
- setProfile({
30
- name: userProfile.name,
31
- email: userProfile.email,
32
- password: '',
33
- });
34
- }, [userProfile]);
36
+ const handleClearSignature = (e) => {
37
+ if (e) {
38
+ e.preventDefault();
39
+ signatureRef.current.clear();
40
+ }
41
+ };
35
42
 
36
43
  const handleChangeProfile = (e) => {
37
44
  const { name, value } = e.target;
@@ -50,32 +57,54 @@ const Profile = ({ userProfile, setUserProfile }) => {
50
57
  // Validate required fields
51
58
  if (profile.name.trim() === '' || profile.email.trim() === '') {
52
59
  setInputClasses({
53
- name: profile.name.trim() === '' ? 'inputError' : '',
54
- email: profile.email.trim() === '' ? 'inputError' : '',
60
+ name: profile.name.trim() === '' ? styles.inputError : '',
61
+ email: profile.email.trim() === '' ? styles.inputError : '',
55
62
  });
56
63
 
57
64
  toast.error('Please fill in all the required fields.');
58
- } else {
59
- // Create a new payload object
60
- let payload = {
61
- name: profile.name,
62
- email: profile.email,
63
- };
64
-
65
- // Conditionally add password to payload if it has a value
66
- if (profile.password.trim() !== '') {
67
- payload.password = profile.password;
68
- }
69
-
70
- const res = await CustomFetch(
71
- `/ajax/users/${userProfile.id}`,
72
- 'PUT',
73
- payload
74
- );
75
-
76
- setUserProfile(res.data.data);
77
- toast.success('Your profile has been successfully updated.');
65
+ return;
66
+ }
67
+
68
+ // Validate password and confirmation
69
+ if (
70
+ profile.password &&
71
+ profile.password !== profile.password_confirmation
72
+ ) {
73
+ setInputClasses({
74
+ ...inputClasses,
75
+ password: styles.inputError,
76
+ password_confirmation: styles.inputError,
77
+ });
78
+
79
+ toast.error('Passwords do not match.');
80
+ return;
81
+ }
82
+
83
+ // Create a new payload object
84
+ let payload = {
85
+ name: profile.name,
86
+ email: profile.email,
87
+ };
88
+
89
+ // Conditionally add password to payload if it has a value
90
+ if (profile.password.trim() !== '') {
91
+ payload.password = profile.password;
78
92
  }
93
+
94
+ payload.signature = signatureRef.current.toDataURL();
95
+
96
+ const res = await CustomFetch(
97
+ `/ajax/users/${userProfile.id}`,
98
+ 'PUT',
99
+ payload
100
+ );
101
+
102
+ setUserProfile((prevState) => ({
103
+ ...prevState,
104
+ name: res.data.name,
105
+ signature: res.data.signature,
106
+ }));
107
+ toast.success('Your profile has been successfully updated.');
79
108
  } catch (err) {
80
109
  console.log(err);
81
110
  }
@@ -84,17 +113,17 @@ const Profile = ({ userProfile, setUserProfile }) => {
84
113
  const renderContent = (filter) => {
85
114
  if (filter.show && filter.id === 'overview') {
86
115
  return (
87
- <div className="gridtxt" key={filter.id}>
88
- <div className="gridtxt__header">
116
+ <div className={styles.gridtxt} key={filter.id}>
117
+ <div className={styles.gridtxt__header}>
89
118
  <span>Overview</span>
90
119
  </div>
91
- <div className="formcontainer">
120
+ <div className={styles.formcontainer}>
92
121
  <form
93
- className="modalForm"
122
+ className={styles.modalForm}
94
123
  onSubmit={handleSubmitProfile}
95
124
  >
96
- <div className="formItem">
97
- <label className="fi__label">
125
+ <div className={styles.formItem}>
126
+ <label className={styles.fi__label}>
98
127
  <input
99
128
  type="text"
100
129
  name="name"
@@ -102,67 +131,140 @@ const Profile = ({ userProfile, setUserProfile }) => {
102
131
  className={inputClasses.name}
103
132
  value={profile.name}
104
133
  />
105
- <span className="fi__span">Name *</span>
134
+ <span className={styles.fi__span}>
135
+ Name *
136
+ </span>
106
137
  </label>
107
138
  </div>
108
- <div className="formItem">
109
- <label className="fi__label">
139
+ <div className={styles.formItem}>
140
+ <label className={styles.fi__label}>
110
141
  <input
111
142
  type="text"
112
143
  name="email"
113
- onChange={handleChangeProfile}
144
+ readOnly
114
145
  className={inputClasses.email}
115
146
  value={profile.email}
116
147
  />
117
- <span className="fi__span">Email *</span>
148
+ <span className={styles.fi__span}>
149
+ Email *
150
+ </span>
118
151
  </label>
119
152
  </div>
120
- <div className="formItem">
121
- <label className="fi__label">
122
- <span className="fi__span prefocus">
153
+ <div className={styles.formItem}>
154
+ <label className={styles.fi__label}>
155
+ <span
156
+ className={`${styles.fi__span} ${styles.prefocus}`}
157
+ >
123
158
  Password
124
159
  </span>
125
160
  <input
126
161
  type="password"
127
162
  name="password"
128
163
  onChange={handleChangeProfile}
164
+ value={profile.password}
165
+ className={inputClasses.password}
129
166
  />
130
167
  <PasswordStrengthBar
131
168
  password={profile.password}
132
169
  />
133
170
  </label>
134
171
  </div>
135
- <div className="formItem fwItem lastItem">
136
- <button className="btn modalsave" type="submit">
137
- Update
138
- </button>
172
+ <div className={styles.formItem}>
173
+ <label className={styles.fi__label}>
174
+ <span
175
+ className={`${styles.fi__span} ${styles.prefocus}`}
176
+ >
177
+ Password Confirmation
178
+ </span>
179
+ <input
180
+ type="password"
181
+ name="password_confirmation"
182
+ onChange={handleChangeProfile}
183
+ value={profile.password_confirmation}
184
+ className={
185
+ inputClasses.password_confirmation
186
+ }
187
+ />
188
+ </label>
189
+ </div>
190
+ <div className={styles.formItem}>
191
+ <label className={styles.fi__label}>
192
+ <SignaturePad
193
+ ref={signatureRef}
194
+ height={200}
195
+ options={{
196
+ penColor: 'black',
197
+ }}
198
+ redrawOnResize
199
+ canvasProps={{
200
+ style: {
201
+ border: '2px solid #ccc',
202
+ borderRadius: '10px',
203
+ padding: '10px',
204
+ },
205
+ className: styles.sigcanvas,
206
+ }}
207
+ />
208
+ <span className={styles.fi__span}>
209
+ Signature
210
+ </span>
211
+ </label>
139
212
  </div>
140
213
  </form>
141
214
  </div>
215
+
216
+ <div className={styles.polActions}>
217
+ <button
218
+ className={styles.btn}
219
+ onClick={handleSubmitProfile}
220
+ >
221
+ Save
222
+ </button>
223
+ <button
224
+ className={styles.btn}
225
+ onClick={handleClearSignature}
226
+ >
227
+ Clear
228
+ </button>
229
+ </div>
142
230
  </div>
143
231
  );
144
232
  }
145
233
  return null;
146
234
  };
147
235
 
236
+ useEffect(() => {
237
+ setProfile((prevState) => ({
238
+ ...prevState,
239
+ name: userProfile.name,
240
+ email: userProfile.email,
241
+ password: '',
242
+ password_confirmation: '',
243
+ }));
244
+
245
+ if (userProfile.signature) {
246
+ signatureRef.current.fromDataURL(userProfile.signature);
247
+ }
248
+ }, [userProfile]);
249
+
148
250
  return (
149
251
  <div>
150
- <div className="grid">
151
- <div className="grid__row">
152
- <div className="grid__full crmtitle">
252
+ <div className={styles.grid}>
253
+ <div className={styles.grid__row}>
254
+ <div className={`${styles.grid__full} ${styles.crmtitle}`}>
153
255
  <h1>My Profile</h1>
154
256
  </div>
155
257
  </div>
156
258
  </div>
157
- <div className="grid">
158
- <div className="grid__subrow">
159
- <div className="grid__subnav">
259
+ <div className={styles.grid}>
260
+ <div className={styles.grid__subrow}>
261
+ <div className={styles.grid__subnav}>
160
262
  <TableFilter
161
263
  filters={filters}
162
264
  setFilters={setFilters}
163
265
  />
164
266
  </div>
165
- <div className="grid__subcontent">
267
+ <div className={styles.grid__subcontent}>
166
268
  {filters.map((filter) => (
167
269
  <React.Fragment key={`filter-${filter.id}`}>
168
270
  {renderContent(filter)}
@@ -0,0 +1,219 @@
1
+ /* Profile.module.css */
2
+
3
+ .grid {
4
+ width: 100%;
5
+ display: flex;
6
+ align-items: flex-start;
7
+ flex-wrap: nowrap;
8
+ height: auto;
9
+ }
10
+
11
+ .grid__row {
12
+ width: 100%;
13
+ display: flex;
14
+ align-items: flex-start;
15
+ flex-wrap: nowrap;
16
+ height: auto;
17
+ }
18
+
19
+ .grid__full {
20
+ width: 100%;
21
+ background: white;
22
+ border-radius: var(--br);
23
+ border: 1px solid var(--border-color);
24
+ box-sizing: border-box;
25
+ overflow: visible;
26
+ position: relative;
27
+ padding: 0;
28
+ margin: 5px;
29
+ }
30
+
31
+ .crmtitle {
32
+ border: none;
33
+ min-height: auto;
34
+ padding: 10px 20px;
35
+ margin: 5px;
36
+ background: var(--item-color);
37
+ border-radius: var(--br);
38
+ border: 1px solid var(--border-color);
39
+ position: relative;
40
+ }
41
+
42
+ .crmtitle h1 {
43
+ font-weight: 700;
44
+ font-size: 1.25em;
45
+ margin: 0;
46
+ padding: 0.25rem 0;
47
+ color: var(--paragraph-color);
48
+ text-transform: capitalize;
49
+ }
50
+
51
+ .grid__subrow {
52
+ width: 100%;
53
+ display: flex;
54
+ flex-wrap: wrap;
55
+ height: auto;
56
+ }
57
+
58
+ .grid__subnav {
59
+ flex: 1;
60
+ background: white;
61
+ border-radius: var(--br);
62
+ border: 1px solid var(--border-color);
63
+ box-sizing: border-box;
64
+ padding: 5px;
65
+ margin: 5px;
66
+ height: auto;
67
+ }
68
+
69
+ .grid__subcontent {
70
+ flex: 0 1 85%;
71
+ background: white;
72
+ border-radius: var(--br);
73
+ border: 1px solid var(--border-color);
74
+ box-sizing: border-box;
75
+ padding: 0;
76
+ margin: 5px;
77
+ height: auto;
78
+ position: relative;
79
+ }
80
+
81
+ .gridtxt__header {
82
+ width: 100%;
83
+ display: block;
84
+ background: var(--border-color);
85
+ box-sizing: border-box;
86
+ padding: 10px 20px;
87
+ border-top-left-radius: var(--br);
88
+ border-top-right-radius: var(--br);
89
+ margin-bottom: 0;
90
+ font-weight: 700;
91
+ text-align: center;
92
+ color: var(--paragraph-color);
93
+ position: relative;
94
+ }
95
+
96
+ .formcontainer {
97
+ width: 100%;
98
+ }
99
+
100
+ .modalForm {
101
+ width: 100%;
102
+ display: flex;
103
+ align-items: flex-start;
104
+ flex-wrap: wrap;
105
+ }
106
+
107
+ .formItem {
108
+ width: 50%;
109
+ padding: 0.35em;
110
+ position: relative;
111
+ box-sizing: border-box;
112
+ }
113
+
114
+ .fi__label {
115
+ position: relative;
116
+ display: block;
117
+ }
118
+
119
+ .fi__span {
120
+ position: absolute;
121
+ transition: all 200ms;
122
+ opacity: 0.8;
123
+ left: 0;
124
+ padding: 19px 20px;
125
+ transform-origin: top left;
126
+ cursor: text;
127
+ }
128
+
129
+ .prefocus {
130
+ transform: translateY(-40%) translateX(10px) scale(0.75);
131
+ opacity: 1;
132
+ padding: 0 4px;
133
+ background: var(--tertiary-color);
134
+ font-weight: 300;
135
+ border-radius: var(--br);
136
+ z-index: 500;
137
+ }
138
+
139
+ input[type='text'],
140
+ input[type='password'] {
141
+ background: var(--item-color);
142
+ border-radius: var(--br);
143
+ border: 1px solid transparent;
144
+ padding: 1rem;
145
+ outline: none;
146
+ width: 100%;
147
+ box-sizing: border-box;
148
+ color: var(--paragraph-color);
149
+ transition: box-shadow 0.15s linear;
150
+ }
151
+
152
+ input[type='text']:hover,
153
+ input[type='password']:hover {
154
+ border: 1px solid rgba(var(--highlight-color), 0.85);
155
+ transition: border 0.15s linear;
156
+ }
157
+
158
+ input[type='text']:focus,
159
+ input[type='password']:focus {
160
+ border: 1px solid rgba(var(--highlight-color), 0.85);
161
+ }
162
+
163
+ input:not(:placeholder-shown) + .fi__span,
164
+ textarea:not(:placeholder-shown) + .fi__span,
165
+ select:not(:placeholder-shown) + .fi__span {
166
+ transform: translateY(-40%) translateX(10px) scale(0.75);
167
+ opacity: 1;
168
+ padding: 0 4px;
169
+ background: var(--tertiary-color);
170
+ font-weight: 300;
171
+ border-radius: var(--br);
172
+ }
173
+
174
+ .sigcanvas {
175
+ border: 2px solid #ccc;
176
+ border-radius: 10px;
177
+ padding: 10px;
178
+ }
179
+
180
+ .polActions {
181
+ position: fixed;
182
+ bottom: 20px;
183
+ right: 20px;
184
+ width: auto;
185
+ }
186
+
187
+ .polActions button {
188
+ display: block;
189
+ float: left;
190
+ padding: 0.65em 1em;
191
+ margin: 0 0.25em;
192
+ }
193
+
194
+ .btn {
195
+ width: max-content;
196
+ display: inline-block;
197
+ position: relative;
198
+ padding: 0.65rem 1rem;
199
+ cursor: pointer;
200
+ font-size: 1rem;
201
+ color: var(--secondary-color);
202
+ text-decoration: none;
203
+ overflow: hidden;
204
+ background: var(--primary-color);
205
+ border: 1px solid darken(var(--primary-color), 10%);
206
+ border-radius: var(--br);
207
+ outline: none;
208
+ transition: all 0.2s cubic-bezier(0.85, 0, 0.15, 1) 0s;
209
+ }
210
+
211
+ .btn:hover {
212
+ color: var(--tertiary-color);
213
+ background: var(--secondary-color);
214
+ border: 1px solid darken(var(--secondary-color), 10%);
215
+ }
216
+
217
+ .inputError {
218
+ border-color: red !important;
219
+ }