@visns-studio/visns-components 5.6.13 → 5.7.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.
package/package.json CHANGED
@@ -33,7 +33,6 @@
33
33
  "quill-image-uploader": "^1.3.0",
34
34
  "react-big-calendar": "^1.18.0",
35
35
  "react-color": "^2.19.3",
36
- "react-confirm-alert": "^3.0.6",
37
36
  "react-copy-to-clipboard": "^5.1.0",
38
37
  "react-datepicker": "^8.3.0",
39
38
  "react-dropzone": "^14.3.8",
@@ -84,7 +83,7 @@
84
83
  "react-dom": "^17.0.0 || ^18.0.0"
85
84
  },
86
85
  "name": "@visns-studio/visns-components",
87
- "version": "5.6.13",
86
+ "version": "5.7.0",
88
87
  "description": "Various packages to assist in the development of our Custom Applications.",
89
88
  "main": "src/index.js",
90
89
  "files": [
@@ -10,9 +10,9 @@ import NumberFilter from '@visns-studio/visns-datagrid-enterprise/NumberFilter';
10
10
  import SelectFilter from '@visns-studio/visns-datagrid-enterprise/SelectFilter';
11
11
  import DateFilter from '@visns-studio/visns-datagrid-enterprise/DateFilter';
12
12
  import ReactDataGrid from '@visns-studio/visns-datagrid-enterprise';
13
- import { confirmAlert } from 'react-confirm-alert';
14
13
  import { toast } from 'react-toastify';
15
14
  import Toggle from 'react-toggle';
15
+ import { confirmDialog } from '../utils/ConfirmDialog';
16
16
  import {
17
17
  Backspace,
18
18
  Check,
@@ -32,7 +32,6 @@ import {
32
32
  } from 'akar-icons';
33
33
 
34
34
  import '@visns-studio/visns-datagrid-enterprise/index.css';
35
- import 'react-confirm-alert/src/react-confirm-alert.css';
36
35
  import 'react-toggle/style.css';
37
36
 
38
37
  import CustomFetch from '../crm/Fetch';
@@ -171,11 +170,12 @@ const DataGrid = ({
171
170
  modalOpen('update', d.id);
172
171
  break;
173
172
  case 'delete':
174
- confirmAlert({
173
+ confirmDialog({
175
174
  title: 'Delete Item',
176
175
  message: `Are you sure you want to delete ${
177
176
  d.name ? d.name : d.label ? d.label : 'this item'
178
177
  }?`,
178
+ data: d, // Pass the row data
179
179
  buttons: [
180
180
  {
181
181
  label: 'Yes',
@@ -213,9 +213,10 @@ const DataGrid = ({
213
213
  });
214
214
  break;
215
215
  default:
216
- confirmAlert({
216
+ confirmDialog({
217
217
  title: s.title,
218
218
  message: '',
219
+ data: d, // Pass the row data
219
220
  buttons: [
220
221
  {
221
222
  label: 'Yes',
@@ -1208,7 +1209,69 @@ const DataGrid = ({
1208
1209
  onClick={(e) => {
1209
1210
  e.preventDefault();
1210
1211
  e.stopPropagation();
1211
- handleSettingClick(setting, data);
1212
+
1213
+ // Actions that should have confirmation dialogs
1214
+ const actionsRequiringConfirmation = [
1215
+ 'complete',
1216
+ 'primary',
1217
+ 'ssa',
1218
+ ];
1219
+
1220
+ // If this action requires confirmation and is not delete (which has its own confirmation)
1221
+ if (
1222
+ actionsRequiringConfirmation.includes(
1223
+ setting.id
1224
+ ) &&
1225
+ setting.id !== 'delete'
1226
+ ) {
1227
+ // Get tooltip content for the message
1228
+ const tooltipContent =
1229
+ setting.active &&
1230
+ data.hasOwnProperty(
1231
+ setting.active.id
1232
+ ) &&
1233
+ data[setting.active.id] ===
1234
+ setting.active.value
1235
+ ? setting.active.title
1236
+ : setting.title;
1237
+
1238
+ // Create a message based on the tooltip
1239
+ let message = `Are you sure you want to ${tooltipContent.toLowerCase()}?`;
1240
+
1241
+ // Add item identifier if available
1242
+ const itemName =
1243
+ data.name ||
1244
+ data.label ||
1245
+ data.title ||
1246
+ data.id;
1247
+ if (itemName) {
1248
+ message += ` Item: "${itemName}"`;
1249
+ }
1250
+
1251
+ // Show confirmation dialog
1252
+ confirmDialog({
1253
+ title: tooltipContent,
1254
+ message: message,
1255
+ data: data,
1256
+ buttons: [
1257
+ {
1258
+ label: 'Yes',
1259
+ onClick: () =>
1260
+ handleSettingClick(
1261
+ setting,
1262
+ data
1263
+ ),
1264
+ },
1265
+ {
1266
+ label: 'No',
1267
+ onClick: () => {},
1268
+ },
1269
+ ],
1270
+ });
1271
+ } else {
1272
+ // For actions that don't need confirmation or already have it (delete)
1273
+ handleSettingClick(setting, data);
1274
+ }
1212
1275
  }}
1213
1276
  >
1214
1277
  {renderSetting(setting, data)}
@@ -1,15 +1,13 @@
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 { confirmAlert } from 'react-confirm-alert';
5
4
  import { CircleX, File, TrashCan } from 'akar-icons';
6
5
  import { toast } from 'react-toastify';
7
6
  import { arrayMoveImmutable } from 'array-move';
8
7
  import Popup from 'reactjs-popup';
9
8
  import imageCompression from 'browser-image-compression';
10
9
 
11
- import 'react-confirm-alert/src/react-confirm-alert.css';
12
-
10
+ import { confirmDialog } from '../utils/ConfirmDialog';
13
11
  import CustomFetch from '../crm/Fetch';
14
12
  import SortableList from './sorting/List';
15
13
 
@@ -122,9 +120,10 @@ function VisnsDropZone({ fetchData, files, settings }) {
122
120
 
123
121
  const handleDelete = (id, name) => {
124
122
  if (id && id > 0) {
125
- confirmAlert({
123
+ confirmDialog({
126
124
  title: 'Confirm to Delete File',
127
125
  message: 'Are you sure you want to delete ' + name,
126
+ data: { name: name }, // Pass the file name as data
128
127
  buttons: [
129
128
  {
130
129
  label: 'Yes',
@@ -5,11 +5,9 @@ import slugify from 'react-slugify';
5
5
  import moment from 'moment';
6
6
  import Reveal from 'react-reveal/Reveal';
7
7
  import parse from 'html-react-parser';
8
- import { confirmAlert } from 'react-confirm-alert';
9
8
  import { toast } from 'react-toastify';
10
9
  import { Copy, TrashBin } from 'akar-icons';
11
-
12
- import 'react-confirm-alert/src/react-confirm-alert.css';
10
+ import { confirmDialog } from '../utils/ConfirmDialog';
13
11
 
14
12
  function Form(props) {
15
13
  const { dataId, navigate, form } = props;
@@ -245,9 +243,10 @@ function Form(props) {
245
243
 
246
244
  const handleDelete = (e) => {
247
245
  if (e) {
248
- confirmAlert({
246
+ confirmDialog({
249
247
  title: 'Delete this entry',
250
248
  message: 'Are you sure you want to delete it?',
249
+ data: data, // Pass the data object for context
251
250
  buttons: [
252
251
  {
253
252
  label: 'Yes',
@@ -4,8 +4,6 @@ import Reveal from 'react-reveal/Reveal';
4
4
  import { ToastContainer } from 'react-toastify';
5
5
  import CmsForm from '../Form';
6
6
 
7
- import 'react-confirm-alert/src/react-confirm-alert.css';
8
-
9
7
  function CmsDetail({ setting }) {
10
8
  const { dataId } = useParams();
11
9
  const navigate = useNavigate();
@@ -22,11 +22,11 @@ import NumberFilter from '@visns-studio/visns-datagrid-enterprise/NumberFilter';
22
22
  import SelectFilter from '@visns-studio/visns-datagrid-enterprise/SelectFilter';
23
23
  import DateFilter from '@visns-studio/visns-datagrid-enterprise/DateFilter';
24
24
  import ReactDataGrid from '@visns-studio/visns-datagrid-enterprise';
25
- import { confirmAlert } from 'react-confirm-alert';
26
25
  import { toast } from 'react-toastify';
27
26
  import imageCompression from 'browser-image-compression';
28
27
  import Vapor from 'laravel-vapor';
29
28
  import Lightbox from 'yet-another-react-lightbox';
29
+ import { confirmDialog } from '../utils/ConfirmDialog';
30
30
  import {
31
31
  Alarm,
32
32
  ArrowCounterClockwise,
@@ -59,7 +59,6 @@ import {
59
59
  import styles from './styles/DataGrid.module.scss';
60
60
 
61
61
  import '@visns-studio/visns-datagrid-enterprise/index.css';
62
- import 'react-confirm-alert/src/react-confirm-alert.css';
63
62
  import 'yet-another-react-lightbox/styles.css';
64
63
 
65
64
  import CustomFetch from './Fetch';
@@ -491,7 +490,7 @@ const DataGrid = forwardRef(
491
490
  }
492
491
  };
493
492
 
494
- const handleTimer = async (id, key) => {
493
+ const handleTimer = async (id, key, data) => {
495
494
  try {
496
495
  const res = await CustomFetch(`${form.url}/${id}`, 'PUT', {
497
496
  [key]: moment().toDate(),
@@ -499,7 +498,6 @@ const DataGrid = forwardRef(
499
498
 
500
499
  if (res.data.error === '') {
501
500
  toast.success('Timer has been updated.');
502
-
503
501
  handleReload();
504
502
  } else {
505
503
  toast.error(res.data.error);
@@ -511,32 +509,74 @@ const DataGrid = forwardRef(
511
509
 
512
510
  const handleSelectionChange = useCallback(
513
511
  (param) => {
514
- if (param.selected === true) {
515
- const s = {};
516
-
517
- param.data.forEach((obj) => {
518
- s[obj.id] = obj;
519
- });
512
+ // If this is a new selection (not a deselection)
513
+ if (
514
+ param.selected === true ||
515
+ (typeof param.selected === 'object' &&
516
+ Object.keys(param.selected).length > 0)
517
+ ) {
518
+ // Show confirmation dialog for selection
519
+ const selectedCount =
520
+ param.selected === true ? param.data.length : 1;
521
+ const itemText = selectedCount === 1 ? 'item' : 'items';
522
+
523
+ confirmDialog({
524
+ title: 'Selection Confirmation',
525
+ message: `You have selected ${selectedCount} ${itemText}. Do you want to proceed with this selection?`,
526
+ data:
527
+ param.selected === true
528
+ ? param.data
529
+ : param.selected, // Pass the selected data
530
+ buttons: [
531
+ {
532
+ label: 'Yes',
533
+ onClick: () => {
534
+ // Process the selection as before
535
+ if (param.selected === true) {
536
+ const s = {};
537
+ param.data.forEach((obj) => {
538
+ s[obj.id] = obj;
539
+ });
540
+ setSelected(s);
541
+ } else if (
542
+ typeof param.selected === 'object'
543
+ ) {
544
+ const selectedKey = Object.keys(
545
+ param.selected
546
+ )[0];
547
+ const isSelectedAlready =
548
+ selected.hasOwnProperty(
549
+ selectedKey
550
+ );
520
551
 
521
- setSelected(s);
522
- } else if (typeof param.selected === 'object') {
523
- // Assuming param.selected is an object where keys are the ids of the selections
524
- const selectedKey = Object.keys(param.selected)[0]; // Get the key of the selected object
525
- const isSelectedAlready =
526
- selected.hasOwnProperty(selectedKey); // Check if this key is already in selected
552
+ if (isSelectedAlready) {
553
+ setSelected({});
554
+ } else {
555
+ setSelected((prevSelected) => ({
556
+ ...prevSelected,
557
+ [selectedKey]:
558
+ param.selected[selectedKey],
559
+ }));
560
+ }
561
+ }
527
562
 
528
- if (isSelectedAlready) {
529
- // If the key already exists, reset selected
530
- setSelected({});
531
- } else {
532
- // If it does not exist, update selected with the new object
533
- setSelected((prevSelected) => ({
534
- ...prevSelected,
535
- [selectedKey]: param.selected[selectedKey],
536
- }));
537
- }
563
+ // Show a success message
564
+ toast.success(
565
+ `Selection of ${selectedCount} ${itemText} confirmed`
566
+ );
567
+ },
568
+ },
569
+ {
570
+ label: 'No',
571
+ onClick: () => {
572
+ // Clear selection if user cancels
573
+ setSelected({});
574
+ },
575
+ },
576
+ ],
577
+ });
538
578
  } else {
539
- // Handle other cases as needed
579
+ // Handle deselection directly without confirmation
540
580
  setSelected(param.selected);
541
581
  }
542
582
  },
@@ -618,18 +658,86 @@ const DataGrid = forwardRef(
618
658
  case 'file':
619
659
  case 'image':
620
660
  case 'undo':
621
- CustomFetch(s.url, 'POST', { id: d[s.key] }, (result) => {
622
- toast.success(result.message);
661
+ // Create a user-friendly action name from the ID
662
+ const actionName =
663
+ s.title || s.id.charAt(0).toUpperCase() + s.id.slice(1);
664
+
665
+ // Create a message based on the action type
666
+ let message = `Are you sure you want to ${actionName.toLowerCase()}?`;
667
+
668
+ // Add item identifier if available
669
+ const itemName = d.name || d.label || d.title || d.id;
670
+ if (itemName) {
671
+ message += ` Item: "${itemName}"`;
672
+ }
673
+
674
+ // Show confirmation dialog
675
+ confirmDialog({
676
+ title: actionName,
677
+ message: message,
678
+ data: d, // Pass the row data for context
679
+ buttons: [
680
+ {
681
+ label: 'Yes',
682
+ onClick: () => {
683
+ CustomFetch(
684
+ s.url,
685
+ 'POST',
686
+ { id: d[s.key] },
687
+ (result) => {
688
+ toast.success(result.message);
689
+ }
690
+ );
691
+ },
692
+ },
693
+ {
694
+ label: 'No',
695
+ onClick: () => {},
696
+ },
697
+ ],
623
698
  });
624
699
  break;
625
700
  case 'clone':
626
701
  if (s.url && s.url !== '') {
627
- const cloneUrl = `${s.url}/${d[s.key]}/clone`;
628
-
629
- CustomFetch(cloneUrl, 'POST', {}, (result) => {
630
- toast.success(result.message);
702
+ // Create a message for clone action
703
+ let cloneMessage = `Are you sure you want to clone this item?`;
704
+
705
+ // Add item identifier if available
706
+ const cloneItemName =
707
+ d.name || d.label || d.title || d.id;
708
+ if (cloneItemName) {
709
+ cloneMessage += ` Item: "${cloneItemName}"`;
710
+ }
631
711
 
632
- handleReload();
712
+ // Show confirmation dialog
713
+ confirmDialog({
714
+ title: 'Clone Item',
715
+ message: cloneMessage,
716
+ data: d, // Pass the row data for context
717
+ buttons: [
718
+ {
719
+ label: 'Yes',
720
+ onClick: () => {
721
+ const cloneUrl = `${s.url}/${
722
+ d[s.key]
723
+ }/clone`;
724
+
725
+ CustomFetch(
726
+ cloneUrl,
727
+ 'POST',
728
+ {},
729
+ (result) => {
730
+ toast.success(result.message);
731
+ handleReload();
732
+ }
733
+ );
734
+ },
735
+ },
736
+ {
737
+ label: 'No',
738
+ onClick: () => {},
739
+ },
740
+ ],
633
741
  });
634
742
  }
635
743
  break;
@@ -721,9 +829,10 @@ const DataGrid = forwardRef(
721
829
  }?`;
722
830
  }
723
831
 
724
- confirmAlert({
832
+ confirmDialog({
725
833
  title: 'Delete Item',
726
834
  message: confirmMessage,
835
+ data: d, // Pass the row data
727
836
  buttons: [
728
837
  {
729
838
  label: 'Yes',
@@ -862,9 +971,10 @@ const DataGrid = forwardRef(
862
971
  modalOpen('update', d.id);
863
972
  break;
864
973
  default:
865
- confirmAlert({
974
+ confirmDialog({
866
975
  title: s.title,
867
976
  message: '',
977
+ data: d, // Pass the row data
868
978
  buttons: [
869
979
  {
870
980
  label: 'Yes',
@@ -1482,11 +1592,71 @@ const DataGrid = forwardRef(
1482
1592
  e.preventDefault();
1483
1593
  e.stopPropagation();
1484
1594
 
1485
- // Ensure both s and d are defined before calling handleSettingClick
1486
- if (s && d) {
1487
- handleSettingClick(s, d);
1488
- } else {
1595
+ // Ensure both s and d are defined before proceeding
1596
+ if (!s || !d) {
1489
1597
  console.warn('Missing settings or data for icon click');
1598
+ return;
1599
+ }
1600
+
1601
+ // Actions that should have confirmation dialogs
1602
+ const actionsRequiringConfirmation = [
1603
+ 'activate',
1604
+ 'arrowCycle',
1605
+ 'cloudUpload',
1606
+ 'clone',
1607
+ 'envelope',
1608
+ 'file',
1609
+ 'image',
1610
+ 'undo',
1611
+ 'restore',
1612
+ ];
1613
+
1614
+ // If this action requires confirmation, show a dialog
1615
+ if (actionsRequiringConfirmation.includes(s.id)) {
1616
+ // Get a user-friendly action name from the title or ID
1617
+ const actionName =
1618
+ s.title || s.id.charAt(0).toUpperCase() + s.id.slice(1);
1619
+
1620
+ // Create a message based on the action type
1621
+ let message = '';
1622
+ if (s.id === 'delete') {
1623
+ // Delete already has its own confirmation message
1624
+ handleSettingClick(s, d);
1625
+ return;
1626
+ } else {
1627
+ // For other actions, create a message based on the tooltip content
1628
+ const tooltipContent =
1629
+ s.active && iconStyle.color
1630
+ ? s.active.title
1631
+ : s.title;
1632
+ message = `Are you sure you want to ${tooltipContent.toLowerCase()}?`;
1633
+
1634
+ // Add item identifier if available
1635
+ const itemName = d.name || d.label || d.title || d.id;
1636
+ if (itemName) {
1637
+ message += ` Item: "${itemName}"`;
1638
+ }
1639
+ }
1640
+
1641
+ // Show the confirmation dialog
1642
+ confirmDialog({
1643
+ title: actionName,
1644
+ message: message,
1645
+ data: d, // Pass the row data for context
1646
+ buttons: [
1647
+ {
1648
+ label: 'Yes',
1649
+ onClick: () => handleSettingClick(s, d),
1650
+ },
1651
+ {
1652
+ label: 'No',
1653
+ onClick: () => {},
1654
+ },
1655
+ ],
1656
+ });
1657
+ } else {
1658
+ // For actions that don't need confirmation, proceed directly
1659
+ handleSettingClick(s, d);
1490
1660
  }
1491
1661
  };
1492
1662
 
@@ -2807,7 +2977,8 @@ const DataGrid = forwardRef(
2807
2977
  form
2808
2978
  .primaryKey
2809
2979
  ],
2810
- column.id
2980
+ column.id,
2981
+ data
2811
2982
  );
2812
2983
  } else {
2813
2984
  // Format field names to be more readable
@@ -2852,7 +3023,8 @@ const DataGrid = forwardRef(
2852
3023
  form
2853
3024
  .primaryKey
2854
3025
  ],
2855
- column.id
3026
+ column.id,
3027
+ data
2856
3028
  );
2857
3029
  }
2858
3030
  }}
@@ -1085,7 +1085,7 @@ function Field({
1085
1085
  ? settings.options
1086
1086
  : options
1087
1087
  }
1088
- isSearchable={settings.isSearchable || false}
1088
+ isSearchable={settings.isSearchable || true}
1089
1089
  isCreatable={settings.isCreatable || false}
1090
1090
  dataOptions={dataOptions}
1091
1091
  style={style}
@@ -10,11 +10,10 @@ import parse from 'html-react-parser';
10
10
  import _ from 'lodash';
11
11
  import ReactDataGrid from '@visns-studio/visns-datagrid-enterprise';
12
12
  import { CircleX } from 'akar-icons';
13
- import { confirmAlert } from 'react-confirm-alert';
14
13
  import imageCompression from 'browser-image-compression';
14
+ import { confirmDialog } from '../utils/ConfirmDialog';
15
15
 
16
16
  import '@visns-studio/visns-datagrid-enterprise/index.css';
17
- import 'react-confirm-alert/src/react-confirm-alert.css';
18
17
 
19
18
  import CustomFetch from './Fetch';
20
19
  import Download from './Download';
@@ -598,11 +597,12 @@ function Form({
598
597
 
599
598
  try {
600
599
  if (s.customButton.confirmation) {
601
- confirmAlert({
600
+ confirmDialog({
602
601
  title: '',
603
602
  message:
604
603
  s.customButton.confirmation.message ||
605
604
  'Are you sure you want to proceed?',
605
+ data: formData, // Add context data
606
606
  buttons: [
607
607
  {
608
608
  label: 'Yes',
@@ -9,8 +9,7 @@ import dayjs from 'dayjs';
9
9
  import parse from 'html-react-parser';
10
10
  import { createSwapy } from 'swapy';
11
11
  import { CircleX, Minus, Plus, Star, TrashCan } from 'akar-icons';
12
- import { confirmAlert } from 'react-confirm-alert';
13
- import 'react-confirm-alert/src/react-confirm-alert.css';
12
+ import { confirmDialog } from '../../utils/ConfirmDialog';
14
13
 
15
14
  import CustomFetch from '../../crm/Fetch';
16
15
  import MultiSelect from '../../crm/MultiSelect';
@@ -321,9 +320,10 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
321
320
  };
322
321
 
323
322
  const confirmDelete = (widgetId) => {
324
- confirmAlert({
323
+ confirmDialog({
325
324
  title: 'Confirm to delete',
326
325
  message: 'Are you sure you want to delete this widget?',
326
+ data: { id: widgetId, name: 'this widget' }, // Add context data
327
327
  buttons: [
328
328
  { label: 'Yes', onClick: () => handleDeleteWidget(widgetId) },
329
329
  { label: 'No' },
@@ -28,7 +28,6 @@ import parse from 'html-react-parser';
28
28
  import Popup from 'reactjs-popup';
29
29
  import { motion } from 'framer-motion';
30
30
  import Dropzone from 'react-dropzone';
31
- import { confirmAlert } from 'react-confirm-alert';
32
31
  import truncate from 'truncate';
33
32
  import { CopyToClipboard } from 'react-copy-to-clipboard';
34
33
  import { saveAs } from 'file-saver';
@@ -43,8 +42,8 @@ import {
43
42
  Pencil,
44
43
  TrashCan,
45
44
  } from 'akar-icons';
45
+ import { confirmDialog } from '../../utils/ConfirmDialog';
46
46
 
47
- import 'react-confirm-alert/src/react-confirm-alert.css';
48
47
  import 'react-big-calendar/lib/css/react-big-calendar.css';
49
48
  import 'react-big-calendar/lib/addons/dragAndDrop/styles.css';
50
49
 
@@ -1277,11 +1276,12 @@ function GenericDetail({
1277
1276
  if (e) {
1278
1277
  e.stopPropagation();
1279
1278
 
1280
- confirmAlert({
1279
+ confirmDialog({
1281
1280
  title: 'Confirm to Delete File',
1282
1281
  message:
1283
1282
  'Are you sure you want to delete ' +
1284
1283
  name,
1284
+ data: { name: name }, // Add context data
1285
1285
  buttons: [
1286
1286
  {
1287
1287
  label: 'Yes',
@@ -1,11 +1,10 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
2
  import moment from 'moment';
3
- import 'react-confirm-alert/src/react-confirm-alert.css';
4
3
  import { toast } from 'react-toastify';
5
- import { confirmAlert } from 'react-confirm-alert';
6
4
  import { saveAs } from 'file-saver';
7
5
  import parse from 'html-react-parser';
8
6
  import { Backspace, CloudDownload } from 'akar-icons';
7
+ import { confirmDialog } from '../../utils/ConfirmDialog';
9
8
 
10
9
  import CustomFetch from '../Fetch';
11
10
  import Download from '../Download';
@@ -687,9 +686,10 @@ const GenericDynamic = ({
687
686
  }
688
687
  };
689
688
 
690
- confirmAlert({
689
+ confirmDialog({
691
690
  title: 'Delete File',
692
691
  message: 'Are you sure?',
692
+ data: { name: 'this file' }, // Add some context
693
693
  buttons: [
694
694
  {
695
695
  label: 'Yes',
@@ -2,14 +2,12 @@ import React, { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import ReactDOM from 'react-dom';
3
3
  import debounce from 'lodash.debounce';
4
4
  import { toast } from 'react-toastify';
5
- import { confirmAlert } from 'react-confirm-alert';
6
5
  import { TrashCan, ArrowUp, ArrowDown, Copy, Water } from 'akar-icons';
7
6
  import { CompactPicker } from 'react-color';
7
+ import { confirmDialog } from '../../utils/ConfirmDialog';
8
8
 
9
9
  import CustomFetch from '../Fetch';
10
10
  import MultiSelect from '../MultiSelect';
11
-
12
- import 'react-confirm-alert/src/react-confirm-alert.css';
13
11
  import styles from './styles/GenericEditableTable.module.scss';
14
12
 
15
13
  // Updated ColourPicker with an expanded pastel palette
@@ -593,9 +591,10 @@ const GenericEditableTable = ({
593
591
 
594
592
  // 8) Deletion
595
593
  const handleDeleteRow = (entry) => {
596
- confirmAlert({
594
+ confirmDialog({
597
595
  title: 'Confirm to Delete',
598
596
  message: 'Are you sure you want to delete this entry?',
597
+ data: entry, // Pass the row data
599
598
  buttons: [
600
599
  {
601
600
  label: 'Yes',
@@ -4,17 +4,16 @@ import React, { useEffect, useRef, useState } from 'react';
4
4
  import { useParams } from 'react-router-dom';
5
5
  import Popup from 'reactjs-popup';
6
6
  import { arrayMoveImmutable } from 'array-move';
7
- import { confirmAlert } from 'react-confirm-alert';
8
7
  import parse from 'html-react-parser';
9
8
  import Toggle from 'react-toggle';
10
9
  import { toast } from 'react-toastify';
11
10
  import { v4 as uuidv4 } from 'uuid';
12
11
  import { Editor } from '@tinymce/tinymce-react';
13
12
  import { CirclePlus, CircleX, TrashCan } from 'akar-icons';
13
+ import { confirmDialog } from '../../utils/ConfirmDialog';
14
14
 
15
15
  import 'react-toggle/style.css';
16
16
  import 'react-datepicker/dist/react-datepicker.css';
17
- import 'react-confirm-alert/src/react-confirm-alert.css';
18
17
 
19
18
  import Breadcrumb from '../Breadcrumb';
20
19
  import CustomFetch from '../Fetch';
@@ -278,9 +277,10 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
278
277
  };
279
278
 
280
279
  const handleDeleteField = (id, label) => {
281
- confirmAlert({
280
+ confirmDialog({
282
281
  title: `Delete "${label}" Field`,
283
282
  message: 'Are you sure you want to delete this field?',
283
+ data: { name: label, id: id }, // Add context data
284
284
  buttons: [
285
285
  {
286
286
  label: 'Yes',
@@ -24,18 +24,42 @@
24
24
  line-height: 1.4 !important;
25
25
  }
26
26
 
27
- .swal2-confirm {
28
- background-color: #2563eb !important;
27
+ /* Button styles for symmetrical appearance */
28
+ .swal2-actions {
29
+ display: flex !important;
30
+ justify-content: center !important;
31
+ gap: 10px !important;
32
+ width: 100% !important;
33
+ }
34
+
35
+ .swal2-confirm,
36
+ .swal2-cancel {
37
+ flex: 1 !important;
38
+ max-width: 120px !important;
39
+ min-width: 100px !important;
29
40
  border-radius: 4px !important;
30
41
  font-weight: 500 !important;
31
- padding: 6px 14px !important;
42
+ padding: 8px 16px !important;
32
43
  font-size: 13px !important;
44
+ margin: 0 !important;
45
+ }
46
+
47
+ .swal2-confirm {
48
+ background-color: #2563eb !important;
49
+ }
50
+
51
+ .swal2-cancel {
52
+ background-color: #6b7280 !important;
33
53
  }
34
54
 
35
55
  .swal2-confirm:focus {
36
56
  box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.3) !important;
37
57
  }
38
58
 
59
+ .swal2-cancel:focus {
60
+ box-shadow: 0 0 0 2px rgba(107, 114, 128, 0.3) !important;
61
+ }
62
+
39
63
  /* Make the modal more compact */
40
64
  .swal2-popup.swal2-modal {
41
65
  max-width: 90%;
@@ -0,0 +1,155 @@
1
+ import Swal from 'sweetalert2';
2
+ import '../crm/generic/styles/SweetAlertCustom.css';
3
+
4
+ /**
5
+ * A utility function that replaces react-confirm-alert with SweetAlert2
6
+ * while maintaining a similar look and feel.
7
+ *
8
+ * @param {Object} options - Configuration options
9
+ * @param {string} options.title - The title of the confirmation dialog
10
+ * @param {string} options.message - The message to display in the dialog
11
+ * @param {Array} options.buttons - Array of button objects with label and onClick properties
12
+ * @param {Object} options.customUI - Custom UI function (ignored, for compatibility only)
13
+ * @param {boolean} options.closeOnClickOutside - Whether to close on outside click (default: true)
14
+ * @param {boolean} options.closeOnEscape - Whether to close on escape key (default: true)
15
+ * @param {string} options.keyCodeForClose - Key code for closing (ignored, for compatibility only)
16
+ * @param {boolean} options.willUnmount - Unmount callback (ignored, for compatibility only)
17
+ * @param {boolean} options.afterClose - After close callback (ignored, for compatibility only)
18
+ * @param {boolean} options.onClickOutside - On click outside callback (ignored, for compatibility only)
19
+ * @param {boolean} options.onKeypressEscape - On keypress escape callback (ignored, for compatibility only)
20
+ * @param {Object} options.overlayClassName - Overlay class name (ignored, for compatibility only)
21
+ * @param {Object} options.overlayStyle - Overlay style (ignored, for compatibility only)
22
+ * @param {Object} options.contentClassName - Content class name (ignored, for compatibility only)
23
+ * @param {Object} options.contentStyle - Content style (ignored, for compatibility only)
24
+ * @param {Object} options.bodyClassName - Body class name (ignored, for compatibility only)
25
+ * @param {Object} options.titleClassName - Title class name (ignored, for compatibility only)
26
+ * @param {Object} options.titleStyle - Title style (ignored, for compatibility only)
27
+ * @param {Object} options.messageClassName - Message class name (ignored, for compatibility only)
28
+ * @param {Object} options.messageStyle - Message style (ignored, for compatibility only)
29
+ * @param {Object} options.buttonClassName - Button class name (ignored, for compatibility only)
30
+ * @param {Object} options.buttonStyle - Button style (ignored, for compatibility only)
31
+ * @param {Object} options.childrenClassName - Children class name (ignored, for compatibility only)
32
+ */
33
+ export const confirmDialog = (options) => {
34
+ const {
35
+ title = '',
36
+ message = '',
37
+ buttons = [],
38
+ closeOnClickOutside = true,
39
+ closeOnEscape = true,
40
+ data = null, // Optional data object from the selected row
41
+ } = options;
42
+
43
+ // Find Yes and No buttons if they exist
44
+ const yesButton = buttons.find((btn) => btn.label === 'Yes');
45
+ const noButton = buttons.find((btn) => btn.label === 'No');
46
+
47
+ // Default button text
48
+ const confirmButtonText = yesButton ? yesButton.label : 'Yes';
49
+ const cancelButtonText = noButton ? noButton.label : 'No';
50
+
51
+ // Enhanced message with item details if available
52
+ let enhancedMessage = message;
53
+ let itemDetails = '';
54
+
55
+ // Extract meaningful information from the data object if available
56
+ if (data) {
57
+ // Common identifiers that might be present in data objects
58
+ const identifiers = [
59
+ 'name',
60
+ 'label',
61
+ 'title',
62
+ 'email',
63
+ 'username',
64
+ 'id',
65
+ 'code',
66
+ 'reference',
67
+ ];
68
+
69
+ // Find the first available identifier
70
+ for (const id of identifiers) {
71
+ if (
72
+ data[id] &&
73
+ typeof data[id] === 'string' &&
74
+ data[id].trim() !== ''
75
+ ) {
76
+ itemDetails = data[id];
77
+ break;
78
+ }
79
+ }
80
+
81
+ // If we found an identifier, enhance the message
82
+ if (itemDetails && !message.includes(itemDetails)) {
83
+ // If the message already contains a question mark, add the details before it
84
+ if (message.includes('?')) {
85
+ enhancedMessage = message.replace('?', `"${itemDetails}"?`);
86
+ } else {
87
+ // Otherwise, append the details
88
+ enhancedMessage = `${message} "${itemDetails}"`;
89
+ }
90
+ }
91
+ }
92
+
93
+ // Configure SweetAlert2 options
94
+ const swalOptions = {
95
+ title: title,
96
+ html: enhancedMessage,
97
+ icon: 'question',
98
+ showCancelButton: true,
99
+ confirmButtonText: confirmButtonText,
100
+ cancelButtonText: cancelButtonText,
101
+ confirmButtonColor: 'var(--primary-color, #4f46e5)',
102
+ cancelButtonColor: '#6b7280',
103
+ allowOutsideClick: closeOnClickOutside,
104
+ allowEscapeKey: closeOnEscape,
105
+ reverseButtons: true,
106
+ focusCancel: false,
107
+ buttonsStyling: true,
108
+ showClass: {
109
+ popup: 'swal2-show',
110
+ backdrop: 'swal2-backdrop-show',
111
+ icon: 'swal2-icon-show',
112
+ },
113
+ customClass: {
114
+ container: 'swal2-container',
115
+ popup: 'swal2-popup',
116
+ header: 'swal2-header',
117
+ title: 'swal2-title',
118
+ closeButton: 'swal2-close-button',
119
+ icon: 'swal2-icon',
120
+ image: 'swal2-image',
121
+ htmlContainer: 'swal2-html-container',
122
+ input: 'swal2-input',
123
+ inputLabel: 'swal2-input-label',
124
+ validationMessage: 'swal2-validation-message',
125
+ actions: 'swal2-actions',
126
+ confirmButton: 'swal2-confirm',
127
+ denyButton: 'swal2-deny',
128
+ cancelButton: 'swal2-cancel',
129
+ loader: 'swal2-loader',
130
+ footer: 'swal2-footer',
131
+ },
132
+ };
133
+
134
+ // Show SweetAlert2 dialog
135
+ Swal.fire(swalOptions).then((result) => {
136
+ if (
137
+ result.isConfirmed &&
138
+ yesButton &&
139
+ typeof yesButton.onClick === 'function'
140
+ ) {
141
+ yesButton.onClick();
142
+ } else if (
143
+ result.dismiss === Swal.DismissReason.cancel &&
144
+ noButton &&
145
+ typeof noButton.onClick === 'function'
146
+ ) {
147
+ noButton.onClick();
148
+ }
149
+ });
150
+ };
151
+
152
+ // Export as default for compatibility with react-confirm-alert
153
+ export default {
154
+ confirmAlert: confirmDialog,
155
+ };