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);
109 className={`btn-animate btn py-0 px-1 ${
110 this.props.my_vote === 1 ? "text-info" : "text-muted"
112 data-tippy-content={tippy(this.props.counts)}
113 onClick={linkEvent(this, handleUpvote)}
114 aria-label={I18NextService.i18n.t("upvote")}
115 aria-pressed={this.props.my_vote === 1}
117 {this.state.upvoteLoading ? (
121 <Icon icon="arrow-up1" classes="icon-inline small" />
123 <span className="ms-2">
124 {numToSI(this.props.counts.upvotes)}
130 {this.props.enableDownvotes && (
132 className={`ms-2 btn-animate btn py-0 px-1 ${
133 this.props.my_vote === -1 ? "text-danger" : "text-muted"
135 onClick={linkEvent(this, handleDownvote)}
136 data-tippy-content={tippy(this.props.counts)}
137 aria-label={I18NextService.i18n.t("downvote")}
138 aria-pressed={this.props.my_vote === -1}
140 {this.state.downvoteLoading ? (
144 <Icon icon="arrow-down1" classes="icon-inline small" />
147 className={classNames("ms-2", {
148 invisible: this.props.counts.downvotes === 0,
151 {numToSI(this.props.counts.downvotes)}
163 export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
164 state: VoteButtonsState = {
165 upvoteLoading: false,
166 downvoteLoading: false,
169 constructor(props: any, context: any) {
170 super(props, context);
175 <div className={`vote-bar col-1 pe-0 small text-center`}>
177 className={`btn-animate btn btn-link p-0 ${
178 this.props.my_vote == 1 ? "text-info" : "text-muted"
180 onClick={linkEvent(this, handleUpvote)}
181 data-tippy-content={I18NextService.i18n.t("upvote")}
182 aria-label={I18NextService.i18n.t("upvote")}
183 aria-pressed={this.props.my_vote === 1}
185 {this.state.upvoteLoading ? (
188 <Icon icon="arrow-up1" classes="upvote" />
193 className={`unselectable pointer text-muted px-1 post-score`}
194 data-tippy-content={tippy(this.props.counts)}
196 {numToSI(this.props.counts.score)}
199 <div className="p-1"></div>
201 {this.props.enableDownvotes && (
203 className={`btn-animate btn btn-link p-0 ${
204 this.props.my_vote == -1 ? "text-danger" : "text-muted"
206 onClick={linkEvent(this, handleDownvote)}
207 data-tippy-content={I18NextService.i18n.t("downvote")}
208 aria-label={I18NextService.i18n.t("downvote")}
209 aria-pressed={this.props.my_vote === -1}
211 {this.state.downvoteLoading ? (
214 <Icon icon="arrow-down1" classes="downvote" />