1 import { showScores } from "@utils/app";
2 import { numToSI } from "@utils/helpers";
3 import classNames from "classnames";
4 import { Component, linkEvent } from "inferno";
5 import { CommentAggregates, PostAggregates } from "lemmy-js-client";
6 import { I18NextService } from "../../services";
7 import { Icon, Spinner } from "../common/icon";
8 import { PostListing } from "../post/post-listing";
10 interface VoteButtonsProps {
11 postListing: PostListing;
12 enableDownvotes?: boolean;
13 upvoteLoading?: boolean;
14 downvoteLoading?: boolean;
15 handleUpvote: (i: PostListing) => void;
16 handleDownvote: (i: PostListing) => void;
17 counts: CommentAggregates | PostAggregates;
21 interface VoteButtonsState {
22 upvoteLoading: boolean;
23 downvoteLoading: boolean;
26 const tippy = (counts: CommentAggregates | PostAggregates): string => {
27 const points = I18NextService.i18n.t("number_of_points", {
28 count: Number(counts.score),
29 formattedCount: Number(counts.score),
32 const upvotes = I18NextService.i18n.t("number_of_upvotes", {
33 count: Number(counts.upvotes),
34 formattedCount: Number(counts.upvotes),
37 const downvotes = I18NextService.i18n.t("number_of_downvotes", {
38 count: Number(counts.downvotes),
39 formattedCount: Number(counts.downvotes),
42 return `${points} • ${upvotes} • ${downvotes}`;
45 export class VoteButtonsCompact extends Component<
49 state: VoteButtonsState = {
51 downvoteLoading: false,
54 constructor(props: any, context: any) {
55 super(props, context);
62 className={`btn-animate btn py-0 px-1 ${
63 this.props.my_vote === 1 ? "text-info" : "text-muted"
65 data-tippy-content={tippy(this.props.counts)}
66 onClick={linkEvent(this.props.postListing, this.props.handleUpvote)}
67 aria-label={I18NextService.i18n.t("upvote")}
68 aria-pressed={this.props.my_vote === 1}
70 {this.state.upvoteLoading ? (
74 <Icon icon="arrow-up1" classes="icon-inline small" />
76 <span className="ms-2">
77 {numToSI(this.props.counts.upvotes)}
83 {this.props.enableDownvotes && (
85 className={`ms-2 btn-animate btn py-0 px-1 ${
86 this.props.my_vote === -1 ? "text-danger" : "text-muted"
89 this.props.postListing,
90 this.props.handleDownvote
92 data-tippy-content={tippy(this.props.counts)}
93 aria-label={I18NextService.i18n.t("downvote")}
94 aria-pressed={this.props.my_vote === -1}
96 {this.state.downvoteLoading ? (
100 <Icon icon="arrow-down1" classes="icon-inline small" />
103 className={classNames("ms-2", {
104 invisible: this.props.counts.downvotes === 0,
107 {numToSI(this.props.counts.downvotes)}
119 export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
120 state: VoteButtonsState = {
121 upvoteLoading: false,
122 downvoteLoading: false,
125 constructor(props: any, context: any) {
126 super(props, context);
131 <div className={`vote-bar col-1 pe-0 small text-center`}>
133 className={`btn-animate btn btn-link p-0 ${
134 this.props.my_vote == 1 ? "text-info" : "text-muted"
136 onClick={linkEvent(this.props.postListing, this.props.handleUpvote)}
137 data-tippy-content={I18NextService.i18n.t("upvote")}
138 aria-label={I18NextService.i18n.t("upvote")}
139 aria-pressed={this.props.my_vote === 1}
141 {this.state.upvoteLoading ? (
144 <Icon icon="arrow-up1" classes="upvote" />
149 className={`unselectable pointer text-muted px-1 post-score`}
150 data-tippy-content={tippy(this.props.counts)}
152 {numToSI(this.props.counts.score)}
155 <div className="p-1"></div>
157 {this.props.enableDownvotes && (
159 className={`btn-animate btn btn-link p-0 ${
160 this.props.my_vote == -1 ? "text-danger" : "text-muted"
163 this.props.postListing,
164 this.props.handleDownvote
166 data-tippy-content={I18NextService.i18n.t("downvote")}
167 aria-label={I18NextService.i18n.t("downvote")}
168 aria-pressed={this.props.my_vote === -1}
170 {this.state.downvoteLoading ? (
173 <Icon icon="arrow-down1" classes="downvote" />