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 { VoteType } from "../../interfaces";
12 import { I18NextService } from "../../services";
13 import { Icon, Spinner } from "../common/icon";
15 interface VoteButtonsProps {
17 onVote: (i: CreateCommentLike | CreatePostLike) => void;
18 enableDownvotes?: boolean;
19 counts: CommentAggregates | PostAggregates;
23 interface VoteButtonsState {
24 upvoteLoading: boolean;
25 downvoteLoading: boolean;
28 const tippy = (counts: CommentAggregates | PostAggregates): string => {
29 const points = I18NextService.i18n.t("number_of_points", {
30 count: Number(counts.score),
31 formattedCount: Number(counts.score),
34 const upvotes = I18NextService.i18n.t("number_of_upvotes", {
35 count: Number(counts.upvotes),
36 formattedCount: Number(counts.upvotes),
39 const downvotes = I18NextService.i18n.t("number_of_downvotes", {
40 count: Number(counts.downvotes),
41 formattedCount: Number(counts.downvotes),
44 return `${points} • ${upvotes} • ${downvotes}`;
47 const handleUpvote = (i: VoteButtons) => {
48 i.setState({ upvoteLoading: true });
51 score: newVote(VoteType.Upvote, i.props.my_vote),
52 auth: myAuthRequired(),
54 i.setState({ upvoteLoading: false });
57 const handleDownvote = (i: VoteButtons) => {
58 i.setState({ downvoteLoading: true });
61 score: newVote(VoteType.Downvote, i.props.my_vote),
62 auth: myAuthRequired(),
64 i.setState({ downvoteLoading: false });
67 export class VoteButtonsCompact extends Component<
71 state: VoteButtonsState = {
73 downvoteLoading: false,
76 constructor(props: any, context: any) {
77 super(props, context);
84 className={`btn-animate btn py-0 px-1 ${
85 this.props.my_vote === 1 ? "text-info" : "text-muted"
87 data-tippy-content={tippy(this.props.counts)}
88 onClick={linkEvent(this, handleUpvote)}
89 aria-label={I18NextService.i18n.t("upvote")}
90 aria-pressed={this.props.my_vote === 1}
92 {this.state.upvoteLoading ? (
96 <Icon icon="arrow-up1" classes="icon-inline small" />
98 <span className="ms-2">
99 {numToSI(this.props.counts.upvotes)}
105 {this.props.enableDownvotes && (
107 className={`ms-2 btn-animate btn py-0 px-1 ${
108 this.props.my_vote === -1 ? "text-danger" : "text-muted"
110 onClick={linkEvent(this, handleDownvote)}
111 data-tippy-content={tippy(this.props.counts)}
112 aria-label={I18NextService.i18n.t("downvote")}
113 aria-pressed={this.props.my_vote === -1}
115 {this.state.downvoteLoading ? (
119 <Icon icon="arrow-down1" classes="icon-inline small" />
122 className={classNames("ms-2", {
123 invisible: this.props.counts.downvotes === 0,
126 {numToSI(this.props.counts.downvotes)}
138 export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
139 state: VoteButtonsState = {
140 upvoteLoading: false,
141 downvoteLoading: false,
144 constructor(props: any, context: any) {
145 super(props, context);
150 <div className={`vote-bar col-1 pe-0 small text-center`}>
152 className={`btn-animate btn btn-link p-0 ${
153 this.props.my_vote == 1 ? "text-info" : "text-muted"
155 onClick={linkEvent(this, handleUpvote)}
156 data-tippy-content={I18NextService.i18n.t("upvote")}
157 aria-label={I18NextService.i18n.t("upvote")}
158 aria-pressed={this.props.my_vote === 1}
160 {this.state.upvoteLoading ? (
163 <Icon icon="arrow-up1" classes="upvote" />
168 className={`unselectable pointer text-muted px-1 post-score`}
169 data-tippy-content={tippy(this.props.counts)}
171 {numToSI(this.props.counts.score)}
174 <div className="p-1"></div>
176 {this.props.enableDownvotes && (
178 className={`btn-animate btn btn-link p-0 ${
179 this.props.my_vote == -1 ? "text-danger" : "text-muted"
181 onClick={linkEvent(this, handleDownvote)}
182 data-tippy-content={I18NextService.i18n.t("downvote")}
183 aria-label={I18NextService.i18n.t("downvote")}
184 aria-pressed={this.props.my_vote === -1}
186 {this.state.downvoteLoading ? (
189 <Icon icon="arrow-down1" classes="downvote" />