diff --git a/app/soapbox/actions/compose.js b/app/soapbox/actions/compose.js
index bd91daaae..6c3057436 100644
--- a/app/soapbox/actions/compose.js
+++ b/app/soapbox/actions/compose.js
@@ -164,6 +164,34 @@ export function submitCompose(routerHistory, group) {
return function(dispatch, getState) {
if (!isLoggedIn(getState)) return;
+ function onModalSubmitCompose() {
+ dispatch(submitComposeRequest());
+ dispatch(closeModal());
+
+ api(getState).post('/api/v1/statuses', {
+ status,
+ in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
+ media_ids: media.map(item => item.get('id')),
+ sensitive: getState().getIn(['compose', 'sensitive']),
+ spoiler_text: getState().getIn(['compose', 'spoiler_text'], ''),
+ visibility: getState().getIn(['compose', 'privacy']),
+ content_type: getState().getIn(['compose', 'content_type']),
+ poll: getState().getIn(['compose', 'poll'], null),
+ scheduled_at: getState().getIn(['compose', 'schedule'], null),
+ }, {
+ headers: {
+ 'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
+ },
+ }).then(function(response) {
+ if (response.data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0 && routerHistory) {
+ routerHistory.push('/messages');
+ }
+ handleComposeSubmit(dispatch, getState, response, status);
+ }).catch(function(error) {
+ dispatch(submitComposeFail(error));
+ });
+ }
+
const status = getState().getIn(['compose', 'text'], '');
const media = getState().getIn(['compose', 'media_attachments']);
@@ -171,31 +199,13 @@ export function submitCompose(routerHistory, group) {
return;
}
- dispatch(submitComposeRequest());
- dispatch(closeModal());
+ const missingDescriptionModal = getSettings(getState()).get('missingDescriptionModal');
- api(getState).post('/api/v1/statuses', {
- status,
- in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
- media_ids: media.map(item => item.get('id')),
- sensitive: getState().getIn(['compose', 'sensitive']),
- spoiler_text: getState().getIn(['compose', 'spoiler_text'], ''),
- visibility: getState().getIn(['compose', 'privacy']),
- content_type: getState().getIn(['compose', 'content_type']),
- poll: getState().getIn(['compose', 'poll'], null),
- scheduled_at: getState().getIn(['compose', 'schedule'], null),
- }, {
- headers: {
- 'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
- },
- }).then(function(response) {
- if (response.data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0 && routerHistory) {
- routerHistory.push('/messages');
- }
- handleComposeSubmit(dispatch, getState, response, status);
- }).catch(function(error) {
- dispatch(submitComposeFail(error));
- });
+ if (missingDescriptionModal && media.filter(item => !item.get('description')).size) {
+ dispatch(openModal('MISSING_DESCRIPTION', {
+ onContinue: () => onModalSubmitCompose(),
+ }));
+ } else onModalSubmitCompose();
};
};
diff --git a/app/soapbox/actions/settings.js b/app/soapbox/actions/settings.js
index d3d572715..d857fd1e9 100644
--- a/app/soapbox/actions/settings.js
+++ b/app/soapbox/actions/settings.js
@@ -21,6 +21,7 @@ export const defaultSettings = ImmutableMap({
unfollowModal: false,
boostModal: false,
deleteModal: true,
+ missingDescriptionModal: false,
defaultPrivacy: 'public',
defaultContentType: 'text/plain',
themeMode: 'light',
diff --git a/app/soapbox/features/compose/components/schedule_form.js b/app/soapbox/features/compose/components/schedule_form.js
index 56fed1780..ad444ec95 100644
--- a/app/soapbox/features/compose/components/schedule_form.js
+++ b/app/soapbox/features/compose/components/schedule_form.js
@@ -20,41 +20,34 @@ class ScheduleForm extends React.Component {
active: PropTypes.bool,
};
- setSchedule(date)
- {
+ setSchedule(date) {
this.setState({ schedule: date });
this.props.onSchedule(date);
}
- openDatePicker(datePicker)
- {
- if (!datePicker)
- {
+ openDatePicker(datePicker) {
+ if (!datePicker) {
return;
}
datePicker.setOpen(true);
}
- componentDidMount()
- {
+ componentDidMount() {
this.setState({ schedule: this.props.schedule });
}
- constructor(props)
- {
+ constructor(props) {
super(props);
this.setSchedule = this.setSchedule.bind(this);
}
- isCurrentOrFutureDate(date)
- {
+ isCurrentOrFutureDate(date) {
return date && new Date().setHours(0, 0, 0, 0) <= new Date(date).setHours(0, 0, 0, 0);
}
- isFiveMinutesFromNow(time)
- {
+ isFiveMinutesFromNow(time) {
const fiveMinutesFromNow = new Date(new Date().getTime() + 300000); // now, plus five minutes (Pleroma won't schedule posts )
const selectedDate = new Date(time);
@@ -62,8 +55,7 @@ class ScheduleForm extends React.Component {
};
render() {
- if (!this.props.active || !this.state)
- {
+ if (!this.props.active || !this.state) {
return null;
}
diff --git a/app/soapbox/features/preferences/index.js b/app/soapbox/features/preferences/index.js
index dd1072c49..7d188afc6 100644
--- a/app/soapbox/features/preferences/index.js
+++ b/app/soapbox/features/preferences/index.js
@@ -202,6 +202,10 @@ class Preferences extends ImmutablePureComponent {
label={}
path={['deleteModal']}
/>
+ }
+ path={['missingDescriptionModal']}
+ />
diff --git a/app/soapbox/features/ui/components/missing_description_modal.js b/app/soapbox/features/ui/components/missing_description_modal.js
new file mode 100644
index 000000000..0cbdad660
--- /dev/null
+++ b/app/soapbox/features/ui/components/missing_description_modal.js
@@ -0,0 +1,51 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { injectIntl, FormattedMessage } from 'react-intl';
+import Button from '../../../components/button';
+
+export default @injectIntl
+class MissingDescriptionModal extends React.PureComponent {
+
+ static propTypes = {
+ onClose: PropTypes.func,
+ onContinue: PropTypes.func.isRequired,
+ intl: PropTypes.object.isRequired,
+ };
+
+ componentDidMount() {
+ this.button.focus();
+ }
+
+ handleContinue = () => {
+ this.props.onClose();
+ this.props.onContinue();
+ }
+
+ handleCancel = () => {
+ this.props.onClose();
+ }
+
+ setRef = (c) => {
+ this.button = c;
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+}
diff --git a/app/soapbox/features/ui/components/modal_root.js b/app/soapbox/features/ui/components/modal_root.js
index b3f7f8681..657df1a26 100644
--- a/app/soapbox/features/ui/components/modal_root.js
+++ b/app/soapbox/features/ui/components/modal_root.js
@@ -9,6 +9,7 @@ import MediaModal from './media_modal';
import VideoModal from './video_modal';
import BoostModal from './boost_modal';
import ConfirmationModal from './confirmation_modal';
+import MissingDescriptionModal from './missing_description_modal';
import FocalPointModal from './focal_point_modal';
import HotkeysModal from './hotkeys_modal';
import ComposeModal from './compose_modal';
@@ -28,6 +29,7 @@ const MODAL_COMPONENTS = {
'VIDEO': () => Promise.resolve({ default: VideoModal }),
'BOOST': () => Promise.resolve({ default: BoostModal }),
'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
+ 'MISSING_DESCRIPTION': () => Promise.resolve({ default: MissingDescriptionModal }),
'MUTE': MuteModal,
'REPORT': ReportModal,
'ACTIONS': () => Promise.resolve({ default: ActionsModal }),
diff --git a/app/soapbox/locales/pl.json b/app/soapbox/locales/pl.json
index 42c75dd6b..532770f18 100644
--- a/app/soapbox/locales/pl.json
+++ b/app/soapbox/locales/pl.json
@@ -421,6 +421,9 @@
"mfa.setup_otp_title": "Wyłączono OTP",
"mfa.setup_recoverycodes": "Kody przywracania",
"mfa.setup_warning": "Zapisz te kody gdzieś w bezpiecznym miejscu – jeżeli tego nie zrobisz, już ich nie zobaczysz. Jeśli utracisz dostęp do aplikacji 2FA i tych kodów, stracisz dostęp do swojego konta.",
+ "missing_description_modal.cancel": "Anuluj",
+ "missing_description_modal.continue": "Opublikuj",
+ "missing_description_modal.text": "Nie podałeś(-aś) opisu dla wszystkich załączników. Czy na pewno chcesz kontynuować?",
"missing_indicator.label": "Nie znaleziono",
"missing_indicator.sublabel": "Nie można odnaleźć tego zasobu",
"morefollows.followers_label": "…i {count} więcej {count, plural, one {obserwujący(-a)} few {obserwujących} many {obserwujących} other {obserwujących}} na zdalnych stronach.",
@@ -497,6 +500,7 @@
"preferences.fields.halloween_label": "Tryb Halloween",
"preferences.fields.language_label": "Język",
"preferences.fields.media_display_label": "Wyświetlanie zawartości multimedialnej",
+ "preferences.fields.missing_description_modal_label": "Pytaj o potwierdzenie przed wysłaniem zawartości multimedialnej bez opisu",
"preferences.fields.privacy_label": "Prywatność wpisów",
"preferences.fields.reduce_motion_label": "Ogranicz ruch w animacjach",
"preferences.fields.system_font_label": "Używaj domyślnej czcionki systemu",