Validator.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import React, { Component } from "react";
  2. import { Activity, Star } from "react-feather";
  3. import Nominators from "./Nominators";
  4. import MemberBox from "../Members/MemberBox";
  5. import {
  6. Handles,
  7. Member,
  8. Post,
  9. ProposalDetail,
  10. Seat,
  11. Stakes,
  12. RewardPoints,
  13. } from "../../types";
  14. import { domain } from "../../config";
  15. interface IProps {
  16. toggleStar: (account: string) => void;
  17. sortBy: (sortBy: string) => void;
  18. validator: string;
  19. councils: Seat[][];
  20. handles: Handles;
  21. members: Member[];
  22. posts: Post[];
  23. proposals: ProposalDetail[];
  24. validators: string[];
  25. startTime: number;
  26. starred: string | undefined;
  27. stakes?: { [key: string]: Stakes };
  28. rewardPoints?: RewardPoints;
  29. reward?: number;
  30. }
  31. interface IState {
  32. expandNominators: boolean;
  33. hidden: boolean;
  34. }
  35. const fNum = (n: number) =>
  36. n.toLocaleString(undefined, {
  37. minimumFractionDigits: 2,
  38. maximumFractionDigits: 2,
  39. });
  40. class Validator extends Component<IProps, IState> {
  41. constructor(props: IProps) {
  42. super(props);
  43. this.state = { expandNominators: false, hidden: false };
  44. this.hide = this.hide.bind(this);
  45. this.toggleExpandNominators = this.toggleExpandNominators.bind(this);
  46. }
  47. hide() {
  48. this.setState({ hidden: true });
  49. }
  50. toggleExpandNominators() {
  51. this.setState({ expandNominators: !this.state.expandNominators });
  52. }
  53. render() {
  54. const {
  55. sortBy = () => {},
  56. toggleStar,
  57. member,
  58. validator,
  59. councils,
  60. council,
  61. posts,
  62. proposals,
  63. startTime,
  64. starred,
  65. stakes,
  66. rewardPoints,
  67. reward = 0,
  68. } = this.props;
  69. const { expandNominators, hidden } = this.state;
  70. if (hidden) return <div />;
  71. const points = rewardPoints ? rewardPoints.individual[validator] : "";
  72. const stake = stakes ? stakes[validator] : undefined;
  73. let totalStake = 0;
  74. let ownStake = 0;
  75. let commission = "";
  76. let ownReward = 0;
  77. let nomReward = 0;
  78. if (stake) {
  79. commission = `${stake.commission}%`;
  80. const comm = stake.commission / 100;
  81. // A commission of 5% means that for every 100tJOY earned,
  82. // validator takes 5 before splitting the remaining 95 based on stake
  83. totalStake = stake.total;
  84. ownStake = stake.own;
  85. const nom = 1 - ownStake / totalStake;
  86. nomReward = reward * (1 - comm) * nom;
  87. ownReward = reward - nomReward;
  88. }
  89. return (
  90. <div className="mt-2 d-flex flex-row justify-content-around">
  91. <div
  92. className="col-1 text-right"
  93. onClick={() => sortBy("points")}
  94. title="era points"
  95. >
  96. {points}
  97. <a
  98. href={`${domain}/#/staking/query/${validator}`}
  99. title="Show Stats (External)"
  100. >
  101. <Activity width={15} />
  102. </a>
  103. </div>
  104. <div className="col-2 text-right">
  105. <MemberBox
  106. id={0}
  107. account={validator}
  108. placement={"right"}
  109. councils={councils}
  110. council={council}
  111. member={member}
  112. posts={posts}
  113. proposals={proposals}
  114. startTime={startTime}
  115. validators={this.props.validators}
  116. />
  117. <Star
  118. width={15}
  119. color={"black"}
  120. fill={starred ? "black" : "teal"}
  121. className="ml-2 mb-2"
  122. onClick={() => toggleStar(validator)}
  123. />
  124. </div>
  125. <div
  126. className="col-1 text-right"
  127. onClick={() => sortBy("commission")}
  128. title="commission"
  129. >
  130. {commission}
  131. </div>
  132. <div
  133. className="col-2 text-black text-right"
  134. onClick={() => sortBy("totalStake")}
  135. title="total stake"
  136. >
  137. {totalStake > 0 && fNum(totalStake)}
  138. </div>
  139. <div
  140. className="col-2 text-right"
  141. onClick={() => sortBy("ownStake")}
  142. title="own stake"
  143. >
  144. {ownStake > 0 && fNum(ownStake)}
  145. </div>
  146. {ownReward ? (
  147. <div className="col-1 text-warning" title="reward">
  148. +{Math.round(ownReward)}
  149. </div>
  150. ) : (
  151. <div />
  152. )}
  153. <div className="d-none d-md-block col-3 mb-1 text-left">
  154. <Nominators
  155. fNum={fNum}
  156. reward={nomReward}
  157. toggleExpand={this.toggleExpandNominators}
  158. sortBy={sortBy}
  159. expand={expandNominators}
  160. nominators={stake ? stake.others : undefined}
  161. handles={handles}
  162. />
  163. </div>
  164. </div>
  165. );
  166. }
  167. }
  168. export default Validator;