]> Untitled Git - lemmy-ui.git/blob - src/shared/components/common/vote-buttons.tsx
fix: Remove tippy duplicate functions
[lemmy-ui.git] / src / shared / components / common / vote-buttons.tsx
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";
9
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;
18   my_vote?: number;
19 }
20
21 interface VoteButtonsState {
22   upvoteLoading: boolean;
23   downvoteLoading: boolean;
24 }
25
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),
30   });
31
32   const upvotes = I18NextService.i18n.t("number_of_upvotes", {
33     count: Number(counts.upvotes),
34     formattedCount: Number(counts.upvotes),
35   });
36
37   const downvotes = I18NextService.i18n.t("number_of_downvotes", {
38     count: Number(counts.downvotes),
39     formattedCount: Number(counts.downvotes),
40   });
41
42   return `${points} • ${upvotes} • ${downvotes}`;
43 };
44
45 export class VoteButtonsCompact extends Component<
46   VoteButtonsProps,
47   VoteButtonsState
48 > {
49   state: VoteButtonsState = {
50     upvoteLoading: false,
51     downvoteLoading: false,
52   };
53
54   constructor(props: any, context: any) {
55     super(props, context);
56   }
57
58   render() {
59     return (
60       <div>
61         <button
62           className={`btn-animate btn py-0 px-1 ${
63             this.props.my_vote === 1 ? "text-info" : "text-muted"
64           }`}
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}
69         >
70           {this.state.upvoteLoading ? (
71             <Spinner />
72           ) : (
73             <>
74               <Icon icon="arrow-up1" classes="icon-inline small" />
75               {showScores() && (
76                 <span className="ms-2">
77                   {numToSI(this.props.counts.upvotes)}
78                 </span>
79               )}
80             </>
81           )}
82         </button>
83         {this.props.enableDownvotes && (
84           <button
85             className={`ms-2 btn-animate btn py-0 px-1 ${
86               this.props.my_vote === -1 ? "text-danger" : "text-muted"
87             }`}
88             onClick={linkEvent(
89               this.props.postListing,
90               this.props.handleDownvote
91             )}
92             data-tippy-content={tippy(this.props.counts)}
93             aria-label={I18NextService.i18n.t("downvote")}
94             aria-pressed={this.props.my_vote === -1}
95           >
96             {this.state.downvoteLoading ? (
97               <Spinner />
98             ) : (
99               <>
100                 <Icon icon="arrow-down1" classes="icon-inline small" />
101                 {showScores() && (
102                   <span
103                     className={classNames("ms-2", {
104                       invisible: this.props.counts.downvotes === 0,
105                     })}
106                   >
107                     {numToSI(this.props.counts.downvotes)}
108                   </span>
109                 )}
110               </>
111             )}
112           </button>
113         )}
114       </div>
115     );
116   }
117 }
118
119 export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
120   state: VoteButtonsState = {
121     upvoteLoading: false,
122     downvoteLoading: false,
123   };
124
125   constructor(props: any, context: any) {
126     super(props, context);
127   }
128
129   render() {
130     return (
131       <div className={`vote-bar col-1 pe-0 small text-center`}>
132         <button
133           className={`btn-animate btn btn-link p-0 ${
134             this.props.my_vote == 1 ? "text-info" : "text-muted"
135           }`}
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}
140         >
141           {this.state.upvoteLoading ? (
142             <Spinner />
143           ) : (
144             <Icon icon="arrow-up1" classes="upvote" />
145           )}
146         </button>
147         {showScores() ? (
148           <div
149             className={`unselectable pointer text-muted px-1 post-score`}
150             data-tippy-content={tippy(this.props.counts)}
151           >
152             {numToSI(this.props.counts.score)}
153           </div>
154         ) : (
155           <div className="p-1"></div>
156         )}
157         {this.props.enableDownvotes && (
158           <button
159             className={`btn-animate btn btn-link p-0 ${
160               this.props.my_vote == -1 ? "text-danger" : "text-muted"
161             }`}
162             onClick={linkEvent(
163               this.props.postListing,
164               this.props.handleDownvote
165             )}
166             data-tippy-content={I18NextService.i18n.t("downvote")}
167             aria-label={I18NextService.i18n.t("downvote")}
168             aria-pressed={this.props.my_vote === -1}
169           >
170             {this.state.downvoteLoading ? (
171               <Spinner />
172             ) : (
173               <Icon icon="arrow-down1" classes="downvote" />
174             )}
175           </button>
176         )}
177       </div>
178     );
179   }
180 }