Adding vote display modes (#2426)

* Adding vote display modes

* Only show downvotes setting if site has downvotes enabled.
This commit is contained in:
Dessalines 2024-04-18 20:20:37 -04:00 committed by GitHub
parent 643c1f6f01
commit d8a92812d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 580 additions and 171 deletions

View file

@ -1,4 +1,4 @@
import { colorList, getCommentParentId, showScores } from "@utils/app";
import { colorList, getCommentParentId } from "@utils/app";
import { futureDaysToUnixTime, numToSI } from "@utils/helpers";
import classNames from "classnames";
import { isBefore, parseISO, subMinutes } from "date-fns";
@ -22,6 +22,7 @@ import {
EditComment,
GetComments,
Language,
LocalUserVoteDisplayMode,
MarkCommentReplyAsRead,
MarkPersonMentionAsRead,
PersonMentionView,
@ -54,6 +55,7 @@ import { CommentNodes } from "./comment-nodes";
import { BanUpdateForm } from "../common/mod-action-form-modal";
import CommentActionDropdown from "../common/content-actions/comment-action-dropdown";
import { RequestState } from "../../services/HttpService";
import { VoteDisplay } from "../common/vote-display";
type CommentNodeState = {
showReply: boolean;
@ -80,6 +82,7 @@ interface CommentNodeProps {
showContext?: boolean;
showCommunity?: boolean;
enableDownvotes?: boolean;
voteDisplayMode: LocalUserVoteDisplayMode;
viewType: CommentViewType;
allLanguages: Language[];
siteLanguages: number[];
@ -264,20 +267,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{/* This is an expanding spacer for mobile */}
<div className="me-lg-5 flex-grow-1 flex-lg-grow-0 unselectable pointer mx-2" />
{showScores() && (
<>
<span
className={`me-1 fw-bold ${this.scoreColor}`}
aria-label={I18NextService.i18n.t("number_of_points", {
count: Number(counts.score),
formattedCount: numToSI(counts.score),
})}
>
{numToSI(counts.score)}
</span>
<span className="me-1"></span>
</>
)}
<VoteDisplay
voteDisplayMode={this.props.voteDisplayMode}
myVote={my_vote}
counts={counts}
/>
<span>
<MomentTime published={published} updated={updated} />
</span>
@ -354,8 +348,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
id={id}
onVote={this.props.onCommentVote}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
counts={counts}
my_vote={my_vote}
myVote={my_vote}
/>
<button
type="button"
@ -445,6 +440,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
moderators={this.props.moderators}
admins={this.props.admins}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
viewType={this.props.viewType}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
@ -536,35 +532,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
return this.commentView.creator.id === this.commentView.post.creator_id;
}
get scoreColor() {
if (this.commentView.my_vote === 1) {
return "text-info";
} else if (this.commentView.my_vote === -1) {
return "text-danger";
} else {
return "text-muted";
}
}
get pointsTippy(): string {
const points = I18NextService.i18n.t("number_of_points", {
count: Number(this.commentView.counts.score),
formattedCount: numToSI(this.commentView.counts.score),
});
const upvotes = I18NextService.i18n.t("number_of_upvotes", {
count: Number(this.commentView.counts.upvotes),
formattedCount: numToSI(this.commentView.counts.upvotes),
});
const downvotes = I18NextService.i18n.t("number_of_downvotes", {
count: Number(this.commentView.counts.downvotes),
formattedCount: numToSI(this.commentView.counts.downvotes),
});
return `${points}${upvotes}${downvotes}`;
}
get expandText(): string {
return this.state.collapsed
? I18NextService.i18n.t("expand")

View file

@ -18,6 +18,7 @@ import {
EditComment,
GetComments,
Language,
LocalUserVoteDisplayMode,
MarkCommentReplyAsRead,
MarkPersonMentionAsRead,
PersonView,
@ -44,6 +45,7 @@ interface CommentNodesProps {
showContext?: boolean;
showCommunity?: boolean;
enableDownvotes?: boolean;
voteDisplayMode: LocalUserVoteDisplayMode;
viewType: CommentViewType;
allLanguages: Language[];
siteLanguages: number[];
@ -115,6 +117,7 @@ export class CommentNodes extends Component<CommentNodesProps, any> {
showContext={this.props.showContext}
showCommunity={this.props.showCommunity}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
viewType={this.props.viewType}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}

View file

@ -3,6 +3,7 @@ import { T } from "inferno-i18next-dess";
import {
CommentReportView,
CommentView,
LocalUserVoteDisplayMode,
ResolveCommentReport,
} from "lemmy-js-client";
import { CommentNodeI, CommentViewType } from "../../interfaces";
@ -15,6 +16,8 @@ import { tippyMixin } from "../mixins/tippy-mixin";
interface CommentReportProps {
report: CommentReportView;
enableDownvotes?: boolean;
voteDisplayMode: LocalUserVoteDisplayMode;
onResolveReport(form: ResolveCommentReport): void;
}
@ -79,7 +82,8 @@ export class CommentReport extends Component<
<CommentNode
node={node}
viewType={CommentViewType.Flat}
enableDownvotes={true}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
viewOnly={true}
showCommunity={true}
allLanguages={[]}

View file

@ -1,17 +1,18 @@
import { newVote, showScores } from "@utils/app";
import { calculateUpvotePct, newVote, showScores } from "@utils/app";
import { numToSI } from "@utils/helpers";
import classNames from "classnames";
import { Component, InfernoNode, linkEvent } from "inferno";
import {
CommentAggregates,
CreateCommentLike,
CreatePostLike,
LocalUserVoteDisplayMode,
PostAggregates,
} from "lemmy-js-client";
import { VoteContentType, VoteType } from "../../interfaces";
import { I18NextService, UserService } from "../../services";
import { Icon, Spinner } from "../common/icon";
import { tippyMixin } from "../mixins/tippy-mixin";
import classNames from "classnames";
interface VoteButtonsProps {
voteContentType: VoteContentType;
@ -19,7 +20,8 @@ interface VoteButtonsProps {
onVote: (i: CreateCommentLike | CreatePostLike) => void;
enableDownvotes?: boolean;
counts: CommentAggregates | PostAggregates;
my_vote?: number;
voteDisplayMode: LocalUserVoteDisplayMode;
myVote?: number;
}
interface VoteButtonsState {
@ -27,61 +29,81 @@ interface VoteButtonsState {
downvoteLoading: boolean;
}
const tippy = (counts: CommentAggregates | PostAggregates): string => {
const points = I18NextService.i18n.t("number_of_points", {
count: Number(counts.score),
formattedCount: Number(counts.score),
});
function tippy(
voteDisplayMode: LocalUserVoteDisplayMode,
counts: CommentAggregates | PostAggregates,
): string {
const scoreStr =
voteDisplayMode.score &&
I18NextService.i18n.t("number_of_points", {
count: Number(counts.score),
formattedCount: Number(counts.score),
});
const upvotes = I18NextService.i18n.t("number_of_upvotes", {
count: Number(counts.upvotes),
formattedCount: Number(counts.upvotes),
});
const pct = calculateUpvotePct(counts.upvotes, counts.downvotes);
const downvotes = I18NextService.i18n.t("number_of_downvotes", {
count: Number(counts.downvotes),
formattedCount: Number(counts.downvotes),
});
const upvotePctStr =
voteDisplayMode.upvote_percentage &&
I18NextService.i18n.t("upvote_percentage", {
count: Number(pct),
formattedCount: Number(pct),
});
return `${points}${upvotes}${downvotes}`;
};
const upvoteStr =
voteDisplayMode.upvotes &&
I18NextService.i18n.t("number_of_upvotes", {
count: Number(counts.upvotes),
formattedCount: Number(counts.upvotes),
});
const handleUpvote = (i: VoteButtons) => {
const downvoteStr =
voteDisplayMode.downvotes &&
I18NextService.i18n.t("number_of_downvotes", {
count: Number(counts.downvotes),
formattedCount: Number(counts.downvotes),
});
return [scoreStr, upvotePctStr, upvoteStr, downvoteStr]
.filter(Boolean)
.join(" · ");
}
function handleUpvote(i: VoteButtons | VoteButtonsCompact) {
i.setState({ upvoteLoading: true });
switch (i.props.voteContentType) {
case VoteContentType.Comment:
i.props.onVote({
comment_id: i.props.id,
score: newVote(VoteType.Upvote, i.props.my_vote),
score: newVote(VoteType.Upvote, i.props.myVote),
});
break;
case VoteContentType.Post:
default:
i.props.onVote({
post_id: i.props.id,
score: newVote(VoteType.Upvote, i.props.my_vote),
score: newVote(VoteType.Upvote, i.props.myVote),
});
}
};
}
const handleDownvote = (i: VoteButtons) => {
function handleDownvote(i: VoteButtons | VoteButtonsCompact) {
i.setState({ downvoteLoading: true });
switch (i.props.voteContentType) {
case VoteContentType.Comment:
i.props.onVote({
comment_id: i.props.id,
score: newVote(VoteType.Downvote, i.props.my_vote),
score: newVote(VoteType.Downvote, i.props.myVote),
});
break;
case VoteContentType.Post:
default:
i.props.onVote({
post_id: i.props.id,
score: newVote(VoteType.Downvote, i.props.my_vote),
score: newVote(VoteType.Downvote, i.props.myVote),
});
}
};
}
@tippyMixin
export class VoteButtonsCompact extends Component<
@ -114,24 +136,28 @@ export class VoteButtonsCompact extends Component<
<button
type="button"
className={`btn btn-animate btn-sm btn-link py-0 px-1 ${
this.props.my_vote === 1 ? "text-info" : "text-muted"
this.props.myVote === 1 ? "text-info" : "text-muted"
}`}
data-tippy-content={tippy(this.props.counts)}
data-tippy-content={tippy(
this.props.voteDisplayMode,
this.props.counts,
)}
disabled={!UserService.Instance.myUserInfo}
onClick={linkEvent(this, handleUpvote)}
aria-label={I18NextService.i18n.t("upvote")}
aria-pressed={this.props.my_vote === 1}
aria-pressed={this.props.myVote === 1}
>
{this.state.upvoteLoading ? (
<Spinner />
) : (
<>
<Icon icon="arrow-up1" classes="icon-inline small" />
{showScores() && (
<span className="ms-2">
{numToSI(this.props.counts.upvotes)}
</span>
)}
{showScores() &&
this.props.voteContentType === VoteContentType.Post && (
<span className="ms-2">
{numToSI(this.props.counts.upvotes)}
</span>
)}
</>
)}
</button>
@ -139,28 +165,32 @@ export class VoteButtonsCompact extends Component<
<button
type="button"
className={`ms-2 btn btn-sm btn-link btn-animate btn py-0 px-1 ${
this.props.my_vote === -1 ? "text-danger" : "text-muted"
this.props.myVote === -1 ? "text-danger" : "text-muted"
}`}
disabled={!UserService.Instance.myUserInfo}
onClick={linkEvent(this, handleDownvote)}
data-tippy-content={tippy(this.props.counts)}
data-tippy-content={tippy(
this.props.voteDisplayMode,
this.props.counts,
)}
aria-label={I18NextService.i18n.t("downvote")}
aria-pressed={this.props.my_vote === -1}
aria-pressed={this.props.myVote === -1}
>
{this.state.downvoteLoading ? (
<Spinner />
) : (
<>
<Icon icon="arrow-down1" classes="icon-inline small" />
{showScores() && (
<span
className={classNames("ms-2", {
invisible: this.props.counts.downvotes === 0,
})}
>
{numToSI(this.props.counts.downvotes)}
</span>
)}
{showScores() &&
this.props.voteContentType === VoteContentType.Post && (
<span
className={classNames("ms-2", {
invisible: this.props.counts.downvotes === 0,
})}
>
{numToSI(this.props.counts.downvotes)}
</span>
)}
</>
)}
</button>
@ -198,13 +228,16 @@ export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
<button
type="button"
className={`btn-animate btn btn-link p-0 ${
this.props.my_vote === 1 ? "text-info" : "text-muted"
this.props.myVote === 1 ? "text-info" : "text-muted"
}`}
disabled={!UserService.Instance.myUserInfo}
onClick={linkEvent(this, handleUpvote)}
data-tippy-content={I18NextService.i18n.t("upvote")}
data-tippy-content={tippy(
this.props.voteDisplayMode,
this.props.counts,
)}
aria-label={I18NextService.i18n.t("upvote")}
aria-pressed={this.props.my_vote === 1}
aria-pressed={this.props.myVote === 1}
>
{this.state.upvoteLoading ? (
<Spinner />
@ -215,7 +248,10 @@ export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
{showScores() ? (
<div
className="unselectable pointer text-muted post-score"
data-tippy-content={tippy(this.props.counts)}
data-tippy-content={tippy(
this.props.voteDisplayMode,
this.props.counts,
)}
>
{numToSI(this.props.counts.score)}
</div>
@ -226,13 +262,16 @@ export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
<button
type="button"
className={`btn-animate btn btn-link p-0 ${
this.props.my_vote === -1 ? "text-danger" : "text-muted"
this.props.myVote === -1 ? "text-danger" : "text-muted"
}`}
disabled={!UserService.Instance.myUserInfo}
onClick={linkEvent(this, handleDownvote)}
data-tippy-content={I18NextService.i18n.t("downvote")}
data-tippy-content={tippy(
this.props.voteDisplayMode,
this.props.counts,
)}
aria-label={I18NextService.i18n.t("downvote")}
aria-pressed={this.props.my_vote === -1}
aria-pressed={this.props.myVote === -1}
>
{this.state.downvoteLoading ? (
<Spinner />

View file

@ -0,0 +1,184 @@
import { numToSI } from "@utils/helpers";
import { Component } from "inferno";
import {
CommentAggregates,
LocalUserVoteDisplayMode,
PostAggregates,
} from "lemmy-js-client";
import { I18NextService } from "../../services";
import { tippyMixin } from "../mixins/tippy-mixin";
import { Icon } from "./icon";
import classNames from "classnames";
import { calculateUpvotePct } from "@utils/app";
interface Props {
voteDisplayMode: LocalUserVoteDisplayMode;
counts: CommentAggregates | PostAggregates;
myVote?: number;
}
const BADGE_CLASSES = "unselectable";
const UPVOTE_PCT_THRESHOLD = 90;
@tippyMixin
export class VoteDisplay extends Component<Props, any> {
constructor(props: any, context: any) {
super(props, context);
}
render() {
const {
voteDisplayMode,
counts: { score, upvotes },
} = this.props;
// If the score is the same as the upvotes,
// and both score and upvotes are enabled,
// only show the upvotes.
const hideScore =
voteDisplayMode.score && voteDisplayMode.upvotes && score === upvotes;
return (
<div>
{voteDisplayMode.score && !hideScore && this.score()}
{voteDisplayMode.upvote_percentage && this.upvotePct()}
{this.upvotesAndDownvotes()}
</div>
);
}
score() {
const {
myVote,
counts: { score },
} = this.props;
const scoreStr = numToSI(score);
const scoreTippy = I18NextService.i18n.t("number_of_points", {
count: Number(score),
formattedCount: scoreStr,
});
return (
<span
className={`${BADGE_CLASSES} ${scoreColor(myVote)}`}
aria-label={scoreTippy}
data-tippy-content={scoreTippy}
>
<Icon icon="heart" classes="me-1 icon-inline small" />
{scoreStr}
<span className="mx-2">·</span>
</span>
);
}
upvotePct() {
const { upvotes, downvotes } = this.props.counts;
const pct = calculateUpvotePct(upvotes, downvotes);
const pctStr = `${pct.toFixed(0)}%`;
const thresholdCheck = pct < UPVOTE_PCT_THRESHOLD;
const upvotesPctTippy = I18NextService.i18n.t("upvote_percentage", {
count: Number(pct),
formattedCount: Number(pct),
});
return (
thresholdCheck && (
<span
className={BADGE_CLASSES}
aria-label={upvotesPctTippy}
data-tippy-content={upvotesPctTippy}
>
<Icon icon="smile" classes="me-1 icon-inline small" />
{pctStr}
<span className="mx-2">·</span>
</span>
)
);
}
// A special case since they are both wrapped in a badge
upvotesAndDownvotes() {
const voteDisplayMode = this.props.voteDisplayMode;
const votesCheck = voteDisplayMode.upvotes || voteDisplayMode.downvotes;
const downvotesCheck = this.props.counts.downvotes > 0;
return (
votesCheck && (
<span className={BADGE_CLASSES}>
{voteDisplayMode.upvotes && (
<span className={classNames({ "me-1": downvotesCheck })}>
{this.upvotes()}
</span>
)}
{voteDisplayMode.downvotes && downvotesCheck && this.downvotes()}
<span className="mx-2">·</span>
</span>
)
);
}
upvotes() {
const {
myVote,
counts: { upvotes },
} = this.props;
const upvotesStr = numToSI(upvotes);
const upvotesTippy = I18NextService.i18n.t("number_of_upvotes", {
count: Number(upvotes),
formattedCount: upvotesStr,
});
return (
<span
className={classNames({
"text-info": myVote === 1,
})}
aria-label={upvotesTippy}
data-tippy-content={upvotesTippy}
>
<Icon icon="arrow-up" classes="me-1 icon-inline small" />
{upvotesStr}
</span>
);
}
downvotes() {
const {
myVote,
counts: { downvotes },
} = this.props;
const downvotesStr = numToSI(downvotes);
const downvotesTippy = I18NextService.i18n.t("number_of_downvotes", {
count: Number(downvotes),
formattedCount: downvotesStr,
});
return (
<span
className={classNames({
"text-danger": myVote === -1,
})}
aria-label={downvotesTippy}
data-tippy-content={downvotesTippy}
>
<Icon icon="arrow-down" classes="me-1 icon-inline small" />
{downvotesStr}
</span>
);
}
}
function scoreColor(myVote?: number): string {
if (myVote === 1) {
return "text-info";
} else if (myVote === -1) {
return "text-danger";
} else {
return "text-muted";
}
}

View file

@ -13,6 +13,7 @@ import {
showLocal,
updateCommunityBlock,
updatePersonBlock,
voteDisplayMode,
} from "@utils/app";
import {
getQueryParams,
@ -422,11 +423,11 @@ export class Community extends Component<CommunityRouteProps, State> {
}
sidebar(res: GetCommunityResponse) {
const { site_res } = this.isoData;
const siteRes = this.isoData.site_res;
// For some reason, this returns an empty vec if it matches the site langs
const communityLangs =
res.discussion_languages.length === 0
? site_res.all_languages.map(({ id }) => id)
? siteRes.all_languages.map(({ id }) => id)
: res.discussion_languages;
return (
@ -434,11 +435,11 @@ export class Community extends Component<CommunityRouteProps, State> {
<Sidebar
community_view={res.community_view}
moderators={res.moderators}
admins={site_res.admins}
enableNsfw={enableNsfw(site_res)}
admins={siteRes.admins}
enableNsfw={enableNsfw(siteRes)}
editable
allLanguages={site_res.all_languages}
siteLanguages={site_res.discussion_languages}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
communityLanguages={communityLangs}
onDeleteCommunity={this.handleDeleteCommunity}
onRemoveCommunity={this.handleRemoveCommunity}
@ -457,7 +458,7 @@ export class Community extends Component<CommunityRouteProps, State> {
listings(communityRes: GetCommunityResponse) {
const { dataType } = this.props;
const { site_res } = this.isoData;
const siteRes = this.isoData.site_res;
if (dataType === DataType.Post) {
switch (this.state.postsRes.state) {
@ -468,10 +469,11 @@ export class Community extends Component<CommunityRouteProps, State> {
<PostListings
posts={this.state.postsRes.data.posts}
removeDuplicates
enableDownvotes={enableDownvotes(site_res)}
enableNsfw={enableNsfw(site_res)}
allLanguages={site_res.all_languages}
siteLanguages={site_res.discussion_languages}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onBlockPerson={this.handleBlockPerson}
onPostEdit={this.handlePostEdit}
onPostVote={this.handlePostVote}
@ -505,11 +507,12 @@ export class Community extends Component<CommunityRouteProps, State> {
finished={this.state.finished}
isTopLevel
showContext
enableDownvotes={enableDownvotes(site_res)}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
moderators={communityRes.moderators}
admins={site_res.admins}
allLanguages={site_res.all_languages}
siteLanguages={site_res.discussion_languages}
admins={siteRes.admins}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
onBlockPerson={this.handleBlockPerson}
onDeleteComment={this.handleDeleteComment}

View file

@ -12,6 +12,7 @@ import {
setIsoData,
showLocal,
updatePersonBlock,
voteDisplayMode,
} from "@utils/app";
import {
getQueryParams,
@ -729,6 +730,7 @@ export class Home extends Component<HomeRouteProps, HomeState> {
showCommunity
removeDuplicates
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
@ -769,6 +771,7 @@ export class Home extends Component<HomeRouteProps, HomeState> {
showCommunity
showContext
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}

View file

@ -9,6 +9,7 @@ import {
myAuth,
setIsoData,
updatePersonBlock,
voteDisplayMode,
} from "@utils/app";
import {
capitalizeFirstLetter,
@ -500,6 +501,7 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
}
renderReplyType(i: ReplyType) {
const siteRes = this.state.siteRes;
switch (i.type_) {
case ReplyEnum.Reply:
return (
@ -513,9 +515,10 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
markable
showCommunity
showContext
enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
onBlockPerson={this.handleBlockPerson}
onDeleteComment={this.handleDeleteComment}
@ -552,9 +555,10 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
markable
showCommunity
showContext
enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
onBlockPerson={this.handleBlockPerson}
onDeleteComment={this.handleDeleteComment}
@ -607,6 +611,7 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
}
replies() {
const siteRes = this.state.siteRes;
switch (this.state.repliesRes.state) {
case "loading":
return <CommentsLoadingSkeleton />;
@ -621,9 +626,10 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
markable
showCommunity
showContext
enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
onBlockPerson={this.handleBlockPerson}
onDeleteComment={this.handleDeleteComment}
@ -650,6 +656,7 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
}
mentions() {
const siteRes = this.state.siteRes;
switch (this.state.mentionsRes.state) {
case "loading":
return <CommentsLoadingSkeleton />;
@ -666,9 +673,10 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
markable
showCommunity
showContext
enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
onBlockPerson={this.handleBlockPerson}
onDeleteComment={this.handleDeleteComment}

View file

@ -23,6 +23,7 @@ import {
GetComments,
GetPersonDetailsResponse,
Language,
LocalUserVoteDisplayMode,
LockPost,
MarkCommentReplyAsRead,
MarkPersonMentionAsRead,
@ -56,6 +57,7 @@ interface PersonDetailsProps {
limit: number;
sort: SortType;
enableDownvotes: boolean;
voteDisplayMode: LocalUserVoteDisplayMode;
enableNsfw: boolean;
view: PersonDetailsView;
onPageChange(page: number): number | any;
@ -157,6 +159,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
showCommunity
showContext
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
onCommentReplyRead={this.props.onCommentReplyRead}
@ -190,6 +193,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
admins={this.props.admins}
showCommunity
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
@ -267,6 +271,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
showCommunity
showContext
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
onCommentReplyRead={this.props.onCommentReplyRead}
@ -303,6 +308,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
admins={this.props.admins}
showCommunity
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}

View file

@ -7,6 +7,7 @@ import {
getCommentParentId,
setIsoData,
updatePersonBlock,
voteDisplayMode,
} from "@utils/app";
import { scrollMixin } from "../mixins/scroll-mixin";
import {
@ -409,6 +410,7 @@ export class Profile extends Component<ProfileRouteProps, ProfileState> {
limit={fetchLimit}
finished={this.state.finished}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
view={view}
onPageChange={this.handlePageChange}

View file

@ -2,7 +2,10 @@ import {
editCommentReport,
editPostReport,
editPrivateMessageReport,
enableDownvotes,
enableNsfw,
setIsoData,
voteDisplayMode,
} from "@utils/app";
import { randomStr, resourcesSettled } from "@utils/helpers";
import { scrollMixin } from "../mixins/scroll-mixin";
@ -412,12 +415,15 @@ export class Reports extends Component<ReportsRouteProps, ReportsState> {
}
renderItemType(i: ItemType) {
const siteRes = this.state.siteRes;
switch (i.type_) {
case MessageEnum.CommentReport:
return (
<CommentReport
key={i.id}
report={i.view as CommentReportView}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
onResolveReport={this.handleResolveCommentReport}
/>
);
@ -426,6 +432,9 @@ export class Reports extends Component<ReportsRouteProps, ReportsState> {
<PostReport
key={i.id}
report={i.view as PostReportView}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
onResolveReport={this.handleResolvePostReport}
/>
);
@ -457,6 +466,7 @@ export class Reports extends Component<ReportsRouteProps, ReportsState> {
commentReports() {
const res = this.state.commentReportsRes;
const siteRes = this.state.siteRes;
switch (res.state) {
case "loading":
return (
@ -474,6 +484,8 @@ export class Reports extends Component<ReportsRouteProps, ReportsState> {
<CommentReport
key={cr.comment_report.id}
report={cr}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
onResolveReport={this.handleResolveCommentReport}
/>
</>
@ -486,6 +498,7 @@ export class Reports extends Component<ReportsRouteProps, ReportsState> {
postReports() {
const res = this.state.postReportsRes;
const siteRes = this.state.siteRes;
switch (res.state) {
case "loading":
return (
@ -502,6 +515,9 @@ export class Reports extends Component<ReportsRouteProps, ReportsState> {
<hr />
<PostReport
key={pr.post_report.id}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
report={pr}
onResolveReport={this.handleResolvePostReport}
/>

View file

@ -1,5 +1,6 @@
import {
communityToChoice,
enableDownvotes,
fetchCommunities,
fetchThemeList,
fetchUsers,
@ -100,6 +101,9 @@ interface SettingsState {
matrix_user_id?: string;
show_avatars?: boolean;
show_scores?: boolean;
show_upvotes?: boolean;
show_downvotes?: boolean;
show_upvote_percentage?: boolean;
send_notifications_to_email?: boolean;
bot_account?: boolean;
show_bot_accounts?: boolean;
@ -276,7 +280,6 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
interface_language,
show_avatars,
show_bot_accounts,
show_scores,
show_read_posts,
send_notifications_to_email,
email,
@ -290,6 +293,12 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
bio,
matrix_user_id,
},
local_user_vote_display_mode: {
score: show_scores,
upvotes: show_upvotes,
downvotes: show_downvotes,
upvote_percentage: show_upvote_percentage,
},
} = mui.local_user_view;
this.state = {
@ -314,6 +323,9 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
bot_account,
show_bot_accounts,
show_scores,
show_upvotes,
show_downvotes,
show_upvote_percentage,
show_read_posts,
email,
bio,
@ -703,6 +715,7 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
saveUserSettingsHtmlForm() {
const selectedLangs = this.state.saveUserSettingsForm.discussion_languages;
const siteRes = this.state.siteRes;
return (
<>
@ -735,8 +748,8 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
onContentChange={this.handleBioChange}
maxLength={300}
hideNavigationWarnings
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
/>
</div>
</div>
@ -832,8 +845,8 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
</div>
</div>
<LanguageSelect
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
selectedLanguageIds={selectedLangs}
multiple={true}
showLanguageWarning={true}
@ -958,6 +971,59 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
</label>
</div>
</div>
<div className="input-group mb-3">
<div className="form-check">
<input
className="form-check-input"
id="user-show-upvotes"
type="checkbox"
checked={this.state.saveUserSettingsForm.show_upvotes}
onChange={linkEvent(this, this.handleShowUpvotesChange)}
/>
<label className="form-check-label" htmlFor="user-show-upvotes">
{I18NextService.i18n.t("show_upvotes")}
</label>
</div>
</div>
{enableDownvotes(siteRes) && (
<div className="input-group mb-3">
<div className="form-check">
<input
className="form-check-input"
id="user-show-downvotes"
type="checkbox"
checked={this.state.saveUserSettingsForm.show_downvotes}
onChange={linkEvent(this, this.handleShowDownvotesChange)}
/>
<label
className="form-check-label"
htmlFor="user-show-downvotes"
>
{I18NextService.i18n.t("show_downvotes")}
</label>
</div>
</div>
)}
<div className="input-group mb-3">
<div className="form-check">
<input
className="form-check-input"
id="user-show-upvote-percentage"
type="checkbox"
checked={this.state.saveUserSettingsForm.show_upvote_percentage}
onChange={linkEvent(
this,
this.handleShowUpvotePercentageChange,
)}
/>
<label
className="form-check-label"
htmlFor="user-show-upvote-percentage"
>
{I18NextService.i18n.t("show_upvote_percentage")}
</label>
</div>
</div>
<div className="input-group mb-3">
<div className="form-check">
<input
@ -1442,13 +1508,50 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
handleShowScoresChange(i: Settings, event: any) {
const mui = UserService.Instance.myUserInfo;
if (mui) {
mui.local_user_view.local_user.show_scores = event.target.checked;
mui.local_user_view.local_user_vote_display_mode.score =
event.target.checked;
}
i.setState(
s => ((s.saveUserSettingsForm.show_scores = event.target.checked), s),
);
}
handleShowUpvotesChange(i: Settings, event: any) {
const mui = UserService.Instance.myUserInfo;
if (mui) {
mui.local_user_view.local_user_vote_display_mode.upvotes =
event.target.checked;
}
i.setState(
s => ((s.saveUserSettingsForm.show_upvotes = event.target.checked), s),
);
}
handleShowDownvotesChange(i: Settings, event: any) {
const mui = UserService.Instance.myUserInfo;
if (mui) {
mui.local_user_view.local_user_vote_display_mode.downvotes =
event.target.checked;
}
i.setState(
s => ((s.saveUserSettingsForm.show_downvotes = event.target.checked), s),
);
}
handleShowUpvotePercentageChange(i: Settings, event: any) {
const mui = UserService.Instance.myUserInfo;
if (mui) {
mui.local_user_view.local_user_vote_display_mode.upvote_percentage =
event.target.checked;
}
i.setState(
s => (
(s.saveUserSettingsForm.show_upvote_percentage = event.target.checked),
s
),
);
}
async handleGenerateTotp(i: Settings) {
i.setState({ generateTotpRes: LOADING_REQUEST });
@ -1584,7 +1687,9 @@ export class Settings extends Component<SettingsRouteProps, SettingsState> {
}
toast(I18NextService.i18n.t("saved"));
snapToTop();
// You need to reload the page, to properly update the siteRes everywhere
setTimeout(() => location.reload(), 500);
}
setThemeOverride(undefined);

View file

@ -3,6 +3,7 @@ import {
enableDownvotes,
enableNsfw,
setIsoData,
voteDisplayMode,
} from "@utils/app";
import { getIdFromString, getQueryParams } from "@utils/helpers";
import { Choice, RouteDataResponse } from "@utils/types";
@ -163,7 +164,7 @@ export class CreatePost extends Component<
}
render() {
const { selectedCommunityChoice } = this.state;
const { selectedCommunityChoice, siteRes } = this.state;
const locationState = this.props.history.location.state as
| PostFormParams
@ -191,10 +192,11 @@ export class CreatePost extends Component<
<PostForm
onCreate={this.handlePostCreate}
params={locationState}
enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
selectedCommunityChoice={selectedCommunityChoice}
onSelectCommunity={this.handleSelectedCommunityChange}
initialCommunities={

View file

@ -18,6 +18,7 @@ import {
EditPost,
GetSiteMetadataResponse,
Language,
LocalUserVoteDisplayMode,
PostView,
SearchResponse,
} from "lemmy-js-client";
@ -57,6 +58,7 @@ interface PostFormProps {
onEdit?(form: EditPost): void;
enableNsfw?: boolean;
enableDownvotes?: boolean;
voteDisplayMode: LocalUserVoteDisplayMode;
selectedCommunityChoice?: Choice;
onSelectCommunity?: (choice: Choice) => void;
initialCommunities?: CommunityView[];
@ -453,6 +455,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
showCommunity
posts={this.props.crossPosts}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
@ -667,6 +670,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
showCommunity
posts={suggestedPosts}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}

View file

@ -21,6 +21,7 @@ import {
FeaturePost,
HidePost,
Language,
LocalUserVoteDisplayMode,
LockPost,
MarkPostAsRead,
PersonView,
@ -73,6 +74,7 @@ interface PostListingProps {
showBody?: boolean;
hideImage?: boolean;
enableDownvotes?: boolean;
voteDisplayMode: LocalUserVoteDisplayMode;
enableNsfw?: boolean;
viewOnly?: boolean;
onPostEdit(form: EditPost): Promise<RequestState<PostResponse>>;
@ -168,6 +170,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onCancel={this.handleEditCancel}
enableNsfw={this.props.enableNsfw}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
/>
@ -392,7 +395,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
}
</span>
)}{" "}
<MomentTime published={pv.post.published} updated={pv.post.updated} />
· <MomentTime published={pv.post.published} updated={pv.post.updated} />
</div>
);
}
@ -553,12 +556,18 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
}
commentsLine(mobile = false) {
const { admins, moderators, showBody, onPostVote, enableDownvotes } =
this.props;
const {
admins,
moderators,
showBody,
onPostVote,
enableDownvotes,
voteDisplayMode,
} = this.props;
const {
post: { ap_id, id, body },
counts,
my_vote,
counts,
} = this.postView;
return (
@ -585,9 +594,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
voteContentType={VoteContentType.Post}
id={id}
onVote={onPostVote}
enableDownvotes={enableDownvotes}
counts={counts}
my_vote={my_vote}
enableDownvotes={enableDownvotes}
voteDisplayMode={voteDisplayMode}
myVote={my_vote}
/>
)}
@ -743,8 +753,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
id={this.postView.post.id}
onVote={this.props.onPostVote}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
counts={this.postView.counts}
my_vote={this.postView.my_vote}
myVote={this.postView.my_vote}
/>
</div>
)}

View file

@ -14,6 +14,7 @@ import {
FeaturePost,
HidePost,
Language,
LocalUserVoteDisplayMode,
LockPost,
MarkPostAsRead,
PostResponse,
@ -35,6 +36,7 @@ interface PostListingsProps {
showCommunity?: boolean;
removeDuplicates?: boolean;
enableDownvotes?: boolean;
voteDisplayMode: LocalUserVoteDisplayMode;
enableNsfw?: boolean;
viewOnly?: boolean;
onPostEdit(form: EditPost): Promise<RequestState<PostResponse>>;
@ -81,6 +83,7 @@ export class PostListings extends Component<PostListingsProps, any> {
crossPosts={this.duplicatesMap.get(post_view.post.id)}
showCommunity={this.props.showCommunity}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
enableNsfw={this.props.enableNsfw}
viewOnly={this.props.viewOnly}
allLanguages={this.props.allLanguages}

View file

@ -1,6 +1,11 @@
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import { PostReportView, PostView, ResolvePostReport } from "lemmy-js-client";
import {
LocalUserVoteDisplayMode,
PostReportView,
PostView,
ResolvePostReport,
} from "lemmy-js-client";
import { I18NextService } from "../../services";
import { Icon, Spinner } from "../common/icon";
import { PersonListing } from "../person/person-listing";
@ -10,6 +15,9 @@ import { tippyMixin } from "../mixins/tippy-mixin";
interface PostReportProps {
report: PostReportView;
enableDownvotes?: boolean;
voteDisplayMode: LocalUserVoteDisplayMode;
enableNsfw?: boolean;
onResolveReport(form: ResolvePostReport): void;
}
@ -70,8 +78,9 @@ export class PostReport extends Component<PostReportProps, PostReportState> {
<PostListing
post_view={pv}
showCommunity={true}
enableDownvotes={true}
enableNsfw={true}
enableDownvotes={this.props.enableDownvotes}
voteDisplayMode={this.props.voteDisplayMode}
enableNsfw={this.props.enableNsfw}
viewOnly={true}
allLanguages={[]}
siteLanguages={[]}

View file

@ -12,6 +12,7 @@ import {
setIsoData,
updateCommunityBlock,
updatePersonBlock,
voteDisplayMode,
} from "@utils/app";
import { isBrowser } from "@utils/browser";
import {
@ -369,6 +370,7 @@ export class Post extends Component<PostRouteProps, PostState> {
);
case "success": {
const res = this.state.postRes.data;
const siteRes = this.state.siteRes;
return (
<div className="row">
<main className="col-12 col-md-8 col-lg-9 mb-3">
@ -385,11 +387,12 @@ export class Post extends Component<PostRouteProps, PostState> {
showBody
showCommunity
moderators={res.moderators}
admins={this.state.siteRes.admins}
enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
admins={siteRes.admins}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onBlockPerson={this.handleBlockPerson}
onPostEdit={this.handlePostEdit}
onPostVote={this.handlePostVote}
@ -419,8 +422,8 @@ export class Post extends Component<PostRouteProps, PostState> {
<CommentForm
node={res.post_view.post.id}
disabled={res.post_view.post.locked}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
containerClass="post-comment-container"
onUpsertComment={this.handleCreateComment}
finished={this.state.finished.get(0)}
@ -581,6 +584,7 @@ export class Post extends Component<PostRouteProps, PostState> {
// These are already sorted by new
const commentsRes = this.state.commentsRes;
const postRes = this.state.postRes;
const siteRes = this.state.siteRes;
if (commentsRes.state === "success" && postRes.state === "success") {
return (
@ -592,12 +596,13 @@ export class Post extends Component<PostRouteProps, PostState> {
isTopLevel
locked={postRes.data.post_view.post.locked}
moderators={postRes.data.moderators}
admins={this.state.siteRes.admins}
enableDownvotes={enableDownvotes(this.state.siteRes)}
admins={siteRes.admins}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
showContext
finished={this.state.finished}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
onBlockPerson={this.handleBlockPerson}
onDeleteComment={this.handleDeleteComment}
@ -652,6 +657,7 @@ export class Post extends Component<PostRouteProps, PostState> {
const firstComment = this.commentTree().at(0)?.comment_view.comment;
const depth = getDepthFromComment(firstComment);
const showContextButton = depth ? depth > 0 : false;
const siteRes = this.state.siteRes;
return (
res.state === "success" && (
@ -680,11 +686,12 @@ export class Post extends Component<PostRouteProps, PostState> {
maxCommentsShown={this.state.maxCommentsShown}
locked={res.data.post_view.post.locked}
moderators={res.data.moderators}
admins={this.state.siteRes.admins}
enableDownvotes={enableDownvotes(this.state.siteRes)}
admins={siteRes.admins}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
finished={this.state.finished}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
onBlockPerson={this.handleBlockPerson}
onDeleteComment={this.handleDeleteComment}

View file

@ -10,6 +10,7 @@ import {
personToChoice,
setIsoData,
showLocal,
voteDisplayMode,
} from "@utils/app";
import { scrollMixin } from "./mixins/scroll-mixin";
import {
@ -707,6 +708,7 @@ export class Search extends Component<SearchRouteProps, SearchState> {
get all() {
const combined = this.buildCombined();
const siteRes = this.state.siteRes;
return (
<div>
@ -718,10 +720,11 @@ export class Search extends Component<SearchRouteProps, SearchState> {
key={(i.data as PostView).post.id}
post_view={i.data as PostView}
showCommunity
enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
viewOnly
// All of these are unused, since its view only
onPostEdit={async () => EMPTY_REQUEST}
@ -758,9 +761,10 @@ export class Search extends Component<SearchRouteProps, SearchState> {
viewOnly
locked
isTopLevel
enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
// All of these are unused, since its viewonly
finished={new Map()}
onSaveComment={async () => {}}
@ -820,6 +824,7 @@ export class Search extends Component<SearchRouteProps, SearchState> {
locked
isTopLevel
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
// All of these are unused, since its viewonly
@ -871,6 +876,7 @@ export class Search extends Component<SearchRouteProps, SearchState> {
post_view={pv}
showCommunity
enableDownvotes={enableDownvotes(siteRes)}
voteDisplayMode={voteDisplayMode(siteRes)}
enableNsfw={enableNsfw(siteRes)}
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}

View file

@ -0,0 +1,6 @@
export default function calculateUpvotePct(
upvotes: number,
downvotes: number,
): number {
return (upvotes / (upvotes + downvotes)) * 100;
}

View file

@ -18,6 +18,8 @@ import editPrivateMessageReport from "./edit-private-message-report";
import editRegistrationApplication from "./edit-registration-application";
import editWith from "./edit-with";
import enableDownvotes from "./enable-downvotes";
import voteDisplayMode from "./vote-display-mode";
import calculateUpvotePct from "./calculate-upvote-pct";
import enableNsfw from "./enable-nsfw";
import fetchCommunities from "./fetch-communities";
import fetchSearchResults from "./fetch-search-results";
@ -112,4 +114,6 @@ export {
instanceToChoice,
updateInstanceBlock,
isAnonymousPath,
voteDisplayMode,
calculateUpvotePct,
};

View file

@ -3,5 +3,7 @@ import { UserService } from "../../services";
export default function showScores(
myUserInfo = UserService.Instance.myUserInfo,
): boolean {
return myUserInfo?.local_user_view.local_user.show_scores ?? true;
const voteDisplayMode =
myUserInfo?.local_user_view.local_user_vote_display_mode;
return (voteDisplayMode?.score || voteDisplayMode?.upvotes) ?? true;
}

View file

@ -0,0 +1,15 @@
import { GetSiteResponse, LocalUserVoteDisplayMode } from "lemmy-js-client";
export default function voteDisplayMode(
siteRes: GetSiteResponse,
): LocalUserVoteDisplayMode {
return (
siteRes?.my_user?.local_user_view.local_user_vote_display_mode ?? {
local_user_id: -1,
upvotes: true,
downvotes: true,
score: false,
upvote_percentage: false,
}
);
}