qantler-flaz-dataview 1.0.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.
Files changed (43) hide show
  1. package/package.json +11 -0
  2. package/src/FlazDataView.css +4423 -0
  3. package/src/FlazDataView.jsx +2943 -0
  4. package/src/FlazDataViewList.jsx +787 -0
  5. package/src/MdtActiveFilterBar.jsx +263 -0
  6. package/src/MdtBulkSelectionBar.jsx +91 -0
  7. package/src/MdtColumnPickerPopup.jsx +59 -0
  8. package/src/MdtColumnVisibilityList.jsx +38 -0
  9. package/src/MdtCreateViewModal.jsx +280 -0
  10. package/src/MdtDatetimeValueEditor.jsx +259 -0
  11. package/src/MdtDeleteViewConfirmModal.jsx +83 -0
  12. package/src/MdtDisplayPopup.jsx +170 -0
  13. package/src/MdtEmptyState.jsx +20 -0
  14. package/src/MdtFilterColumnPicker.jsx +66 -0
  15. package/src/MdtFilterOperatorDropdown.jsx +58 -0
  16. package/src/MdtFilterSection.jsx +73 -0
  17. package/src/MdtFilterToolbar.jsx +81 -0
  18. package/src/MdtInlineField.css +221 -0
  19. package/src/MdtInlineField.jsx +187 -0
  20. package/src/MdtInlineFieldRow.jsx +71 -0
  21. package/src/MdtNoDataIllustration.jsx +64 -0
  22. package/src/MdtPopupChecklist.jsx +70 -0
  23. package/src/MdtRowActionsMenu.jsx +281 -0
  24. package/src/MdtSidebarNav.jsx +26 -0
  25. package/src/MdtTabsRow.jsx +354 -0
  26. package/src/MdtTabsSection.jsx +35 -0
  27. package/src/MdtTruncateWithTooltip.jsx +82 -0
  28. package/src/MdtValueEditorPopup.jsx +950 -0
  29. package/src/filterDisplayUtils.jsx +96 -0
  30. package/src/mdtClientSideFilter.js +68 -0
  31. package/src/mdtColumnEditUtils.js +403 -0
  32. package/src/mdtDateFilterUtils.js +135 -0
  33. package/src/mdtExportUtils.js +234 -0
  34. package/src/mdtFilterUtils.js +56 -0
  35. package/src/mdtInlineFieldDisplay.js +66 -0
  36. package/src/mdtMobilePopupPosition.js +107 -0
  37. package/src/mdtMultiSelectDisplay.jsx +279 -0
  38. package/src/mdtSavedViewFilterMatch.js +154 -0
  39. package/src/mdtTabChangeUtils.js +12 -0
  40. package/src/mdtTabStatusRules.js +111 -0
  41. package/src/mdtTableConstants.js +2 -0
  42. package/src/mdtTooltipFormat.js +44 -0
  43. package/src/renderInlineFieldValue.jsx +183 -0
@@ -0,0 +1,280 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+ import { createPortal } from "react-dom";
3
+ import { Layout, Loader2, Menu, SlidersHorizontal } from "lucide-react";
4
+ import MdtDisplayPopup from "./MdtDisplayPopup";
5
+ import MdtDeleteViewConfirmModal from "./MdtDeleteViewConfirmModal";
6
+
7
+ const VIEW_OPTIONS = [
8
+ { id: "list", label: "List", icon: Menu },
9
+ { id: "table", label: "Table", icon: Layout },
10
+ ];
11
+
12
+ const MdtCreateViewModal = ({
13
+ open,
14
+ onClose,
15
+ onCreate,
16
+ onDelete,
17
+ mode = "create",
18
+ editingView = null,
19
+ initialViewMode = "table",
20
+ defaultName = "",
21
+ filterBar = null,
22
+ displayPopupProps = null,
23
+ }) => {
24
+ const isEdit = mode === "edit";
25
+ const [name, setName] = useState(defaultName || "Untitled");
26
+ const [description, setDescription] = useState("");
27
+ const [viewMode, setViewMode] = useState(initialViewMode);
28
+ const [viewMenuOpen, setViewMenuOpen] = useState(false);
29
+ const [displayMenuOpen, setDisplayMenuOpen] = useState(false);
30
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
31
+ const [isSaving, setIsSaving] = useState(false);
32
+ const [isDeleting, setIsDeleting] = useState(false);
33
+ const [isPublic, setIsPublic] = useState(false);
34
+ const isBusy = isSaving || isDeleting;
35
+ const viewMenuRef = useRef(null);
36
+ const displayMenuRef = useRef(null);
37
+
38
+ useEffect(() => {
39
+ if (!open) {
40
+ setIsSaving(false);
41
+ setIsDeleting(false);
42
+ return;
43
+ }
44
+ setName(editingView?.name ?? defaultName ?? "Untitled");
45
+ setDescription(editingView?.description ?? "");
46
+ const modeValue = editingView?.viewMode ?? initialViewMode;
47
+ setViewMode(modeValue === "list" ? "list" : "table");
48
+ setIsPublic(editingView?.isPublic ?? false);
49
+ setViewMenuOpen(false);
50
+ setDisplayMenuOpen(false);
51
+ setShowDeleteConfirm(false);
52
+ setIsSaving(false);
53
+ setIsDeleting(false);
54
+ }, [open, editingView, defaultName, initialViewMode]);
55
+
56
+ useEffect(() => {
57
+ if (!open || showDeleteConfirm) return undefined;
58
+ const onKey = (e) => {
59
+ if (e.key === "Escape" && !isBusy) onClose();
60
+ };
61
+ document.addEventListener("keydown", onKey);
62
+ return () => document.removeEventListener("keydown", onKey);
63
+ }, [open, showDeleteConfirm, onClose, isBusy]);
64
+
65
+ useEffect(() => {
66
+ if (!viewMenuOpen && !displayMenuOpen) return undefined;
67
+ const handleOutside = (e) => {
68
+ if (viewMenuOpen && viewMenuRef.current && !viewMenuRef.current.contains(e.target)) {
69
+ setViewMenuOpen(false);
70
+ }
71
+ if (displayMenuOpen && displayMenuRef.current && !displayMenuRef.current.contains(e.target)) {
72
+ setDisplayMenuOpen(false);
73
+ }
74
+ };
75
+ document.addEventListener("mousedown", handleOutside, true);
76
+ return () => document.removeEventListener("mousedown", handleOutside, true);
77
+ }, [viewMenuOpen, displayMenuOpen]);
78
+
79
+ if (!open) return null;
80
+
81
+ const activeView = VIEW_OPTIONS.find((v) => v.id === viewMode) || VIEW_OPTIONS[1];
82
+ const ActiveViewIcon = activeView.icon;
83
+
84
+ const handleSubmit = async () => {
85
+ if (isBusy || !onCreate) return;
86
+ setIsSaving(true);
87
+ try {
88
+ await onCreate({
89
+ name: name.trim() || "Untitled",
90
+ description: description.trim(),
91
+ viewMode,
92
+ isPublic,
93
+ });
94
+ } catch {
95
+ // Parent logs the error; keep modal open for retry.
96
+ setIsSaving(false);
97
+ }
98
+ };
99
+
100
+ const handleDeleteConfirm = async () => {
101
+ if (isBusy || !onDelete) return;
102
+ setIsDeleting(true);
103
+ try {
104
+ await onDelete();
105
+ setShowDeleteConfirm(false);
106
+ } catch {
107
+ // Parent logs the error; keep confirm open for retry.
108
+ setIsDeleting(false);
109
+ }
110
+ };
111
+
112
+ return createPortal(
113
+ <div
114
+ className="mdt-cv-overlay"
115
+ onMouseDown={(e) => {
116
+ if (isBusy) return;
117
+ if (e.target === e.currentTarget) onClose();
118
+ }}
119
+ >
120
+ <div
121
+ className="mdt-cv-modal"
122
+ role="dialog"
123
+ aria-modal="true"
124
+ aria-labelledby="mdt-cv-title"
125
+ onMouseDown={(e) => e.stopPropagation()}
126
+ >
127
+ <h2 id="mdt-cv-title" className="mdt-cv-heading">
128
+ {isEdit ? "Update View" : "Create View"}
129
+ </h2>
130
+
131
+ <div className="mdt-cv-body">
132
+ <input
133
+ type="text"
134
+ className="mdt-cv-name-input"
135
+ value={name}
136
+ onChange={(e) => setName(e.target.value)}
137
+ placeholder="Untitled"
138
+ />
139
+
140
+ <textarea
141
+ className="mdt-cv-description"
142
+ placeholder="Description"
143
+ value={description}
144
+ onChange={(e) => setDescription(e.target.value)}
145
+ rows={4}
146
+ />
147
+
148
+ <div className="mdt-cv-view-row">
149
+ <div className="mdt-cv-view-picker" ref={viewMenuRef}>
150
+ <button
151
+ type="button"
152
+ className="mdt-cv-view-btn"
153
+ onClick={() => {
154
+ setDisplayMenuOpen(false);
155
+ setViewMenuOpen((v) => !v);
156
+ }}
157
+ >
158
+ <ActiveViewIcon size={11} />
159
+ <span>{activeView.label}</span>
160
+ </button>
161
+ {viewMenuOpen && (
162
+ <div className="mdt-cv-view-menu">
163
+ {VIEW_OPTIONS.map((opt) => {
164
+ const Icon = opt.icon;
165
+ const selected = viewMode === opt.id;
166
+ return (
167
+ <button
168
+ key={opt.id}
169
+ type="button"
170
+ className={`mdt-cv-view-option${selected ? " mdt-cv-view-option--selected" : ""}`}
171
+ onClick={() => {
172
+ setViewMode(opt.id);
173
+ setViewMenuOpen(false);
174
+ }}
175
+ >
176
+ <Icon size={11} />
177
+ <span>{opt.label}</span>
178
+ </button>
179
+ );
180
+ })}
181
+ </div>
182
+ )}
183
+ </div>
184
+
185
+ {displayPopupProps && (
186
+ <div className="mdt-cv-view-picker mdt-cv-display-picker" ref={displayMenuRef}>
187
+ <button
188
+ type="button"
189
+ className={`mdt-cv-view-btn mdt-cv-display-btn${displayMenuOpen ? " mdt-cv-display-btn--open" : ""}`}
190
+ title="Display"
191
+ aria-label="Display"
192
+ onClick={() => {
193
+ setViewMenuOpen(false);
194
+ setDisplayMenuOpen((v) => !v);
195
+ }}
196
+ >
197
+ <SlidersHorizontal size={11} />
198
+ </button>
199
+ {displayMenuOpen && (
200
+ <MdtDisplayPopup
201
+ {...displayPopupProps}
202
+ viewMode={viewMode}
203
+ className="mdt-cv-display-popup"
204
+ />
205
+ )}
206
+ </div>
207
+ )}
208
+ </div>
209
+
210
+ {filterBar && (
211
+ <div className="mdt-cv-filter-slot">
212
+ {filterBar}
213
+ </div>
214
+ )}
215
+
216
+ <label className="mdt-cv-public-toggle">
217
+ <input
218
+ type="checkbox"
219
+ checked={isPublic}
220
+ onChange={(e) => setIsPublic(e.target.checked)}
221
+ />
222
+ <span>Visible to All</span>
223
+ </label>
224
+ </div>
225
+
226
+ <div className={`mdt-cv-footer${isEdit ? " mdt-cv-footer--edit" : ""}`}>
227
+ {isEdit && onDelete && (
228
+ <button
229
+ type="button"
230
+ className="mdt-cv-btn-delete"
231
+ disabled={isBusy}
232
+ onClick={() => setShowDeleteConfirm(true)}
233
+ >
234
+ Delete
235
+ </button>
236
+ )}
237
+ <div className="mdt-cv-footer-actions">
238
+ <button
239
+ type="button"
240
+ className="mdt-cv-btn-cancel"
241
+ disabled={isBusy}
242
+ onClick={onClose}
243
+ >
244
+ Cancel
245
+ </button>
246
+ <button
247
+ type="button"
248
+ className="mdt-cv-btn-create"
249
+ disabled={isBusy}
250
+ onClick={handleSubmit}
251
+ >
252
+ {isSaving && <Loader2 size={14} className="mdt-cv-btn-spinner" aria-hidden />}
253
+ {isSaving
254
+ ? isEdit
255
+ ? "Updating..."
256
+ : "Creating..."
257
+ : isEdit
258
+ ? "Update"
259
+ : "Create"}
260
+ </button>
261
+ </div>
262
+ </div>
263
+ </div>
264
+
265
+ <MdtDeleteViewConfirmModal
266
+ open={showDeleteConfirm}
267
+ viewName={editingView?.name || name}
268
+ isDeleting={isDeleting}
269
+ onCancel={() => {
270
+ if (isDeleting) return;
271
+ setShowDeleteConfirm(false);
272
+ }}
273
+ onConfirm={handleDeleteConfirm}
274
+ />
275
+ </div>,
276
+ document.body,
277
+ );
278
+ };
279
+
280
+ export default MdtCreateViewModal;
@@ -0,0 +1,259 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ import moment from "moment";
3
+ import MdtValueEditorPopup from "./MdtValueEditorPopup";
4
+ import { EDIT_MODE } from "./mdtColumnEditUtils";
5
+ import { isDatetimeBetweenValue } from "./mdtDateFilterUtils";
6
+ import "../JobApplications/JobApplications.css";
7
+
8
+ const HOURS = Array.from({ length: 12 }, (_, index) =>
9
+ String(index + 1).padStart(2, "0"),
10
+ );
11
+ const MINUTES = Array.from({ length: 60 }, (_, index) =>
12
+ String(index).padStart(2, "0"),
13
+ );
14
+
15
+ export const parseDatetimeValue = (value) => {
16
+ if (!value) {
17
+ return { date: "", hour: "12", minute: "00", period: "AM" };
18
+ }
19
+
20
+ const parsed = moment(value);
21
+ if (!parsed.isValid()) {
22
+ return { date: "", hour: "12", minute: "00", period: "AM" };
23
+ }
24
+
25
+ return {
26
+ date: parsed.format("YYYY-MM-DD"),
27
+ hour: parsed.format("hh"),
28
+ minute: parsed.format("mm"),
29
+ period: parsed.format("A"),
30
+ };
31
+ };
32
+
33
+ export const buildDatetimeValue = ({ date, hour, minute, period }) => {
34
+ if (!date) return "";
35
+
36
+ const parsed = moment(`${date} ${hour}:${minute} ${period}`, "YYYY-MM-DD hh:mm A");
37
+ if (!parsed.isValid()) return "";
38
+
39
+ return parsed.format("YYYY-MM-DDTHH:mm");
40
+ };
41
+
42
+ export const formatDatetimeFilterDisplay = (value) => {
43
+ if (!value) return "";
44
+
45
+ const parsed = moment(value);
46
+ return parsed.isValid() ? parsed.format("DD MMM YYYY, h:mm A") : "";
47
+ };
48
+
49
+ const TimeColumn = ({ items, value, onChange }) => {
50
+ const columnRef = useRef(null);
51
+
52
+ useEffect(() => {
53
+ const selected = columnRef.current?.querySelector(
54
+ ".ja-interview-datetime-time__option--selected",
55
+ );
56
+ selected?.scrollIntoView({ block: "center" });
57
+ }, [value]);
58
+
59
+ return (
60
+ <div ref={columnRef} className="ja-interview-datetime-time__column">
61
+ {items.map((item) => (
62
+ <button
63
+ key={item}
64
+ type="button"
65
+ className={`ja-interview-datetime-time__option${
66
+ value === item ? " ja-interview-datetime-time__option--selected" : ""
67
+ }`}
68
+ onMouseDown={(event) => event.preventDefault()}
69
+ onClick={() => onChange(item)}
70
+ >
71
+ {item}
72
+ </button>
73
+ ))}
74
+ </div>
75
+ );
76
+ };
77
+
78
+ const MdtDatetimeValueEditor = ({
79
+ value,
80
+ onApply,
81
+ onCancel,
82
+ className = "",
83
+ columnLabel = "Date & Time",
84
+ filterOperator = "is",
85
+ isFilterMode = false,
86
+ min,
87
+ }) => {
88
+ const isRangeFilter = isFilterMode && filterOperator === "between";
89
+ const [rangeStart, setRangeStart] = useState(null);
90
+ const [pickingEnd, setPickingEnd] = useState(false);
91
+ const [draft, setDraft] = useState(parseDatetimeValue(""));
92
+ const [saveError, setSaveError] = useState("");
93
+
94
+ useEffect(() => {
95
+ if (isRangeFilter && isDatetimeBetweenValue(value)) {
96
+ setRangeStart(value[0]);
97
+ setPickingEnd(true);
98
+ setDraft(parseDatetimeValue(value[1]));
99
+ setSaveError("");
100
+ return;
101
+ }
102
+
103
+ if (isRangeFilter && value) {
104
+ setRangeStart(Array.isArray(value) ? value[0] : value);
105
+ setPickingEnd(true);
106
+ setDraft(parseDatetimeValue(""));
107
+ setSaveError("");
108
+ return;
109
+ }
110
+
111
+ setRangeStart(null);
112
+ setPickingEnd(false);
113
+ const nextValue = Array.isArray(value) ? value[0] : value;
114
+ setDraft(parseDatetimeValue(nextValue));
115
+ setSaveError("");
116
+ }, [value, isRangeFilter]);
117
+
118
+ const handleSave = () => {
119
+ const nextValue = buildDatetimeValue(draft);
120
+ if (!nextValue) {
121
+ setSaveError("Select a date and time.");
122
+ return;
123
+ }
124
+
125
+ const parsedNext = moment(nextValue, "YYYY-MM-DDTHH:mm", true);
126
+ const parsedMin = min ? moment(min, "YYYY-MM-DDTHH:mm", true) : null;
127
+ if (parsedMin?.isValid() && parsedNext.isBefore(parsedMin)) {
128
+ setSaveError("Date and time must be on or after the minimum allowed time.");
129
+ return;
130
+ }
131
+
132
+ if (isRangeFilter) {
133
+ if (!pickingEnd || !rangeStart) {
134
+ setRangeStart(nextValue);
135
+ setPickingEnd(true);
136
+ setDraft(parseDatetimeValue(""));
137
+ setSaveError("");
138
+ return;
139
+ }
140
+
141
+ const startMoment = moment(rangeStart, "YYYY-MM-DDTHH:mm", true);
142
+ const endMoment = parsedNext;
143
+ const [start, end] = endMoment.isBefore(startMoment)
144
+ ? [nextValue, rangeStart]
145
+ : [rangeStart, nextValue];
146
+
147
+ setSaveError("");
148
+ onApply?.([start, end]);
149
+ return;
150
+ }
151
+
152
+ setSaveError("");
153
+ onApply?.(nextValue);
154
+ };
155
+
156
+ const popupColumn = {
157
+ accessorKey: columnLabel,
158
+ header: columnLabel,
159
+ editVariant: "date",
160
+ };
161
+
162
+ const primaryLabel = isRangeFilter
163
+ ? pickingEnd && rangeStart
164
+ ? "Apply"
165
+ : "Next"
166
+ : isFilterMode
167
+ ? "Apply"
168
+ : "Save";
169
+
170
+ return (
171
+ <div
172
+ className={`ja-interview-datetime-popup mdt-datetime-value-editor ${className}`.trim()}
173
+ onMouseDown={(event) => event.stopPropagation()}
174
+ onClick={(event) => event.stopPropagation()}
175
+ >
176
+ {isRangeFilter ? (
177
+ <p className="ja-interview-datetime-range-hint">
178
+ {pickingEnd && rangeStart
179
+ ? `End: after ${formatDatetimeFilterDisplay(rangeStart)}`
180
+ : "Start date and time"}
181
+ </p>
182
+ ) : null}
183
+ <div className="ja-interview-datetime-body">
184
+ <div className="ja-interview-datetime-calendar">
185
+ <MdtValueEditorPopup
186
+ className="cand-edit-popup-override"
187
+ column={popupColumn}
188
+ mode={EDIT_MODE.INLINE}
189
+ value={draft.date}
190
+ showActions={false}
191
+ onApply={(dateStr) => {
192
+ setDraft((prev) => ({ ...prev, date: dateStr || "" }));
193
+ }}
194
+ />
195
+ </div>
196
+ <div className="ja-interview-datetime-time">
197
+ <TimeColumn
198
+ items={HOURS}
199
+ value={draft.hour}
200
+ onChange={(hour) => {
201
+ setDraft((prev) => ({ ...prev, hour }));
202
+ }}
203
+ />
204
+ <TimeColumn
205
+ items={MINUTES}
206
+ value={draft.minute}
207
+ onChange={(minute) => {
208
+ setDraft((prev) => ({ ...prev, minute }));
209
+ }}
210
+ />
211
+ <TimeColumn
212
+ items={["AM", "PM"]}
213
+ value={draft.period}
214
+ onChange={(period) => {
215
+ setDraft((prev) => ({ ...prev, period }));
216
+ }}
217
+ />
218
+ </div>
219
+ </div>
220
+ <div className="ja-interview-datetime-footer">
221
+ {saveError ? (
222
+ <p className="ja-interview-datetime-footer__error">{saveError}</p>
223
+ ) : null}
224
+ <div className="ja-interview-datetime-footer__actions">
225
+ <button
226
+ type="button"
227
+ className="mdt-ghost"
228
+ onMouseDown={(event) => event.preventDefault()}
229
+ onClick={() => {
230
+ if (isFilterMode) {
231
+ onApply?.(null);
232
+ } else {
233
+ onCancel?.();
234
+ }
235
+ }}
236
+ >
237
+ {isFilterMode ? "Clear" : "Cancel"}
238
+ </button>
239
+ <button
240
+ type="button"
241
+ className="mdt-primary"
242
+ disabled={!draft.date}
243
+ onMouseDown={(event) => {
244
+ event.preventDefault();
245
+ event.stopPropagation();
246
+ if (draft.date) {
247
+ handleSave();
248
+ }
249
+ }}
250
+ >
251
+ {primaryLabel}
252
+ </button>
253
+ </div>
254
+ </div>
255
+ </div>
256
+ );
257
+ };
258
+
259
+ export default MdtDatetimeValueEditor;
@@ -0,0 +1,83 @@
1
+ import React, { useEffect } from "react";
2
+ import { createPortal } from "react-dom";
3
+ import { Loader2, TriangleAlert } from "lucide-react";
4
+
5
+ const MdtDeleteViewConfirmModal = ({
6
+ open,
7
+ viewName = "",
8
+ isDeleting = false,
9
+ onCancel,
10
+ onConfirm,
11
+ }) => {
12
+ useEffect(() => {
13
+ if (!open) return undefined;
14
+ const onKey = (e) => {
15
+ if (e.key === "Escape" && !isDeleting) onCancel?.();
16
+ };
17
+ document.addEventListener("keydown", onKey);
18
+ return () => document.removeEventListener("keydown", onKey);
19
+ }, [open, onCancel, isDeleting]);
20
+
21
+ if (!open) return null;
22
+
23
+ const displayName = viewName?.trim() || "Untitled";
24
+
25
+ return createPortal(
26
+ <div
27
+ className="mdt-del-confirm-overlay"
28
+ onMouseDown={(e) => {
29
+ if (isDeleting) return;
30
+ if (e.target === e.currentTarget) onCancel?.();
31
+ }}
32
+ >
33
+ <div
34
+ className="mdt-del-confirm-modal"
35
+ role="alertdialog"
36
+ aria-modal="true"
37
+ aria-labelledby="mdt-del-confirm-title"
38
+ aria-describedby="mdt-del-confirm-desc"
39
+ onMouseDown={(e) => e.stopPropagation()}
40
+ >
41
+ <div className="mdt-del-confirm-body">
42
+ <span className="mdt-del-confirm-icon-wrap" aria-hidden="true">
43
+ <TriangleAlert size={20} strokeWidth={2} />
44
+ </span>
45
+ <div className="mdt-del-confirm-content">
46
+ <h2 id="mdt-del-confirm-title" className="mdt-del-confirm-title">
47
+ Delete View
48
+ </h2>
49
+ <p id="mdt-del-confirm-desc" className="mdt-del-confirm-desc">
50
+ Are you sure you want to delete view{" "}
51
+ <strong>{displayName}</strong>? All filters and display settings for
52
+ this view will be permanently removed. This action cannot be undone.
53
+ </p>
54
+ </div>
55
+ </div>
56
+ <div className="mdt-del-confirm-footer">
57
+ <button
58
+ type="button"
59
+ className="mdt-del-confirm-btn-cancel"
60
+ disabled={isDeleting}
61
+ onClick={onCancel}
62
+ >
63
+ Cancel
64
+ </button>
65
+ <button
66
+ type="button"
67
+ className="mdt-del-confirm-btn-delete"
68
+ disabled={isDeleting}
69
+ onClick={onConfirm}
70
+ >
71
+ {isDeleting && (
72
+ <Loader2 size={14} className="mdt-cv-btn-spinner" aria-hidden />
73
+ )}
74
+ {isDeleting ? "Deleting..." : "Delete"}
75
+ </button>
76
+ </div>
77
+ </div>
78
+ </div>,
79
+ document.body,
80
+ );
81
+ };
82
+
83
+ export default MdtDeleteViewConfirmModal;