@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 +1 -2
- package/src/components/cms/DataGrid.jsx +68 -5
- package/src/components/cms/DropZone.jsx +3 -4
- package/src/components/cms/Form.jsx +3 -4
- package/src/components/cms/generic/CmsDetail.jsx +0 -2
- package/src/components/crm/DataGrid.jsx +214 -42
- package/src/components/crm/Field.jsx +1 -1
- package/src/components/crm/Form.jsx +3 -3
- package/src/components/crm/generic/GenericDashboard.jsx +3 -3
- package/src/components/crm/generic/GenericDetail.jsx +3 -3
- package/src/components/crm/generic/GenericDynamic.jsx +3 -3
- package/src/components/crm/generic/GenericEditableTable.jsx +3 -4
- package/src/components/crm/generic/GenericFormBuilder.jsx +3 -3
- package/src/components/crm/generic/styles/SweetAlertCustom.css +27 -3
- package/src/components/utils/ConfirmDialog.js +155 -0
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 '
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
param.
|
|
518
|
-
|
|
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
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
552
|
+
if (isSelectedAlready) {
|
|
553
|
+
setSelected({});
|
|
554
|
+
} else {
|
|
555
|
+
setSelected((prevSelected) => ({
|
|
556
|
+
...prevSelected,
|
|
557
|
+
[selectedKey]:
|
|
558
|
+
param.selected[selectedKey],
|
|
559
|
+
}));
|
|
560
|
+
}
|
|
561
|
+
}
|
|
527
562
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
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
|
|
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
|
-
|
|
622
|
-
|
|
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
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1486
|
-
if (s
|
|
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 ||
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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:
|
|
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
|
+
};
|