@visns-studio/visns-components 5.6.14 → 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.14",
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';
@@ -493,43 +492,15 @@ const DataGrid = forwardRef(
493
492
 
494
493
  const handleTimer = async (id, key, data) => {
495
494
  try {
496
- // Special handling for galvanizing timers to generate dip numbers
497
- if (
498
- key === 'galvanizing_start_1' ||
499
- key === 'galvanizing_start_2'
500
- ) {
501
- // For galvanizing_start_1 and galvanizing_start_2, we need to generate dip numbers
502
- const payload = {
503
- [key]: moment().toDate(),
504
- timer_type: key, // Pass the timer type to the backend
505
- };
506
-
507
- const res = await CustomFetch(
508
- `${form.url}/${id}/timer`,
509
- 'PUT',
510
- payload
511
- );
495
+ const res = await CustomFetch(`${form.url}/${id}`, 'PUT', {
496
+ [key]: moment().toDate(),
497
+ });
512
498
 
513
- if (res.data.error === '') {
514
- toast.success(
515
- 'Timer has been updated and dip number generated.'
516
- );
517
- handleReload();
518
- } else {
519
- toast.error(res.data.error);
520
- }
499
+ if (res.data.error === '') {
500
+ toast.success('Timer has been updated.');
501
+ handleReload();
521
502
  } else {
522
- // Normal timer handling for other stages
523
- const res = await CustomFetch(`${form.url}/${id}`, 'PUT', {
524
- [key]: moment().toDate(),
525
- });
526
-
527
- if (res.data.error === '') {
528
- toast.success('Timer has been updated.');
529
- handleReload();
530
- } else {
531
- toast.error(res.data.error);
532
- }
503
+ toast.error(res.data.error);
533
504
  }
534
505
  } catch (error) {
535
506
  console.info(error);
@@ -538,32 +509,74 @@ const DataGrid = forwardRef(
538
509
 
539
510
  const handleSelectionChange = useCallback(
540
511
  (param) => {
541
- if (param.selected === true) {
542
- const s = {};
543
-
544
- param.data.forEach((obj) => {
545
- s[obj.id] = obj;
546
- });
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
+ );
547
551
 
548
- setSelected(s);
549
- } else if (typeof param.selected === 'object') {
550
- // Assuming param.selected is an object where keys are the ids of the selections
551
- const selectedKey = Object.keys(param.selected)[0]; // Get the key of the selected object
552
- const isSelectedAlready =
553
- 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
+ }
554
562
 
555
- if (isSelectedAlready) {
556
- // If the key already exists, reset selected
557
- setSelected({});
558
- } else {
559
- // If it does not exist, update selected with the new object
560
- setSelected((prevSelected) => ({
561
- ...prevSelected,
562
- [selectedKey]: param.selected[selectedKey],
563
- }));
564
- }
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
+ });
565
578
  } else {
566
- // Handle other cases as needed
579
+ // Handle deselection directly without confirmation
567
580
  setSelected(param.selected);
568
581
  }
569
582
  },
@@ -645,18 +658,86 @@ const DataGrid = forwardRef(
645
658
  case 'file':
646
659
  case 'image':
647
660
  case 'undo':
648
- CustomFetch(s.url, 'POST', { id: d[s.key] }, (result) => {
649
- 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
+ ],
650
698
  });
651
699
  break;
652
700
  case 'clone':
653
701
  if (s.url && s.url !== '') {
654
- const cloneUrl = `${s.url}/${d[s.key]}/clone`;
655
-
656
- CustomFetch(cloneUrl, 'POST', {}, (result) => {
657
- 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
+ }
658
711
 
659
- 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
+ ],
660
741
  });
661
742
  }
662
743
  break;
@@ -748,9 +829,10 @@ const DataGrid = forwardRef(
748
829
  }?`;
749
830
  }
750
831
 
751
- confirmAlert({
832
+ confirmDialog({
752
833
  title: 'Delete Item',
753
834
  message: confirmMessage,
835
+ data: d, // Pass the row data
754
836
  buttons: [
755
837
  {
756
838
  label: 'Yes',
@@ -889,9 +971,10 @@ const DataGrid = forwardRef(
889
971
  modalOpen('update', d.id);
890
972
  break;
891
973
  default:
892
- confirmAlert({
974
+ confirmDialog({
893
975
  title: s.title,
894
976
  message: '',
977
+ data: d, // Pass the row data
895
978
  buttons: [
896
979
  {
897
980
  label: 'Yes',
@@ -1509,11 +1592,71 @@ const DataGrid = forwardRef(
1509
1592
  e.preventDefault();
1510
1593
  e.stopPropagation();
1511
1594
 
1512
- // Ensure both s and d are defined before calling handleSettingClick
1513
- if (s && d) {
1514
- handleSettingClick(s, d);
1515
- } else {
1595
+ // Ensure both s and d are defined before proceeding
1596
+ if (!s || !d) {
1516
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);
1517
1660
  }
1518
1661
  };
1519
1662
 
@@ -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
+ };