forked from openedx/frontend-app-authoring
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTypeXToConfirmModal.tsx
More file actions
125 lines (116 loc) · 3.46 KB
/
TypeXToConfirmModal.tsx
File metadata and controls
125 lines (116 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import React, { useEffect } from 'react';
import { Button, Card, Form, Icon, ModalDialog } from '@openedx/paragon';
import { WarningFilled } from '@openedx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
import messages from './messages';
interface TypeXToConfirmModalProps {
label: string;
bodyText: string | React.ReactNode;
confirmLabel: string;
cancelLabel: string;
X: string;
// any additional context that the caller wants to pass to the onConfirm callback; not a React context.
context?: Record<string, any> | null;
isOpen: boolean;
onConfirm: (context?: Record<string, any> | null) => void;
onCancel: () => void;
setContext?: (context: Record<string, any> | null) => void;
}
const TypeXToConfirmModal: React.FC<TypeXToConfirmModalProps> = ({
label,
X,
bodyText,
confirmLabel,
cancelLabel,
isOpen,
context,
onConfirm,
onCancel,
setContext,
}) => {
const [confirmedByTyping, setConfirmedByTyping] = React.useState(false);
const intl = useIntl();
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (!confirmedByTyping) { return; }
if (e.key === 'Enter') {
onConfirm(context);
}
};
const handleConfirm = () => {
if (!confirmedByTyping) { return; }
setConfirmedByTyping(false);
onConfirm(context);
};
const handleCancel = () => {
setConfirmedByTyping(false);
onCancel();
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.value === X) {
setConfirmedByTyping(true);
} else {
setConfirmedByTyping(false);
}
};
// Don't remove. This is necessary to prevent an old state from erroneously enabling the confirm button
useEffect(() => {
if (!isOpen) {
setConfirmedByTyping(false);
if (setContext) {
// reset onConfirm callback context when modal is closed
setContext(null);
}
}
}, [X, isOpen, context, setContext]);
return (
<ModalDialog
title={label}
isOpen={isOpen}
onClose={handleCancel}
isOverflowVisible
>
<ModalDialog.Header>
<ModalDialog.Title>{label}</ModalDialog.Title>
</ModalDialog.Header>
<ModalDialog.Body>
<Card className="bg-warning-100">
<Card.Section>
<div className="d-flex align-items-start mb-2">
<Icon src={WarningFilled} className="text-warning-500 mr-2" />
<div className="small">{bodyText}</div>
</div>
</Card.Section>
</Card>
<div className="mt-3">
<div>
{(() => {
const messageText = intl.formatMessage(messages.typeToConfirmInstruction, { X });
const parts = messageText.split(X);
return (
<>
{parts[0]}
<strong>{X}</strong>
{parts[1]}
</>
);
})()}
</div>
<Form.Control
onKeyDown={handleKeyDown}
onChange={handleChange}
className="mt-4"
/>
</div>
<ModalDialog.Footer>
<Button variant="tertiary" onClick={handleCancel}>
{cancelLabel}
</Button>
<Button onClick={handleConfirm} disabled={!confirmedByTyping} variant="danger">
{confirmLabel}
</Button>
</ModalDialog.Footer>
</ModalDialog.Body>
</ModalDialog>
);
};
export default React.memo(TypeXToConfirmModal);