1 import { myAuthRequired, newVote, showScores } from "@utils/app";
2 import { numToSI } from "@utils/helpers";
3 import classNames from "classnames";
4 import { Component, linkEvent } from "inferno";
10 } from "lemmy-js-client";
11 import { VoteContentType, VoteType } from "../../interfaces";
12 import { I18NextService } from "../../services";
13 import { Icon, Spinner } from "../common/icon";
15 interface VoteButtonsProps {
16 voteContentType: VoteContentType;
18 onVote: (i: CreateCommentLike | CreatePostLike) => void;
19 enableDownvotes?: boolean;
20 counts: CommentAggregates | PostAggregates;
24 interface VoteButtonsState {
25 upvoteLoading: boolean;
26 downvoteLoading: boolean;
29 const tippy = (counts: CommentAggregates | PostAggregates): string => {
30 const points = I18NextService.i18n.t("number_of_points", {
31 count: Number(counts.score),
32 formattedCount: Number(counts.score),
35 const upvotes = I18NextService.i18n.t("number_of_upvotes", {
36 count: Number(counts.upvotes),
37 formattedCount: Number(counts.upvotes),
40 const downvotes = I18NextService.i18n.t("number_of_downvotes", {
41 count: Number(counts.downvotes),
42 formattedCount: Number(counts.downvotes),
45 return `${points} • ${upvotes} • ${downvotes}`;
48 const handleUpvote = (i: VoteButtons) => {
49 i.setState({ upvoteLoading: true });
51 switch (i.props.voteContentType) {
52 case VoteContentType.Comment:
54 comment_id: i.props.id,
55 score: newVote(VoteType.Upvote, i.props.my_vote),
56 auth: myAuthRequired(),
59 case VoteContentType.Post:
63 score: newVote(VoteType.Upvote, i.props.my_vote),
64 auth: myAuthRequired(),
68 i.setState({ upvoteLoading: false });
71 const handleDownvote = (i: VoteButtons) => {
72 i.setState({ downvoteLoading: true });
73 switch (i.props.voteContentType) {
74 case VoteContentType.Comment:
76 comment_id: i.props.id,
77 score: newVote(VoteType.Downvote, i.props.my_vote),
78 auth: myAuthRequired(),
81 case VoteContentType.Post:
85 score: newVote(VoteType.Downvote, i.props.my_vote),
86 auth: myAuthRequired(),
89 i.setState({ downvoteLoading: false });
92 export class VoteButtonsCompact extends Component<
96 state: VoteButtonsState = {
98 downvoteLoading: false,
101 constructor(props: any, context: any) {
102 super(props, context);
110 className={`btn-animate btn py-0 px-1 ${
111 this.props.my_vote === 1 ? "text-info" : "text-muted"
113 data-tippy-content={tippy(this.props.counts)}
114 onClick={linkEvent(this, handleUpvote)}
115 aria-label={I18NextService.i18n.t("upvote")}
116 aria-pressed={this.props.my_vote === 1}
118 {this.state.upvoteLoading ? (
122 <Icon icon="arrow-up1" classes="icon-inline small" />
124 <span className="ms-2">
125 {numToSI(this.props.counts.upvotes)}
131 {this.props.enableDownvotes && (
134 className={`ms-2 btn-animate btn py-0 px-1 ${
135 this.props.my_vote === -1 ? "text-danger" : "text-muted"
137 onClick={linkEvent(this, handleDownvote)}
138 data-tippy-content={tippy(this.props.counts)}
139 aria-label={I18NextService.i18n.t("downvote")}
140 aria-pressed={this.props.my_vote === -1}
142 {this.state.downvoteLoading ? (
146 <Icon icon="arrow-down1" classes="icon-inline small" />
149 className={classNames("ms-2", {
150 invisible: this.props.counts.downvotes === 0,
153 {numToSI(this.props.counts.downvotes)}
165 export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
166 state: VoteButtonsState = {
167 upvoteLoading: false,
168 downvoteLoading: false,
171 constructor(props: any, context: any) {
172 super(props, context);
177 <div className={`vote-bar pe-0 small text-center`}>
180 className={`btn-animate btn btn-link p-0 ${
181 this.props.my_vote == 1 ? "text-info" : "text-muted"
183 onClick={linkEvent(this, handleUpvote)}
184 data-tippy-content={I18NextService.i18n.t("upvote")}
185 aria-label={I18NextService.i18n.t("upvote")}
186 aria-pressed={this.props.my_vote === 1}
188 {this.state.upvoteLoading ? (
191 <Icon icon="arrow-up1" classes="upvote" />
196 className={`unselectable pointer text-muted px-1 post-score`}
197 data-tippy-content={tippy(this.props.counts)}
199 {numToSI(this.props.counts.score)}
202 <div className="p-1"></div>
204 {this.props.enableDownvotes && (
207 className={`btn-animate btn btn-link p-0 ${
208 this.props.my_vote == -1 ? "text-danger" : "text-muted"
210 onClick={linkEvent(this, handleDownvote)}
211 data-tippy-content={I18NextService.i18n.t("downvote")}
212 aria-label={I18NextService.i18n.t("downvote")}
213 aria-pressed={this.props.my_vote === -1}
215 {this.state.downvoteLoading ? (
218 <Icon icon="arrow-down1" classes="downvote" />