Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert beatmap discussions main component to typescript #10409

Merged
merged 140 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 122 commits
Commits
Show all changes
140 commits
Select commit Hold shift + click to select a range
ffee8c7
convert to typescript (rename)
notbakaneko Jun 1, 2023
3908748
convert to typescript wip
notbakaneko Jun 1, 2023
a67ca1c
convert entrypoint to typescript (rename)
notbakaneko Jun 13, 2023
d8e8696
convert entrypoint to typescript
notbakaneko Jun 13, 2023
be8af65
move state to DiscussionsState
notbakaneko Jun 6, 2023
a66df33
serialize
notbakaneko Jun 7, 2023
5b37da8
more wips whee
notbakaneko Jun 7, 2023
0a19645
wip
notbakaneko Jul 6, 2023
a132ae4
more functionality into discussions state
notbakaneko Jul 6, 2023
82bc4e7
use plain array of discussions in chart
notbakaneko Jul 6, 2023
8b5b21f
use shorthand
notbakaneko Jul 6, 2023
a2414c1
remove the context class
notbakaneko Jul 6, 2023
7d48fee
update editor to use discussions state
notbakaneko Jul 6, 2023
5852506
use DiscussionsState in NewReply
notbakaneko Jul 7, 2023
b3712b0
update NewReview to use DiscussionsState
notbakaneko Jul 7, 2023
874ce77
update NewDiscussion to use DiscussionsState
notbakaneko Jul 7, 2023
08c203f
Nominator use DiscussionsState
notbakaneko Jul 7, 2023
4a4b35b
Nominations use DiscussionsState
notbakaneko Jul 7, 2023
bf1c9ac
ReviewPost and ReviewPostEmbed use DiscussionsState
notbakaneko Jul 7, 2023
14f82a3
UserFilter use DiscussionsState
notbakaneko Jul 7, 2023
aa4aa65
ModeSwitcher uses DiscussionsState
notbakaneko Jul 7, 2023
264227a
Header uses DiscussionsState
notbakaneko Jul 7, 2023
326d55d
Post uses DiscussionsState
notbakaneko Jul 7, 2023
14ce2d9
Discussion uses DiscussionsState
notbakaneko Jul 7, 2023
b2e9720
Discussions uses DiscussionsState
notbakaneko Jul 7, 2023
cdb95d8
beatmap discussions Main component uses DiscussionsState
notbakaneko Jul 7, 2023
91b5c42
use Map instead of Record
notbakaneko Jul 7, 2023
5548eb1
add type for modding profile bundle json
notbakaneko Jul 10, 2023
83419ea
relax the param typing for startingPost, otherwise it makes consolida…
notbakaneko Jul 11, 2023
5215fb9
use the more general type
notbakaneko Jul 11, 2023
75047a1
extract parseState
notbakaneko Jul 18, 2023
be11313
separating object store from ui state
notbakaneko Jul 19, 2023
38a2c78
handle separate store and uistate in Discussion component
notbakaneko Jul 19, 2023
90738e0
maybe split the props?
notbakaneko Jul 19, 2023
bf77dd0
less refering to beatmapset property for discussions and users, etc;
notbakaneko Jul 20, 2023
61869b4
splitting up stores
notbakaneko Jul 20, 2023
e2e38d0
remove contexts
notbakaneko Jul 21, 2023
b00cd74
skip the extra indirection
notbakaneko Jul 21, 2023
f46495d
move evaluation of resovled flag to parent
notbakaneko Jul 21, 2023
0668d65
no editing actions without discussions state
notbakaneko Jul 21, 2023
14a1e87
more separation of store and discussionsState
notbakaneko Jul 21, 2023
29a3e13
missing computeds
notbakaneko Jul 25, 2023
cf8a288
rename property
notbakaneko Jul 25, 2023
b8410d4
renaming and fixing some non-functioning things
notbakaneko Jul 25, 2023
3e3ca16
empty import
notbakaneko Jul 25, 2023
d22b4e8
export default
notbakaneko Jul 25, 2023
6bd6b2c
fix the mode counts
notbakaneko Jul 25, 2023
ae0656b
just spread the props
notbakaneko Jul 25, 2023
c55a920
compute discussions array; discussions already non-null from store
notbakaneko Jul 25, 2023
6d7fd55
fix browser test clicking
notbakaneko Jul 26, 2023
fbfb68b
handle guest user
notbakaneko Jul 26, 2023
9551dd3
unused event
notbakaneko Jul 26, 2023
23cf59c
should be jumping when not restoring
notbakaneko Jul 26, 2023
36d8ae7
these are json date strings, not timestamps...
notbakaneko Jul 26, 2023
ef03a48
update correct beatmapset observable
notbakaneko Jul 26, 2023
4258e90
pass whole response in
notbakaneko Jul 26, 2023
513e6b7
class name hasn't been updated yet in this branch
notbakaneko Jul 26, 2023
26e914a
action should have makeObservable?
notbakaneko Jul 31, 2023
e83bab1
mobx doesn't like undefined 0 index
notbakaneko Jul 31, 2023
c790067
account for type of everyone option
notbakaneko Jul 31, 2023
67d89e5
mobx doesn't like accessing index 0 of empty array
notbakaneko Aug 1, 2023
eea679f
only show users with discussions in user filter
notbakaneko Aug 1, 2023
d4d3464
lint fix
notbakaneko Aug 1, 2023
7f89086
update max-warnings count
notbakaneko Aug 1, 2023
32206c4
move to correct directory
notbakaneko Aug 4, 2023
d16e41e
filter discussionsByMode in a single loop; helper functions also ende…
notbakaneko Aug 8, 2023
ef944d7
discussionsByFilter in single loop
notbakaneko Aug 9, 2023
604e59d
show deleted discussions if canModerate
notbakaneko Aug 10, 2023
225e078
doesn't need extra params or be bound
notbakaneko Aug 28, 2023
d2dcf29
wrong type
notbakaneko Aug 28, 2023
f9bee98
fix jumping to discussion;
notbakaneko Aug 28, 2023
4e2f401
also set correct beatmap
notbakaneko Aug 28, 2023
0f5fa7c
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Aug 28, 2023
4a19356
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Aug 30, 2023
c9d7206
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Sep 8, 2023
117e377
convert changes from 98507a2a to typescript
notbakaneko Sep 8, 2023
e10bf86
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Sep 13, 2023
9f940d1
nominations should be non-null
notbakaneko Sep 13, 2023
54ccfe7
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Sep 15, 2023
4c80969
don't double parse
notbakaneko Sep 15, 2023
805ae01
one or the other, not both
notbakaneko Sep 15, 2023
72eb9d3
moved to UserFilter; also remove hype from list
notbakaneko Sep 25, 2023
dd36005
missing annotations
notbakaneko Sep 25, 2023
a0bc4ba
use Page naming when including events
notbakaneko Sep 25, 2023
c9e6a40
split discussion page and mode
notbakaneko Sep 25, 2023
16bb4e2
skip checking for update instead of cancelling if already in progress
notbakaneko Sep 25, 2023
5574f6a
some cleanups
notbakaneko Sep 25, 2023
080a3b2
should be no empty beatmaps or discussions
notbakaneko Sep 26, 2023
c810b57
split line + remove comment
notbakaneko Sep 26, 2023
18cf66c
put the wrong set of discussions while reorganizing
notbakaneko Sep 26, 2023
1a364d4
add back missing user filtering
notbakaneko Sep 26, 2023
723f074
should be Object.assign :facepalm:
notbakaneko Sep 26, 2023
4456c7c
also doesn't need to return observable object
notbakaneko Sep 26, 2023
8f1757b
this page is read only
notbakaneko Sep 26, 2023
0ae327f
unused event
notbakaneko Sep 26, 2023
2fd5087
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Sep 26, 2023
6d7daf7
lint fixes
notbakaneko Sep 26, 2023
847491d
preview and readonly stopped being different when editing was removed…
notbakaneko Sep 26, 2023
f3e7c1b
skip parsing old beatmapset json if container has saved beatmapset
notbakaneko Oct 31, 2023
595e5af
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Oct 31, 2023
e124314
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Nov 14, 2023
4d52d41
navigating history needs original data
notbakaneko Nov 14, 2023
915881d
rename store interface
notbakaneko Nov 14, 2023
dc7605f
inline and clearly comment
notbakaneko Nov 14, 2023
1d34e82
derive readonly from presence of DiscussionsState, use typeguard to d…
notbakaneko Nov 14, 2023
3f356bd
seperate type filters into component
notbakaneko Nov 15, 2023
18a80c9
update url from state
notbakaneko Nov 15, 2023
f261596
dispose reaction
notbakaneko Nov 15, 2023
597cf51
missing observer
notbakaneko Nov 15, 2023
d99b502
add TODO
notbakaneko Nov 15, 2023
ba42975
beatmapset comes from store now
notbakaneko Nov 15, 2023
e76a52b
overwrite existing json data on the page when saving state
notbakaneko Nov 15, 2023
a1e335e
remove initialData prop
notbakaneko Nov 15, 2023
96d5acd
store state into script element, remove container
notbakaneko Nov 15, 2023
41bbea6
limit types getting serialized;
notbakaneko Nov 15, 2023
4d46929
undisable rule
notbakaneko Nov 15, 2023
17a7641
invoke update directly
notbakaneko Nov 15, 2023
6ee2a02
add note on which properties they're for
notbakaneko Nov 15, 2023
cba066a
store local observable; make mobx7 compatible
notbakaneko Nov 16, 2023
9ef120e
accessors (and thus observables) won't be iterable for stringify in m…
notbakaneko Nov 16, 2023
ff92baf
get array index with bounds check helper for mobx
notbakaneko Nov 16, 2023
cca62cf
rename for mobx since oob behaviour is specific for mobx warnings
notbakaneko Nov 16, 2023
32f1b96
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Jan 11, 2024
711b991
move cleanups to turbolinks:before-cache
notbakaneko Jan 11, 2024
e168dbd
remove listener on destroy
notbakaneko Jan 11, 2024
b74f5f5
getter order
notbakaneko Jan 11, 2024
1aeef0c
count unresolved only
notbakaneko Jan 11, 2024
3f374b5
pass discussionState to beatmap list component
notbakaneko Jan 12, 2024
e214e2c
mobx the state
notbakaneko Jan 12, 2024
dc67466
just loop once since the values are always used
notbakaneko Jan 12, 2024
e7078e9
combine unresolved discussion counts
notbakaneko Jan 12, 2024
1be1eb8
unused
notbakaneko Jan 12, 2024
a4320df
exclude deleted discussions from counts and filters
notbakaneko Jan 12, 2024
a1872a2
combine getter/functions
notbakaneko Jan 12, 2024
bfe562f
fix missing polling
notbakaneko Jan 12, 2024
c4e2824
more consistent naming?
notbakaneko Jan 12, 2024
5ec3929
add note
notbakaneko Jan 12, 2024
2c3a264
discriminate pased on props; remove unused default prop
notbakaneko Jan 12, 2024
0066879
skip destructuring
notbakaneko Jan 26, 2024
1693c18
Merge branch 'master' into feature/ts-discussions-main
notbakaneko Jan 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: Install js dependencies
run: yarn --frozen-lockfile

- run: 'yarn lint --max-warnings 96 > /dev/null'
- run: 'yarn lint --max-warnings 95 > /dev/null'

- run: ./bin/update_licence.sh -nf

Expand Down
114 changes: 33 additions & 81 deletions resources/js/beatmap-discussions-history/main.tsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,50 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the GNU Affero General Public License v3.0.
// See the LICENCE file in the repository root for full licence text.

import { BeatmapsContext } from 'beatmap-discussions/beatmaps-context';
import { BeatmapsetsContext } from 'beatmap-discussions/beatmapsets-context';
import { Discussion } from 'beatmap-discussions/discussion';
import { DiscussionsContext } from 'beatmap-discussions/discussions-context';
import BeatmapsetCover from 'components/beatmapset-cover';
import BeatmapsetDiscussionsBundleJson from 'interfaces/beatmapset-discussions-bundle-json';
import { keyBy } from 'lodash';
import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import { deletedUserJson } from 'models/user';
import * as React from 'react';
import BeatmapsetDiscussionsBundleStore from 'stores/beatmapset-discussions-bundle-store';
import { makeUrl } from 'utils/beatmapset-discussion-helper';
import { trans } from 'utils/lang';

interface Props {
bundle: BeatmapsetDiscussionsBundleJson;
}

@observer
export default class Main extends React.Component<Props> {
@computed
private get beatmaps() {
return keyBy(this.props.bundle.beatmaps, 'id');
}

@computed
private get beatmapsets() {
return keyBy(this.props.bundle.beatmapsets, 'id');
}

@computed
private get discussions() {
return keyBy(this.props.bundle.included_discussions, 'id');
}

@computed
private get users() {
const values = keyBy(this.props.bundle.users, 'id');
// eslint-disable-next-line id-blacklist
values.null = values.undefined = deletedUserJson;

return values;
}

constructor(props: Props) {
super(props);

makeObservable(this);
}
export default class Main extends React.Component<BeatmapsetDiscussionsBundleJson> {
private readonly store = new BeatmapsetDiscussionsBundleStore(this.props);

render() {
return (
<DiscussionsContext.Provider value={this.discussions}>
<BeatmapsetsContext.Provider value={this.beatmapsets}>
<BeatmapsContext.Provider value={this.beatmaps}>
<div className='modding-profile-list modding-profile-list--index'>
{this.props.bundle.discussions.length === 0 ? (
<div className='modding-profile-list__empty'>
{trans('beatmap_discussions.index.none_found')}
</div>
) : (this.props.bundle.discussions.map((discussion) => {
// TODO: handle in child component? Refactored state might not have beatmapset here (and uses Map)
const beatmapset = this.beatmapsets[discussion.beatmapset_id];

return beatmapset != null && (
<div key={discussion.id} className='modding-profile-list__row'>
<a
className='modding-profile-list__thumbnail'
href={makeUrl({ discussion })}
>
<BeatmapsetCover
beatmapset={beatmapset}
size='list'
/>
</a>
<Discussion
beatmapset={beatmapset}
currentBeatmap={discussion.beatmap_id != null ? this.beatmaps[discussion.beatmap_id] : null}
discussion={discussion}
isTimelineVisible={false}
preview
readonly
showDeleted
users={this.users}
/>
</div>
);
}))}
<div className='modding-profile-list modding-profile-list--index'>
{this.props.discussions.length === 0 ? (
<div className='modding-profile-list__empty'>
{trans('beatmap_discussions.index.none_found')}
</div>
) : (this.props.discussions.map((discussion) => {
// TODO: handle in child component? Refactored state might not have beatmapset here (and uses Map)
const beatmapset = this.store.beatmapsets.get(discussion.beatmapset_id);

return beatmapset != null && (
<div key={discussion.id} className='modding-profile-list__row'>
<a
className='modding-profile-list__thumbnail'
href={makeUrl({ discussion })}
>
<BeatmapsetCover
beatmapset={beatmapset}
size='list'
/>
</a>
<Discussion
discussion={discussion}
discussionsState={null}
isTimelineVisible={false}
readonly
store={this.store}
/>
</div>
</BeatmapsContext.Provider>
</BeatmapsetsContext.Provider>
</DiscussionsContext.Provider>
);
}))}
</div>
);
}
}
6 changes: 3 additions & 3 deletions resources/js/beatmap-discussions/beatmap-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import BeatmapListItem from 'components/beatmap-list-item';
import BeatmapExtendedJson from 'interfaces/beatmap-extended-json';
import BeatmapsetJson from 'interfaces/beatmapset-json';
import UserJson from 'interfaces/user-json';
import { deletedUser } from 'models/user';
import { deletedUserJson } from 'models/user';
import * as React from 'react';
import { blackoutToggle } from 'utils/blackout';
import { classWithModifiers } from 'utils/css';
Expand All @@ -19,7 +19,7 @@ interface Props {
currentBeatmap: BeatmapExtendedJson;
getCount: (beatmap: BeatmapExtendedJson) => number | undefined;
onSelectBeatmap: (beatmapId: number) => void;
users: Partial<Record<number, UserJson>>;
users: Map<number | null | undefined, UserJson>;
}

interface State {
Expand Down Expand Up @@ -86,7 +86,7 @@ export default class BeatmapList extends React.PureComponent<Props, State> {
beatmap={beatmap}
beatmapUrl={this.props.createLink(beatmap)}
beatmapset={this.props.beatmapset}
mapper={this.props.users[beatmap.user_id] ?? deletedUser}
mapper={this.props.users.get(beatmap.user_id) ?? deletedUserJson}
showNonGuestMapper={false}
/>
{count != null &&
Expand Down
12 changes: 6 additions & 6 deletions resources/js/beatmap-discussions/beatmap-owner-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Spinner } from 'components/spinner';
import UserAvatar from 'components/user-avatar';
import UserLink from 'components/user-link';
import BeatmapJson from 'interfaces/beatmap-json';
import BeatmapsetExtendedJson from 'interfaces/beatmapset-extended-json';
import BeatmapsetWithDiscussionsJson from 'interfaces/beatmapset-with-discussions-json';
import UserJson from 'interfaces/user-json';
import { route } from 'laroute';
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
Expand All @@ -16,17 +16,17 @@ import { onErrorWithCallback } from 'utils/ajax';
import { classWithModifiers } from 'utils/css';
import { transparentGif } from 'utils/html';
import { trans } from 'utils/lang';

type BeatmapsetWithDiscussionJson = BeatmapsetExtendedJson;
import DiscussionsState from './discussions-state';

interface XhrCollection {
updateOwner: JQuery.jqXHR<BeatmapsetWithDiscussionJson>;
updateOwner: JQuery.jqXHR<BeatmapsetWithDiscussionsJson>;
userLookup: JQuery.jqXHR<UserJson>;
}

interface Props {
beatmap: BeatmapJson;
beatmapsetUser: UserJson;
discussionsState: DiscussionsState;
user: UserJson;
userByName: Map<string, UserJson>;
}
Expand Down Expand Up @@ -245,8 +245,8 @@ export default class BeatmapOwnerEditor extends React.Component<Props> {
data: { beatmap: { user_id: userId } },
method: 'PUT',
});
this.xhr.updateOwner.done((data) => runInAction(() => {
$.publish('beatmapsetDiscussions:update', { beatmapset: data });
this.xhr.updateOwner.done((beatmapset) => runInAction(() => {
this.props.discussionsState.update({ beatmapset });
this.editing = false;
})).fail(onErrorWithCallback(() => {
this.updateOwner(userId);
Expand Down
9 changes: 0 additions & 9 deletions resources/js/beatmap-discussions/beatmaps-context.ts

This file was deleted.

9 changes: 6 additions & 3 deletions resources/js/beatmap-discussions/beatmaps-owner-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import * as React from 'react';
import { group as groupBeatmaps } from 'utils/beatmap-helper';
import { trans } from 'utils/lang';
import BeatmapOwnerEditor from './beatmap-owner-editor';
import DiscussionsState from './discussions-state';

interface Props {
beatmapset: BeatmapsetExtendedJson;
discussionsState: DiscussionsState;
onClose: () => void;
users: Partial<Record<number, UserJson>>;
users: Map<number | null | undefined, UserJson>;
}

@observer
Expand All @@ -26,7 +28,7 @@ export default class BeatmapsOwnerEditor extends React.Component<Props> {

// this will be outdated on new props but it's fine
// as there's separate process handling unknown users
for (const user of Object.values(props.users)) {
for (const user of this.props.users.values()) {
if (user != null) {
this.userByName.set(normaliseUsername(user.username), user);
}
Expand Down Expand Up @@ -61,6 +63,7 @@ export default class BeatmapsOwnerEditor extends React.Component<Props> {
key={beatmap.id}
beatmap={beatmap}
beatmapsetUser={beatmapsetUser}
discussionsState={this.props.discussionsState}
user={this.getUser(beatmap.user_id)}
userByName={this.userByName}
/>
Expand All @@ -82,6 +85,6 @@ export default class BeatmapsOwnerEditor extends React.Component<Props> {
}

private getUser(userId: number) {
return this.props.users[userId] ?? deletedUserJson;
return this.props.users.get(userId) ?? deletedUserJson;
}
}
9 changes: 0 additions & 9 deletions resources/js/beatmap-discussions/beatmapsets-context.ts

This file was deleted.

4 changes: 2 additions & 2 deletions resources/js/beatmap-discussions/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { formatTimestamp, makeUrl } from 'utils/beatmapset-discussion-helper';
import { classWithModifiers } from 'utils/css';

interface Props {
discussions: Partial<Record<string, BeatmapsetDiscussionJson>>;
discussions: BeatmapsetDiscussionJson[];
duration: number;
}

Expand All @@ -22,7 +22,7 @@ export default function Chart(props: Props) {
const items: React.ReactNode[] = [];

if (props.duration !== 0) {
Object.values(props.discussions).forEach((discussion) => {
props.discussions.forEach((discussion) => {
if (discussion == null || discussion.timestamp == null) return;

let className = classWithModifiers('beatmapset-discussions-chart__item', [
Expand Down
5 changes: 2 additions & 3 deletions resources/js/beatmap-discussions/discussion-mode.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the GNU Affero General Public License v3.0.
// See the LICENCE file in the repository root for full licence text.

// In display order on discussion page tabs
export const discussionPages = ['reviews', 'generalAll', 'general', 'timeline', 'events'] as const;
export type DiscussionPage = (typeof discussionPages)[number];
import DiscussionPage from './discussion-page';

type DiscussionMode = Exclude<DiscussionPage, 'events'>;
export const discussionModes: Readonly<DiscussionMode[]> = ['reviews', 'generalAll', 'general', 'timeline'] as const;

export default DiscussionMode;
14 changes: 14 additions & 0 deletions resources/js/beatmap-discussions/discussion-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the GNU Affero General Public License v3.0.
// See the LICENCE file in the repository root for full licence text.

// In display order on discussion page tabs
export const discussionPages = ['reviews', 'generalAll', 'general', 'timeline', 'events'] as const;
type DiscussionPage = (typeof discussionPages)[number];

const discussionPageSet = new Set<unknown>(discussionPages);

export function isDiscussionPage(value: unknown): value is DiscussionPage {
return discussionPageSet.has(value);
}

export default DiscussionPage;
11 changes: 7 additions & 4 deletions resources/js/beatmap-discussions/discussion-vote-buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import UserListPopup, { createTooltip } from 'components/user-list-popup';
import { BeatmapsetDiscussionJsonForShow } from 'interfaces/beatmapset-discussion-json';
import BeatmapsetWithDiscussionsJson from 'interfaces/beatmapset-with-discussions-json';
import UserJson from 'interfaces/user-json';
import { route } from 'laroute';
import { action, computed, makeObservable, observable } from 'mobx';
Expand All @@ -14,20 +15,22 @@ import { onError } from 'utils/ajax';
import { classWithModifiers } from 'utils/css';
import { trans } from 'utils/lang';
import { hideLoadingOverlay, showLoadingOverlay } from 'utils/loading-overlay';
import DiscussionsState from './discussions-state';

const voteTypes = ['up', 'down'] as const;
type VoteType = typeof voteTypes[number];

interface Props {
cannotVote: boolean;
discussion: BeatmapsetDiscussionJsonForShow;
users: Partial<Record<number | string, UserJson>>;
discussionsState: DiscussionsState;
users: Map<number | null | undefined, UserJson>;
}

@observer
export default class DiscussionVoteButtons extends React.Component<Props> {
private readonly tooltips: Partial<Record<VoteType, JQuery>> = {};
@observable private voteXhr: JQuery.jqXHR<BeatmapsetDiscussionJsonForShow> | null = null;
@observable private voteXhr: JQuery.jqXHR<BeatmapsetWithDiscussionsJson> | null = null;

@computed
private get canDownvote() {
Expand Down Expand Up @@ -68,7 +71,7 @@ export default class DiscussionVoteButtons extends React.Component<Props> {
? trans(`beatmaps.discussions.votes.none.${type}`)
: `${trans(`beatmaps.discussions.votes.latest.${type}`)}:`;

const users = this.props.discussion.votes.voters[type].map((id) => this.props.users[id] ?? { id });
const users = this.props.discussion.votes.voters[type].map((id) => this.props.users.get(id) ?? { id });

return renderToStaticMarkup(<UserListPopup count={count} title={title} users={users} />);
}
Expand All @@ -89,7 +92,7 @@ export default class DiscussionVoteButtons extends React.Component<Props> {
});

this.voteXhr
.done((beatmapset) => $.publish('beatmapsetDiscussions:update', { beatmapset }))
.done((beatmapset) => this.props.discussionsState.update({ beatmapset }))
.fail(onError)
.always(action(() => {
hideLoadingOverlay();
Expand Down
Loading