@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 +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 +216 -73
- 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';
|
|
@@ -493,43 +492,15 @@ const DataGrid = forwardRef(
|
|
|
493
492
|
|
|
494
493
|
const handleTimer = async (id, key, data) => {
|
|
495
494
|
try {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
-
|
|
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
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
param.
|
|
545
|
-
|
|
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
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
552
|
+
if (isSelectedAlready) {
|
|
553
|
+
setSelected({});
|
|
554
|
+
} else {
|
|
555
|
+
setSelected((prevSelected) => ({
|
|
556
|
+
...prevSelected,
|
|
557
|
+
[selectedKey]:
|
|
558
|
+
param.selected[selectedKey],
|
|
559
|
+
}));
|
|
560
|
+
}
|
|
561
|
+
}
|
|
554
562
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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
|
|
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
|
-
|
|
649
|
-
|
|
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
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1513
|
-
if (s
|
|
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
|
-
|
|
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
|
+
};
|