From 80e552921705b36941b4b18912084e9d066a18af Mon Sep 17 00:00:00 2001 From: ihateblueb Date: Sat, 15 Mar 2025 11:06:04 -0400 Subject: [PATCH] add bite user and bite status buttons on status and status detailed components --- README.md | 1 + .../flavours/glitch/actions/interactions.js | 82 +++++++++++++++++++ .../flavours/glitch/components/status.jsx | 2 + .../glitch/components/status_action_bar.jsx | 16 ++++ .../glitch/containers/status_container.js | 10 ++- .../features/status/components/action_bar.jsx | 17 ++++ .../containers/detailed_status_container.js | 10 ++- .../flavours/glitch/features/status/index.jsx | 12 ++- 8 files changed, 147 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b81c593b7f..5834bdc543 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # with harper's tweaks - added bite notification support +- add bite user and bite status buttons on status and status detailed components # Chuckya (standalone frontend) diff --git a/app/javascript/flavours/glitch/actions/interactions.js b/app/javascript/flavours/glitch/actions/interactions.js index db9b5a2dbd..f0a9add638 100644 --- a/app/javascript/flavours/glitch/actions/interactions.js +++ b/app/javascript/flavours/glitch/actions/interactions.js @@ -47,6 +47,14 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST'; export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS'; export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL'; +export const BITE_REQUEST = 'BITE_REQUEST'; +export const BITE_REQUEST_SUCCESS = 'BITE_REQUEST_SUCCESS'; +export const BITE_REQUEST_FAIL = 'BITE_REQUEST_FAIL'; + +export const BITE_USER_REQUEST = 'BITE_USER_REQUEST'; +export const BITE_USER_REQUEST_SUCCESS = 'BITE_USER_REQUEST_SUCCESS'; +export const BITE_USER_REQUEST_FAIL = 'BITE_USER_REQUEST_FAIL'; + export const REACTION_UPDATE = 'REACTION_UPDATE'; export const REACTION_ADD_REQUEST = 'REACTION_ADD_REQUEST'; @@ -505,6 +513,80 @@ export function toggleFavourite(statusId, skipModal = false) { }; } +export function bite(statusId) { + return (dispatch) => { + dispatch(biteRequest(statusId)); + + api().post(`/api/v1/statuses/${statusId}/bite`).then(function () { + dispatch(biteRequestSuccess(statusId)); + }).catch(function (error) { + dispatch(biteRequestFail(statusId, error)); + }); + }; +} + +export function biteRequest(statusId) { + return { + type: BITE_REQUEST, + status: statusId, + skipLoading: true, + }; +} + +export function biteRequestSuccess(statusId) { + return { + type: BITE_REQUEST_SUCCESS, + status: statusId, + skipLoading: true, + }; +} + +export function biteRequestFail(statusId, error) { + return { + type: BITE_REQUEST_FAIL, + status: statusId, + error: error, + skipLoading: true, + }; +} + +export function biteUser(accountId) { + return (dispatch) => { + dispatch(biteUserRequest(accountId)); + + api().post(`/api/v1/users/${accountId}/bite`).then(function () { + dispatch(biteUserRequestSuccess(accountId)); + }).catch(function (error) { + dispatch(biteUserRequestFail(accountId, error)); + }); + }; +} + +export function biteUserRequest(accountId) { + return { + type: BITE_USER_REQUEST, + status: accountId, + skipLoading: true, + }; +} + +export function biteUserRequestSuccess(accountId) { + return { + type: BITE_USER_REQUEST_SUCCESS, + status: accountId, + skipLoading: true, + }; +} + +export function biteUserRequestFail(accountId, error) { + return { + type: BITE_USER_REQUEST_FAIL, + status: accountId, + error: error, + skipLoading: true, + }; +} + export const addReaction = (statusId, name, url) => (dispatch, getState) => { const status = getState().get('statuses').get(statusId); let alreadyAdded = false; diff --git a/app/javascript/flavours/glitch/components/status.jsx b/app/javascript/flavours/glitch/components/status.jsx index aa5db535c1..0054b88e62 100644 --- a/app/javascript/flavours/glitch/components/status.jsx +++ b/app/javascript/flavours/glitch/components/status.jsx @@ -93,6 +93,8 @@ class Status extends ImmutablePureComponent { onBookmark: PropTypes.func, onDelete: PropTypes.func, onDirect: PropTypes.func, + onBite: PropTypes.func, + onBiteUser: PropTypes.func, onMention: PropTypes.func, onReactionAdd: PropTypes.func, onReactionRemove: PropTypes.func, diff --git a/app/javascript/flavours/glitch/components/status_action_bar.jsx b/app/javascript/flavours/glitch/components/status_action_bar.jsx index 2ec6b8c887..1265754b74 100644 --- a/app/javascript/flavours/glitch/components/status_action_bar.jsx +++ b/app/javascript/flavours/glitch/components/status_action_bar.jsx @@ -38,6 +38,8 @@ const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' }, edit: { id: 'status.edit', defaultMessage: 'Edit' }, + bite: { id: 'status.bite', defaultMessage: 'Bite post' }, + biteUser: { id: 'account.bite', defaultMessage: 'Bite @{name}' }, direct: { id: 'status.direct', defaultMessage: 'Privately mention @{name}' }, mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' }, mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, @@ -80,6 +82,8 @@ class StatusActionBar extends ImmutablePureComponent { onReblog: PropTypes.func, onDelete: PropTypes.func, onDirect: PropTypes.func, + onBite: PropTypes.func, + onBiteUser: PropTypes.func, onMention: PropTypes.func, onMute: PropTypes.func, onBlock: PropTypes.func, @@ -172,6 +176,14 @@ class StatusActionBar extends ImmutablePureComponent { this.props.onMention(this.props.status.get('account')); }; + handleBiteClick = () => { + this.props.onBite(this.props.status.get('id')); + }; + + handleBiteUserClick = () => { + this.props.onBiteUser(this.props.status.getIn(['account', 'id'])); + }; + handleDirectClick = () => { this.props.onDirect(this.props.status.get('account')); }; @@ -263,6 +275,10 @@ class StatusActionBar extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick, dangerous: true }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick, dangerous: true }); } else { + menu.push({ text: intl.formatMessage(messages.bite), action: this.handleBiteClick }); + menu.push({ text: intl.formatMessage(messages.biteUser, { name: status.getIn(['account', 'username']) }), action: this.handleBiteUserClick }); + menu.push(null); + 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 }); menu.push(null); diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js index cf01d67060..36b8df3ff8 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, addReaction, - removeReaction, + removeReaction, bite, biteUser, } from 'flavours/glitch/actions/interactions'; import { openModal } from 'flavours/glitch/actions/modal'; import { initMuteModal } from 'flavours/glitch/actions/mutes'; @@ -159,6 +159,14 @@ const mapDispatchToProps = (dispatch, { contextType }) => ({ dispatch(directCompose(account)); }, + onBite (statusId) { + dispatch(bite(statusId)); + }, + + onBiteUser (accountId) { + dispatch(biteUser(accountId)); + }, + onMention (account) { dispatch(mentionCompose(account)); }, diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.jsx b/app/javascript/flavours/glitch/features/status/components/action_bar.jsx index e40411a680..59a9bfeacd 100644 --- a/app/javascript/flavours/glitch/features/status/components/action_bar.jsx +++ b/app/javascript/flavours/glitch/features/status/components/action_bar.jsx @@ -33,6 +33,8 @@ const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' }, edit: { id: 'status.edit', defaultMessage: 'Edit' }, + bite: { id: 'status.bite', defaultMessage: 'Bite post' }, + biteUser: { id: 'account.bite', defaultMessage: 'Bite @{name}' }, direct: { id: 'status.direct', defaultMessage: 'Privately mention @{name}' }, mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' }, reply: { id: 'status.reply', defaultMessage: 'Reply' }, @@ -73,6 +75,8 @@ class ActionBar extends PureComponent { onEdit: PropTypes.func.isRequired, onDirect: PropTypes.func.isRequired, onMention: PropTypes.func.isRequired, + onBite: PropTypes.func, + onBiteUser: PropTypes.func, onMute: PropTypes.func, onBlock: PropTypes.func, onMuteConversation: PropTypes.func, @@ -122,6 +126,14 @@ class ActionBar extends PureComponent { this.props.onMention(this.props.status.get('account')); }; + handleBiteClick = () => { + this.props.onBite(this.props.status.get('id')); + }; + + handleBiteUserClick = () => { + this.props.onBiteUser(this.props.status.getIn(['account', 'id'])); + }; + handleMuteClick = () => { this.props.onMute(this.props.status.get('account')); }; @@ -198,9 +210,14 @@ class ActionBar extends PureComponent { menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick, dangerous: true }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick, dangerous: true }); } else { + menu.push({ text: intl.formatMessage(messages.bite), action: this.handleBiteClick }); + menu.push({ text: intl.formatMessage(messages.biteUser, { name: status.getIn(['account', 'username']) }), action: this.handleBiteUserClick }); + menu.push(null); + 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 }); menu.push(null); + menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick, dangerous: true }); menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick, dangerous: true }); menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport, dangerous: true }); 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 34bde2fc6e..035f7cbd5c 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 @@ -13,7 +13,7 @@ import { toggleReblog, toggleFavourite, pin, - unpin, + unpin, bite, biteUser, } from '../../../actions/interactions'; import { openModal } from '../../../actions/modal'; import { initMuteModal } from '../../../actions/mutes'; @@ -94,6 +94,14 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(mentionCompose(account)); }, + onBite (statusId) { + dispatch(bite(statusId)); + }, + + onBiteUser (accountId) { + dispatch(biteUser(accountId)); + }, + onOpenMedia (media, index, lang) { dispatch(openModal({ modalType: 'MEDIA', diff --git a/app/javascript/flavours/glitch/features/status/index.jsx b/app/javascript/flavours/glitch/features/status/index.jsx index 0a8f75e73d..56b92109c2 100644 --- a/app/javascript/flavours/glitch/features/status/index.jsx +++ b/app/javascript/flavours/glitch/features/status/index.jsx @@ -39,7 +39,7 @@ import { pin, unpin, addReaction, - removeReaction, + removeReaction, bite, biteUser, } from '../../actions/interactions'; import { openModal } from '../../actions/modal'; import { initMuteModal } from '../../actions/mutes'; @@ -377,6 +377,14 @@ class Status extends ImmutablePureComponent { this.props.dispatch(mentionCompose(account)); }; + handleBiteClick = (statusId) => { + this.props.dispatch(bite(statusId)); + }; + + handleBiteUserClick = (accountId) => { + this.props.dispatch(biteUser(accountId)); + }; + handleOpenMedia = (media, index, lang) => { this.props.dispatch(openModal({ modalType: 'MEDIA', @@ -731,6 +739,8 @@ class Status extends ImmutablePureComponent { onEdit={this.handleEditClick} onDirect={this.handleDirectClick} onMention={this.handleMentionClick} + onBite={this.handleBiteClick} + onBiteUser={this.handleBiteUserClick} onMute={this.handleMuteClick} onMuteConversation={this.handleConversationMuteClick} onBlock={this.handleBlockClick}