@visns-studio/visns-components 5.0.1-8.1 → 5.0.1

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 (28) hide show
  1. package/package.json +1 -3
  2. package/src/components/crm/AsyncSelect.jsx +15 -121
  3. package/src/components/crm/DataGrid.jsx +5 -25
  4. package/src/components/crm/Field.jsx +148 -174
  5. package/src/components/crm/Form.jsx +28 -41
  6. package/src/components/crm/MultiSelect.jsx +29 -96
  7. package/src/components/crm/Navigation.jsx +81 -2
  8. package/src/components/crm/QrCode.jsx +8 -12
  9. package/src/components/crm/auth/Login.jsx +1 -9
  10. package/src/components/crm/auth/Profile.jsx +2 -4
  11. package/src/components/crm/auth/styles/Login.module.scss +3 -4
  12. package/src/components/crm/auth/styles/Profile.module.scss +14 -56
  13. package/src/components/crm/generic/GenericAuth.jsx +2 -5
  14. package/src/components/crm/generic/GenericDetail.jsx +18 -509
  15. package/src/components/crm/generic/styles/AuditLog.module.scss +0 -4
  16. package/src/components/crm/generic/styles/GenericDetail.module.scss +121 -261
  17. package/src/components/crm/generic/styles/GenericDynamic.module.scss +67 -35
  18. package/src/components/crm/generic/styles/GenericFormBuilder.module.scss +43 -4
  19. package/src/components/crm/generic/styles/GenericIndex.module.scss +1 -1
  20. package/src/components/crm/styles/Autocomplete.module.scss +20 -12
  21. package/src/components/crm/styles/DataGrid.module.scss +3 -2
  22. package/src/components/crm/styles/Field.module.scss +13 -19
  23. package/src/components/crm/styles/Form.module.scss +5 -5
  24. package/src/components/crm/styles/Navigation.module.scss +61 -11
  25. package/src/components/crm/styles/QrCode.module.scss +0 -4
  26. package/src/components/styles/global.css +5 -95
  27. package/src/components/crm/generic/GenericEditableTable.jsx +0 -407
  28. package/src/components/crm/generic/styles/GenericEditableTable.module.scss +0 -178
@@ -1,120 +1,54 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
2
- import CustomFetch from './Fetch';
3
- import Select, { createFilter, components } from 'react-select';
4
- import CreatableSelect from 'react-select/creatable';
1
+ import React, { useEffect, useState } from 'react';
2
+ import SelectList from './SelectList';
3
+ import Select, { createFilter } from 'react-select';
5
4
  import styles from './styles/AsyncSelect.module.scss';
6
5
 
7
- const CustomOption = (props) => (
8
- <components.Option {...props}>
9
- <div>
10
- {props.data.label}
11
- {props.data.description && props.data.description !== '' && (
12
- <div style={{ fontSize: '0.85em', color: '#888' }}>
13
- {props.data.description}
14
- </div>
15
- )}
16
- </div>
17
- </components.Option>
18
- );
19
-
20
6
  function MultiSelect({
21
7
  className,
22
- inputValue = [],
8
+ inputValue,
23
9
  multi,
24
10
  onChange,
25
- options = [],
11
+ options,
26
12
  placeholder,
27
13
  settings,
28
14
  style,
29
- isCreatable = false,
30
- creatableConfig = {},
31
15
  }) {
32
16
  const [selectOptions, setSelectOptions] = useState([]);
33
- const [selectValue, setSelectValue] = useState([]);
34
-
35
- // Memoize transformed options
36
- const memoizedOptions = useMemo(() => {
37
- return options
38
- .filter((a) => a?.label || a?.name || a?.description) // Filter out options with no label, name, or description
39
- .map((a) => ({
40
- value: a?.id,
41
- label: a?.label || a?.name || a?.description || 'Unknown',
42
- description: a?.description || '',
43
- ...a,
44
- }));
45
- }, [options]);
46
-
47
- // Memoize transformed input values
48
- const memoizedInputValue = useMemo(() => {
49
- const normalizeInputValue = (value) =>
50
- Array.isArray(value) ? value : value ? [value] : [];
51
-
52
- return normalizeInputValue(inputValue)
53
- .filter((a) => a?.label || a?.name || a?.description) // Filter out values with no label, name, or description
54
- .map((a) => ({
55
- value: a?.id,
56
- label: a?.label || a?.name || a?.description || 'Unknown',
57
- description: a?.description || '',
58
- ...a,
59
- }));
60
- }, [inputValue]);
61
-
62
- // Set options when memoizedOptions changes
63
- useEffect(() => {
64
- if (JSON.stringify(selectOptions) !== JSON.stringify(memoizedOptions)) {
65
- setSelectOptions(memoizedOptions);
66
- }
67
- }, [memoizedOptions, selectOptions]);
68
17
 
69
- // Set value when memoizedInputValue changes
70
18
  useEffect(() => {
71
- if (
72
- JSON.stringify(selectValue) !== JSON.stringify(memoizedInputValue)
73
- ) {
74
- setSelectValue(memoizedInputValue);
75
- }
76
- }, [memoizedInputValue, selectValue]);
19
+ let _options = [];
77
20
 
78
- const handleCreate = async (inputValue) => {
79
- if (creatableConfig.url && creatableConfig.method) {
80
- const res = await CustomFetch(
81
- creatableConfig.url,
82
- creatableConfig.method,
83
- { label: inputValue }
84
- );
85
-
86
- if (res && res.data) {
87
- const newOption = {
88
- value: res.data.id,
89
- label: res.data.label || inputValue,
90
- description: res.data.description || 'Newly created item',
91
- ...res.data,
21
+ if (options.length > 0) {
22
+ options.forEach((a) => {
23
+ let _optionItem = {
24
+ value: a.id,
25
+ label: a.label,
92
26
  };
93
27
 
94
- setSelectOptions((prevOptions) => [...prevOptions, newOption]);
95
- setSelectValue((prevValues) =>
96
- multi ? [...prevValues, newOption] : [newOption]
97
- );
28
+ Object.keys(a).forEach((b) => {
29
+ if (b !== 'id') {
30
+ _optionItem = {
31
+ ..._optionItem,
32
+ [b]: a[b],
33
+ };
34
+ }
35
+ });
98
36
 
99
- onChange(
100
- multi ? [...selectValue, newOption] : newOption,
101
- { action: 'create-option' },
102
- settings.id
103
- );
104
- }
105
- }
106
- };
37
+ _options.push(_optionItem);
38
+ });
107
39
 
108
- const SelectComponent = isCreatable ? CreatableSelect : Select;
40
+ setSelectOptions(_options);
41
+ }
42
+ }, [options]);
109
43
 
110
44
  return (
111
- <SelectComponent
112
- closeMenuOnSelect={!multi}
45
+ <Select
46
+ closeMenuOnSelect={multi ? false : true}
113
47
  isClearable
114
48
  isSearchable
115
49
  isMulti={multi}
116
50
  filterOption={createFilter({ ignoreAccents: false })}
117
- components={{ Option: CustomOption }}
51
+ components={{ SelectList }}
118
52
  options={selectOptions}
119
53
  onChange={(inputValue, action) => {
120
54
  onChange(inputValue, action, settings.id);
@@ -135,9 +69,8 @@ function MultiSelect({
135
69
  : '52px',
136
70
  }),
137
71
  }}
138
- value={selectValue}
139
- onCreateOption={isCreatable ? handleCreate : undefined}
140
- placeholder={placeholder || 'Select...'}
72
+ value={inputValue}
73
+ placeholder={placeholder ? placeholder : 'Select...'}
141
74
  />
142
75
  );
143
76
  }
@@ -1,13 +1,45 @@
1
1
  import React, { useEffect, useRef, useState, useCallback } from 'react';
2
2
  import { Link, useLocation, useNavigate } from 'react-router-dom';
3
3
  import {
4
+ ArrowCycle,
5
+ BookClose,
6
+ BookOpen,
7
+ Briefcase,
4
8
  Bug,
5
9
  Calendar,
10
+ ChatDots,
11
+ Clipboard,
12
+ DoubleSword,
6
13
  Draft,
14
+ Envelope,
15
+ File,
16
+ Folder,
17
+ FolderAdd,
18
+ Gear,
19
+ Grid,
20
+ Home,
21
+ HomeAlt1,
22
+ Inbox,
23
+ Info,
24
+ LightBulb,
25
+ Microphone,
26
+ Money,
27
+ Newspaper,
28
+ Paper,
29
+ PeopleGroup,
30
+ PeopleMultiple,
7
31
  Person,
32
+ Question,
33
+ QuestionFill,
8
34
  Search,
35
+ SettingsVertical,
36
+ ShippingBoxV1,
9
37
  SignOut,
10
38
  Shield,
39
+ StatisticUp,
40
+ TextAlignLeft,
41
+ Ticket,
42
+ Utensils,
11
43
  } from 'akar-icons';
12
44
  import CustomFetch from './Fetch';
13
45
  import Notification from './Notification';
@@ -262,6 +294,47 @@ function Navigation({
262
294
  };
263
295
 
264
296
  const renderNav = (n) => {
297
+ const iconComponents = {
298
+ arrowCycle: ArrowCycle,
299
+ bookClose: BookClose,
300
+ bookOpen: BookOpen,
301
+ briefcase: Briefcase,
302
+ calendar: Calendar,
303
+ chatDots: ChatDots,
304
+ clipboard: Clipboard,
305
+ doubleSword: DoubleSword,
306
+ draft: Draft,
307
+ envelope: Envelope,
308
+ file: File,
309
+ folder: Folder,
310
+ folderAdd: FolderAdd,
311
+ gear: Gear,
312
+ grid: Grid,
313
+ home: Home,
314
+ homeAlt1: HomeAlt1,
315
+ inbox: Inbox,
316
+ info: Info,
317
+ lightBulb: LightBulb,
318
+ microphone: Microphone,
319
+ money: Money,
320
+ newspaper: Newspaper,
321
+ paper: Paper,
322
+ peopleGroup: PeopleGroup,
323
+ peopleMultiple: PeopleMultiple,
324
+ question: Question,
325
+ questionFill: QuestionFill,
326
+ search: Search,
327
+ settingsVertical: SettingsVertical,
328
+ signOut: SignOut,
329
+ shippingBoxV1: ShippingBoxV1,
330
+ statisticUp: StatisticUp,
331
+ textAlignLeft: TextAlignLeft,
332
+ ticket: Ticket,
333
+ utensils: Utensils,
334
+ };
335
+
336
+ const IconComponent = iconComponents[n.icon];
337
+
265
338
  let navItemClasses;
266
339
 
267
340
  if (n.class.includes('active')) {
@@ -302,9 +375,15 @@ function Navigation({
302
375
  return (
303
376
  <li className={navItemClasses}>
304
377
  {n.url ? (
305
- <Link to={n.url}>{n.label}</Link>
378
+ <Link to={n.url}>
379
+ <IconComponent strokeWidth={2} size={18} />
380
+ {n.label}
381
+ </Link>
306
382
  ) : (
307
- <span title={n.label}>{n.label}</span>
383
+ <span title={n.label}>
384
+ <IconComponent strokeWidth={2} size={18} />
385
+ {n.label}
386
+ </span>
308
387
  )}
309
388
  {renderChildren()}
310
389
  </li>
@@ -1,12 +1,11 @@
1
1
  import { useEffect, useRef, useState } from 'react';
2
- import { useReactToPrint } from 'react-to-print';
2
+ import ReactToPrint from 'react-to-print';
3
3
 
4
4
  import CustomFetch from './Fetch';
5
5
  import styles from './styles/QrCode.module.scss';
6
6
 
7
7
  const QrCode = ({ config, dataId }) => {
8
- const contentRef = useRef(null);
9
- const reactToPrintFn = useReactToPrint({ contentRef });
8
+ const printComponentRef = useRef();
10
9
  const [qrCodeData, setQrCodeData] = useState({
11
10
  logo: '',
12
11
  qrCode: '',
@@ -27,13 +26,9 @@ const QrCode = ({ config, dataId }) => {
27
26
  fetchQrCode(config);
28
27
  }, []);
29
28
 
30
- useEffect(() => {
31
- console.info(qrCodeData);
32
- }, [qrCodeData]);
33
-
34
29
  return (
35
30
  <>
36
- <div className={styles.gridtxt} ref={contentRef}>
31
+ <div className={styles.gridtxt} ref={printComponentRef}>
37
32
  {qrCodeData.logo && qrCodeData.logo !== '' && (
38
33
  <ul className={styles.customer__overview}>
39
34
  <li
@@ -57,7 +52,7 @@ const QrCode = ({ config, dataId }) => {
57
52
  textAlign: 'center',
58
53
  }}
59
54
  >
60
- {qrCodeData.title || ''}
55
+ {qrCodeData.title}
61
56
  </li>
62
57
  </ul>
63
58
  <ul className={styles.customer__overview}>
@@ -76,9 +71,10 @@ const QrCode = ({ config, dataId }) => {
76
71
  </ul>
77
72
  </div>
78
73
  <div className={styles.polActions}>
79
- <button className={styles.btn} onClick={() => reactToPrintFn()}>
80
- Print
81
- </button>
74
+ <ReactToPrint
75
+ trigger={() => <button className="btn">Print</button>}
76
+ content={() => printComponentRef.current}
77
+ />
82
78
  </div>
83
79
  </>
84
80
  );
@@ -28,15 +28,7 @@ const Login = ({ logo, providers, setSystemAuth, setUserProfile }) => {
28
28
  let content =
29
29
  providers && providers.length > 0 ? (
30
30
  <div className="formItem fwItem lastItem forgotten">
31
- <span
32
- style={{
33
- display: 'block',
34
- textAlign: 'center',
35
- width: '100%',
36
- }}
37
- >
38
- OR
39
- </span>
31
+ <span>OR</span>
40
32
  </div>
41
33
  ) : null;
42
34
 
@@ -101,12 +101,10 @@ const Profile = ({ userProfile, setUserProfile }) => {
101
101
  payload
102
102
  );
103
103
 
104
- const updatedUserData = res.data.user ? res.data.user : res.data;
105
-
106
104
  setUserProfile((prevState) => ({
107
105
  ...prevState,
108
- name: updatedUserData.name,
109
- signature: updatedUserData.signature,
106
+ name: res.data.user.name,
107
+ signature: res.data.user.signature,
110
108
  }));
111
109
  toast.success('Your profile has been successfully updated.');
112
110
  } catch (err) {
@@ -12,7 +12,7 @@
12
12
  .fi__span {
13
13
  position: absolute;
14
14
  transition: all 200ms;
15
- opacity: 1;
15
+ opacity: 0.8;
16
16
  left: 0;
17
17
  transform-origin: top left;
18
18
  cursor: text;
@@ -164,11 +164,10 @@
164
164
  input:not(:placeholder-shown) + .fi__span,
165
165
  textarea:not(:placeholder-shown) + .fi__span,
166
166
  select:not(:placeholder-shown) + .fi__span {
167
- transform: translateY(-135%) translateX(10px) scale(0.9);
167
+ transform: translateY(-110%) translateX(10px) scale(0.75);
168
168
  opacity: 1;
169
169
  padding: 0;
170
170
  background: var(--bg-color);
171
- font-weight: 400;
171
+ font-weight: 300;
172
172
  transition: all 0.5s cubic-bezier(0.5, 0.5, 0, 1);
173
- color: rgba(var(--paragraph-rgb), 0.65) !important;
174
173
  }
@@ -3,11 +3,11 @@
3
3
  input:not(:placeholder-shown) + .fi__span,
4
4
  textarea:not(:placeholder-shown) + .fi__span,
5
5
  select:not(:placeholder-shown) + .fi__span {
6
- transform: translateY(-40%) translateX(10px) scale(0.9);
6
+ transform: translateY(-40%) translateX(10px) scale(0.75);
7
7
  opacity: 1;
8
- padding: 0 0.25rem;
8
+ padding: 0 4px;
9
9
  background: var(--tertiary-color);
10
- font-weight: 400;
10
+ font-weight: 300;
11
11
  border-radius: var(--br);
12
12
  }
13
13
 
@@ -111,72 +111,30 @@ select:not(:placeholder-shown) + .fi__span {
111
111
  }
112
112
 
113
113
  .grid__subcontent {
114
- flex: 0 1 80%;
115
- background: var(--tertiary-color);
114
+ flex: 0 1 85%;
115
+ background: white;
116
116
  border-radius: var(--br);
117
- border: 1px solid rgba(var(--primary-rgb), 0.05);
117
+ border: 1px solid var(--border-color);
118
118
  box-sizing: border-box;
119
- padding: 2px;
120
- margin: 8px 0;
119
+ padding: 0;
120
+ margin: 0.5rem 0;
121
121
  height: auto;
122
122
  position: relative;
123
123
  }
124
124
 
125
- .grid__subcontent h2 {
126
- color: var(--primary-color);
127
- font-size: 1.35em;
128
- padding: 0;
129
- margin: 0 0 30px 0;
130
- }
131
-
132
125
  .gridtxt__header {
133
126
  width: 100%;
134
127
  display: block;
135
- background: rgba(var(--primary-rgb), 0.05);
128
+ background: var(--border-color);
136
129
  box-sizing: border-box;
137
130
  padding: 10px 20px;
138
- border-radius: var(--br);
131
+ border-top-left-radius: var(--br);
132
+ border-top-right-radius: var(--br);
139
133
  margin-bottom: 0;
140
134
  font-weight: 700;
141
135
  text-align: center;
142
136
  color: var(--paragraph-color);
143
- }
144
-
145
- .gridtxt__header span {
146
- font-weight: 700;
147
- }
148
-
149
- .gridtxt > ul {
150
- width: 100%;
151
- display: flex;
152
- justify-content: flex-start;
153
- flex-direction: row;
154
- flex-wrap: wrap;
155
- list-style: none;
156
- box-sizing: border-box;
157
- padding: 0.85rem;
158
- margin: 0;
159
- }
160
-
161
- .gridtxt > ul li {
162
- flex: 0 0 calc(50% - 10px);
163
- padding: 0.85rem;
164
- box-sizing: border-box;
165
- border: 1px solid rgba(var(--primary-rgb), 0.095);
166
- color: var(--paragraph-color);
167
- background: rgba(var(--primary-rgb), 0.015);
168
- margin: 5px;
169
- border-radius: var(--br);
170
- line-height: 1.45;
171
- font-size: 1rem;
172
- }
173
-
174
- .gridtxt > ul .fw-grid-item {
175
- flex: 0 0 calc(100% - 10px);
176
- }
177
-
178
- .gridtxt > ul .notecolor {
179
- border: 1px solid var(--secondary-color);
137
+ position: relative;
180
138
  }
181
139
 
182
140
  .formcontainer {
@@ -205,7 +163,7 @@ select:not(:placeholder-shown) + .fi__span {
205
163
  .fi__span {
206
164
  position: absolute;
207
165
  transition: all 200ms;
208
- opacity: 1;
166
+ opacity: 0.8;
209
167
  left: 0;
210
168
  padding: 19px 20px;
211
169
  transform-origin: top left;
@@ -319,7 +277,7 @@ select:not(:placeholder-shown) + .fi__span {
319
277
  a {
320
278
  text-decoration: none;
321
279
  color: var(--secondary-color);
322
- font-weight: 400;
280
+ font-weight: 300;
323
281
  }
324
282
 
325
283
  svg {
@@ -51,11 +51,8 @@ const GenericAuth = ({
51
51
  const updateAuthStatus = async () => {
52
52
  try {
53
53
  const { data } = await CustomFetch('/ajax/user/profile', 'GET');
54
-
55
- if (data && data.id) {
56
- setUserProfile(data);
57
- setIsAuthenticated(true);
58
- }
54
+ setUserProfile(data);
55
+ setIsAuthenticated(true);
59
56
  setIsLoading(false);
60
57
 
61
58
  if (location.pathname.split('/')[1] === 'login') {