Browse Source

Quorum and threshold on ProposalType preview

Leszek Wiesner 4 years ago
parent
commit
d4bd54176b

+ 1 - 5
packages/joy-proposals/src/Proposal/ProposalType.css

@@ -13,11 +13,7 @@
 }
 .ProposalType .actions {
   margin: 0 2em;
-  padding-top: 2em;
-}
-.ProposalType .btn-create {
-  white-space: nowrap;
-  margin-right: 0;
+  padding-top: 1em;
 }
 .ProposalType .proposal-details {
   display: flex;

+ 78 - 4
packages/joy-proposals/src/Proposal/ProposalTypePreview.tsx

@@ -1,14 +1,47 @@
 import React from "react";
 
 import { History } from "history";
-import { Item, Icon, Button } from "semantic-ui-react";
+import { Item, Icon, Button, Label } from "semantic-ui-react";
 
 import { Category } from "./ChooseProposalType";
 import { ProposalType } from "../runtime";
 import { slugify, splitOnUpperCase } from "../utils";
+import styled from 'styled-components';
+import useVoteStyles from './useVoteStyles';
 
 import "./ProposalType.css";
 
+const QuorumsAndThresholds = styled.div`
+  display: grid;
+  grid-template-columns: min-content min-content;
+  grid-template-rows: auto auto;
+  grid-row-gap: 0.5rem;
+  grid-column-gap: 0.5rem;
+  margin-bottom: 1rem;
+  @media screen and (max-width: 480px) {
+    grid-template-columns: min-content;
+  }
+`;
+
+const QuorumThresholdLabel = styled(Label)`
+  opacity: 0.75;
+  white-space: nowrap;
+  margin: 0 !important;
+  display: flex !important;
+  align-items: center;
+  & b {
+    font-size: 1.2em;
+    margin-left: auto;
+    padding-left: 0.3rem;
+  }
+`;
+
+const CreateButton = styled(Button)`
+  font-size: 1.1em !important;
+  white-space: nowrap;
+  margin-right: 0;
+`;
+
 export type ProposalTypeInfo = {
   type: ProposalType;
   category: Category;
@@ -18,6 +51,10 @@ export type ProposalTypeInfo = {
   cancellationFee?: number;
   gracePeriod: number;
   votingPeriod: number;
+  approvalQuorum: number;
+  approvalThreshold: number;
+  slashingQuorum: number;
+  slashingThreshold: number;
 };
 
 type ProposalTypePreviewProps = {
@@ -34,7 +71,18 @@ const ProposalTypeDetail = (props: { title: string, value: string }) => (
 
 export default function ProposalTypePreview(props: ProposalTypePreviewProps) {
   const {
-    typeInfo: { type, description, stake, cancellationFee, gracePeriod, votingPeriod }
+    typeInfo: {
+      type,
+      description,
+      stake,
+      cancellationFee,
+      gracePeriod,
+      votingPeriod,
+      approvalQuorum,
+      approvalThreshold,
+      slashingQuorum,
+      slashingThreshold
+    }
   } = props;
 
   const handleClick = () => {
@@ -65,12 +113,38 @@ export default function ProposalTypePreview(props: ProposalTypePreviewProps) {
             title="Voting period"
             value={ votingPeriod ? `${votingPeriod} block${votingPeriod > 1 ? "s" : ""}` : "NONE" } />
         </div>
+        <QuorumsAndThresholds>
+          { approvalQuorum && (
+            <QuorumThresholdLabel color={ useVoteStyles("Approve").color }>
+              <Icon name={ useVoteStyles("Approve").icon } />
+              Approval Quorum: <b>{ approvalQuorum }%</b>
+            </QuorumThresholdLabel>
+          ) }
+          { approvalThreshold && (
+            <QuorumThresholdLabel color={ useVoteStyles("Approve").color }>
+              <Icon name={ useVoteStyles("Approve").icon } />
+              Approval Threshold: <b>{ approvalThreshold }%</b>
+            </QuorumThresholdLabel>
+          ) }
+          { slashingQuorum && (
+            <QuorumThresholdLabel color={ useVoteStyles("Slash").color }>
+              <Icon name={ useVoteStyles("Slash").icon } />
+              Slashing Quorum: <b>{ slashingQuorum }%</b>
+            </QuorumThresholdLabel>
+          ) }
+          { slashingThreshold && (
+            <QuorumThresholdLabel color={ useVoteStyles("Slash").color }>
+              <Icon name={ useVoteStyles("Slash").icon } />
+              Slashing Threshold: <b>{ slashingThreshold }%</b>
+            </QuorumThresholdLabel>
+          ) }
+        </QuorumsAndThresholds>
       </Item.Content>
       <div className="actions">
-        <Button primary className="btn-create" size="medium" onClick={handleClick}>
+        <CreateButton primary size="medium" onClick={handleClick}>
           Create
           <Icon name="chevron right" />
-        </Button>
+        </CreateButton>
       </div>
     </Item>
   );

+ 2 - 3
packages/joy-proposals/src/Proposal/VotingSection.tsx

@@ -8,10 +8,9 @@ import { ProposalId } from "@joystream/types/proposals";
 import { useTransport } from "../runtime";
 import { VoteKind } from '@joystream/types/proposals';
 import { usePromise } from "../utils";
+import { VoteKinds } from "@joystream/types/proposals";
 
-// TODO: joy-types (there's something similar already I think)
-const voteKinds = ["Approve", "Slash", "Abstain", "Reject"] as const;
-export type VoteKindStr = "Approve" | "Slash" | "Abstain" | "Reject";
+export type VoteKindStr = typeof VoteKinds[number];
 
 type VoteButtonProps = {
   memberId: MemberId,

+ 81 - 30
packages/joy-proposals/src/utils.ts

@@ -155,58 +155,109 @@ export function calculateStake(type: ProposalType, issuance: number) {
 }
 
 export function calculateMetaFromType(type: ProposalType) {
-  let description = "";
   const image = "";
-  let category: Category = "Other";
   switch (type) {
     case "EvictStorageProvider": {
-      description = "Evicting Storage Provider Proposal";
-      category = "Storage";
-      break;
+      return {
+        description: "Evicting Storage Provider Proposal",
+        category: "Storage",
+        image,
+        approvalQuorum: 50,
+        approvalThreshold: 75,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     case "Text": {
-      description = "Signal Proposal";
-      category = "Other";
-      break;
+      return {
+        description: "Signal Proposal",
+        category: "Other",
+        image,
+        approvalQuorum: 60,
+        approvalThreshold: 80,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     case "SetStorageRoleParameters": {
-      description = "Set Storage Role Params Proposal";
-      category = "Storage";
-      break;
+      return {
+        description: "Set Storage Role Params Proposal",
+        category: "Storage",
+        image,
+        approvalQuorum: 66,
+        approvalThreshold: 80,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     case "SetValidatorCount": {
-      description = "Set Max Validator Count Proposal";
-      category = "Validators";
-      break;
+      return {
+        description: "Set Max Validator Count Proposal",
+        category: "Validators",
+        image,
+        approvalQuorum: 66,
+        approvalThreshold: 80,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     case "SetLead": {
-      description = "Set Lead Proposal";
-      category = "Content Working Group";
-      break;
+      return {
+        description: "Set Lead Proposal",
+        category: "Content Working Group",
+        image,
+        approvalQuorum: 60,
+        approvalThreshold: 75,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     case "SetContentWorkingGroupMintCapacity": {
-      description = "Set WG Mint Capacity Proposal";
-      category = "Content Working Group";
-      break;
+      return {
+        description: "Set WG Mint Capacity Proposal",
+        category: "Content Working Group",
+        image,
+        approvalQuorum: 60,
+        approvalThreshold: 75,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     case "Spending": {
-      description = "Spending Proposal";
-      category = "Other";
-      break;
+      return {
+        description: "Spending Proposal",
+        category: "Other",
+        image,
+        approvalQuorum: 60,
+        approvalThreshold: 80,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     case "SetElectionParameters": {
-      description = "Set Election Parameters Proposal";
-      category = "Council";
-      break;
+      return {
+        description: "Set Election Parameters Proposal",
+        category: "Council",
+        image,
+        approvalQuorum: 66,
+        approvalThreshold: 80,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     case "RuntimeUpgrade": {
-      description = "Runtime Upgrade Proposal";
-      category = "Other";
-      break;
+      return {
+        description: "Runtime Upgrade Proposal",
+        category: "Other",
+        image,
+        approvalQuorum: 80,
+        approvalThreshold: 100,
+        slashingQuorum: 60,
+        slashingThreshold: 80,
+      }
     }
     default: {
       throw new Error("'Proposal Type is invalid. Can't calculate metadata.");
     }
   }
-  return { description, image, category };
 }

+ 7 - 0
packages/joy-types/src/proposals.ts

@@ -237,6 +237,13 @@ export class ProposalStatus extends Enum {
   }
 }
 
+export const VoteKinds = [
+  "Approve",
+  "Reject",
+  "Slash",
+  "Abstain"
+] as const;
+
 export class VoteKind extends Enum {
   constructor(value?: any, index?: number) {
     super(["Approve", "Reject", "Slash", "Abstain"], value, index);