Skip to content

Commit

Permalink
confirm delete modal for removing documents and annexes
Browse files Browse the repository at this point in the history
  • Loading branch information
tsubik committed Dec 3, 2024
1 parent 3a92b04 commit fe982cc
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function DocumentsCertification(props) {
user.operator_ids.includes(+id))) && (
<DocCardUpload
{...doc}
title={intl.formatMessage({ id: 'operator-detail.license' })}
properties={{
type: 'operator',
id,
Expand Down
59 changes: 59 additions & 0 deletions components/ui/confirm-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useState } from 'react';
import { useIntl } from 'react-intl';

import Spinner from 'components/ui/spinner';

const ConfirmModal = ({
title,
text,
confirmText,
cancelText,
onCancel,
onConfirm
}) => {
const intl = useIntl();
const [submitting, setSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
const _cancelText = cancelText || intl.formatMessage({ id: 'cancel', defaultMessage: 'Cancel' });
const _confirmText = confirmText || intl.formatMessage({ id: 'confirm', defaultMessage: 'Confirm' });

const handleConfirm = () => {
setSubmitting(true);
onConfirm({
onSuccess: () => {
setErrorMessage(null);
},
onError: (errorMessage) => {
setSubmitting(false);
setErrorMessage(errorMessage);
}
});
};

return (
<div className="c-confirm-modal">
<Spinner
isLoading={submitting}
className="-tiny"
/>

{title && <h2 className="c-title -extrabig">{title}</h2>}
<p className="c-text">
{text}
</p>
<p className="c-text -error">
{errorMessage}
</p>
<div className="actions">
<button className="c-button -primary" data-test-id="confirm-modal-cancel" onClick={onCancel}>
{_cancelText}
</button>
<button className="c-button -dangerous" data-test-id="confirm-modal-confirm" onClick={handleConfirm}>
{_confirmText}
</button>
</div>
</div>
)
};

export default ConfirmModal;
7 changes: 2 additions & 5 deletions components/ui/doc-annex.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
// import classnames from 'classnames';
import Tooltip from 'rc-tooltip';
import { useIntl } from 'react-intl';

import Icon from 'components/ui/icon';
import Spinner from 'components/ui/spinner';

export default function DocAnnex({ annex, isRemoving, showRemoveButton, onRemove }) {
export default function DocAnnex({ annex, showRemoveButton, visible, onRemove }) {
const intl = useIntl();
const formatDate = (date) => intl.formatDate(date, {
day: '2-digit',
Expand All @@ -18,12 +16,12 @@ export default function DocAnnex({ annex, isRemoving, showRemoveButton, onRemove
return (
<Tooltip
placement="bottom"
visible={visible}
align={{
offset: [0, 10],
}}
overlay={
<div>
<Spinner isLoading={isRemoving} className="-tiny -transparent" />
<h4 className="c-title -default tooltip-title"><strong>{annex.name}</strong></h4>
<dl className="tooltip-content">
<dt><strong>{intl.formatMessage({ id: 'annex.start_date' })}:</strong></dt>
Expand Down Expand Up @@ -68,6 +66,5 @@ DocAnnex.defaultProps = {
DocAnnex.propTypes = {
annex: PropTypes.object.isRequired,
showRemoveButton: PropTypes.bool,
isRemoving: PropTypes.bool,
onRemove: PropTypes.func
}
42 changes: 27 additions & 15 deletions components/ui/doc-card-upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import dayjs from 'dayjs';
import * as Sentry from '@sentry/nextjs';

import { connect } from 'react-redux';

Expand All @@ -15,18 +16,13 @@ import DocumentationService from 'services/documentationService';
import modal from 'services/modal';

// Components
import ConfirmModal from 'components/ui/confirm-modal';
import DocModal from 'components/ui/doc-modal';
import Spinner from 'components/ui/spinner';

class DocCardUpload extends React.Component {
constructor(props) {
super(props);

// STATE
this.state = {
deleteLoading: false,
};

// BINDINGS
this.triggerAddFile = this.triggerAddFile.bind(this);
this.triggerEditFile = this.triggerEditFile.bind(this);
Expand Down Expand Up @@ -92,24 +88,43 @@ class DocCardUpload extends React.Component {

triggerDeleteFile(e) {
e && e.preventDefault();
const { docId } = this.props;
const { title, intl } = this.props;

modal.toggleModal(true, {
children: ConfirmModal,
childrenProps: {
title: intl.formatMessage({ id: 'delete.document.title', defaultMessage: 'Delete {document}?' }, { document: title }),
text: intl.formatMessage(
{ id: 'delete.document.text', defaultMessage: 'Are you sure you want to delete document {document}?' }, { document: title }
),
confirmText: intl.formatMessage({ id: 'delete', defaultMessage: 'Delete' }),
onConfirm: this.triggerConfirmedDeleteFile.bind(this),
onCancel: () => modal.toggleModal(false),
},
size: '-small'
});
}

this.setState({ deleteLoading: true });
triggerConfirmedDeleteFile({ onSuccess, onError } = {}) {
const { docId, intl } = this.props;

this.documentationService.deleteDocument(docId)
.then(() => {
this.setState({ deleteLoading: false });
modal.toggleModal(false);
onSuccess && onSuccess();
this.props.onChange && this.props.onChange();
})
.catch((err) => {
this.setState({ deleteLoading: false });
onError && onError(
intl.formatMessage({ id: 'document.delete.error', defaultMessage: 'An error occurred while deleting the document.' })
);
Sentry.captureException(err);
console.error(err);
});
}

render() {
const { status, buttons, date } = this.props;
const { deleteLoading } = this.state;
const currentDate = dayjs(new Date());
const selectedDate = dayjs(date);
const isEditable =
Expand Down Expand Up @@ -153,10 +168,6 @@ class DocCardUpload extends React.Component {
className="c-button -small -primary"
>
{this.props.intl.formatMessage({ id: 'delete' })}
<Spinner
isLoading={deleteLoading}
className="-tiny -transparent"
/>
</button>
</li>
)}
Expand Down Expand Up @@ -215,6 +226,7 @@ class DocCardUpload extends React.Component {

DocCardUpload.propTypes = {
status: PropTypes.string,
title: PropTypes.string,
user: PropTypes.object,
docId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
onChange: PropTypes.func,
Expand Down
58 changes: 45 additions & 13 deletions components/ui/doc-card.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import * as Sentry from '@sentry/nextjs';

// Intl
import { connect } from 'react-redux';
Expand All @@ -11,6 +12,7 @@ import modal from 'services/modal';
import DocumentationService from 'services/documentationService';

// Components
import ConfirmModal from 'components/ui/confirm-modal';
import DocAnnexesModal from 'components/ui/doc-annexes-modal';
import DocAnnex from 'components/ui/doc-annex';
import Icon from 'components/ui/icon';
Expand Down Expand Up @@ -47,16 +49,15 @@ class DocCard extends React.Component {
constructor(props) {
super(props);

this.state = {
annexTooltipVisible: undefined
};

this.documentationService = new DocumentationService({
authorization: props.user.token
});
}

state = {
deleteLoading: false
}


triggerWhy = (e) => {
e && e.preventDefault();
const { title, reason } = this.props;
Expand Down Expand Up @@ -125,23 +126,54 @@ class DocCard extends React.Component {
}

triggerRemoveAnnex = (id) => {
this.setState({ deleteLoading: true });
const { annexes, title, intl } = this.props;
const annex = annexes.find(a => a.id === id);

// workaround to close tooltip before opening modal, but show it again when hovering
this.setState({ annexTooltipVisible: false });
setTimeout(() => {
this.setState({ annexTooltipVisible: undefined });
});

modal.toggleModal(true, {
children: ConfirmModal,
childrenProps: {
title: intl.formatMessage({ id: 'delete.document.title', defaultMessage: 'Delete {document}?' }, { document: annex.name }),
text: intl.formatMessage(
{ id: 'delete.document.text', defaultMessage: 'Are you sure you want to delete document {document}?' }, { document: annex.name }
),
confirmText: intl.formatMessage({ id: 'delete', defaultMessage: 'Delete' }),
onConfirm: (options) => {
this.triggerConfirmedRemoveAnnex({ ...options, annexId: id });
},
onCancel: () => modal.toggleModal(false),
},
size: '-small'
});
}

triggerConfirmedRemoveAnnex({ annexId, onSuccess, onError } = {}) {
const { intl } = this.props;

this.documentationService.deleteAnnex(id)
this.documentationService.deleteAnnex(annexId)
.then(() => {
this.setState({ deleteLoading: false });
modal.toggleModal(false);
onSuccess && onSuccess();
this.props.onChange && this.props.onChange();
})
.catch((err) => {
this.setState({ deleteLoading: false });
onError && onError(
intl.formatMessage({ id: 'document.delete.error', defaultMessage: 'An error occurred while deleting the document.' })
);
Sentry.captureException(err);
console.error(err);
});
}

render() {
const { user, adminComment, public: publicState, startDate, endDate, status, source, sourceInfo, title, explanation, url, annexes, layout, properties } = this.props;
const { id } = properties;
const { deleteLoading } = this.state;
const { annexTooltipVisible } = this.state;
const isActiveUser = (user && user.role === 'admin') ||
(user && (user.role === 'operator' || user.role === 'holding') && user.operator_ids && user.operator_ids.includes(+id)) ||
(user && user.role === 'government' && user.country && user.country.toString() === id);
Expand Down Expand Up @@ -223,7 +255,7 @@ class DocCard extends React.Component {
<ul className="doc-card-list">
{approvedAnnexes.map(annex => (
<li className="doc-card-list-item" key={annex.id}>
<DocAnnex annex={annex} isRemoving={deleteLoading} showRemoveButton={isActiveUser} onRemove={this.triggerRemoveAnnex} />
<DocAnnex annex={annex} showRemoveButton={isActiveUser} onRemove={this.triggerRemoveAnnex} visible={annexTooltipVisible} />
</li>
))}
{isActiveUser &&
Expand Down Expand Up @@ -296,7 +328,7 @@ class DocCard extends React.Component {
<ul className="doc-card-list">
{approvedAnnexes.map(annex => (
<li className="doc-card-list-item" key={annex.id}>
<DocAnnex annex={annex} isRemoving={deleteLoading} showRemoveButton={isActiveUser} onRemove={this.triggerRemoveAnnex} />
<DocAnnex annex={annex} showRemoveButton={isActiveUser} onRemove={this.triggerRemoveAnnex} visible={annexTooltipVisible} />
</li>
))}
{isActiveUser &&
Expand Down Expand Up @@ -363,7 +395,7 @@ class DocCard extends React.Component {
<ul className="doc-card-list">
{approvedAnnexes.map(annex => (
<li className="doc-card-list-item" key={annex.id}>
<DocAnnex annex={annex} isRemoving={deleteLoading} showRemoveButton={isActiveUser} onRemove={this.triggerRemoveAnnex} />
<DocAnnex annex={annex} showRemoveButton={isActiveUser} onRemove={this.triggerRemoveAnnex} visible={annexTooltipVisible} />
</li>
))}

Expand Down
12 changes: 12 additions & 0 deletions css/components/ui/_button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@
}
}

&.-dangerous {
border-color: $color-error;
color: $color-text-2;
fill: $color-error;
background: $color-error;

&:hover {
color: darken($color-text-2, 10%);
fill: darken($color-text-2, 10%);
}
}

&.-tertiary {
border-color: $color-tertiary;
color: $color-text-1;
Expand Down
19 changes: 19 additions & 0 deletions css/components/ui/_confirm-modal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.c-confirm-modal {
padding: 20px;

p {
font-size: $font-size-big;
}

p.-error {
color: $color-error;
font-size: $font-size-default;
}

.actions {
display: flex;
margin-top: 30px;
gap: 20px;
justify-content: flex-end;
}
}
11 changes: 11 additions & 0 deletions css/components/ui/_modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,17 @@
}
}

&.-small {
.modal-container {
width: calc(100% - 20px);

@include breakpoint(medium) {
width: unset;
max-width: 600px;
}
}
}

&.-auto {
.modal-container {
width: unset;
Expand Down
1 change: 1 addition & 0 deletions css/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
@import 'components/ui/chart';
@import 'components/ui/chart-legend';
@import 'components/ui/country-card';
@import 'components/ui/confirm-modal';
@import 'components/ui/datepicker';
@import 'components/ui/doc-by-category';
@import 'components/ui/doc-card';
Expand Down
Loading

0 comments on commit fe982cc

Please sign in to comment.