From dbc3aac14e0c0f3fc531457acc0c83a9c81eea96 Mon Sep 17 00:00:00 2001 From: David Sevilla Martin Date: Sat, 28 Mar 2020 09:09:46 -0400 Subject: [PATCH] forum: add RenameDiscussionModal, DiscussionRenamedPost and EventPost components --- js/src/forum/Forum.ts | 9 ++- .../components/DiscussionRenamedPost.tsx | 29 +++++++ js/src/forum/components/EventPost.tsx | 68 ++++++++++++++++ .../components/RenameDiscussionModal.tsx | 81 +++++++++++++++++++ js/src/forum/utils/DiscussionControls.tsx | 2 +- 5 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 js/src/forum/components/DiscussionRenamedPost.tsx create mode 100644 js/src/forum/components/EventPost.tsx create mode 100644 js/src/forum/components/RenameDiscussionModal.tsx diff --git a/js/src/forum/Forum.ts b/js/src/forum/Forum.ts index 117c446c1..c8df1f9d4 100644 --- a/js/src/forum/Forum.ts +++ b/js/src/forum/Forum.ts @@ -6,6 +6,7 @@ import HeaderSecondary from './components/HeaderSecondary'; import Page from './components/Page'; import DiscussionList from './components/DiscussionList'; import CommentPost from './components/CommentPost'; +import DiscussionRenamedPost from './components/DiscussionRenamedPost'; import Notification from '../common/models/Notification'; @@ -29,7 +30,7 @@ export default class Forum extends Application { postComponents = { comment: CommentPost, - // discussionRenamed: DiscussionRenamedPost + discussionRenamed: DiscussionRenamedPost, }; previous?: Page; @@ -74,11 +75,11 @@ export default class Forum extends Application { $('#home-link').click((e: MouseEvent) => { if (e.ctrlKey || e.metaKey || e.which === 2) return; e.preventDefault(); - app.history.home(); + this.history.home(); // Reload the current user so that their unread notification count is refreshed. - if (app.session.user) { - app.store.find('users', app.session.user.id()); + if (this.session.user) { + this.store.find('users', this.session.user.id()); m.redraw(); } }); diff --git a/js/src/forum/components/DiscussionRenamedPost.tsx b/js/src/forum/components/DiscussionRenamedPost.tsx new file mode 100644 index 000000000..7d0ae7bff --- /dev/null +++ b/js/src/forum/components/DiscussionRenamedPost.tsx @@ -0,0 +1,29 @@ +import EventPost from './EventPost'; + +/** + * The `DiscussionRenamedPost` component displays a discussion event post + * indicating that the discussion has been renamed. + */ +export default class DiscussionRenamedPost extends EventPost { + icon() { + return 'fas fa-pencil-alt'; + } + + description(data) { + const renamed = app.translator.trans('core.forum.post_stream.discussion_renamed_text', data); + const oldName = app.translator.transText('core.forum.post_stream.discussion_renamed_old_tooltip', data); + + return {renamed}; + } + + descriptionData() { + const post = this.props.post; + const oldTitle = post.content()[0]; + const newTitle = post.content()[1]; + + return { + old: oldTitle, + new: {newTitle}, + }; + } +} diff --git a/js/src/forum/components/EventPost.tsx b/js/src/forum/components/EventPost.tsx new file mode 100644 index 000000000..375401e15 --- /dev/null +++ b/js/src/forum/components/EventPost.tsx @@ -0,0 +1,68 @@ +import Post from './Post'; +import { ucfirst } from '../../common/utils/string'; +import usernameHelper from '../../common/helpers/username'; +import icon from '../../common/helpers/icon'; + +interface DescriptionData { + [key: string]: any; +} + +/** + * The `EventPost` component displays a post which indicating a discussion + * event, like a discussion being renamed or stickied. Subclasses must implement + * the `icon` and `description` methods. + */ +export default abstract class EventPost extends Post { + attrs() { + const attrs = super.attrs(); + + attrs.className = classNames(attrs.className, 'EventPost', ucfirst(this.props.post.contentType()) + 'Post'); + + return attrs; + } + + content() { + const user = this.props.post.user(); + const username = usernameHelper(user); + const data: DescriptionData = Object.assign(this.descriptionData(), { + user, + username: user ? ( + + {username} + + ) : ( + username + ), + }); + + return super + .content() + .concat([icon(this.icon(), { className: 'EventPost-icon' }),
{this.description(data)}
]); + } + + /** + * Get the name of the event icon. + */ + abstract icon(): string; + + /** + * Get the translation data for the description of the event. + */ + abstract descriptionData(): DescriptionData; + + /** + * Get the description text for the event. + * + * @return The description to render in the DOM + */ + description(data: DescriptionData): any { + return app.translator.transChoice(this.descriptionKey(), data.count, data); + } + + /** + * Get the translation key for the description of the event. + */ + descriptionKey(): string { + return ''; + } +} diff --git a/js/src/forum/components/RenameDiscussionModal.tsx b/js/src/forum/components/RenameDiscussionModal.tsx new file mode 100644 index 000000000..2a52cb8e2 --- /dev/null +++ b/js/src/forum/components/RenameDiscussionModal.tsx @@ -0,0 +1,81 @@ +import app from '../app'; + +import Modal from '../../common/components/Modal'; +import Button from '../../common/components/Button'; +import Discussion from '../../common/models/Discussion'; + +/** + * The 'RenameDiscussionModal' displays a modal dialog with an input to rename a discussion + */ +export default class RenameDiscussionModal extends Modal { + discussion!: Discussion; + currentTitle!: string; + newTitle!: Mithril.Stream; + + oninit(vnode) { + super.oninit(vnode); + + this.discussion = this.props.discussion; + this.currentTitle = this.props.currentTitle; + this.newTitle = m.prop(this.currentTitle); + } + + className() { + return 'RenameDiscussionModal Modal--small'; + } + + title() { + return app.translator.transText('core.forum.rename_discussion.title'); + } + + content() { + return ( +
+
+
+ +
+
+ {Button.component({ + className: 'Button Button--primary Button--block', + type: 'submit', + loading: this.loading, + children: app.translator.trans('core.forum.rename_discussion.submit_button'), + })} +
+
+
+ ); + } + + onsubmit(e) { + e.preventDefault(); + + this.loading = true; + + const title = this.newTitle; + const currentTitle = this.currentTitle; + + // If the title is different to what it was before, then save it. After the + // save has completed, update the post stream as there will be a new post + // indicating that the discussion was renamed. + if (title && title !== currentTitle) { + return this.discussion + .save({ title }) + .then(() => { + // if (app.viewingDiscussion(this.discussion)) { + app.current.stream.update(); + // } + + m.redraw(); + this.hide(); + }) + .catch(() => { + this.loading = false; + m.redraw(); + }); + } else { + this.hide(); + } + } +} diff --git a/js/src/forum/utils/DiscussionControls.tsx b/js/src/forum/utils/DiscussionControls.tsx index 58d7ca1d1..3a14ad770 100644 --- a/js/src/forum/utils/DiscussionControls.tsx +++ b/js/src/forum/utils/DiscussionControls.tsx @@ -3,7 +3,7 @@ import DiscussionPage from '../components/DiscussionPage'; import LogInModal from '../components/LogInModal'; import Button from '../../common/components/Button'; import Separator from '../../common/components/Separator'; -// import RenameDiscussionModal from '../components/RenameDiscussionModal'; +import RenameDiscussionModal from '../components/RenameDiscussionModal'; import ItemList from '../../common/utils/ItemList'; import extractText from '../../common/utils/extractText'; import Discussion from '../../common/models/Discussion';