@visns-studio/visns-components 5.7.14 → 5.7.16

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 CHANGED
@@ -20,12 +20,12 @@
20
20
  "dayjs": "^1.11.13",
21
21
  "fabric": "^6.6.4",
22
22
  "file-saver": "^2.0.5",
23
- "framer-motion": "^12.9.4",
23
+ "framer-motion": "^12.9.7",
24
24
  "html-react-parser": "^5.2.3",
25
25
  "lodash": "^4.17.21",
26
26
  "lodash.debounce": "^4.0.8",
27
27
  "moment": "^2.30.1",
28
- "motion": "^12.9.4",
28
+ "motion": "^12.9.7",
29
29
  "numeral": "^2.0.6",
30
30
  "pluralize": "^8.0.0",
31
31
  "qrcode.react": "^4.2.0",
@@ -58,7 +58,7 @@
58
58
  "truncate": "^3.0.0",
59
59
  "uuid": "^11.1.0",
60
60
  "validator": "^13.15.0",
61
- "vite": "^6.3.4",
61
+ "vite": "^6.3.5",
62
62
  "yarn": "^1.22.22",
63
63
  "yet-another-react-lightbox": "^3.23.0"
64
64
  },
@@ -82,7 +82,7 @@
82
82
  "react-dom": "^17.0.0 || ^18.0.0"
83
83
  },
84
84
  "name": "@visns-studio/visns-components",
85
- "version": "5.7.14",
85
+ "version": "5.7.16",
86
86
  "description": "Various packages to assist in the development of our Custom Applications.",
87
87
  "main": "src/index.js",
88
88
  "files": [
@@ -267,6 +267,9 @@ const Login = ({ logo, providers, setSystemAuth, setUserProfile }) => {
267
267
  fontWeight: '500',
268
268
  fontSize: '0.875rem',
269
269
  }}
270
+ className={
271
+ styles.forgotPasswordLink
272
+ }
270
273
  >
271
274
  Forgot password?
272
275
  </Link>
@@ -1,167 +1,167 @@
1
1
  // Client Auth styles
2
2
  .container {
3
- min-height: 100vh;
4
- display: flex;
5
- align-items: center;
6
- justify-content: center;
7
- background-color: #f5f5f5;
3
+ min-height: 100vh;
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ background-color: #f5f5f5;
8
8
  }
9
9
 
10
10
  .loginBox {
11
- width: 100%;
12
- max-width: 500px;
13
- padding: 2.5rem;
14
- margin: 0 auto;
15
- background-color: white;
16
- border-radius: 8px;
17
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
11
+ width: 100%;
12
+ max-width: 500px;
13
+ padding: 2.5rem;
14
+ margin: 0 auto;
15
+ background-color: white;
16
+ border-radius: 8px;
17
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
18
18
  }
19
19
 
20
20
  .logo {
21
- display: block;
22
- width: 100%;
23
- max-width: 240px;
24
- height: auto;
25
- margin: 0 auto 2rem;
21
+ display: block;
22
+ width: 100%;
23
+ max-width: 240px;
24
+ height: auto;
25
+ margin: 0 auto 2rem;
26
26
  }
27
27
 
28
28
  .title {
29
- font-size: 1.75rem;
30
- font-weight: 600;
31
- color: #333;
32
- margin-bottom: 0.5rem;
33
- text-align: center;
29
+ font-size: 1.75rem;
30
+ font-weight: 600;
31
+ color: #333;
32
+ margin-bottom: 0.5rem;
33
+ text-align: center;
34
34
  }
35
35
 
36
36
  .subtitle {
37
- font-size: 1rem;
38
- color: #666;
39
- margin-bottom: 2rem;
40
- text-align: center;
41
- line-height: 1.5;
37
+ font-size: 1rem;
38
+ color: #666;
39
+ margin-bottom: 2rem;
40
+ text-align: center;
41
+ line-height: 1.5;
42
42
  }
43
43
 
44
44
  .formGroup {
45
- margin-bottom: 1.5rem;
46
- position: relative;
45
+ margin-bottom: 1.5rem;
46
+ position: relative;
47
47
  }
48
48
 
49
49
  .inputLabel {
50
- display: block;
51
- font-size: 0.9rem;
52
- font-weight: 500;
53
- color: #555;
54
- margin-bottom: 0.5rem;
50
+ display: block;
51
+ font-size: 0.9rem;
52
+ font-weight: 500;
53
+ color: #555;
54
+ margin-bottom: 0.5rem;
55
55
  }
56
56
 
57
57
  .input {
58
- width: 100%;
59
- padding: 0.75rem 1rem;
60
- font-size: 1rem;
61
- border: 1px solid #ddd;
62
- border-radius: 4px;
63
- background-color: white;
64
- transition: border-color 0.2s ease;
65
-
66
- &:focus {
67
- outline: none;
68
- border-color: var(--primary-color, #4a6741);
69
- box-shadow: 0 0 0 2px rgba(74, 103, 65, 0.1);
70
- }
71
-
72
- &.error {
73
- border-color: #e53935;
74
- }
58
+ width: 100%;
59
+ padding: 0.75rem 1rem;
60
+ font-size: 1rem;
61
+ border: 1px solid #ddd;
62
+ border-radius: 4px;
63
+ background-color: white;
64
+ transition: border-color 0.2s ease;
65
+
66
+ &:focus {
67
+ outline: none;
68
+ border-color: var(--primary-color, #4a6741);
69
+ box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.1);
70
+ }
71
+
72
+ &.error {
73
+ border-color: #e53935;
74
+ }
75
75
  }
76
76
 
77
77
  .inputIcon {
78
- position: absolute;
79
- right: 1rem;
80
- top: 2.4rem;
81
- color: #999;
78
+ position: absolute;
79
+ right: 1rem;
80
+ top: 2.4rem;
81
+ color: #999;
82
82
  }
83
83
 
84
84
  .button {
85
- width: 100%;
86
- padding: 0.9rem 1.5rem;
87
- font-size: 1rem;
88
- font-weight: 500;
89
- color: white;
90
- background-color: var(--primary-color, #0f4229);
91
- border: none;
92
- border-radius: 4px;
93
- cursor: pointer;
94
- transition: background-color 0.2s ease;
95
-
96
- &:hover {
97
- background-color: var(--secondary-color, #0a2e1c);
98
- }
99
-
100
- &:disabled {
101
- background-color: #ccc;
102
- cursor: not-allowed;
103
- }
85
+ width: 100%;
86
+ padding: 0.9rem 1.5rem;
87
+ font-size: 1rem;
88
+ font-weight: 500;
89
+ color: white;
90
+ background-color: var(--primary-color, #0f4229);
91
+ border: none;
92
+ border-radius: 4px;
93
+ cursor: pointer;
94
+ transition: background-color 0.2s ease;
95
+
96
+ &:hover {
97
+ background-color: var(--secondary-color, #3cbf7d);
98
+ }
99
+
100
+ &:disabled {
101
+ background-color: #ccc;
102
+ cursor: not-allowed;
103
+ }
104
104
  }
105
105
 
106
106
  .linkText {
107
- display: block;
108
- text-align: center;
109
- margin-top: 1.5rem;
110
- font-size: 0.9rem;
111
- color: #666;
112
-
113
- a {
114
- color: var(--primary-color, #0f4229);
115
- text-decoration: none;
116
- font-weight: 500;
117
-
118
- &:hover {
119
- text-decoration: underline;
107
+ display: block;
108
+ text-align: center;
109
+ margin-top: 1.5rem;
110
+ font-size: 0.9rem;
111
+ color: #666;
112
+
113
+ a {
114
+ color: var(--primary-color, #0f4229);
115
+ text-decoration: none;
116
+ font-weight: 500;
117
+
118
+ &:hover {
119
+ text-decoration: underline;
120
+ }
120
121
  }
121
- }
122
122
  }
123
123
 
124
124
  // OTP verification specific styles
125
125
  .otpInput {
126
- letter-spacing: 0.25rem;
127
- font-size: 1.2rem;
128
- text-align: center;
126
+ letter-spacing: 0.25rem;
127
+ font-size: 1.2rem;
128
+ text-align: center;
129
129
  }
130
130
 
131
131
  .resendLink {
132
- color: var(--primary-color, #0f4229);
133
- text-decoration: none;
134
- font-weight: 500;
135
- cursor: pointer;
136
-
137
- &:hover {
138
- text-decoration: underline;
139
- }
140
-
141
- &.disabled {
142
- color: #999;
143
- cursor: default;
132
+ color: var(--primary-color, #0f4229);
144
133
  text-decoration: none;
145
- }
134
+ font-weight: 500;
135
+ cursor: pointer;
136
+
137
+ &:hover {
138
+ text-decoration: underline;
139
+ }
140
+
141
+ &.disabled {
142
+ color: #999;
143
+ cursor: default;
144
+ text-decoration: none;
145
+ }
146
146
  }
147
147
 
148
148
  .emailHighlight {
149
- font-weight: 600;
149
+ font-weight: 600;
150
150
  }
151
151
 
152
152
  .backLink {
153
- display: inline-flex;
154
- align-items: center;
155
- margin-top: 1rem;
156
- color: #666;
157
- text-decoration: none;
158
- font-size: 0.9rem;
159
-
160
- svg {
161
- margin-right: 0.5rem;
162
- }
163
-
164
- &:hover {
165
- color: var(--primary-color, #0f4229);
166
- }
153
+ display: inline-flex;
154
+ align-items: center;
155
+ margin-top: 1rem;
156
+ color: #666;
157
+ text-decoration: none;
158
+ font-size: 0.9rem;
159
+
160
+ svg {
161
+ margin-right: 0.5rem;
162
+ }
163
+
164
+ &:hover {
165
+ color: var(--secondary-color, #3cbf7d);
166
+ }
167
167
  }
@@ -166,6 +166,15 @@
166
166
  accent-color: var(--primary-color, #4f46e5);
167
167
  border-radius: 0.25rem;
168
168
  margin-right: 0.5rem;
169
+
170
+ &:hover {
171
+ accent-color: var(--secondary-color, #3cbf7d);
172
+ }
173
+
174
+ &:focus {
175
+ outline: 2px solid rgba(var(--primary-rgb), 0.25);
176
+ outline-offset: 2px;
177
+ }
169
178
  }
170
179
 
171
180
  .lcontainer {
@@ -208,12 +217,12 @@
208
217
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
209
218
 
210
219
  &:hover {
211
- background: #4338ca;
212
- border-color: #4338ca;
220
+ background: var(--secondary-color, #3cbf7d);
221
+ border-color: var(--secondary-color, #3cbf7d);
213
222
  }
214
223
 
215
224
  &:focus {
216
- box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.25);
225
+ box-shadow: 0 0 0 2px rgba(var(--secondary-rgb, 60, 191, 125), 0.25);
217
226
  }
218
227
  }
219
228
 
@@ -229,6 +238,20 @@ select:not(:placeholder-shown) + .fi__span {
229
238
  color: var(--primary-color, #4f46e5) !important;
230
239
  }
231
240
 
241
+ input:focus + .fi__span,
242
+ textarea:focus + .fi__span,
243
+ select:focus + .fi__span {
244
+ color: var(--primary-color, #4f46e5) !important;
245
+ }
246
+
247
+ input:focus,
248
+ textarea:focus,
249
+ select:focus {
250
+ border-color: var(--primary-color, #4f46e5) !important;
251
+ outline: none;
252
+ box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.25);
253
+ }
254
+
232
255
  /* Add divider styling for the OR section */
233
256
  .divider {
234
257
  display: flex;
@@ -271,11 +294,23 @@ select:not(:placeholder-shown) + .fi__span {
271
294
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
272
295
 
273
296
  &:hover {
274
- background-color: #f9fafb;
275
- border-color: #d1d5db;
297
+ background-color: var(--bg-color, #f5f3ef);
298
+ border-color: var(--border-color, #e1e1e1);
276
299
  }
277
300
 
278
301
  img {
279
302
  margin-right: 0.5rem;
280
303
  }
281
304
  }
305
+
306
+ .forgotPasswordLink {
307
+ &:hover {
308
+ color: var(--secondary-color, #3cbf7d) !important;
309
+ text-decoration: underline !important;
310
+ }
311
+
312
+ &:focus {
313
+ outline: 2px solid rgba(var(--primary-rgb), 0.25) !important;
314
+ outline-offset: 2px !important;
315
+ }
316
+ }
@@ -415,7 +415,7 @@ select:focus + .fi__span {
415
415
  padding: 0.5rem 0.85rem;
416
416
 
417
417
  &:hover:not(:disabled) {
418
- filter: brightness(90%);
418
+ background-color: rgba(var(--primary-rgb), 0.9);
419
419
  }
420
420
  }
421
421
 
@@ -427,7 +427,8 @@ select:focus + .fi__span {
427
427
  padding: 0.5rem 0.85rem;
428
428
 
429
429
  &:hover:not(:disabled) {
430
- background-color: #e5e5e5;
430
+ background-color: var(--bg-color, #f5f3ef);
431
+ border-color: var(--border-color, #e1e1e1);
431
432
  }
432
433
  }
433
434
 
@@ -438,7 +439,7 @@ select:focus + .fi__span {
438
439
  padding: 0.5rem 0.85rem;
439
440
 
440
441
  &:hover:not(:disabled) {
441
- background-color: #c0392b;
442
+ background-color: rgba(231, 76, 60, 0.85);
442
443
  }
443
444
  }
444
445
 
@@ -177,12 +177,12 @@
177
177
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
178
178
 
179
179
  &:hover {
180
- background: #4338ca;
181
- border-color: #4338ca;
180
+ background: var(--secondary-color, #3cbf7d);
181
+ border-color: var(--secondary-color, #3cbf7d);
182
182
  }
183
183
 
184
184
  &:focus {
185
- box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.25);
185
+ box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.25);
186
186
  }
187
187
  }
188
188
 
@@ -150,12 +150,12 @@
150
150
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
151
151
 
152
152
  &:hover {
153
- background: #4338ca;
154
- border-color: #4338ca;
153
+ background: var(--secondary-color, #3cbf7d);
154
+ border-color: var(--secondary-color, #3cbf7d);
155
155
  }
156
156
 
157
157
  &:focus {
158
- box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.25);
158
+ box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.25);
159
159
  }
160
160
  }
161
161
 
@@ -177,12 +177,12 @@
177
177
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
178
178
 
179
179
  &:hover {
180
- background: #4338ca;
181
- border-color: #4338ca;
180
+ background: var(--secondary-color, #3cbf7d);
181
+ border-color: var(--secondary-color, #3cbf7d);
182
182
  }
183
183
 
184
184
  &:focus {
185
- box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.25);
185
+ box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.25);
186
186
  }
187
187
  }
188
188
 
@@ -45,6 +45,8 @@ function useConfig(setting, tabs, filters, setRowsSelected, tableSetting) {
45
45
  style: setting.style || {},
46
46
  tableSetting,
47
47
  type: setting.type ? setting.type : 'table',
48
+ // Make sure to include functions if they exist in the setting
49
+ functions: setting.functions || {},
48
50
  };
49
51
 
50
52
  setConfig(newConfig);
@@ -135,6 +137,11 @@ function useConfig(setting, tabs, filters, setRowsSelected, tableSetting) {
135
137
  type: activeTabConfig.type
136
138
  ? activeTabConfig.type
137
139
  : 'table',
140
+ tableSetting:
141
+ activeTabConfig.tableSetting || tableSetting,
142
+ // Preserve functions from the tab config, falling back to the original config functions
143
+ functions:
144
+ activeTabConfig.functions || config.functions || {},
138
145
  };
139
146
 
140
147
  setConfig(updatedConfig);
@@ -156,6 +163,8 @@ function useConfig(setting, tabs, filters, setRowsSelected, tableSetting) {
156
163
  style: config.style || setting.style || {},
157
164
  tableSetting,
158
165
  type: setting.type ? setting.type : 'table',
166
+ // Preserve functions from the original config or setting
167
+ functions: config.functions || setting.functions || {},
159
168
  };
160
169
 
161
170
  // Add the filter for the active child
@@ -353,12 +362,32 @@ function GenericIndex({
353
362
  rowsSelectedRef.current = rowsSelected;
354
363
  }, [rowsSelected]);
355
364
 
356
- const handleCustomAction = async () => {
365
+ // Helper function to get function config from any of the three possible locations
366
+ const getFunctionConfig = useCallback(
367
+ (functionName) => {
368
+ // Check in priority order:
369
+ // 1. First check if it exists directly in setting.functions
370
+ if (setting?.functions?.[functionName]) {
371
+ return setting.functions[functionName];
372
+ }
373
+ // 2. Then check if it exists in config.form.functions
374
+ if (config?.form?.functions?.[functionName]) {
375
+ return config.form.functions[functionName];
376
+ }
377
+ // 3. Finally check if it exists in config.functions
378
+ if (config?.functions?.[functionName]) {
379
+ return config.functions[functionName];
380
+ }
381
+ // Return null if not found in any location
382
+ return null;
383
+ },
384
+ [setting, config]
385
+ );
386
+
387
+ const handleCustomAction = useCallback(async () => {
357
388
  try {
358
- // Get the custom action configuration
359
- const customActionConfig = setting?.functions?.customAction
360
- ? setting.functions.customAction
361
- : config.form.functions.customAction;
389
+ // Get the custom action configuration using our helper
390
+ const customActionConfig = getFunctionConfig('customAction');
362
391
 
363
392
  if (customActionConfig) {
364
393
  // Implementation will be added when needed
@@ -368,14 +397,18 @@ function GenericIndex({
368
397
  console.error(err);
369
398
  toast.error('An error occurred while performing the custom action');
370
399
  }
371
- };
400
+ }, [getFunctionConfig]);
372
401
 
373
402
  const handleCheckboxUpdate = useCallback(async () => {
374
403
  try {
375
- const { data, method, message, url } = setting?.functions
376
- ?.checkboxUpdate
377
- ? setting.functions.checkboxUpdate
378
- : config.form.functions.checkboxUpdate;
404
+ const checkboxUpdateConfig = getFunctionConfig('checkboxUpdate');
405
+
406
+ if (!checkboxUpdateConfig) {
407
+ console.error('checkboxUpdate configuration not found');
408
+ return;
409
+ }
410
+
411
+ const { data, method, message, url } = checkboxUpdateConfig;
379
412
 
380
413
  if (!Object.keys(rowsSelectedRef.current).length) {
381
414
  toast.warning(message.warning);
@@ -408,18 +441,18 @@ function GenericIndex({
408
441
  } catch (error) {
409
442
  console.error(error);
410
443
  }
411
- }, [
412
- setting?.functions?.checkboxUpdate,
413
- config.form?.functions?.checkboxUpdate,
414
- tableData,
415
- ]);
444
+ }, [getFunctionConfig, tableData]);
416
445
 
417
- const handleCheckboxDelete = async () => {
446
+ const handleCheckboxDelete = useCallback(async () => {
418
447
  try {
419
- const { data, method, message, url } = setting?.functions
420
- ?.checkboxDelete
421
- ? setting.functions.checkboxDelete
422
- : config.form?.functions?.checkboxDelete;
448
+ const checkboxDeleteConfig = getFunctionConfig('checkboxDelete');
449
+
450
+ if (!checkboxDeleteConfig) {
451
+ console.error('checkboxDelete configuration not found');
452
+ return;
453
+ }
454
+
455
+ const { data, method, message, url } = checkboxDeleteConfig;
423
456
 
424
457
  if (!Object.keys(rowsSelectedRef.current).length) {
425
458
  toast.warning(message.warning);
@@ -458,7 +491,7 @@ function GenericIndex({
458
491
  'An error occurred while processing the delete request'
459
492
  );
460
493
  }
461
- };
494
+ }, [getFunctionConfig, tableData]);
462
495
 
463
496
  const handleExport = async (e) => {
464
497
  try {
@@ -684,48 +717,31 @@ function GenericIndex({
684
717
  <Outlet />
685
718
 
686
719
  <div className={styles.polActions}>
687
- {setting.functions?.checkboxUpdate && (
720
+ {/* Render Update button if checkboxUpdate function is configured in any location */}
721
+ {getFunctionConfig('checkboxUpdate') && (
688
722
  <button
689
723
  className={styles.btn}
690
724
  onClick={handleCheckboxUpdate}
691
725
  >
692
- {setting.functions.checkboxUpdate.label || 'Update'}
693
- </button>
694
- )}
695
- {config?.form?.functions?.checkboxUpdate && (
696
- <button
697
- className={styles.btn}
698
- onClick={handleCheckboxUpdate}
699
- >
700
- {config.form.functions.checkboxUpdate.label || 'Update'}
726
+ {getFunctionConfig('checkboxUpdate').label || 'Update'}
701
727
  </button>
702
728
  )}
703
729
 
704
- {setting.functions?.checkboxDelete && (
730
+ {/* Render Delete button if checkboxDelete function is configured in any location */}
731
+ {getFunctionConfig('checkboxDelete') && (
705
732
  <button
706
733
  className={styles.btn}
707
734
  onClick={handleCheckboxDelete}
708
735
  >
709
- {setting.functions.checkboxDelete.label || 'Delete'}
710
- </button>
711
- )}
712
- {config?.form?.functions?.checkboxDelete && (
713
- <button
714
- className={styles.btn}
715
- onClick={handleCheckboxDelete}
716
- >
717
- {config.form.functions.checkboxDelete.label || 'Delete'}
736
+ {getFunctionConfig('checkboxDelete').label || 'Delete'}
718
737
  </button>
719
738
  )}
720
739
 
721
- {setting.functions?.customAction && (
722
- <button className={styles.btn} onClick={handleCustomAction}>
723
- {setting.functions.customAction.label || 'Delete'}
724
- </button>
725
- )}
726
- {config?.form?.functions?.customAction && (
740
+ {/* Render Custom Action button if customAction function is configured in any location */}
741
+ {getFunctionConfig('customAction') && (
727
742
  <button className={styles.btn} onClick={handleCustomAction}>
728
- {config.form.functions.customAction.label || 'Delete'}
743
+ {getFunctionConfig('customAction').label ||
744
+ 'Custom Action'}
729
745
  </button>
730
746
  )}
731
747