Skip to content

Commit

Permalink
chore: TS refactor (#107)
Browse files Browse the repository at this point in the history
* wip: full ts

* wip

* progress..

* fix some ts erros

* more ts

* ts

* disable ts

* chore: install typescript-coverage-report, reenable TS in workflow

* fix: add a11y label to jump button

* Update js/src/forum/components/SelectBestAnswerNotification.ts

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/components/SolutionSearchItem.tsx

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/components/SolutionSearchItem.tsx

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/components/SolutionSearchItem.tsx

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/extend.ts

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/extenders/extendDiscussionComposer.tsx

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/extenders/extendDiscussionSearchSource.tsx

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/components/AwardedBestAnswerNotification.ts

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/components/BestAnswerInDiscussionNotification.ts

Co-authored-by: Davide Iadeluca <[email protected]>

* chore: remove unneeded tsignore

* Update js/src/forum/addBestAnswerCountToUsers.tsx

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/@types/shims.d.ts

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/@types/shims.d.ts

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/extenders/extendIndexPage.tsx

Co-authored-by: Davide Iadeluca <[email protected]>

* Update js/src/forum/extenders/extendIndexPage.tsx

Co-authored-by: Davide Iadeluca <[email protected]>

* import type PaginatedListParams

* chore: format

* chore: add dummy imports

* chore: format

---------

Co-authored-by: Davide Iadeluca <[email protected]>
Co-authored-by: Davide Iadeluca <[email protected]>
  • Loading branch information
3 people authored Nov 2, 2024
1 parent 52cecc7 commit 95aa3c6
Show file tree
Hide file tree
Showing 21 changed files with 915 additions and 181 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
with:
enable_bundlewatch: false
enable_prettier: true
enable_typescript: false
enable_typescript: true

frontend_directory: ./js
backend_directory: .
Expand Down
11 changes: 5 additions & 6 deletions js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
"version": "0.0.0",
"private": true,
"prettier": "@flarum/prettier-config",
"dependencies": {
"devDependencies": {
"@flarum/prettier-config": "^1.0.0",
"flarum-tsconfig": "^1.0.2",
"flarum-tsconfig": "^1.0.3",
"flarum-webpack-config": "^2.0.2",
"webpack": "^5.88.0",
"webpack-cli": "^5.1.4"
},
"devDependencies": {
"prettier": "^3.0.3"
"webpack-cli": "^5.1.4",
"prettier": "^3.3.3",
"typescript-coverage-report": "^0.6.1"
},
"scripts": {
"dev": "webpack --mode development --watch",
Expand Down
35 changes: 28 additions & 7 deletions js/src/@types/shims.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,39 @@
import Post from 'flarum/common/models/Post';
import User from 'flarum/common/models/User';
import 'flarum/common/models/Discussion';
import 'flarum/tags/common/models/Tag';
import 'flarum/forum/states/DiscussionListState';
import 'flarum/common/models/User';

import type Post from 'flarum/common/models/Post';
import type Discussion from 'flarum/common/models/Discussion';
import type User from 'flarum/common/models/User';
import type Tag from 'flarum/tags/common/models/Tag';
import type DiscussionListState from 'flarum/forum/states/DiscussionListState';

declare module 'flarum/common/models/Discussion' {
export default interface Discussion {
hasBestAnswer(): boolean;
bestAnswerPost(): Post;
bestAnswerUser(): User;
hasBestAnswer(): boolean | undefined;
bestAnswerPost(): Post | null;
bestAnswerUser(): User | null;
canSelectBestAnswer(): boolean;
bestAnswerSetAt(): Date;
bestAnswerSetAt(): Date | null;
}
}

declare module 'flarum/tags/models/Tag' {
declare module 'flarum/tags/common/models/Tag' {
export default interface Tag {
isQnA(): boolean;
reminders(): boolean;
}
}

declare module 'flarum/forum/states/DiscussionListState' {
export default interface DiscussionListState {
bestAnswer: string | undefined;
}
}

declare module 'flarum/common/models/User' {
export default interface User {
bestAnswerCount(): number;
}
}
3 changes: 1 addition & 2 deletions js/src/common/extend.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Extend from 'flarum/common/extenders';
// @ts-ignore
import Tag from 'flarum/tags/models/Tag';
import Tag from 'flarum/tags/common/models/Tag';

export default [
new Extend.Model(Tag) //
Expand Down
117 changes: 0 additions & 117 deletions js/src/forum/addBestAnswerAction.js

This file was deleted.

123 changes: 123 additions & 0 deletions js/src/forum/addBestAnswerAction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import app from 'flarum/forum/app';
import { extend } from 'flarum/common/extend';
import Button from 'flarum/common/components/Button';
import PostControls from 'flarum/forum/utils/PostControls';
import DiscussionPage from 'flarum/forum/components/DiscussionPage';
import CommentPost from 'flarum/forum/components/CommentPost';
import Discussion from 'flarum/common/models/Discussion';
import Post from 'flarum/common/models/Post';
import extractText from 'flarum/common/utils/extractText';

export default function addBestAnswerAction() {
const ineligible = (discussion: Discussion, post: Post) => {
return post.isHidden() || post.number() === 1 || !discussion.canSelectBestAnswer() || !app.session.user;
};

const blockSelectOwnPost = (post: Post): boolean => {
const user = post.user();
return !app.forum.attribute<boolean>('canSelectBestAnswerOwnPost') && user !== false && user.id() === app.session.user?.id();
};

const isThisBestAnswer = (discussion: Discussion, post: Post): boolean => {
const bestAnswerPost = discussion.bestAnswerPost();
const hasBestAnswer = discussion.hasBestAnswer();
return hasBestAnswer !== undefined && hasBestAnswer && bestAnswerPost !== null && bestAnswerPost.id() === post.id();
};

const actionLabel = (isBestAnswer: boolean): string => {
return extractText(app.translator.trans(isBestAnswer ? 'fof-best-answer.forum.remove_best_answer' : 'fof-best-answer.forum.this_best_answer'));
};

const saveDiscussion = (discussion: Discussion, isBestAnswer: boolean, post: Post) =>
discussion
.save(
{
bestAnswerPostId: isBestAnswer ? post.id() : 0,
bestAnswerUserId: app.session.user?.id(),
relationships: isBestAnswer ? { bestAnswerPost: post, bestAnswerUser: app.session.user } : { bestAnswerPost: null },
},
{
params: {
include: 'tags',
},
}
)
.then(() => {
if (!isBestAnswer) {
if (discussion.data.relationships) {
delete discussion.data.relationships.bestAnswerPost;
delete discussion.data.relationships.bestAnswerUser;
}
}

if (app.current.matches(DiscussionPage)) {
app.current.get('stream').update();
}

m.redraw();

if (isBestAnswer) {
m.route.set(app.route.discussion(discussion));
}
});

extend(PostControls, 'moderationControls', function (items, post) {
if (app.forum.attribute('useAlternativeBestAnswerUi')) return;

const discussion = post.discussion();
let isBestAnswer = isThisBestAnswer(discussion, post);

post.pushAttributes({ isBestAnswer });

if (post.contentType() !== 'comment') return;

if (ineligible(discussion, post) || blockSelectOwnPost(post) || !app.current.matches(DiscussionPage)) return;

items.add(
'bestAnswer',
<Button
icon={`fa${isBestAnswer ? 's' : 'r'} fa-comment-dots`}
onclick={() => {
isBestAnswer = !isBestAnswer;

saveDiscussion(discussion, isBestAnswer, post).finally(() => {
isBestAnswer = isThisBestAnswer(discussion, post);
});
}}
>
{actionLabel(isBestAnswer)}
</Button>
);
});

extend(CommentPost.prototype, 'actionItems', function (items) {
if (!app.forum.attribute('useAlternativeBestAnswerUi')) return;

const post = this.attrs.post;
const discussion = this.attrs.post.discussion();
let isBestAnswer = isThisBestAnswer(discussion, post);
let hasBestAnswer = discussion.bestAnswerPost() !== null;

post.pushAttributes({ isBestAnswer });

if (ineligible(discussion, post) || blockSelectOwnPost(post) || !app.current.matches(DiscussionPage)) return;

items.add(
'bestAnswer',
<Button
className={`Button Button--${!hasBestAnswer || isBestAnswer ? 'primary' : 'link'}`}
onclick={() => {
hasBestAnswer = !hasBestAnswer;
isBestAnswer = !isBestAnswer;

saveDiscussion(discussion, isBestAnswer, post).finally(() => {
hasBestAnswer = !!discussion.hasBestAnswer() && discussion.bestAnswerPost() !== null;
isBestAnswer = isThisBestAnswer(discussion, post);
});
}}
>
{actionLabel(isBestAnswer)}
</Button>
);
});
}
4 changes: 3 additions & 1 deletion js/src/forum/addBestAnswerCountToUsers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import UserCard from 'flarum/forum/components/UserCard';
import icon from 'flarum/common/helpers/icon';

import type Mithril from 'mithril';
import type User from 'flarum/common/models/User';

export default function addBestAnswerCountToUsers() {
extend(UserCard.prototype, 'infoItems', function (items: ItemList<Mithril.Children>) {
const user = this.attrs.user;
// @ts-expect-error
const user = this.attrs.user as User;

items.add(
'best-answer-count',
Expand Down
15 changes: 10 additions & 5 deletions js/src/forum/addBestAnswerView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default () => {
const post = this.attrs.post;
const discussion = post.discussion();

if (discussion?.hasBestAnswer() && discussion.bestAnswerPost() && discussion.bestAnswerPost().id() === post.id() && !post.isHidden()) {
if (discussion?.hasBestAnswer() && discussion.bestAnswerPost() && discussion.bestAnswerPost()?.id() === post.id() && !post.isHidden()) {
items.add('isBestAnswer', <SelectBestAnswerItem post={post} discussion={discussion} />, -100);
}
});
Expand Down Expand Up @@ -41,17 +41,22 @@ export default () => {
extend(DiscussionPage.prototype, 'sidebarItems', function (items) {
if (!app.forum.attribute<boolean>('bestAnswerDiscussionSidebarJumpButton')) return;

/** @ts-ignore */
// @ts-ignore
const discussion = this.discussion;

if (!discussion) return;
if (discussion === null) return;

const post = discussion.hasBestAnswer() && discussion.bestAnswerPost();

if (post && !post.isHidden() && post.number() !== 1 && !discussion.bestAnswerPost().isHidden()) {
if (post && !post.isHidden() && post.number() !== 1 && !discussion.bestAnswerPost()?.isHidden()) {
items.add(
'jumpToBestAnswer',
<Button className="Button Button-jumpBestAnswer" icon="fas fa-check" onclick={() => app.current.get('stream').goToNumber(post.number())}>
<Button
className="Button Button-jumpBestAnswer"
icon="fas fa-check"
onclick={() => app.current.get('stream').goToNumber(post.number())}
aria-label={app.translator.trans('fof-best-answer.forum.discussion.jump_to_best_answer_button')}
>
{app.translator.trans('fof-best-answer.forum.discussion.jump_to_best_answer_button')}
</Button>,
90
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type Discussion from 'flarum/common/models/Discussion';
import app from 'flarum/forum/app';
import Notification from 'flarum/forum/components/Notification';

Expand All @@ -8,7 +9,7 @@ export default class AwardedBestAnswerNotification extends Notification {

href() {
const notification = this.attrs.notification;
const discussion = notification.subject();
const discussion = notification.subject() as Discussion;

return app.route.discussion(discussion);
}
Expand Down
Loading

0 comments on commit 95aa3c6

Please sign in to comment.