@visns-studio/visns-components 5.11.1 → 5.11.3

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 (60) hide show
  1. package/package.json +2 -2
  2. package/src/components/cms/DataGrid.jsx +8 -8
  3. package/src/components/cms/DropZone.jsx +1 -1
  4. package/src/components/cms/Form.jsx +1 -1
  5. package/src/components/cms/Gallery.jsx +1 -1
  6. package/src/components/cms/sorting/Item.jsx +1 -1
  7. package/src/components/crm/AssociationManager.jsx +431 -0
  8. package/src/components/crm/Autocomplete.jsx +3 -3
  9. package/src/components/crm/Breadcrumb.jsx +4 -4
  10. package/src/components/crm/BusinessCardOcr.jsx +681 -95
  11. package/src/components/crm/ClientAssociationManager.jsx +362 -0
  12. package/src/components/crm/DataGrid.jsx +34 -32
  13. package/src/components/crm/Field.jsx +12 -12
  14. package/src/components/crm/Form.jsx +2 -2
  15. package/src/components/crm/MergeEntity.jsx +1049 -0
  16. package/src/components/crm/MultiSelect.jsx +14 -3
  17. package/src/components/crm/Navigation.jsx +14 -15
  18. package/src/components/crm/Notification.jsx +2 -2
  19. package/src/components/crm/QuickAction.jsx +3 -3
  20. package/src/components/crm/SectionHeader.jsx +1 -1
  21. package/src/components/crm/SwitchAccount.jsx +4 -4
  22. package/src/components/crm/auth/ClientLogin.jsx +2 -2
  23. package/src/components/crm/auth/ClientOTPVerify.jsx +2 -2
  24. package/src/components/crm/auth/Login.jsx +3 -3
  25. package/src/components/crm/auth/Reset.jsx +2 -2
  26. package/src/components/crm/auth/TwoFactorAuth.jsx +2 -2
  27. package/src/components/crm/cells/CellWithTooltip.jsx +35 -28
  28. package/src/components/crm/columns/ColumnRenderers.jsx +320 -259
  29. package/src/components/crm/controls/DataGridSearch.jsx +5 -5
  30. package/src/components/crm/generic/AlternativeActionModal.jsx +100 -0
  31. package/src/components/crm/generic/ContactSelectorModal.jsx +59 -16
  32. package/src/components/crm/generic/DateRangeSelectorModal.jsx +181 -0
  33. package/src/components/crm/generic/GenericClientPortal.jsx +1 -1
  34. package/src/components/crm/generic/GenericDashboard.jsx +4 -4
  35. package/src/components/crm/generic/GenericDetail.jsx +31 -6
  36. package/src/components/crm/generic/GenericDynamic.jsx +3 -3
  37. package/src/components/crm/generic/GenericEditableTable.jsx +4 -4
  38. package/src/components/crm/generic/GenericFormBuilder.jsx +6 -6
  39. package/src/components/crm/generic/GenericGrid.jsx +1622 -268
  40. package/src/components/crm/generic/GenericReport.jsx +966 -646
  41. package/src/components/crm/generic/GenericReportForm.jsx +1 -1
  42. package/src/components/crm/generic/NotificationList.jsx +1 -1
  43. package/src/components/crm/generic/ReasonCollectorModal.jsx +194 -0
  44. package/src/components/crm/generic/SortableQuoteItems.jsx +3 -3
  45. package/src/components/crm/generic/shared/formatters.js +107 -1
  46. package/src/components/crm/generic/styles/AlternativeActionModal.css +127 -0
  47. package/src/components/crm/generic/styles/DateRangeSelectorModal.css +115 -0
  48. package/src/components/crm/generic/styles/GenericIndex.module.scss +206 -0
  49. package/src/components/crm/generic/styles/GenericReport.module.scss +96 -0
  50. package/src/components/crm/generic/styles/ReasonCollectorModal.css +217 -0
  51. package/src/components/crm/modals/GalleryModal.jsx +2 -2
  52. package/src/components/crm/sorting/Item.jsx +3 -3
  53. package/src/components/crm/styles/AssociationManager.module.scss +364 -0
  54. package/src/components/crm/styles/BusinessCardOcr.module.scss +197 -4
  55. package/src/components/crm/styles/ClientAssociationManager.module.scss +290 -0
  56. package/src/components/crm/styles/MergeEntity.module.scss +690 -0
  57. package/src/components/crm/styles/MultiSelect.module.scss +18 -0
  58. package/src/components/crm/styles/Navigation.module.scss +68 -8
  59. package/src/components/crm/styles/global-datagrid.css +9 -0
  60. package/src/index.js +6 -0
package/package.json CHANGED
@@ -17,7 +17,6 @@
17
17
  "@visns-studio/visns-datagrid-enterprise": "^1.0.14",
18
18
  "@vitejs/plugin-react": "^4.5.2",
19
19
  "add": "^2.0.6",
20
- "akar-icons": "^1.9.31",
21
20
  "array-move": "^4.0.0",
22
21
  "awesome-debounce-promise": "^2.1.0",
23
22
  "browser-image-compression": "^2.0.2",
@@ -28,6 +27,7 @@
28
27
  "html-react-parser": "^5.2.5",
29
28
  "lodash": "^4.17.21",
30
29
  "lodash.debounce": "^4.0.8",
30
+ "lucide-react": "^0.516.0",
31
31
  "moment": "^2.30.1",
32
32
  "motion": "^12.18.1",
33
33
  "numeral": "^2.0.6",
@@ -87,7 +87,7 @@
87
87
  "react-dom": "^17.0.0 || ^18.0.0"
88
88
  },
89
89
  "name": "@visns-studio/visns-components",
90
- "version": "5.11.1",
90
+ "version": "5.11.3",
91
91
  "description": "Various packages to assist in the development of our Custom Applications.",
92
92
  "main": "src/index.js",
93
93
  "files": [
@@ -14,22 +14,22 @@ import Toggle from 'react-toggle';
14
14
  import fetchUtil from '../../utils/fetchUtil';
15
15
  import { confirmDialog } from '../utils/ConfirmDialog';
16
16
  import {
17
- Backspace,
17
+ Trash2 as Backspace,
18
18
  Check,
19
19
  Clock,
20
- CloudDownload,
20
+ Download as CloudDownload,
21
21
  Copy,
22
22
  Edit,
23
23
  Folder,
24
24
  Inbox,
25
25
  Network,
26
- Ribbon,
26
+ Award as Ribbon,
27
27
  Search,
28
- ShippingBoxV1,
29
- ToggleOff,
30
- ToggleOnFill,
31
- TriangleAlert,
32
- } from 'akar-icons';
28
+ Package as ShippingBoxV1,
29
+ ToggleLeft as ToggleOff,
30
+ ToggleRight as ToggleOnFill,
31
+ AlertTriangle as TriangleAlert,
32
+ } from 'lucide-react';
33
33
 
34
34
  import '@visns-studio/visns-datagrid-enterprise/index.css';
35
35
  import 'react-toggle/style.css';
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useState, useCallback } from 'react';
2
2
  import { motion } from 'framer-motion';
3
3
  import { useDropzone } from 'react-dropzone';
4
- import { CircleX, File, TrashCan } from 'akar-icons';
4
+ import { X as CircleX, File, Trash2 as TrashCan } from 'lucide-react';
5
5
  import { toast } from 'react-toastify';
6
6
  import { arrayMoveImmutable } from 'array-move';
7
7
  import Popup from 'reactjs-popup';
@@ -6,7 +6,7 @@ import moment from 'moment';
6
6
  import Reveal from 'react-reveal/Reveal';
7
7
  import parse from 'html-react-parser';
8
8
  import { toast } from 'react-toastify';
9
- import { Copy, TrashBin } from 'akar-icons';
9
+ import { Copy, Trash2 as TrashBin } from 'lucide-react';
10
10
  import { confirmDialog } from '../utils/ConfirmDialog';
11
11
 
12
12
  function Form(props) {
@@ -4,7 +4,7 @@ import {
4
4
  SortableElement,
5
5
  sortableHandle,
6
6
  } from 'react-sortable-hoc';
7
- import { ChevronVertical, Pencil, TrashCan } from 'akar-icons';
7
+ import { GripVertical as ChevronVertical, Edit as Pencil, Trash2 as TrashCan } from 'lucide-react';
8
8
  import styles from './styles/Gallery.module.css';
9
9
 
10
10
  // Drag handle component
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { SortableElement, sortableHandle } from 'react-sortable-hoc';
3
- import { ChevronVertical, Pencil, TrashCan } from 'akar-icons';
3
+ import { GripVertical as ChevronVertical, Edit as Pencil, Trash2 as TrashCan } from 'lucide-react';
4
4
 
5
5
  import styles from './styles/Item.module.scss';
6
6
 
@@ -0,0 +1,431 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { toast } from 'react-toastify';
3
+ import { Star, Trash2, Plus, Users, Calendar, AlertTriangle, X } from 'lucide-react';
4
+ import CustomFetch from './Fetch';
5
+ import MultiSelect from './MultiSelect';
6
+ import styles from './styles/AssociationManager.module.scss';
7
+
8
+ const AssociationManager = ({
9
+ endpoints,
10
+ config,
11
+ dataId,
12
+ onUpdate = () => {}
13
+ }) => {
14
+ const [associations, setAssociations] = useState([]);
15
+ const [availableOptions, setAvailableOptions] = useState([]);
16
+ const [loading, setLoading] = useState(true);
17
+
18
+ // Dynamic state based on config
19
+ const [newAssociation, setNewAssociation] = useState(() => {
20
+ const initialState = {};
21
+
22
+ // Set up dynamic fields based on config
23
+ if (config.fields) {
24
+ config.fields.forEach(field => {
25
+ initialState[field.id] = field.defaultValue || (field.type === 'boolean' ? false :
26
+ field.type === 'select' ? (field.options?.[0]?.value || '') :
27
+ field.type === 'multi-select' ? [] : '');
28
+ });
29
+ }
30
+
31
+ return initialState;
32
+ });
33
+
34
+ // Replace placeholders in endpoint URLs and data
35
+ const processTemplate = (template, data = {}) => {
36
+ let processed = template;
37
+
38
+ // Replace {dataId} with current dataId
39
+ processed = processed.replace(/\{dataId\}/g, dataId);
40
+
41
+ // Replace any other placeholders from provided data
42
+ Object.keys(data).forEach(key => {
43
+ const placeholder = new RegExp(`\\{${key}\\}`, 'g');
44
+ processed = processed.replace(placeholder, data[key]);
45
+ });
46
+
47
+ return processed;
48
+ };
49
+
50
+ // Load existing associations
51
+ const loadAssociations = async () => {
52
+ if (!endpoints.list) return;
53
+
54
+ try {
55
+ setLoading(true);
56
+ const url = processTemplate(endpoints.list);
57
+ const method = endpoints.listMethod || 'GET';
58
+ const response = await CustomFetch(url, method, endpoints.listParams || {});
59
+
60
+ const dataPath = config.dataPath || 'data';
61
+ const associationsData = dataPath.split('.').reduce((obj, key) => obj?.[key], response);
62
+
63
+ // Ensure associationsData is always an array
64
+ const validAssociations = Array.isArray(associationsData) ? associationsData : [];
65
+ setAssociations(validAssociations);
66
+ } catch (error) {
67
+ toast.error(config.messages?.loadError || 'Failed to load associations');
68
+ console.error('Error loading associations:', error);
69
+ setAssociations([]); // Set empty array on error
70
+ } finally {
71
+ setLoading(false);
72
+ }
73
+ };
74
+
75
+ // Load available options for dropdown/select fields
76
+ const loadAvailableOptions = async () => {
77
+ if (!config.optionsEndpoint) return;
78
+
79
+ try {
80
+ const url = processTemplate(config.optionsEndpoint.url);
81
+ const method = config.optionsEndpoint.method || 'POST';
82
+ const params = config.optionsEndpoint.params || {};
83
+
84
+ const response = await CustomFetch(url, method, params);
85
+ const dataPath = config.optionsEndpoint.dataPath || 'data';
86
+ const optionsData = dataPath.split('.').reduce((obj, key) => obj?.[key], response) || [];
87
+
88
+ setAvailableOptions(optionsData);
89
+ } catch (error) {
90
+ console.error('Failed to load options:', error);
91
+ }
92
+ };
93
+
94
+ // Generic action handler
95
+ const handleAction = async (actionKey, data = {}) => {
96
+ const endpoint = endpoints[actionKey];
97
+ if (!endpoint) return;
98
+
99
+ try {
100
+ const url = processTemplate(endpoint.url || endpoint, data);
101
+ const method = endpoint.method || 'POST';
102
+ const params = { ...endpoint.params, ...data };
103
+
104
+ await CustomFetch(url, method, params);
105
+
106
+ const successMessage = config.messages?.[`${actionKey}Success`] ||
107
+ endpoint.successMessage ||
108
+ 'Action completed successfully';
109
+ toast.success(successMessage);
110
+
111
+ // Reset form if it's an associate action
112
+ if (actionKey === 'associate') {
113
+ const resetState = {};
114
+ if (config.fields) {
115
+ config.fields.forEach(field => {
116
+ resetState[field.id] = field.defaultValue || (field.type === 'boolean' ? false :
117
+ field.type === 'select' ? (field.options?.[0]?.value || '') :
118
+ field.type === 'multi-select' ? [] : '');
119
+ });
120
+ }
121
+ setNewAssociation(resetState);
122
+ }
123
+
124
+ loadAssociations();
125
+ onUpdate();
126
+ } catch (error) {
127
+ const errorMessage = config.messages?.[`${actionKey}Error`] ||
128
+ endpoint.errorMessage ||
129
+ 'Action failed';
130
+ toast.error(errorMessage);
131
+ console.error(error);
132
+ }
133
+ };
134
+
135
+ // Associate handler
136
+ const handleAssociate = async () => {
137
+ // Validate required fields
138
+ const requiredField = config.fields?.find(field => field.required);
139
+ const primaryField = config.fields?.find(field => field.isPrimary);
140
+
141
+ if (requiredField && !newAssociation[requiredField.id]) {
142
+ toast.error(`Please select a ${requiredField.label || requiredField.id}`);
143
+ return;
144
+ }
145
+
146
+ // Prepare data for submission
147
+ const submitData = { ...newAssociation };
148
+
149
+ // Handle complex field values (like objects from MultiSelect)
150
+ Object.keys(submitData).forEach(key => {
151
+ const value = submitData[key];
152
+ if (value && typeof value === 'object' && value.value !== undefined) {
153
+ submitData[key] = value.value;
154
+ }
155
+ });
156
+
157
+ await handleAction('associate', submitData);
158
+ };
159
+
160
+ // Remove association handler
161
+ const handleDissociate = async (itemId) => {
162
+ const deleteField = config.deleteField || 'id';
163
+ await handleAction('dissociate', { [deleteField]: itemId });
164
+ };
165
+
166
+ // Set primary handler
167
+ const handleSetPrimary = async (itemId) => {
168
+ if (!endpoints.setPrimary) return;
169
+
170
+ const idField = config.primaryTargetField || config.deleteField || 'id';
171
+
172
+ await handleAction('setPrimary', { [idField]: itemId });
173
+ };
174
+
175
+ // Remove primary handler
176
+ const handleRemovePrimary = async (itemId) => {
177
+ if (!endpoints.removePrimary) return;
178
+
179
+ const idField = config.primaryTargetField || config.deleteField || 'id';
180
+
181
+ await handleAction('removePrimary', { [idField]: itemId });
182
+ };
183
+
184
+ // Clear all primary statuses (useful after merge)
185
+ const handleClearAllPrimary = async () => {
186
+ if (!endpoints.clearAllPrimary) return;
187
+
188
+ await handleAction('clearAllPrimary', { entity_id: dataId });
189
+ };
190
+
191
+ // Check if there are multiple primary associations
192
+ const hasMultiplePrimary = () => {
193
+ const primaryField = config.displayFields?.primary || 'is_primary';
194
+ return associations.filter(assoc => assoc[primaryField]).length > 1;
195
+ };
196
+
197
+ useEffect(() => {
198
+ if (dataId) {
199
+ loadAssociations();
200
+ loadAvailableOptions();
201
+ }
202
+ }, [dataId]);
203
+
204
+ if (loading) {
205
+ return <div className={styles.loading}>{config.messages?.loading || 'Loading associations...'}</div>;
206
+ }
207
+
208
+ return (
209
+ <div className={styles.container}>
210
+ <div className={styles.header}>
211
+ <h3>
212
+ <Users size={20} style={{ marginRight: '8px', verticalAlign: 'middle' }} />
213
+ {config.title || 'Associations'}
214
+ </h3>
215
+ <p>{config.description || 'Manage associations'}</p>
216
+ </div>
217
+
218
+ {/* Multiple Primary Warning */}
219
+ {hasMultiplePrimary() && (
220
+ <div className={styles.multiplePrimaryWarning}>
221
+ <AlertTriangle size={16} style={{ marginRight: '8px' }} />
222
+ <div className={styles.warningContent}>
223
+ <strong>{config.messages?.multiplePrimaryWarning || 'Multiple Primary Associations Detected'}</strong>
224
+ <p>{config.messages?.multiplePrimaryDescription || 'You have multiple associations marked as primary. Please resolve this by keeping only one primary association.'}</p>
225
+ {endpoints.clearAllPrimary && (
226
+ <button
227
+ type="button"
228
+ className={styles.clearAllPrimaryBtn}
229
+ onClick={handleClearAllPrimary}
230
+ >
231
+ {config.labels?.clearAllPrimary || 'Clear All Primary Status'}
232
+ </button>
233
+ )}
234
+ </div>
235
+ </div>
236
+ )}
237
+
238
+ {/* Existing Associations */}
239
+ <div className={styles.existingAssociations}>
240
+ <h4>{config.labels?.currentAssociations || 'Current Associations'}</h4>
241
+ {associations.length === 0 ? (
242
+ <div className={styles.noAssociations}>
243
+ {config.messages?.noAssociations || 'No associations found.'}
244
+ </div>
245
+ ) : (
246
+ <div className={styles.associationsList}>
247
+ {associations.map((association) => {
248
+ const nameField = config.displayFields?.name || 'name';
249
+ const primaryField = config.displayFields?.primary || 'is_primary';
250
+ const relationshipField = config.displayFields?.relationship || 'relationship_type';
251
+ const notesField = config.displayFields?.notes || 'notes';
252
+ const dateField = config.displayFields?.date || 'associated_at';
253
+
254
+ return (
255
+ <div
256
+ key={association.id}
257
+ className={`${styles.associationItem} ${association[primaryField] ? styles.primary : ''}`}
258
+ >
259
+ <div className={styles.associationInfo}>
260
+ <div className={styles.entityName}>
261
+ {association[nameField]}
262
+ {association[primaryField] && (
263
+ <span className={styles.primaryBadge}>
264
+ <Star size={12} style={{ marginRight: '4px' }} />
265
+ {config.labels?.primaryBadge || 'Primary'}
266
+ </span>
267
+ )}
268
+ </div>
269
+ {(association[relationshipField] || association[notesField]) && (
270
+ <div className={styles.relationshipInfo}>
271
+ {association[relationshipField] && (
272
+ <span className={styles.relationshipType}>
273
+ {association[relationshipField]}
274
+ </span>
275
+ )}
276
+ {association[notesField] && (
277
+ <span className={styles.notes}>
278
+ {association[relationshipField] ? ' - ' : ''}{association[notesField]}
279
+ </span>
280
+ )}
281
+ </div>
282
+ )}
283
+ {dateField && association[dateField] && (
284
+ <div className={styles.associatedAt}>
285
+ <Calendar size={12} style={{ marginRight: '4px' }} />
286
+ {config.labels?.associatedAt || 'Associated'}: {new Date(association[dateField]).toLocaleDateString()}
287
+ </div>
288
+ )}
289
+ </div>
290
+ <div className={styles.associationActions}>
291
+ {!association[primaryField] && endpoints.setPrimary && (
292
+ <button
293
+ type="button"
294
+ className={styles.setPrimaryBtn}
295
+ onClick={() => handleSetPrimary(association.id)}
296
+ >
297
+ <Star size={14} style={{ marginRight: '4px' }} />
298
+ {config.labels?.setPrimary || 'Set Primary'}
299
+ </button>
300
+ )}
301
+ {association[primaryField] && endpoints.removePrimary && (
302
+ <button
303
+ type="button"
304
+ className={styles.removePrimaryBtn}
305
+ onClick={() => handleRemovePrimary(association.id)}
306
+ title={config.labels?.removePrimaryTooltip || 'Remove primary status from this association'}
307
+ >
308
+ <X size={14} style={{ marginRight: '4px' }} />
309
+ {config.labels?.removePrimary || 'Remove Primary'}
310
+ </button>
311
+ )}
312
+ <button
313
+ type="button"
314
+ className={styles.removeBtn}
315
+ onClick={() => handleDissociate(association.id)}
316
+ >
317
+ <Trash2 size={14} style={{ marginRight: '4px' }} />
318
+ {config.labels?.remove || 'Remove'}
319
+ </button>
320
+ </div>
321
+ </div>
322
+ );
323
+ })}
324
+ </div>
325
+ )}
326
+ </div>
327
+
328
+ {/* Add New Association */}
329
+ <div className={styles.newAssociation}>
330
+ <h4>{config.labels?.addNew || 'Add New Association'}</h4>
331
+ <div className={styles.associationForm}>
332
+ {config.fields && config.fields.map((field, index) => {
333
+ const fieldValue = newAssociation[field.id] || '';
334
+
335
+ return (
336
+ <div key={field.id} className={styles.formRow}>
337
+ <div className={styles.formField}>
338
+ <label>
339
+ {field.label}{field.required && ' *'}
340
+ </label>
341
+
342
+ {field.type === 'multi-select' && (
343
+ <MultiSelect
344
+ settings={{ id: field.id }}
345
+ multi={field.multi || false}
346
+ onChange={(value) => setNewAssociation(prev => ({ ...prev, [field.id]: value }))}
347
+ inputValue={fieldValue}
348
+ options={availableOptions}
349
+ placeholder={field.placeholder || `Select ${field.label}...`}
350
+ />
351
+ )}
352
+
353
+ {field.type === 'select' && (
354
+ <select
355
+ value={fieldValue}
356
+ onChange={(e) => setNewAssociation(prev => ({
357
+ ...prev,
358
+ [field.id]: e.target.value
359
+ }))}
360
+ className={styles.selectField}
361
+ >
362
+ {field.options && field.options.map(option => (
363
+ <option key={option.value || option} value={option.value || option}>
364
+ {option.label || option}
365
+ </option>
366
+ ))}
367
+ </select>
368
+ )}
369
+
370
+ {field.type === 'boolean' && (
371
+ <label>
372
+ <input
373
+ type="checkbox"
374
+ checked={fieldValue}
375
+ onChange={(e) => setNewAssociation(prev => ({
376
+ ...prev,
377
+ [field.id]: e.target.checked
378
+ }))}
379
+ />
380
+ {field.checkboxLabel || field.label}
381
+ </label>
382
+ )}
383
+
384
+ {field.type === 'textarea' && (
385
+ <textarea
386
+ value={fieldValue}
387
+ onChange={(e) => setNewAssociation(prev => ({
388
+ ...prev,
389
+ [field.id]: e.target.value
390
+ }))}
391
+ placeholder={field.placeholder || ''}
392
+ className={styles.textareaField}
393
+ rows={field.rows || 3}
394
+ />
395
+ )}
396
+
397
+ {field.type === 'text' && (
398
+ <input
399
+ type="text"
400
+ value={fieldValue}
401
+ onChange={(e) => setNewAssociation(prev => ({
402
+ ...prev,
403
+ [field.id]: e.target.value
404
+ }))}
405
+ placeholder={field.placeholder || ''}
406
+ className={styles.textField}
407
+ />
408
+ )}
409
+ </div>
410
+ </div>
411
+ );
412
+ })}
413
+
414
+ <div className={styles.formActions}>
415
+ <button
416
+ type="button"
417
+ className={styles.associateBtn}
418
+ onClick={handleAssociate}
419
+ disabled={!newAssociation[config.fields?.find(f => f.required)?.id || 'id']}
420
+ >
421
+ <Plus size={14} style={{ marginRight: '4px' }} />
422
+ {config.labels?.addButton || 'Add Association'}
423
+ </button>
424
+ </div>
425
+ </div>
426
+ </div>
427
+ </div>
428
+ );
429
+ };
430
+
431
+ export default AssociationManager;
@@ -1,6 +1,6 @@
1
1
  import { useState, useEffect, useCallback, useMemo, memo, useRef } from 'react';
2
2
  import AwesomeDebouncePromise from 'awesome-debounce-promise';
3
- import { ToggleOffFill, ToggleOnFill, Search } from 'akar-icons';
3
+ import { ToggleLeft, ToggleRight, Search } from 'lucide-react';
4
4
  import styles from './styles/Autocomplete.module.scss';
5
5
  import fetchUtil from '../../utils/fetchUtil';
6
6
 
@@ -255,7 +255,7 @@ const VisnsAutocomplete = memo((props) => {
255
255
  />
256
256
 
257
257
  {overwrite ? (
258
- <ToggleOnFill
258
+ <ToggleRight
259
259
  data-tooltip-id="system-tooltip"
260
260
  data-tooltip-content="Enable Autocomplete"
261
261
  strokeWidth={2}
@@ -264,7 +264,7 @@ const VisnsAutocomplete = memo((props) => {
264
264
  className={styles.toggleActive}
265
265
  />
266
266
  ) : (
267
- <ToggleOffFill
267
+ <ToggleLeft
268
268
  data-tooltip-id="system-tooltip"
269
269
  data-tooltip-content="Disable Autocomplete"
270
270
  strokeWidth={2}
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { Link } from 'react-router-dom';
3
3
  import dayjs from 'dayjs';
4
4
  import parse from 'html-react-parser';
5
- import { CircleChevronRight } from 'akar-icons';
5
+ import { ChevronRight } from 'lucide-react';
6
6
 
7
7
  function Breadcrumb({ data, page }) {
8
8
  // Function to get nested data, handling array of keys
@@ -73,7 +73,7 @@ function Breadcrumb({ data, page }) {
73
73
  {page?.parentTitle && page?.parentUrl && (
74
74
  <>
75
75
  <Link to={page.parentUrl}>{parse(page.parentTitle)}</Link>
76
- <CircleChevronRight strokeWidth={2} size={18} />
76
+ <ChevronRight strokeWidth={2} size={18} />
77
77
  </>
78
78
  )}
79
79
 
@@ -87,7 +87,7 @@ function Breadcrumb({ data, page }) {
87
87
  >
88
88
  {parse(nestedData)}
89
89
  </Link>
90
- <CircleChevronRight strokeWidth={2} size={18} />
90
+ <ChevronRight strokeWidth={2} size={18} />
91
91
  </>
92
92
  ) : (
93
93
  page &&
@@ -102,7 +102,7 @@ function Breadcrumb({ data, page }) {
102
102
  >
103
103
  {parse(page.title)}
104
104
  </Link>
105
- <CircleChevronRight strokeWidth={2} size={18} />
105
+ <ChevronRight strokeWidth={2} size={18} />
106
106
  </>
107
107
  )
108
108
  )}