From 21438b54bdaf3c557ec9ebbc482a2c418d8c64f8 Mon Sep 17 00:00:00 2001 From: Fire Demon Date: Sun, 19 Jul 2020 18:50:24 -0500 Subject: [Feature] Add manual publishing option --- app/javascript/flavours/glitch/actions/statuses.js | 43 +++++++++++++++++++++- .../flavours/glitch/components/status.js | 2 + .../glitch/components/status_action_bar.js | 10 +++++ .../flavours/glitch/components/status_content.js | 17 ++++++++- .../flavours/glitch/containers/status_container.js | 12 +++++- .../features/status/components/action_bar.js | 10 +++++ .../features/status/components/detailed_status.js | 2 +- .../status/containers/detailed_status_container.js | 11 ++++++ .../flavours/glitch/features/status/index.js | 15 +++++++- .../flavours/glitch/reducers/statuses.js | 3 ++ .../styles/monsterfork/components/status.scss | 23 +++++++++++- 11 files changed, 140 insertions(+), 8 deletions(-) (limited to 'app/javascript/flavours') diff --git a/app/javascript/flavours/glitch/actions/statuses.js b/app/javascript/flavours/glitch/actions/statuses.js index 72e8f14d8..9b33ed09f 100644 --- a/app/javascript/flavours/glitch/actions/statuses.js +++ b/app/javascript/flavours/glitch/actions/statuses.js @@ -12,6 +12,10 @@ export const STATUS_DELETE_REQUEST = 'STATUS_DELETE_REQUEST'; export const STATUS_DELETE_SUCCESS = 'STATUS_DELETE_SUCCESS'; export const STATUS_DELETE_FAIL = 'STATUS_DELETE_FAIL'; +export const STATUS_PUBLISH_REQUEST = 'STATUS_PUBLISH_REQUEST'; +export const STATUS_PUBLISH_SUCCESS = 'STATUS_PUBLISH_SUCCESS'; +export const STATUS_PUBLISH_FAIL = 'STATUS_PUBLISH_FAIL'; + export const CONTEXT_FETCH_REQUEST = 'CONTEXT_FETCH_REQUEST'; export const CONTEXT_FETCH_SUCCESS = 'CONTEXT_FETCH_SUCCESS'; export const CONTEXT_FETCH_FAIL = 'CONTEXT_FETCH_FAIL'; @@ -34,9 +38,9 @@ export function fetchStatusRequest(id, skipLoading) { }; }; -export function fetchStatus(id) { +export function fetchStatus(id, skipLoading = null) { return (dispatch, getState) => { - const skipLoading = getState().getIn(['statuses', id], null) !== null; + skipLoading = skipLoading === null ? getState().getIn(['statuses', id], null) !== null : skipLoading; dispatch(fetchContext(id)); @@ -73,6 +77,41 @@ export function editStatus(status, routerHistory) { }; }; +export function publishStatus(id) { + return (dispatch, getState) => { + dispatch(publishStatusRequest(id)); + + api(getState).post(`/api/v1/statuses/${id}/publish`).then(() => { + dispatch(publishStatusSuccess(id)); + dispatch(fetchStatus(id, false)); + }).catch(error => { + dispatch(publishStatusFail(id, error)); + }); + }; +}; + +export function publishStatusRequest(id) { + return { + type: STATUS_PUBLISH_REQUEST, + id: id, + }; +}; + +export function publishStatusSuccess(id) { + return { + type: STATUS_PUBLISH_SUCCESS, + id: id, + }; +}; + +export function publishStatusFail(id, error) { + return { + type: STATUS_PUBLISH_FAIL, + id: id, + error: error, + }; +}; + export function fetchStatusSuccess(skipLoading) { return { type: STATUS_FETCH_SUCCESS, diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js index 3a6029b96..4626d1cd8 100644 --- a/app/javascript/flavours/glitch/components/status.js +++ b/app/javascript/flavours/glitch/components/status.js @@ -74,6 +74,7 @@ class Status extends ImmutablePureComponent { onBookmark: PropTypes.func, onDelete: PropTypes.func, onEdit: PropTypes.func, + onPublish: PropTypes.func, onDirect: PropTypes.func, onMention: PropTypes.func, onPin: PropTypes.func, @@ -695,6 +696,7 @@ class Status extends ImmutablePureComponent { const computedClass = classNames('status', `status-${status.get('visibility')}`, { collapsed: isCollapsed, + unpublished: status.get('published') === false, 'has-background': isCollapsed && background, 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js index 6902103c5..e941fb994 100644 --- a/app/javascript/flavours/glitch/components/status_action_bar.js +++ b/app/javascript/flavours/glitch/components/status_action_bar.js @@ -13,6 +13,7 @@ const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' }, edit: { id: 'status.edit', defaultMessage: 'Edit' }, + publish: { id: 'status.publish', defaultMessage: 'Publish' }, direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' }, mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' }, mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, @@ -63,6 +64,7 @@ class StatusActionBar extends ImmutablePureComponent { onReblog: PropTypes.func, onDelete: PropTypes.func, onEdit: PropTypes.func, + onPublish: PropTypes.func, onDirect: PropTypes.func, onMention: PropTypes.func, onMute: PropTypes.func, @@ -139,6 +141,10 @@ class StatusActionBar extends ImmutablePureComponent { this.props.onEdit(this.props.status, this.context.router.history); } + handlePublishClick = () => { + this.props.onPublish(this.props.status); + } + handlePinClick = () => { this.props.onPin(this.props.status); } @@ -238,6 +244,10 @@ class StatusActionBar extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick }); menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); + + if (status.get('published') === false) { + menu.push({ text: intl.formatMessage(messages.publish), action: this.handlePublishClick }); + } } else { menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick }); menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick }); diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js index b353b028b..171aff097 100644 --- a/app/javascript/flavours/glitch/components/status_content.js +++ b/app/javascript/flavours/glitch/components/status_content.js @@ -278,6 +278,7 @@ export default class StatusContent extends React.PureComponent { const edited = (status.get('edited') === 0) ? null : (
+ ); + const unpublished = (status.get('published') === false) && ( +
+ + +
+ ); + const content = { __html: status.get('contentHtml') }; const spoilerContent = { __html: status.get('spoilerHtml') }; const directionStyle = { direction: 'ltr' }; @@ -345,6 +357,8 @@ export default class StatusContent extends React.PureComponent { return (
+ {unpublished} + {edited} - {edited} {mentionsPlaceholder}
@@ -382,6 +395,7 @@ export default class StatusContent extends React.PureComponent { tabIndex='0' ref={this.setRef} > + {unpublished} {edited}
+ {unpublished} {edited}
{media} diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js index 9e011ac6b..bccaba92d 100644 --- a/app/javascript/flavours/glitch/containers/status_container.js +++ b/app/javascript/flavours/glitch/containers/status_container.js @@ -17,7 +17,7 @@ import { pin, unpin, } from 'flavours/glitch/actions/interactions'; -import { muteStatus, unmuteStatus, deleteStatus, editStatus } from 'flavours/glitch/actions/statuses'; +import { muteStatus, unmuteStatus, deleteStatus, editStatus, publishStatus } from 'flavours/glitch/actions/statuses'; import { initMuteModal } from 'flavours/glitch/actions/mutes'; import { initBlockModal } from 'flavours/glitch/actions/blocks'; import { initReport } from 'flavours/glitch/actions/reports'; @@ -38,6 +38,8 @@ const messages = defineMessages({ redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' }, replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' }, replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' }, + publishConfirm: { id: 'confirmations.publish.confirm', defaultMessage: 'Publish' }, + publishMessage: { id: 'confirmations.publish.message', defaultMessage: 'Are you ready to publish your post?' }, unfilterConfirm: { id: 'confirmations.unfilter.confirm', defaultMessage: 'Show' }, author: { id: 'confirmations.unfilter.author', defaultMessage: 'Author' }, matchingFilters: { id: 'confirmations.unfilter.filters', defaultMessage: 'Matching {count, plural, one {filter} other {filters}}' }, @@ -170,6 +172,14 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ dispatch(editStatus(status, history)); }, + onPublish (status) { + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.publishMessage), + confirm: intl.formatMessage(messages.publishConfirm), + onConfirm: () => dispatch(publishStatus(status.get('id'))), + })); + }, + onDirect (account, router) { dispatch(directCompose(account, router)); }, diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.js b/app/javascript/flavours/glitch/features/status/components/action_bar.js index c4f510184..e76d9634b 100644 --- a/app/javascript/flavours/glitch/features/status/components/action_bar.js +++ b/app/javascript/flavours/glitch/features/status/components/action_bar.js @@ -11,6 +11,7 @@ const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' }, edit: { id: 'status.edit', defaultMessage: 'Edit' }, + publish: { id: 'status.publish', defaultMessage: 'Publish' }, direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' }, mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' }, reply: { id: 'status.reply', defaultMessage: 'Reply' }, @@ -52,6 +53,7 @@ class ActionBar extends React.PureComponent { onBlock: PropTypes.func, onDelete: PropTypes.func.isRequired, onEdit: PropTypes.func.isRequired, + onPublish: PropTypes.func.isRequired, onDirect: PropTypes.func.isRequired, onMention: PropTypes.func.isRequired, onReport: PropTypes.func, @@ -88,6 +90,10 @@ class ActionBar extends React.PureComponent { this.props.onEdit(this.props.status, this.context.router.history); } + handlePublishClick = () => { + this.props.onPublish(this.props.status); + } + handleDirectClick = () => { this.props.onDirect(this.props.status.get('account'), this.context.router.history); } @@ -171,6 +177,10 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick }); menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); + + if (status.get('published') === false) { + menu.push({ text: intl.formatMessage(messages.publish), action: this.handlePublishClick }); + } } else { menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick }); menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick }); diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index 24e614a8d..0db0316cc 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -259,7 +259,7 @@ export default class DetailedStatus extends ImmutablePureComponent { return (
-
+
diff --git a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js index eeafc0b08..124de903a 100644 --- a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js +++ b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js @@ -19,6 +19,7 @@ import { unmuteStatus, editStatus, deleteStatus, + publishStatus, hideStatus, revealStatus, } from 'flavours/glitch/actions/statuses'; @@ -35,6 +36,8 @@ const messages = defineMessages({ deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' }, redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' }, redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' }, + publishConfirm: { id: 'confirmations.publish.confirm', defaultMessage: 'Publish' }, + publishMessage: { id: 'confirmations.publish.message', defaultMessage: 'Are you ready to publish your post?' }, replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' }, replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' }, }); @@ -123,6 +126,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(editStatus(status, history)); }, + onPublish (status) { + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.publishMessage), + confirm: intl.formatMessage(messages.publishConfirm), + onConfirm: () => dispatch(publishStatus(status.get('id'))), + })); + }, + onDirect (account, router) { dispatch(directCompose(account, router)); }, diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index beea64341..3a6847e8d 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -26,7 +26,7 @@ import { directCompose, } from 'flavours/glitch/actions/compose'; import { changeLocalSetting } from 'flavours/glitch/actions/local_settings'; -import { muteStatus, unmuteStatus, deleteStatus, editStatus } from 'flavours/glitch/actions/statuses'; +import { muteStatus, unmuteStatus, deleteStatus, editStatus, publishStatus } from 'flavours/glitch/actions/statuses'; import { initMuteModal } from 'flavours/glitch/actions/mutes'; import { initBlockModal } from 'flavours/glitch/actions/blocks'; import { initReport } from 'flavours/glitch/actions/reports'; @@ -50,6 +50,8 @@ const messages = defineMessages({ deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' }, redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' }, redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' }, + publishConfirm: { id: 'confirmations.publish.confirm', defaultMessage: 'Publish' }, + publishMessage: { id: 'confirmations.publish.message', defaultMessage: 'Are you ready to publish your post?' }, revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' }, hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' }, detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' }, @@ -308,6 +310,16 @@ class Status extends ImmutablePureComponent { this.props.dispatch(editStatus(status, history)); } + handlePublishClick = (status) => { + const { dispatch, intl } = this.props; + + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.publishMessage), + confirm: intl.formatMessage(messages.publishConfirm), + onConfirm: () => dispatch(publishStatus(status.get('id'))), + })); + } + handleDirectClick = (account, router) => { this.props.dispatch(directCompose(account, router)); } @@ -593,6 +605,7 @@ class Status extends ImmutablePureComponent { onBookmark={this.handleBookmarkClick} onDelete={this.handleDeleteClick} onEdit={this.handleEditClick} + onPublish={this.handlePublishClick} onDirect={this.handleDirectClick} onMention={this.handleMentionClick} onMute={this.handleMuteClick} diff --git a/app/javascript/flavours/glitch/reducers/statuses.js b/app/javascript/flavours/glitch/reducers/statuses.js index 5db766b96..20822b4cb 100644 --- a/app/javascript/flavours/glitch/reducers/statuses.js +++ b/app/javascript/flavours/glitch/reducers/statuses.js @@ -10,6 +10,7 @@ import { import { STATUS_MUTE_SUCCESS, STATUS_UNMUTE_SUCCESS, + STATUS_PUBLISH_SUCCESS, } from 'flavours/glitch/actions/statuses'; import { TIMELINE_DELETE, @@ -56,6 +57,8 @@ export default function statuses(state = initialState, action) { return state.setIn([action.id, 'muted'], true); case STATUS_UNMUTE_SUCCESS: return state.setIn([action.id, 'muted'], false); + case STATUS_PUBLISH_SUCCESS: + return state.setIn([action.id, 'published'], true); case TIMELINE_DELETE: return deleteStatus(state, action.id, action.references); default: diff --git a/app/javascript/flavours/glitch/styles/monsterfork/components/status.scss b/app/javascript/flavours/glitch/styles/monsterfork/components/status.scss index fb2cfabce..33601b8bf 100644 --- a/app/javascript/flavours/glitch/styles/monsterfork/components/status.scss +++ b/app/javascript/flavours/glitch/styles/monsterfork/components/status.scss @@ -1,9 +1,28 @@ -.status__edit-notice { +.status__edit-notice, .status__unpublished-notice { + margin-bottom: 1em; + & > span { color: $dark-text-color; line-height: normal; font-style: italic; font-size: 12px; + padding-left: 8px; + position: relative; + bottom: 0.25em; + } + + & > i { + color: lighten($dark-text-color, 4%); + } +} + +.status, .detailed-status { + &.unpublished { + background: darken($ui-base-color, 4%); + + &:focus { + background: lighten($ui-base-color, 4%); + } } } @@ -15,4 +34,4 @@ div[data-nest-deep="true"] { border-left: 75px dashed darken($ui-base-color, 8%); -} \ No newline at end of file +} -- cgit