|
| 1 | +import React, { useState, useRef } from 'react'; |
| 2 | +import PropTypes from 'prop-types'; |
| 3 | +import { FormattedMessage } from 'react-intl'; |
| 4 | +import { Row, Col, Modal, FormGroup, FormControl, FormLabel, Overlay, Popover } from 'react-bootstrap'; |
| 5 | + |
| 6 | +import Button, { TheButtonGroup } from '../../widgets/TheButton'; |
| 7 | +import InsetPanel from '../../widgets/InsetPanel'; |
| 8 | +import { BellIcon, CloseIcon, LoadingIcon, SendIcon, WarningIcon } from '../../icons'; |
| 9 | + |
| 10 | +const ExerciseButtons = ({ id, archivedAt = null, permissionHints = null, sendNotification }) => { |
| 11 | + const [message, setMessage] = useState(null); // null = dialog is hidden, string = message (and dialog is open) |
| 12 | + const [sendResult, setSendResult] = useState(null); // null = initial, true = pending, false = error, int = result |
| 13 | + // the sendResult holds, how many users were notified (-1 is server error) |
| 14 | + const buttonTarget = useRef(null); |
| 15 | + |
| 16 | + return !archivedAt && permissionHints && permissionHints.update ? ( |
| 17 | + <> |
| 18 | + <Row> |
| 19 | + <Col className="mb-3" xs={12} lg={true}> |
| 20 | + <TheButtonGroup></TheButtonGroup> |
| 21 | + </Col> |
| 22 | + |
| 23 | + <Col xs={12} lg="auto" className="mb-3"> |
| 24 | + <TheButtonGroup className="text-nowrap"> |
| 25 | + <Button |
| 26 | + variant={ |
| 27 | + sendResult === false || sendResult < 0 |
| 28 | + ? 'danger' |
| 29 | + : sendResult === null || sendResult === true |
| 30 | + ? 'warning' |
| 31 | + : 'success' |
| 32 | + } |
| 33 | + onClick={() => (sendResult !== null && sendResult !== true ? setSendResult(null) : setMessage(''))} |
| 34 | + disabled={sendResult !== null} |
| 35 | + ref={buttonTarget}> |
| 36 | + {sendResult === true ? <LoadingIcon gapRight /> : <BellIcon gapRight />} |
| 37 | + <FormattedMessage id="app.exercise.notificationButton" defaultMessage="Send Notification" /> |
| 38 | + </Button> |
| 39 | + </TheButtonGroup> |
| 40 | + |
| 41 | + <Overlay target={buttonTarget.current} show={sendResult !== null && sendResult !== true} placement="bottom"> |
| 42 | + {props => ( |
| 43 | + <Popover id={id} {...props}> |
| 44 | + <Popover.Title> |
| 45 | + {sendResult === false || sendResult < 0 ? ( |
| 46 | + <> |
| 47 | + <WarningIcon className="text-danger" gapRight /> |
| 48 | + <FormattedMessage |
| 49 | + id="app.exercise.notificationButton.failedMessage" |
| 50 | + defaultMessage="The operation has failed!" |
| 51 | + /> |
| 52 | + </> |
| 53 | + ) : sendResult === 0 ? ( |
| 54 | + <FormattedMessage |
| 55 | + id="app.exercise.notificationButton.noRecipients" |
| 56 | + defaultMessage="No recipients of the notification were found. Please note that the users may choose to ignore these notifications in their personal settings." |
| 57 | + /> |
| 58 | + ) : ( |
| 59 | + <FormattedMessage |
| 60 | + id="app.exercise.notificationButton.successMessage" |
| 61 | + defaultMessage="The notification was successfully sent to {sendResult} {sendResult, plural, one {user} other {users}}." |
| 62 | + values={{ sendResult }} |
| 63 | + /> |
| 64 | + )} |
| 65 | + </Popover.Title> |
| 66 | + <Popover.Content className="text-center"> |
| 67 | + <Button onClick={() => setSendResult(null)} size="xs" variant="success"> |
| 68 | + <FormattedMessage id="generic.acknowledge" defaultMessage="Acknowledge" /> |
| 69 | + </Button> |
| 70 | + </Popover.Content> |
| 71 | + </Popover> |
| 72 | + )} |
| 73 | + </Overlay> |
| 74 | + </Col> |
| 75 | + </Row> |
| 76 | + |
| 77 | + <Modal show={message !== null} backdrop="static" onHide={() => setMessage(null)} size="xl"> |
| 78 | + <Modal.Header closeButton> |
| 79 | + <Modal.Title> |
| 80 | + <FormattedMessage |
| 81 | + id="app.exercise.notificationModal.title" |
| 82 | + defaultMessage="Send a notification to teachers" |
| 83 | + /> |
| 84 | + </Modal.Title> |
| 85 | + </Modal.Header> |
| 86 | + |
| 87 | + <Modal.Body> |
| 88 | + <InsetPanel> |
| 89 | + <FormattedMessage |
| 90 | + id="app.exercise.notificationModal.explain" |
| 91 | + defaultMessage="A notification is sent by email to all group admins and supervisors who have assigned this exercise in their groups. Optionally, you may attach a custom message to the notification. If you leave the message empty, a generic notification informing that the exercise was changed will be sent." |
| 92 | + /> |
| 93 | + </InsetPanel> |
| 94 | + |
| 95 | + <FormGroup controlId="message"> |
| 96 | + <FormLabel> |
| 97 | + <FormattedMessage id="generic.message" defaultMessage="Message" />: |
| 98 | + </FormLabel> |
| 99 | + <FormControl type="text" value={message || ''} onChange={ev => setMessage(ev.target.value)} /> |
| 100 | + </FormGroup> |
| 101 | + </Modal.Body> |
| 102 | + |
| 103 | + <Modal.Footer className="d-block text-center"> |
| 104 | + <TheButtonGroup className="text-nowrap"> |
| 105 | + <Button |
| 106 | + variant="success" |
| 107 | + onClick={() => { |
| 108 | + if (sendResult !== true) { |
| 109 | + setSendResult(true); |
| 110 | + sendNotification(message).then(({ value }) => setSendResult(value)); |
| 111 | + setMessage(null); |
| 112 | + } |
| 113 | + }}> |
| 114 | + <SendIcon gapRight /> |
| 115 | + <FormattedMessage id="generic.send" defaultMessage="Send" /> |
| 116 | + </Button> |
| 117 | + <Button variant="secondary" onClick={() => setMessage(null)}> |
| 118 | + <CloseIcon gapRight /> |
| 119 | + <FormattedMessage id="generic.close" defaultMessage="Close" /> |
| 120 | + </Button> |
| 121 | + </TheButtonGroup> |
| 122 | + </Modal.Footer> |
| 123 | + </Modal> |
| 124 | + </> |
| 125 | + ) : null; |
| 126 | +}; |
| 127 | + |
| 128 | +ExerciseButtons.propTypes = { |
| 129 | + id: PropTypes.string.isRequired, |
| 130 | + archivedAt: PropTypes.number, |
| 131 | + permissionHints: PropTypes.object, |
| 132 | + sendNotification: PropTypes.func.isRequired, |
| 133 | +}; |
| 134 | + |
| 135 | +export default ExerciseButtons; |
0 commit comments