diff --git a/.editorconfig b/.editorconfig index cbb6ac5..e0acaae 100755 --- a/.editorconfig +++ b/.editorconfig @@ -7,5 +7,6 @@ insert_final_newline = true indent_style = space indent_size = 4 [*.md] -indent_size = 2 -trim_trailing_whitespace = false \ No newline at end of file +trim_trailing_whitespace = false +[*.{.md,js}] +indent_size = 2 \ No newline at end of file diff --git a/extend.php b/extend.php index 3b97c2a..ef85134 100644 --- a/extend.php +++ b/extend.php @@ -37,6 +37,8 @@ (new Extend\Routes('api')) ->get('/posts/{id}/reactions', 'post.reactions.index', Controller\ListPostReactionsController::class) + ->delete('/posts/{id}/reactions/specific/{postReactionId}', 'post.reactions.specific.delete', Controller\DeletePostReactionController::class) + ->delete('/posts/{id}/reactions/type/{reactionId}', 'post.reactions.type.delete', Controller\DeletePostReactionController::class) ->get('/reactions', 'reactions.index', Controller\ListReactionsController::class) ->post('/reactions', 'reactions.create', Controller\CreateReactionController::class) ->patch('/reactions/{id}', 'reactions.update', Controller\UpdateReactionController::class) diff --git a/js/src/@types/shims.d.ts b/js/src/@types/shims.d.ts new file mode 100644 index 0000000..fc0b640 --- /dev/null +++ b/js/src/@types/shims.d.ts @@ -0,0 +1,24 @@ +import PostReaction from '../forum/models/PostReaction'; +import Reaction from '../common/models/Reaction'; + +declare module 'flarum/common/models/Post' { + export default interface Post { + reactionCounts(): Record; + userReaction(): number | undefined; + + canReact(): boolean; + canDeletePostReactions(): boolean; + } +} + +declare module 'flarum/common/models/Discussion' { + export default interface Discussion { + canSeeReactions(): boolean; + } +} + +declare module 'flarum/forum/models/Forum' { + export default interface Forum { + reactions(): Reaction[]; + } +} diff --git a/js/src/admin/index.js b/js/src/admin/index.js index 6da9306..b4b6c43 100644 --- a/js/src/admin/index.js +++ b/js/src/admin/index.js @@ -34,5 +34,13 @@ app.initializers.add('fof/reactions', () => { }, 'view' ) + .registerPermission( + { + icon: 'fas fa-trash', + label: app.translator.trans('fof-reactions.admin.permissions.delete_post_reactions_label'), + permission: 'discussion.deleteReactionsPosts', + }, + 'moderate' + ) .registerPage(SettingsPage); }); diff --git a/js/src/common/components/ReactionComponent.js b/js/src/common/components/ReactionComponent.js index 3e593dd..4080de5 100644 --- a/js/src/common/components/ReactionComponent.js +++ b/js/src/common/components/ReactionComponent.js @@ -19,9 +19,9 @@ export default class ReactionComponent extends Component { if (reaction.type() === 'emoji') { const { url } = emoji(reaction.identifier()); - return {display}; + return {display}; } else { - return ; + return ; } } } diff --git a/js/src/forum/components/PostReactAction.js b/js/src/forum/components/PostReactAction.js index d8756c4..b96f3a3 100755 --- a/js/src/forum/components/PostReactAction.js +++ b/js/src/forum/components/PostReactAction.js @@ -63,6 +63,8 @@ export default class PostReactAction extends Component { const reactionCounts = this.post.reactionCounts(); const canReact = this.post.canReact(); + const hasReacted = this.post.userReaction() && reactionCounts[this.post.userReaction()] > 0; + return (
@@ -77,9 +79,7 @@ export default class PostReactAction extends Component { return Button.component( { - className: `Button Button--flat Button-emoji-parent ${ - this.post.userReaction() && this.post.userReaction() == reaction.id() && 'active' - }`, + className: `Button Button--flat Button-emoji-parent ${this.post.userReaction() == reaction.id() && 'active'}`, onclick: canReact ? this.react.bind(this, reaction) : '', 'data-reaction': reaction.identifier(), disabled: !canReact, @@ -92,7 +92,7 @@ export default class PostReactAction extends Component { })}
- {(!Object.keys(this.loading).length || this.loading[null]) && !this.post.userReaction() && canReact && ( + {(!Object.keys(this.loading).length || this.loading[null]) && !hasReacted && canReact && (
{this.reactButton()} diff --git a/js/src/forum/components/ReactionsModal.tsx b/js/src/forum/components/ReactionsModal.tsx index 59f2daa..25b368b 100644 --- a/js/src/forum/components/ReactionsModal.tsx +++ b/js/src/forum/components/ReactionsModal.tsx @@ -12,6 +12,7 @@ import Post from 'flarum/common/models/Post'; import { ApiResponsePlural } from 'flarum/common/Store'; import User from 'flarum/common/models/User'; import Reaction from '../../common/models/Reaction'; +import Button from 'flarum/common/components/Button'; interface ReactionsModalAttrs extends IInternalModalAttrs { post: Post; @@ -19,7 +20,7 @@ interface ReactionsModalAttrs extends IInternalModalAttrs { interface ReactionGroup { reaction: Reaction; - users: User[]; + users: Record; // map the post reaction id to the user anonymousCount: number; } @@ -27,6 +28,9 @@ export default class ReactionsModal extends Modal { reactions: ReactionGroup[] = []; loading: boolean = false; + deletingSpecific: Record = {}; + deletingType: Record = {}; + className() { return 'ReactionsModal Modal--small'; } @@ -53,27 +57,51 @@ export default class ReactionsModal extends Modal {
    {this.reactions.map(({ reaction, users, anonymousCount }) => this.buildReactionSection(reaction, users, anonymousCount))} + + {!this.reactions.length &&

    {app.translator.trans('fof-reactions.forum.modal.no_reactions')}

    }
); } - buildReactionSection(reaction: Reaction, users: User[], anonymousCount: number): Mithril.Children { + buildReactionSection(reaction: Reaction, users: Record, anonymousCount: number): Mithril.Children { + const post = this.attrs.post; + + // The user can delete the reaction if they can delete reactions on the post, or + // if they can react (i.e. modify their reaction) and it's their own reaction + const canDeleteReaction = (user: User) => post.canDeletePostReactions() || (post.canReact() && user === app.session.user); + return (
+ {post.canDeletePostReactions() && ( +