From 9235c83cf26515b228044784ce4b4aaabd29101a Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 16 Mar 2023 15:16:54 -0300 Subject: [PATCH 01/45] refactor: replaced chevron button with common implementation --- .../ActionsBuilder/Action/Action.styled.tsx | 23 +------------------ .../ActionsBuilder/Action/Action.tsx | 14 ++++------- .../components/ExpandButton/ExpandButton.tsx | 1 + .../ProposalInfoCard/ProposalInfoCard.tsx | 20 ++++------------ 4 files changed, 12 insertions(+), 46 deletions(-) diff --git a/apps/davi/src/components/ActionsBuilder/Action/Action.styled.tsx b/apps/davi/src/components/ActionsBuilder/Action/Action.styled.tsx index 6f010219..ab2faaa5 100644 --- a/apps/davi/src/components/ActionsBuilder/Action/Action.styled.tsx +++ b/apps/davi/src/components/ActionsBuilder/Action/Action.styled.tsx @@ -1,7 +1,7 @@ import { EditButton, Grip } from '../common'; import { CardWrapper, Header } from 'components/Card'; import { Box } from 'components/primitives/Layout/Box'; -import styled, { css } from 'styled-components'; +import styled from 'styled-components'; import { CardStatus } from './Action'; import { TenderlyLogo } from '../OptionsList/SimulationModal/SimulationModal.styled'; @@ -44,27 +44,6 @@ export const CardLabel = styled(Box)` font-weight: 500; `; -export const ChevronIcon = styled.span<{ active?: boolean }>` - cursor: pointer; - height: 1.4rem; - width: 1.4rem; - border-radius: 50%; - border: 1px solid ${({ theme }) => theme.colors.border1}; - display: inline-flex; - justify-content: center; - align-items: center; - - &:hover { - border-color: ${({ theme }) => theme.colors.border3}; - } - - ${({ active }) => - active && - css` - border-color: ${({ theme }) => theme.colors.border3}; - `} -`; - export const DetailWrapper = styled(Box)` padding: 1.25rem 1.5rem; `; diff --git a/apps/davi/src/components/ActionsBuilder/Action/Action.tsx b/apps/davi/src/components/ActionsBuilder/Action/Action.tsx index 3e1467e4..2d8a4f9d 100644 --- a/apps/davi/src/components/ActionsBuilder/Action/Action.tsx +++ b/apps/davi/src/components/ActionsBuilder/Action/Action.tsx @@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'; import { BigNumber } from 'ethers'; import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; -import { FiChevronDown, FiChevronUp } from 'react-icons/fi'; import { useHookStoreProvider } from 'stores'; import { preventEmptyString } from 'utils'; @@ -25,7 +24,6 @@ import { CardHeader, CardLabel, CardWrapperWithMargin, - ChevronIcon, DetailWrapper, EditButtonWithMargin, GripWithMargin, @@ -39,6 +37,7 @@ import { } from './Action.styled'; import { useTransactionSimulation } from 'hooks/Guilds/useTenderlyApi'; import { ExternalLink } from 'components/primitives/Links/ExternalLink'; +import { ExpandButton } from 'components/ExpandButton'; interface ActionViewProps { call?: Call; @@ -182,13 +181,10 @@ export const ActionRow: React.FC = ({ {t('actionBuilder.action.remove')} )} - setExpanded(!expanded)}> - {expanded ? ( - - ) : ( - - )} - + setExpanded(!expanded)} + /> diff --git a/apps/davi/src/components/ExpandButton/ExpandButton.tsx b/apps/davi/src/components/ExpandButton/ExpandButton.tsx index bd80f911..e7b8d227 100644 --- a/apps/davi/src/components/ExpandButton/ExpandButton.tsx +++ b/apps/davi/src/components/ExpandButton/ExpandButton.tsx @@ -9,6 +9,7 @@ const ButtonWrapper = styled.span<{ height: ${({ height }) => height}; width: ${({ width }) => width}; border-radius: 50%; + color: ${({ theme }) => theme.colors.text}; border: 1px solid ${({ theme }) => theme.colors.border1}; display: inline-flex; justify-content: center; diff --git a/apps/davi/src/components/ProposalInfoCard/ProposalInfoCard.tsx b/apps/davi/src/components/ProposalInfoCard/ProposalInfoCard.tsx index 397379e8..ae1d8ab1 100644 --- a/apps/davi/src/components/ProposalInfoCard/ProposalInfoCard.tsx +++ b/apps/davi/src/components/ProposalInfoCard/ProposalInfoCard.tsx @@ -1,20 +1,16 @@ import { useState } from 'react'; -import { - InfoDetail, - InfoDetailMuted, - ProposalHistoryIcon, -} from './ProposalInfoCard.styled'; +import { InfoDetail, InfoDetailMuted } from './ProposalInfoCard.styled'; import { SidebarCard, SidebarCardContent, SidebarCardHeaderSpaced, } from 'components/SidebarCard'; import { Loading } from 'components/primitives/Loading'; -import { FiChevronDown, FiChevronUp } from 'react-icons/fi'; import { duration } from 'moment'; import { ProposalInfoCardProps } from './types'; import { ProposalHistory } from './ProposalHistory'; import { useTranslation } from 'react-i18next'; +import { ExpandButton } from 'components/ExpandButton'; const ProposalInfoCard: React.FC = ({ proposal, @@ -63,16 +59,10 @@ const ProposalInfoCard: React.FC = ({ {t('proposal.proposalInfoCard.proposalHistory')} - setIsHistoryExpanded(!isHistoryExpanded)} - > - {isHistoryExpanded ? ( - - ) : ( - - )} - + /> {isHistoryExpanded && } From 6a7502a5ee08e5b1da0930123c31534dd47f23a9 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 16 Mar 2023 15:18:35 -0300 Subject: [PATCH 02/45] feat: added card divider and gap property to flex element --- apps/davi/src/components/Card/Card.tsx | 7 +++++++ apps/davi/src/components/primitives/Layout/Flex.tsx | 11 ++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/davi/src/components/Card/Card.tsx b/apps/davi/src/components/Card/Card.tsx index bf196bfe..5d3006a8 100644 --- a/apps/davi/src/components/Card/Card.tsx +++ b/apps/davi/src/components/Card/Card.tsx @@ -6,6 +6,7 @@ import styled, { ThemeProps, } from 'styled-components'; import { Box } from 'components/primitives/Layout/Box'; +import { Divider } from 'components/Divider'; export interface CardWrapperProps { customStyles?: string | FlattenInterpolation>; @@ -58,3 +59,9 @@ export const Card: React.FC = ({ ); }; + +export const CardDivider = styled(Divider)` + margin: 0; + margin-left: -24px; + width: calc(100% + 48px); +`; diff --git a/apps/davi/src/components/primitives/Layout/Flex.tsx b/apps/davi/src/components/primitives/Layout/Flex.tsx index f5e0f8f8..05efce3e 100644 --- a/apps/davi/src/components/primitives/Layout/Flex.tsx +++ b/apps/davi/src/components/primitives/Layout/Flex.tsx @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; export const Flex = styled.div<{ direction?: string; @@ -6,6 +6,8 @@ export const Flex = styled.div<{ alignItems?: string; margin?: number | string; padding?: number | string; + gap?: number | string; + fullWidth?: boolean; }>` display: Flex; flex-direction: ${({ direction }) => (direction ? direction : 'column')}; @@ -16,4 +18,11 @@ export const Flex = styled.div<{ border-radius: ${({ theme }) => theme.radii.curved}; margin: ${({ margin }) => (margin ? margin : '0')}; padding: ${({ padding }) => (padding ? padding : '0')}; + gap: ${({ gap }) => (gap ? gap : '0')}; + + ${({ fullWidth }) => + fullWidth && + css` + width: 100%; + `} `; From 8593cb4d043260a69fd0f9dd0aa995c58b8d6d57 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 16 Mar 2023 15:18:55 -0300 Subject: [PATCH 03/45] test: updated snapshots --- .../__snapshots__/CallDetails.test.tsx.snap | 2 + .../GenericCallParamsMatcher.test.tsx.snap | 2 + .../SetGuildConfigInfoLine.test.tsx.snap | 1 + .../UpdateENSContentSummary.test.tsx.snap | 1 + .../UndecodableCallDetails.test.tsx.snap | 2 + .../__snapshots__/ActionsModal.test.tsx.snap | 3 + .../DiscussionCard.test.tsx.snap | 2 + .../Filter/__snapshots__/Filter.test.tsx.snap | 1 + .../__snapshots__/GuildCard.test.tsx.snap | 3 + .../__snapshots__/OnlineStatus.test.tsx.snap | 1 + .../ProposalCardWinningOption.test.tsx.snap | 5 + .../__snapshots__/ProposalCard.test.tsx.snap | 3 + .../ProposalInfoCard.test.tsx.snap | 102 +++++++++--------- .../__snapshots__/ProposalTypes.test.tsx.snap | 1 + .../ProposalVoteCard.test.tsx.snap | 1 + .../SidebarInfoCard.test.tsx.snap | 2 + .../TransactionModal.test.tsx.snap | 1 + .../BLockExplorerLink.test.tsx.snap | 1 + 18 files changed, 86 insertions(+), 48 deletions(-) diff --git a/apps/davi/src/components/ActionsBuilder/CallDetails/__snapshots__/CallDetails.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/CallDetails/__snapshots__/CallDetails.test.tsx.snap index 079e68b4..7c762e58 100644 --- a/apps/davi/src/components/ActionsBuilder/CallDetails/__snapshots__/CallDetails.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/CallDetails/__snapshots__/CallDetails.test.tsx.snap @@ -80,6 +80,7 @@ exports[`CallDetails Should match 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c8 { @@ -375,6 +376,7 @@ exports[`CallDetails Should match with empty data 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c16 { diff --git a/apps/davi/src/components/ActionsBuilder/SupportedActions/GenericCall/__snapshots__/GenericCallParamsMatcher.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/SupportedActions/GenericCall/__snapshots__/GenericCallParamsMatcher.test.tsx.snap index ec72d485..40df4649 100644 --- a/apps/davi/src/components/ActionsBuilder/SupportedActions/GenericCall/__snapshots__/GenericCallParamsMatcher.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/SupportedActions/GenericCall/__snapshots__/GenericCallParamsMatcher.test.tsx.snap @@ -52,6 +52,7 @@ exports[`GenericCallParamsMatcher Should match snapshot for all component types border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c4 { @@ -253,6 +254,7 @@ exports[`GenericCallParamsMatcher replaces all component types correctly 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c4 { diff --git a/apps/davi/src/components/ActionsBuilder/SupportedActions/SetGuildConfig/__snapshots__/SetGuildConfigInfoLine.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/SupportedActions/SetGuildConfig/__snapshots__/SetGuildConfigInfoLine.test.tsx.snap index 4325ea1f..633cd5f3 100644 --- a/apps/davi/src/components/ActionsBuilder/SupportedActions/SetGuildConfig/__snapshots__/SetGuildConfigInfoLine.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/SupportedActions/SetGuildConfig/__snapshots__/SetGuildConfigInfoLine.test.tsx.snap @@ -34,6 +34,7 @@ exports[`SetGuildConfigInfoLine Should match snapshot 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; }
diff --git a/apps/davi/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentSummary.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentSummary.test.tsx.snap index 5300459d..75fefcc0 100644 --- a/apps/davi/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentSummary.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentSummary.test.tsx.snap @@ -76,6 +76,7 @@ exports[`UpdateENSNameSummary Should match snapshot 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c5 { diff --git a/apps/davi/src/components/ActionsBuilder/UndecodableCalls/__snapshots__/UndecodableCallDetails.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/UndecodableCalls/__snapshots__/UndecodableCallDetails.test.tsx.snap index 686a7bb1..3faa9df9 100644 --- a/apps/davi/src/components/ActionsBuilder/UndecodableCalls/__snapshots__/UndecodableCallDetails.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/UndecodableCalls/__snapshots__/UndecodableCallDetails.test.tsx.snap @@ -44,6 +44,7 @@ exports[`UndecodableCallDetails Should match snapshot 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c7 { @@ -265,6 +266,7 @@ exports[`UndecodableCallDetails Should match snapshot with approval call 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c7 { diff --git a/apps/davi/src/components/ActionsModal/__snapshots__/ActionsModal.test.tsx.snap b/apps/davi/src/components/ActionsModal/__snapshots__/ActionsModal.test.tsx.snap index 852e8f23..d0e10c7b 100644 --- a/apps/davi/src/components/ActionsModal/__snapshots__/ActionsModal.test.tsx.snap +++ b/apps/davi/src/components/ActionsModal/__snapshots__/ActionsModal.test.tsx.snap @@ -80,6 +80,7 @@ exports[`ActionsModal Should match snapshot 2 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c17 { @@ -99,6 +100,7 @@ exports[`ActionsModal Should match snapshot 2 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c11 { @@ -292,6 +294,7 @@ exports[`ActionsModal Should match snapshot 2 1`] = ` height: 1.25rem; width: 1.25rem; border-radius: 50%; + color: #fff; border: 1px solid #303338; display: -webkit-inline-box; display: -webkit-inline-flex; diff --git a/apps/davi/src/components/DiscussionCard/__snapshots__/DiscussionCard.test.tsx.snap b/apps/davi/src/components/DiscussionCard/__snapshots__/DiscussionCard.test.tsx.snap index ad805eee..ebcccb1e 100644 --- a/apps/davi/src/components/DiscussionCard/__snapshots__/DiscussionCard.test.tsx.snap +++ b/apps/davi/src/components/DiscussionCard/__snapshots__/DiscussionCard.test.tsx.snap @@ -25,6 +25,7 @@ exports[`DiscussionCard should render with full parameters 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c8 { @@ -44,6 +45,7 @@ exports[`DiscussionCard should render with full parameters 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c0 { diff --git a/apps/davi/src/components/Filter/__snapshots__/Filter.test.tsx.snap b/apps/davi/src/components/Filter/__snapshots__/Filter.test.tsx.snap index c6cd0327..e96ee478 100644 --- a/apps/davi/src/components/Filter/__snapshots__/Filter.test.tsx.snap +++ b/apps/davi/src/components/Filter/__snapshots__/Filter.test.tsx.snap @@ -220,6 +220,7 @@ exports[`Filter Should match snapshot 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c1 { diff --git a/apps/davi/src/components/GuildCard/__snapshots__/GuildCard.test.tsx.snap b/apps/davi/src/components/GuildCard/__snapshots__/GuildCard.test.tsx.snap index e73de927..65ca0fa4 100644 --- a/apps/davi/src/components/GuildCard/__snapshots__/GuildCard.test.tsx.snap +++ b/apps/davi/src/components/GuildCard/__snapshots__/GuildCard.test.tsx.snap @@ -40,6 +40,7 @@ exports[`GuildCard Should render 'No proposals' when there are zero proposals' 1 border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c3 { @@ -254,6 +255,7 @@ exports[`GuildCard Should render loading state skeleton 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c3 { @@ -465,6 +467,7 @@ exports[`GuildCard Should render with full parameters 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c3 { diff --git a/apps/davi/src/components/OnlineStatus/__snapshots__/OnlineStatus.test.tsx.snap b/apps/davi/src/components/OnlineStatus/__snapshots__/OnlineStatus.test.tsx.snap index a2f16750..6ef6d39f 100644 --- a/apps/davi/src/components/OnlineStatus/__snapshots__/OnlineStatus.test.tsx.snap +++ b/apps/davi/src/components/OnlineStatus/__snapshots__/OnlineStatus.test.tsx.snap @@ -37,6 +37,7 @@ exports[`OnlineStatus Should match snapshot offline 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; }
diff --git a/apps/davi/src/components/ProposalCard/ProposalCardWinningOption/__snapshots__/ProposalCardWinningOption.test.tsx.snap b/apps/davi/src/components/ProposalCard/ProposalCardWinningOption/__snapshots__/ProposalCardWinningOption.test.tsx.snap index 5477ae94..02537ec2 100644 --- a/apps/davi/src/components/ProposalCard/ProposalCardWinningOption/__snapshots__/ProposalCardWinningOption.test.tsx.snap +++ b/apps/davi/src/components/ProposalCard/ProposalCardWinningOption/__snapshots__/ProposalCardWinningOption.test.tsx.snap @@ -61,6 +61,7 @@ exports[`ProposalCardWinningOption a tooltip shows after clicking in the action border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c1 { @@ -451,6 +452,7 @@ exports[`ProposalCardWinningOption if the option has only one action, no tooltip border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c1 { @@ -658,6 +660,7 @@ exports[`ProposalCardWinningOption renders a loading component when the votes ar border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c1 { @@ -879,6 +882,7 @@ exports[`ProposalCardWinningOption renders an indicator of the number of actions border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c1 { @@ -1084,6 +1088,7 @@ exports[`ProposalCardWinningOption renders properly with one action 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c1 { diff --git a/apps/davi/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap b/apps/davi/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap index 14c95c70..753d8c98 100644 --- a/apps/davi/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap +++ b/apps/davi/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap @@ -25,6 +25,7 @@ exports[`ProposalCard ProposalCard Renders properly with data 1`] = ` border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c11 { @@ -539,6 +540,7 @@ exports[`ProposalCard ProposalCard Renders properly with more than one option 1 border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c11 { @@ -1053,6 +1055,7 @@ exports[`ProposalCard ProposalCard Renders properly with more than one option co border-radius: 10px; margin: 0; padding: 0; + gap: 0; } .c11 { diff --git a/apps/davi/src/components/ProposalInfoCard/__snapshots__/ProposalInfoCard.test.tsx.snap b/apps/davi/src/components/ProposalInfoCard/__snapshots__/ProposalInfoCard.test.tsx.snap index 46bd7f60..f0a5eeff 100644 --- a/apps/davi/src/components/ProposalInfoCard/__snapshots__/ProposalInfoCard.test.tsx.snap +++ b/apps/davi/src/components/ProposalInfoCard/__snapshots__/ProposalInfoCard.test.tsx.snap @@ -27,30 +27,6 @@ exports[`ProposalInfoCard Should render loading state 1`] = ` color: #A1A6B0; } -.c9 { - cursor: pointer; - height: 1.25rem; - width: 1.25rem; - border-radius: 50%; - border: 1px solid #A1A6B0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - -.c9:hover { - border-color: #fff; -} - .c1 { border: 1px solid #303338; border-radius: 10px; @@ -99,6 +75,31 @@ exports[`ProposalInfoCard Should render loading state 1`] = ` color: #fff; } +.c9 { + cursor: pointer; + height: 1.25rem; + width: 1.25rem; + border-radius: 50%; + color: #fff; + border: 1px solid #303338; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.c9:hover { + border-color: #fff; +} +
Date: Thu, 16 Mar 2023 16:53:47 -0300 Subject: [PATCH 04/45] feat: added speedometer library --- apps/davi/package.json | 4 +- pnpm-lock.yaml | 258 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 254 insertions(+), 8 deletions(-) diff --git a/apps/davi/package.json b/apps/davi/package.json index d812865b..032615ce 100644 --- a/apps/davi/package.json +++ b/apps/davi/package.json @@ -116,6 +116,7 @@ "react": "^18.2.0", "react-app-rewired": "^2.1.8", "react-countdown": "^2.3.2", + "react-d3-speedometer": "^1.1.0", "react-datepicker": "^4.8.0", "react-device-detect": "^2.1.2", "react-diff-viewer": "^3.1.1", @@ -133,11 +134,11 @@ "react-switch": "^7.0.0", "react-toastify": "^8.1.0", "react-virtuoso": "^2.16.5", + "showdown": "^2.1.0", "styled-components": "^5.3.5", "swr": "^1.1.2", "ts-generator": "^0.1.1", "ts-node": "^10.9.1", - "showdown": "^2.1.0", "turndown": "^7.1.1", "typechain-target-ethers-v5": "^5.0.1", "typescript": "^4.9.3", @@ -233,4 +234,3 @@ ] } } - diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29b439f3..d69f3dfc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -155,6 +155,7 @@ importers: react: ^18.2.0 react-app-rewired: ^2.1.8 react-countdown: ^2.3.2 + react-d3-speedometer: ^1.1.0 react-datepicker: ^4.8.0 react-device-detect: ^2.1.2 react-diff-viewer: ^3.1.1 @@ -266,6 +267,7 @@ importers: react: 18.2.0 react-app-rewired: 2.2.1_react-scripts@5.0.1 react-countdown: 2.3.3_biqbaboplfbrettd7655fr4n2y + react-d3-speedometer: 1.1.0_biqbaboplfbrettd7655fr4n2y react-datepicker: 4.8.0_biqbaboplfbrettd7655fr4n2y react-device-detect: 2.2.2_biqbaboplfbrettd7655fr4n2y react-diff-viewer: 3.1.1_biqbaboplfbrettd7655fr4n2y @@ -14878,7 +14880,7 @@ packages: /axios/0.26.1: resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} dependencies: - follow-redirects: 1.15.2_debug@4.3.4 + follow-redirects: 1.15.2 transitivePeerDependencies: - debug dev: true @@ -14896,7 +14898,7 @@ packages: /axios/1.1.3: resolution: {integrity: sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==} dependencies: - follow-redirects: 1.15.2_debug@4.3.4 + follow-redirects: 1.15.2 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -18669,6 +18671,223 @@ packages: es5-ext: 0.10.62 type: 1.2.0 + /d3-array/2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + dependencies: + internmap: 1.0.1 + dev: false + + /d3-axis/2.1.0: + resolution: {integrity: sha512-z/G2TQMyuf0X3qP+Mh+2PimoJD41VOCjViJzT0BHeL/+JQAofkiWZbWxlwFGb1N8EN+Cl/CW+MUKbVzr1689Cw==} + dev: false + + /d3-brush/2.1.0: + resolution: {integrity: sha512-cHLLAFatBATyIKqZOkk/mDHUbzne2B3ZwxkzMHvFTCZCmLaXDpZRihQSn8UNXTkGD/3lb/W2sQz0etAftmHMJQ==} + dependencies: + d3-dispatch: 2.0.0 + d3-drag: 2.0.0 + d3-interpolate: 2.0.1 + d3-selection: 2.0.0 + d3-transition: 2.0.0_d3-selection@2.0.0 + dev: false + + /d3-chord/2.0.0: + resolution: {integrity: sha512-D5PZb7EDsRNdGU4SsjQyKhja8Zgu+SHZfUSO5Ls8Wsn+jsAKUUGkcshLxMg9HDFxG3KqavGWaWkJ8EpU8ojuig==} + dependencies: + d3-path: 2.0.0 + dev: false + + /d3-color/2.0.0: + resolution: {integrity: sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==} + dev: false + + /d3-contour/2.0.0: + resolution: {integrity: sha512-9unAtvIaNk06UwqBmvsdHX7CZ+NPDZnn8TtNH1myW93pWJkhsV25JcgnYAu0Ck5Veb1DHiCv++Ic5uvJ+h50JA==} + dependencies: + d3-array: 2.12.1 + dev: false + + /d3-delaunay/5.3.0: + resolution: {integrity: sha512-amALSrOllWVLaHTnDLHwMIiz0d1bBu9gZXd1FiLfXf8sHcX9jrcj81TVZOqD4UX7MgBZZ07c8GxzEgBpJqc74w==} + dependencies: + delaunator: 4.0.1 + dev: false + + /d3-dispatch/2.0.0: + resolution: {integrity: sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==} + dev: false + + /d3-drag/2.0.0: + resolution: {integrity: sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==} + dependencies: + d3-dispatch: 2.0.0 + d3-selection: 2.0.0 + dev: false + + /d3-dsv/2.0.0: + resolution: {integrity: sha512-E+Pn8UJYx9mViuIUkoc93gJGGYut6mSDKy2+XaPwccwkRGlR+LO97L2VCCRjQivTwLHkSnAJG7yo00BWY6QM+w==} + hasBin: true + dependencies: + commander: 2.20.3 + iconv-lite: 0.4.24 + rw: 1.3.3 + dev: false + + /d3-ease/2.0.0: + resolution: {integrity: sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==} + dev: false + + /d3-fetch/2.0.0: + resolution: {integrity: sha512-TkYv/hjXgCryBeNKiclrwqZH7Nb+GaOwo3Neg24ZVWA3MKB+Rd+BY84Nh6tmNEMcjUik1CSUWjXYndmeO6F7sw==} + dependencies: + d3-dsv: 2.0.0 + dev: false + + /d3-force/2.1.1: + resolution: {integrity: sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew==} + dependencies: + d3-dispatch: 2.0.0 + d3-quadtree: 2.0.0 + d3-timer: 2.0.0 + dev: false + + /d3-format/2.0.0: + resolution: {integrity: sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==} + dev: false + + /d3-geo/2.0.2: + resolution: {integrity: sha512-8pM1WGMLGFuhq9S+FpPURxic+gKzjluCD/CHTuUF3mXMeiCo0i6R0tO1s4+GArRFde96SLcW/kOFRjoAosPsFA==} + dependencies: + d3-array: 2.12.1 + dev: false + + /d3-hierarchy/2.0.0: + resolution: {integrity: sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw==} + dev: false + + /d3-interpolate/2.0.1: + resolution: {integrity: sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==} + dependencies: + d3-color: 2.0.0 + dev: false + + /d3-path/2.0.0: + resolution: {integrity: sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==} + dev: false + + /d3-polygon/2.0.0: + resolution: {integrity: sha512-MsexrCK38cTGermELs0cO1d79DcTsQRN7IWMJKczD/2kBjzNXxLUWP33qRF6VDpiLV/4EI4r6Gs0DAWQkE8pSQ==} + dev: false + + /d3-quadtree/2.0.0: + resolution: {integrity: sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw==} + dev: false + + /d3-random/2.2.2: + resolution: {integrity: sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw==} + dev: false + + /d3-scale-chromatic/2.0.0: + resolution: {integrity: sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA==} + dependencies: + d3-color: 2.0.0 + d3-interpolate: 2.0.1 + dev: false + + /d3-scale/3.3.0: + resolution: {integrity: sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==} + dependencies: + d3-array: 2.12.1 + d3-format: 2.0.0 + d3-interpolate: 2.0.1 + d3-time: 2.1.1 + d3-time-format: 3.0.0 + dev: false + + /d3-selection/2.0.0: + resolution: {integrity: sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==} + dev: false + + /d3-shape/2.1.0: + resolution: {integrity: sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==} + dependencies: + d3-path: 2.0.0 + dev: false + + /d3-time-format/3.0.0: + resolution: {integrity: sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==} + dependencies: + d3-time: 2.1.1 + dev: false + + /d3-time/2.1.1: + resolution: {integrity: sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==} + dependencies: + d3-array: 2.12.1 + dev: false + + /d3-timer/2.0.0: + resolution: {integrity: sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==} + dev: false + + /d3-transition/2.0.0_d3-selection@2.0.0: + resolution: {integrity: sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==} + peerDependencies: + d3-selection: '2' + dependencies: + d3-color: 2.0.0 + d3-dispatch: 2.0.0 + d3-ease: 2.0.0 + d3-interpolate: 2.0.1 + d3-selection: 2.0.0 + d3-timer: 2.0.0 + dev: false + + /d3-zoom/2.0.0: + resolution: {integrity: sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==} + dependencies: + d3-dispatch: 2.0.0 + d3-drag: 2.0.0 + d3-interpolate: 2.0.1 + d3-selection: 2.0.0 + d3-transition: 2.0.0_d3-selection@2.0.0 + dev: false + + /d3/6.7.0: + resolution: {integrity: sha512-hNHRhe+yCDLUG6Q2LwvR/WdNFPOJQ5VWqsJcwIYVeI401+d2/rrCjxSXkiAdIlpx7/73eApFB4Olsmh3YN7a6g==} + dependencies: + d3-array: 2.12.1 + d3-axis: 2.1.0 + d3-brush: 2.1.0 + d3-chord: 2.0.0 + d3-color: 2.0.0 + d3-contour: 2.0.0 + d3-delaunay: 5.3.0 + d3-dispatch: 2.0.0 + d3-drag: 2.0.0 + d3-dsv: 2.0.0 + d3-ease: 2.0.0 + d3-fetch: 2.0.0 + d3-force: 2.1.1 + d3-format: 2.0.0 + d3-geo: 2.0.2 + d3-hierarchy: 2.0.0 + d3-interpolate: 2.0.1 + d3-path: 2.0.0 + d3-polygon: 2.0.0 + d3-quadtree: 2.0.0 + d3-random: 2.2.2 + d3-scale: 3.3.0 + d3-scale-chromatic: 2.0.0 + d3-selection: 2.0.0 + d3-shape: 2.1.0 + d3-time: 2.1.1 + d3-time-format: 3.0.0 + d3-timer: 2.0.0 + d3-transition: 2.0.0_d3-selection@2.0.0 + d3-zoom: 2.0.0 + dev: false + /dag-jose-utils/2.0.0: resolution: {integrity: sha512-vE6EyhjSh+dfr8hbs/gLk0v98h2ekjy6r6pXvmB4SvO6awalt95LEetG0QDh5rmMYE3FO8ynp3xrCYsAHHZOlg==} dependencies: @@ -19284,6 +19503,10 @@ packages: /defined/1.0.1: resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} + /delaunator/4.0.1: + resolution: {integrity: sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag==} + dev: false + /delay/5.0.0: resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} engines: {node: '>=10'} @@ -22736,7 +22959,6 @@ packages: peerDependenciesMeta: debug: optional: true - dev: false /follow-redirects/1.15.2_debug@4.1.1: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} @@ -22772,6 +22994,7 @@ packages: optional: true dependencies: debug: 4.3.4 + dev: true /follow-redirects/1.5.10: resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==} @@ -24610,7 +24833,7 @@ packages: engines: {node: '>=8.0.0'} dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.2_debug@4.3.4 + follow-redirects: 1.15.2 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -25001,6 +25224,10 @@ packages: has: 1.0.3 side-channel: 1.0.4 + /internmap/1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + dev: false + /interpret/1.4.0: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} @@ -29441,7 +29668,6 @@ packages: /lodash-es/4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - dev: true /lodash._reinterpolate/3.0.0: resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==} @@ -34548,6 +34774,22 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false + /react-d3-speedometer/1.1.0_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-wA82f/WSUxcclKzaMx9jqNky8+TosdccZtLKsRIWlF5AN1Y2h0LtXyB0LPU/Io2/YOVM9TBgnK5OuZ3OhsJSEQ==} + engines: {node: '>=8.0', npm: '>=3.0.0'} + peerDependencies: + react: ^17.0.0 + react-dom: ^17.0.0 + dependencies: + '@babel/runtime': 7.20.1 + d3: 6.7.0 + lodash-es: 4.17.21 + memoize-one: 5.2.1 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + dev: false + /react-datepicker/4.8.0_biqbaboplfbrettd7655fr4n2y: resolution: {integrity: sha512-u69zXGHMpxAa4LeYR83vucQoUCJQ6m/WBsSxmUMu/M8ahTSVMMyiyQzauHgZA2NUr9y0FUgOAix71hGYUb6tvg==} peerDependencies: @@ -35939,6 +36181,10 @@ packages: /rustbn.js/0.2.0: resolution: {integrity: sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==} + /rw/1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + dev: false + /rxjs/6.6.7: resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} engines: {npm: '>=2.0.0'} @@ -36670,7 +36916,7 @@ packages: dependencies: command-exists: 1.2.9 commander: 3.0.2 - follow-redirects: 1.15.2_debug@4.3.4 + follow-redirects: 1.15.2 fs-extra: 0.30.0 js-sha3: 0.8.0 memorystream: 0.3.1 From 393c910557199b0ed9eaf6a0207848e4fb0d00de Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 16 Mar 2023 16:54:22 -0300 Subject: [PATCH 05/45] feat: formatted scrollbar for sidebar sections --- .../SidebarCard/SidebarCard.styled.tsx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/apps/davi/src/components/SidebarCard/SidebarCard.styled.tsx b/apps/davi/src/components/SidebarCard/SidebarCard.styled.tsx index 5632a4b5..4ed765c2 100644 --- a/apps/davi/src/components/SidebarCard/SidebarCard.styled.tsx +++ b/apps/davi/src/components/SidebarCard/SidebarCard.styled.tsx @@ -29,4 +29,25 @@ export const SidebarCardContentWrapper = styled(Box)` overflow: auto; max-height: 10rem; margin-bottom: 1rem; + padding: 0px 5px; + + // Scrollbar styling + // Firefox + & { + scrollbar-width: 12px; + scrollbar-color: ${({ theme }) => theme.colors.active} transparent; + } + + // Chrome, Edge, and Safari + &::-webkit-scrollbar { + width: 6px; + max-height: 24px; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: ${({ theme }) => theme.colors.active}; + border-radius: 10px; + } `; From b5d9cc54964eb9a73204b9b5bee8732cb9a4c55f Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 17 Mar 2023 08:36:46 -0300 Subject: [PATCH 06/45] feat: hardcoded draft of holographic consensus component --- .../Guilds/pages/Proposal/Proposal.tsx | 3 + apps/davi/src/components/Card/Card.tsx | 1 - .../HolographicConsensusCard.styled.tsx | 84 ++++++++ .../HolographicConsensusCard.tsx | 195 ++++++++++++++++++ .../HolographicConsensusCard/StakeDetails.tsx | 26 +++ 5 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx create mode 100644 apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx create mode 100644 apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx diff --git a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx index 2e82e0dc..a207f03c 100644 --- a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx +++ b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx @@ -39,6 +39,7 @@ import { Flex } from 'components/primitives/Layout'; import { IconButton } from 'components/primitives/Button'; import { getBlockExplorerUrl } from 'provider'; import { useSearchParams } from 'react-router-dom'; +import { HolographicConsensusCard } from 'components/HolographicConsensusCard/HolographicConsensusCard'; const ProposalPage: React.FC = () => { const { @@ -52,6 +53,7 @@ const ProposalPage: React.FC = () => { useTimeDetail, }, }, + capabilities: { consensus }, } = useHookStoreProvider(); const { t } = useTranslation(); const { connector } = useAccount(); @@ -202,6 +204,7 @@ const ProposalPage: React.FC = () => { guildConfig={guildConfig} quorum={quorum} /> + {consensus === 'holographic' && } ); diff --git a/apps/davi/src/components/Card/Card.tsx b/apps/davi/src/components/Card/Card.tsx index 5d3006a8..199fbced 100644 --- a/apps/davi/src/components/Card/Card.tsx +++ b/apps/davi/src/components/Card/Card.tsx @@ -62,6 +62,5 @@ export const Card: React.FC = ({ export const CardDivider = styled(Divider)` margin: 0; - margin-left: -24px; width: calc(100% + 48px); `; diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx new file mode 100644 index 00000000..9d23e027 --- /dev/null +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx @@ -0,0 +1,84 @@ +import { SidebarCardContentWrapper } from 'components/SidebarCard/SidebarCard.styled'; +import styled, { css } from 'styled-components'; +import { StakeOptions } from './HolographicConsensusCard'; + +export const BoostedStatePill = styled.div` + margin-top: -77px; + margin-bottom: 20px; + border-radius: ${({ theme }) => theme.radii.curved}; + font-size: 12px; +`; + +export const StakeButtonsContainer = styled.div` + display: flex; + justify-content: space-around; + margin: 0; + width: calc(100% + 32px); +`; + +export const StakeNumberButton = styled.button<{ + variant: StakeOptions; + active?: boolean; +}>` + cursor: pointer; + width: 50%; + height: 48px; + margin: 0; + border: none; + font-weight: 600; + background-color: ${({ theme }) => theme.colors.bg1}; + color: ${({ variant, theme }) => + variant === 'for' ? theme.colors.yellow : theme.colors.votes[0]}; + + ${({ active, theme }) => + active && + css` + background-color: ${theme.colors.darkGreen2}; + `} +`; + +export const StakeIconButton = styled.button<{ + variant: StakeOptions; + active?: boolean; +}>` + cursor: pointer; + padding: 11px 43px; + border-radius: ${({ theme }) => theme.radii.pill}; + background-color: ${({ theme }) => theme.colors.bg1}; + border: 1px solid + ${({ variant, theme }) => + variant === 'for' ? theme.colors.yellow : theme.colors.votes[0]}; + + ${({ active, variant, theme }) => + active && + css` + ${variant === 'for' + ? `background-color: ${theme.colors.yellow};` + : `background-color: ${theme.colors.votes[0]};`} + `}; +`; + +export const StakeDetailsContainer = styled(SidebarCardContentWrapper)` + width: 100%; + margin-top: 24px; +`; + +export const PredictionMessageSpan = styled.span` + margin: 24px 0px; + font-size: ${({ theme }) => theme.fontSizes.header1}; + font-weight: ${({ theme }) => theme.fontWeights.medium}; + text-align: center; +`; + +export const MutedText = styled.span` + color: ${({ theme }) => theme.colors.grey}; +`; + +export const StakesAmount = styled.div` + display: inline; + border-radius: 8px; + padding: 2px 6px; + margin-right: 12px; + color: ${({ theme }) => theme.colors.grey}; + background-color: ${({ theme }) => theme.colors.darkGreen1}; +`; diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx new file mode 100644 index 00000000..a9e472af --- /dev/null +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -0,0 +1,195 @@ +import ReactSpeedometer from 'react-d3-speedometer'; +import { useTheme } from 'styled-components'; +import { lighten } from 'polished'; +import { FiThumbsUp, FiThumbsDown } from 'react-icons/fi'; +import { useState } from 'react'; + +import { + SidebarCard, + SidebarCardContent, + SidebarCardHeaderSpaced, +} from 'components/SidebarCard'; +import { CardDivider } from 'components/Card'; +import { Flex } from 'components/primitives/Layout'; +import { + BoostedStatePill, + PredictionMessageSpan, + StakeButtonsContainer, + StakeIconButton, + StakeNumberButton, + StakesAmount, +} from './HolographicConsensusCard.styled'; +import { StakeDetails } from './StakeDetails'; +import { ExpandButton } from 'components/ExpandButton'; + +export interface IStake { + address: string; + amount: string; +} + +export interface IStakes { + for: IStake[]; + against: IStake[]; +} + +const fakeStakes: IStakes = { + for: [ + { + address: '0x9578e973bba0cc33bdbc93c7f77bb3fe6d47d68a', + amount: '121', + }, + { + address: '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f', + amount: '34', + }, + { + address: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', + amount: '4', + }, + { + address: '0xd507743abcdb265f5fcef125e3f6cf7250cfe9da', + amount: '21', + }, + { + address: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', + amount: '4', + }, + { + address: '0xd507743abcdb265f5fcef125e3f6cf7250cfe9da', + amount: '21', + }, + { + address: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', + amount: '4', + }, + { + address: '0xd507743abcdb265f5fcef125e3f6cf7250cfe9da', + amount: '21', + }, + { + address: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', + amount: '4', + }, + { + address: '0xd507743abcdb265f5fcef125e3f6cf7250cfe9da', + amount: '21', + }, + ], + against: [ + { + address: '0x84eeb305da0a4309a696d43de9f79f04e66eb4f8', + amount: '100', + }, + { + address: '0x1b929bdde0fb3b7b759696f23d6cac0963d326e6', + amount: '12.46', + }, + ], +}; + +export type StakeOptions = 'for' | 'against'; + +export const HolographicConsensusCard = () => { + const theme = useTheme(); + const [isStakeDetailsOpen, setIsStakeDetailsOpen] = useState(false); + const [selectedStake, setSelectedStake] = useState('for'); + + return ( + + Predictions + setIsStakeDetailsOpen(!isStakeDetailsOpen)} + /> + + } + > + + + + Pending Boost + + + { + setSelectedStake('against'); + if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); + }} + > + {isStakeDetailsOpen && ( + {fakeStakes?.against?.length} + )} + 272.36 + + + { + setSelectedStake('for'); + if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); + }} + > + {isStakeDetailsOpen && ( + {fakeStakes?.for?.length} + )} + 314.15 + + + {isStakeDetailsOpen === true && ( + <> + + + + )} + + + Place your prediction to steer the proposal + + + + + + + + + + + + + ); +}; + +// TODO: Modal +// TODO: Add translations +// TODO: token icon +// TODO: add color to proposal state +// TODO: Logic! +// ? border bottom of non-selected stake button? + +// maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx new file mode 100644 index 00000000..31657af8 --- /dev/null +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -0,0 +1,26 @@ +import { Flex } from 'components/primitives/Layout'; +import { shortenAddress } from 'utils'; +import { IStake, IStakes, StakeOptions } from './HolographicConsensusCard'; +import { + MutedText, + StakeDetailsContainer, +} from './HolographicConsensusCard.styled'; + +export const StakeDetails = ({ + selectedStake, + stakeDetails, +}: { + selectedStake: StakeOptions; + stakeDetails: IStakes; +}) => { + return ( + + {stakeDetails[selectedStake].map((stake: IStake) => ( + +
{shortenAddress(stake.address)}
+ {stake.amount} + + ))} + + ); +}; From 407302190ff52799b6888396da6baa94c9a3e6e9 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 17 Mar 2023 11:16:44 -0300 Subject: [PATCH 07/45] feat: added slider component --- .../primitives/Forms/Slider/Slider.styled.tsx | 65 +++++++++++++++++++ .../primitives/Forms/Slider/Slider.tsx | 20 ++++++ .../primitives/Forms/Slider/index.ts | 1 + 3 files changed, 86 insertions(+) create mode 100644 apps/davi/src/components/primitives/Forms/Slider/Slider.styled.tsx create mode 100644 apps/davi/src/components/primitives/Forms/Slider/Slider.tsx create mode 100644 apps/davi/src/components/primitives/Forms/Slider/index.ts diff --git a/apps/davi/src/components/primitives/Forms/Slider/Slider.styled.tsx b/apps/davi/src/components/primitives/Forms/Slider/Slider.styled.tsx new file mode 100644 index 00000000..f4a76bf0 --- /dev/null +++ b/apps/davi/src/components/primitives/Forms/Slider/Slider.styled.tsx @@ -0,0 +1,65 @@ +import styled from 'styled-components'; + +export const SliderStyle = styled.input` + /* + Track styles + */ + -webkit-appearance: none; + appearance: none; + background: transparent; + + cursor: pointer; + width: 100%; + + /* + Track styles + */ + + // Chrome, Safari + &::-webkit-slider-runnable-track { + height: 8px; + background: ${({ theme }) => theme.colors.darkGreen1}; + border-radius: ${({ theme }) => theme.radii.pill}; + } + // Firefox + &::-moz-range-track { + height: 8px; + background: ${({ theme }) => theme.colors.darkGreen1}; + border-radius: ${({ theme }) => theme.radii.pill}; + } + + /* + Thumb styles + */ + + // Chrome, Safari + &::-webkit-slider-thumb { + -webkit-appearance: none; + height: 20px; + width: 20px; + margin-top: -6px; + cursor: pointer; + background: ${({ theme }) => theme.colors.white}; + border-radius: ${({ theme }) => theme.radii.rounded}; + } + // Firefox + &::-moz-range-thumb { + border: none; + height: 20px; + width: 20px; + cursor: pointer; + border-radius: ${({ theme }) => theme.radii.rounded}; + background: ${({ theme }) => theme.colors.white}; + } + + /* + Progress style (Firefox only) + */ + + // Firefox + &::-moz-range-progress { + height: 8px; + background: ${({ theme }) => theme.colors.grey}; + border-radius: ${({ theme }) => theme.radii.pill}; + } +`; diff --git a/apps/davi/src/components/primitives/Forms/Slider/Slider.tsx b/apps/davi/src/components/primitives/Forms/Slider/Slider.tsx new file mode 100644 index 00000000..79d01744 --- /dev/null +++ b/apps/davi/src/components/primitives/Forms/Slider/Slider.tsx @@ -0,0 +1,20 @@ +import { SliderStyle } from './Slider.styled'; + +interface ISlider { + value: string; + onChange: (arg: string) => void; + min: string; + max: string; +} + +export const Slider = ({ value, onChange, min, max }: ISlider) => { + return ( + onChange(e.target.value)} + /> + ); +}; diff --git a/apps/davi/src/components/primitives/Forms/Slider/index.ts b/apps/davi/src/components/primitives/Forms/Slider/index.ts new file mode 100644 index 00000000..22e6f781 --- /dev/null +++ b/apps/davi/src/components/primitives/Forms/Slider/index.ts @@ -0,0 +1 @@ +export { Slider } from './Slider'; From a8ceb29a7d8c704731d143038a0d8cade45653bf Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 17 Mar 2023 15:56:19 -0300 Subject: [PATCH 08/45] feat: replaced "medium" for "bold" in font weight to match figma designs --- .../Treasury/__snapshots__/Treasury.test.tsx.snap | 2 +- .../ConfirmRemoveActionModal.styled.ts | 2 +- .../__snapshots__/ERC20TransferEditor.test.tsx.snap | 12 ++++++------ .../__snapshots__/RawTransactionEditor.test.tsx.snap | 6 +++--- .../__snapshots__/RepMintEditor.test.tsx.snap | 6 +++--- .../__snapshots__/SetGuildConfigEditor.test.tsx.snap | 4 ++-- .../UpdateENSContentEditor.test.tsx.snap | 4 ++-- .../ActionsBuilder/common/EditButton/EditButton.tsx | 2 +- .../common/ProposalOptionTag/ProposalOptionTag.tsx | 2 +- .../__snapshots__/ActionsModal.test.tsx.snap | 2 +- .../src/components/Discussion/Post/Post.styled.tsx | 2 +- .../__snapshots__/DiscussionCard.test.tsx.snap | 2 +- .../__snapshots__/ProposalCard.test.tsx.snap | 8 ++++---- .../__snapshots__/ProposalInfoCard.test.tsx.snap | 4 ++-- .../__snapshots__/ProposalVoteCard.test.tsx.snap | 4 ++-- .../components/VoteChart/VoteChart.styled.ts | 2 +- .../VoteConfirmationModal.styled.ts | 2 +- .../__snapshots__/VoteOptions.test.tsx.snap | 2 +- .../__snapshots__/SidebarInfoCard.test.tsx.snap | 4 ++-- .../__snapshots__/StakeTokensModal.test.tsx.snap | 2 +- .../StakeTokensForm/StakeTokensForm.styled.ts | 2 +- .../__snapshots__/StakeTokensForm.test.tsx.snap | 4 ++-- .../ToastNotifications/NotificationHeading.tsx | 2 +- .../__snapshots__/TokenPicker.test.tsx.snap | 4 ++-- .../__snapshots__/NetworkModal.test.tsx.snap | 2 +- .../__snapshots__/TransactionModal.test.tsx.snap | 2 +- .../__snapshots__/WalletModal.test.tsx.snap | 2 +- .../__snapshots__/AddressInput.test.tsx.snap | 6 +++--- .../src/components/primitives/Typography/Heading.tsx | 4 ++-- apps/davi/src/components/theme.tsx | 1 + apps/davi/src/theme/GlobalTheme.ts | 2 +- apps/davi/src/theme/dark.json | 7 ++++--- 32 files changed, 57 insertions(+), 55 deletions(-) diff --git a/apps/davi/src/Modules/Guilds/pages/Treasury/__snapshots__/Treasury.test.tsx.snap b/apps/davi/src/Modules/Guilds/pages/Treasury/__snapshots__/Treasury.test.tsx.snap index c5962c12..115f0eb9 100644 --- a/apps/davi/src/Modules/Guilds/pages/Treasury/__snapshots__/Treasury.test.tsx.snap +++ b/apps/davi/src/Modules/Guilds/pages/Treasury/__snapshots__/Treasury.test.tsx.snap @@ -21,7 +21,7 @@ exports[`Treasury Page Should render without data 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c2 strong, diff --git a/apps/davi/src/components/ActionsBuilder/ConfirmRemoveActionModal/ConfirmRemoveActionModal.styled.ts b/apps/davi/src/components/ActionsBuilder/ConfirmRemoveActionModal/ConfirmRemoveActionModal.styled.ts index cd8b4dfb..c13d7896 100644 --- a/apps/davi/src/components/ActionsBuilder/ConfirmRemoveActionModal/ConfirmRemoveActionModal.styled.ts +++ b/apps/davi/src/components/ActionsBuilder/ConfirmRemoveActionModal/ConfirmRemoveActionModal.styled.ts @@ -9,7 +9,7 @@ export const TextContainer = styled.div` padding: 3rem 0 4rem; `; export const Title = styled(Heading)` - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; color: ${({ theme }) => theme.colors.text}; text-align: center; `; diff --git a/apps/davi/src/components/ActionsBuilder/SupportedActions/ERC20Transfer/__snapshots__/ERC20TransferEditor.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/SupportedActions/ERC20Transfer/__snapshots__/ERC20TransferEditor.test.tsx.snap index fc79d4ef..92cbcb5b 100644 --- a/apps/davi/src/components/ActionsBuilder/SupportedActions/ERC20Transfer/__snapshots__/ERC20TransferEditor.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/SupportedActions/ERC20Transfer/__snapshots__/ERC20TransferEditor.test.tsx.snap @@ -89,7 +89,7 @@ exports[`ERC20TransferEditor Should match snapshot 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -169,7 +169,7 @@ exports[`ERC20TransferEditor Should match snapshot 1`] = ` flex-direction: row; color: #A1A6B0; font-size: 14px; - font-weight: 500; + font-weight: 400; } .c3 { @@ -489,7 +489,7 @@ exports[`ERC20TransferEditor Should match snapshot with an address without ENS n color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -569,7 +569,7 @@ exports[`ERC20TransferEditor Should match snapshot with an address without ENS n flex-direction: row; color: #A1A6B0; font-size: 14px; - font-weight: 500; + font-weight: 400; } .c3 { @@ -878,7 +878,7 @@ exports[`ERC20TransferEditor Should match snapshot with default values 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -958,7 +958,7 @@ exports[`ERC20TransferEditor Should match snapshot with default values 1`] = ` flex-direction: row; color: #A1A6B0; font-size: 14px; - font-weight: 500; + font-weight: 400; } .c3 { diff --git a/apps/davi/src/components/ActionsBuilder/SupportedActions/RawTransaction/__snapshots__/RawTransactionEditor.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/SupportedActions/RawTransaction/__snapshots__/RawTransactionEditor.test.tsx.snap index 83946429..3a029ffc 100644 --- a/apps/davi/src/components/ActionsBuilder/SupportedActions/RawTransaction/__snapshots__/RawTransactionEditor.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/SupportedActions/RawTransaction/__snapshots__/RawTransactionEditor.test.tsx.snap @@ -83,7 +83,7 @@ exports[`RawTransactionEditor valid inputs should match snapshot 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -169,7 +169,7 @@ exports[`RawTransactionEditor valid inputs should match snapshot 1`] = ` flex-direction: row; color: #A1A6B0; font-size: 14px; - font-weight: 500; + font-weight: 400; } .c3 { @@ -195,7 +195,7 @@ exports[`RawTransactionEditor valid inputs should match snapshot 1`] = ` color: #fff; font-family: 'Inter',Menlo,Monaco,Consolas,'Courier New',monospace; font-size: 14px; - font-weight: 500; + font-weight: 400; }
diff --git a/apps/davi/src/components/ActionsBuilder/SupportedActions/RepMint/__snapshots__/RepMintEditor.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/SupportedActions/RepMint/__snapshots__/RepMintEditor.test.tsx.snap index b6eabb25..c3d6f7df 100644 --- a/apps/davi/src/components/ActionsBuilder/SupportedActions/RepMint/__snapshots__/RepMintEditor.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/SupportedActions/RepMint/__snapshots__/RepMintEditor.test.tsx.snap @@ -79,7 +79,7 @@ exports[`RepMintEditor Should match snapshot 1`] = ` flex-direction: row; color: #A1A6B0; font-size: 14px; - font-weight: 500; + font-weight: 400; } .c5 { @@ -126,7 +126,7 @@ exports[`RepMintEditor Should match snapshot 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -177,7 +177,7 @@ exports[`RepMintEditor Should match snapshot 1`] = ` color: #A1A6B0; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } diff --git a/apps/davi/src/components/ActionsBuilder/SupportedActions/SetGuildConfig/__snapshots__/SetGuildConfigEditor.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/SupportedActions/SetGuildConfig/__snapshots__/SetGuildConfigEditor.test.tsx.snap index 0b8e9e0d..812dc877 100644 --- a/apps/davi/src/components/ActionsBuilder/SupportedActions/SetGuildConfig/__snapshots__/SetGuildConfigEditor.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/SupportedActions/SetGuildConfig/__snapshots__/SetGuildConfigEditor.test.tsx.snap @@ -31,7 +31,7 @@ exports[`SetGuildConfigEditor Should match snapshot 1`] = ` flex-direction: row; color: #A1A6B0; font-size: 14px; - font-weight: 500; + font-weight: 400; } .c3 { @@ -78,7 +78,7 @@ exports[`SetGuildConfigEditor Should match snapshot 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } diff --git a/apps/davi/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentEditor.test.tsx.snap b/apps/davi/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentEditor.test.tsx.snap index eff5d09a..1d11d7a9 100644 --- a/apps/davi/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentEditor.test.tsx.snap +++ b/apps/davi/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentEditor.test.tsx.snap @@ -51,7 +51,7 @@ exports[`UpdateENSContentEditor Should match snapshot 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -159,7 +159,7 @@ exports[`UpdateENSContentEditor Should match snapshot 1`] = ` flex-direction: row; color: #A1A6B0; font-size: 14px; - font-weight: 500; + font-weight: 400; } .c5 { diff --git a/apps/davi/src/components/ActionsBuilder/common/EditButton/EditButton.tsx b/apps/davi/src/components/ActionsBuilder/common/EditButton/EditButton.tsx index 8e303db6..100d6b84 100644 --- a/apps/davi/src/components/ActionsBuilder/common/EditButton/EditButton.tsx +++ b/apps/davi/src/components/ActionsBuilder/common/EditButton/EditButton.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; export const EditButton = styled(Button).attrs({ variant: 'secondary', })` - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; font-size: ${({ theme }) => theme.fontSizes.label}; margin: 0; padding: 0.25rem 0.75rem; diff --git a/apps/davi/src/components/ActionsBuilder/common/ProposalOptionTag/ProposalOptionTag.tsx b/apps/davi/src/components/ActionsBuilder/common/ProposalOptionTag/ProposalOptionTag.tsx index 694e2d9f..2f7ae3bc 100644 --- a/apps/davi/src/components/ActionsBuilder/common/ProposalOptionTag/ProposalOptionTag.tsx +++ b/apps/davi/src/components/ActionsBuilder/common/ProposalOptionTag/ProposalOptionTag.tsx @@ -11,7 +11,7 @@ const Tag = styled.span<{ color: string }>` border-radius: 0.375rem; padding: 0.25rem 0.5rem; border: 1px solid ${({ theme }) => theme.colors.border1}; - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; color: ${({ color }) => color}; border-color: ${({ color }) => color}; `; diff --git a/apps/davi/src/components/ActionsModal/__snapshots__/ActionsModal.test.tsx.snap b/apps/davi/src/components/ActionsModal/__snapshots__/ActionsModal.test.tsx.snap index d0e10c7b..8d2abbbc 100644 --- a/apps/davi/src/components/ActionsModal/__snapshots__/ActionsModal.test.tsx.snap +++ b/apps/davi/src/components/ActionsModal/__snapshots__/ActionsModal.test.tsx.snap @@ -55,7 +55,7 @@ exports[`ActionsModal Should match snapshot 2 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c4 strong, diff --git a/apps/davi/src/components/Discussion/Post/Post.styled.tsx b/apps/davi/src/components/Discussion/Post/Post.styled.tsx index 52af51f4..0ed61dbe 100644 --- a/apps/davi/src/components/Discussion/Post/Post.styled.tsx +++ b/apps/davi/src/components/Discussion/Post/Post.styled.tsx @@ -15,7 +15,7 @@ export const PostHeader = styled.div` `; export const PostCreatorName = styled.span` - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; `; export const PostCreatorAddressBadge = styled.span` diff --git a/apps/davi/src/components/DiscussionCard/__snapshots__/DiscussionCard.test.tsx.snap b/apps/davi/src/components/DiscussionCard/__snapshots__/DiscussionCard.test.tsx.snap index ebcccb1e..3d92820b 100644 --- a/apps/davi/src/components/DiscussionCard/__snapshots__/DiscussionCard.test.tsx.snap +++ b/apps/davi/src/components/DiscussionCard/__snapshots__/DiscussionCard.test.tsx.snap @@ -72,7 +72,7 @@ exports[`DiscussionCard should render with full parameters 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c5 strong, diff --git a/apps/davi/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap b/apps/davi/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap index 753d8c98..1a2cbce5 100644 --- a/apps/davi/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap +++ b/apps/davi/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap @@ -165,7 +165,7 @@ exports[`ProposalCard ProposalCard Renders properly with data 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c6 strong, @@ -680,7 +680,7 @@ exports[`ProposalCard ProposalCard Renders properly with more than one option 1 font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c6 strong, @@ -1179,7 +1179,7 @@ exports[`ProposalCard ProposalCard Renders properly with more than one option co font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c6 strong, @@ -1580,7 +1580,7 @@ exports[`ProposalCard ProposalCard loading 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c6 strong, diff --git a/apps/davi/src/components/ProposalInfoCard/__snapshots__/ProposalInfoCard.test.tsx.snap b/apps/davi/src/components/ProposalInfoCard/__snapshots__/ProposalInfoCard.test.tsx.snap index f0a5eeff..298f375d 100644 --- a/apps/davi/src/components/ProposalInfoCard/__snapshots__/ProposalInfoCard.test.tsx.snap +++ b/apps/davi/src/components/ProposalInfoCard/__snapshots__/ProposalInfoCard.test.tsx.snap @@ -44,7 +44,7 @@ exports[`ProposalInfoCard Should render loading state 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c3 strong, @@ -265,7 +265,7 @@ exports[`ProposalInfoCard Should render will full parameters 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c3 strong, diff --git a/apps/davi/src/components/ProposalVoteCard/__snapshots__/ProposalVoteCard.test.tsx.snap b/apps/davi/src/components/ProposalVoteCard/__snapshots__/ProposalVoteCard.test.tsx.snap index e3a628c4..86f1b6c0 100644 --- a/apps/davi/src/components/ProposalVoteCard/__snapshots__/ProposalVoteCard.test.tsx.snap +++ b/apps/davi/src/components/ProposalVoteCard/__snapshots__/ProposalVoteCard.test.tsx.snap @@ -25,7 +25,7 @@ exports[`ProposalVoteCard matches the snapshot 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c3 strong, @@ -228,7 +228,7 @@ exports[`ProposalVoteCard matches the snapshot 1`] = ` -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; - font-weight: 500; + font-weight: 400; font-size: 14px; margin: 5px 0px 5px 0px; } diff --git a/apps/davi/src/components/ProposalVoteCard/components/VoteChart/VoteChart.styled.ts b/apps/davi/src/components/ProposalVoteCard/components/VoteChart/VoteChart.styled.ts index a89c4be4..0064d103 100644 --- a/apps/davi/src/components/ProposalVoteCard/components/VoteChart/VoteChart.styled.ts +++ b/apps/davi/src/components/ProposalVoteCard/components/VoteChart/VoteChart.styled.ts @@ -58,7 +58,7 @@ export const VoteQuorumLabel = styled.div<{ quorum: number }>` ? `${theme.radii.pill} 0px ${theme.radii.pill} ${theme.radii.pill}` : `${theme.radii.pill}`}; font-size: ${({ theme }) => theme.fontSizes.body}; - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; align-items: center; display: flex; diff --git a/apps/davi/src/components/ProposalVoteCard/components/VoteConfirmationModal/VoteConfirmationModal.styled.ts b/apps/davi/src/components/ProposalVoteCard/components/VoteConfirmationModal/VoteConfirmationModal.styled.ts index 43768bf2..c55b2606 100644 --- a/apps/davi/src/components/ProposalVoteCard/components/VoteConfirmationModal/VoteConfirmationModal.styled.ts +++ b/apps/davi/src/components/ProposalVoteCard/components/VoteConfirmationModal/VoteConfirmationModal.styled.ts @@ -6,7 +6,7 @@ export const Container = styled.div` padding: 2rem; `; export const Title = styled(Heading)` - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; color: ${({ theme }) => theme.colors.text}; text-align: center; `; diff --git a/apps/davi/src/components/ProposalVoteCard/components/VoteOptions/__snapshots__/VoteOptions.test.tsx.snap b/apps/davi/src/components/ProposalVoteCard/components/VoteOptions/__snapshots__/VoteOptions.test.tsx.snap index 14bac5ae..ef3812e3 100644 --- a/apps/davi/src/components/ProposalVoteCard/components/VoteOptions/__snapshots__/VoteOptions.test.tsx.snap +++ b/apps/davi/src/components/ProposalVoteCard/components/VoteOptions/__snapshots__/VoteOptions.test.tsx.snap @@ -32,7 +32,7 @@ exports[`VoteResults matches the snapshot 1`] = ` -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; - font-weight: 500; + font-weight: 400; font-size: 14px; margin: 5px 0px 5px 0px; } diff --git a/apps/davi/src/components/SidebarInfoCard/__snapshots__/SidebarInfoCard.test.tsx.snap b/apps/davi/src/components/SidebarInfoCard/__snapshots__/SidebarInfoCard.test.tsx.snap index 33e7d375..ee24a167 100644 --- a/apps/davi/src/components/SidebarInfoCard/__snapshots__/SidebarInfoCard.test.tsx.snap +++ b/apps/davi/src/components/SidebarInfoCard/__snapshots__/SidebarInfoCard.test.tsx.snap @@ -27,7 +27,7 @@ Object { font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c3 strong, @@ -185,7 +185,7 @@ Object { font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c3 strong, diff --git a/apps/davi/src/components/StakeTokensModal/__snapshots__/StakeTokensModal.test.tsx.snap b/apps/davi/src/components/StakeTokensModal/__snapshots__/StakeTokensModal.test.tsx.snap index cdbb57d1..c5da26f7 100644 --- a/apps/davi/src/components/StakeTokensModal/__snapshots__/StakeTokensModal.test.tsx.snap +++ b/apps/davi/src/components/StakeTokensModal/__snapshots__/StakeTokensModal.test.tsx.snap @@ -5,7 +5,7 @@ exports[`StakeTokensModal StakeTokensModal renders properly 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c4 strong, diff --git a/apps/davi/src/components/StakeTokensModal/components/StakeTokensForm/StakeTokensForm.styled.ts b/apps/davi/src/components/StakeTokensModal/components/StakeTokensForm/StakeTokensForm.styled.ts index 87109670..85f81a68 100644 --- a/apps/davi/src/components/StakeTokensModal/components/StakeTokensForm/StakeTokensForm.styled.ts +++ b/apps/davi/src/components/StakeTokensModal/components/StakeTokensForm/StakeTokensForm.styled.ts @@ -25,7 +25,7 @@ export const DaoIcon = styled.img` `; export const DaoTitle = styled(Heading)` - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; color: ${({ theme }) => theme.colors.text}; `; diff --git a/apps/davi/src/components/StakeTokensModal/components/StakeTokensForm/__snapshots__/StakeTokensForm.test.tsx.snap b/apps/davi/src/components/StakeTokensModal/components/StakeTokensForm/__snapshots__/StakeTokensForm.test.tsx.snap index 9fb59566..c57e5b96 100644 --- a/apps/davi/src/components/StakeTokensModal/components/StakeTokensForm/__snapshots__/StakeTokensForm.test.tsx.snap +++ b/apps/davi/src/components/StakeTokensModal/components/StakeTokensForm/__snapshots__/StakeTokensForm.test.tsx.snap @@ -5,7 +5,7 @@ exports[`StakeTokensForm StakeTokensForm renders properly 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c3 strong, @@ -46,7 +46,7 @@ exports[`StakeTokensForm StakeTokensForm renders properly 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } diff --git a/apps/davi/src/components/ToastNotifications/NotificationHeading.tsx b/apps/davi/src/components/ToastNotifications/NotificationHeading.tsx index 7c78fc60..c07e117d 100644 --- a/apps/davi/src/components/ToastNotifications/NotificationHeading.tsx +++ b/apps/davi/src/components/ToastNotifications/NotificationHeading.tsx @@ -2,6 +2,6 @@ import styled from 'styled-components'; export const NotificationHeading = styled.div` font-family: ${({ theme }) => theme.fonts.body}; - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; color: ${({ theme }) => theme.colors.text}; `; diff --git a/apps/davi/src/components/TokenPicker/__snapshots__/TokenPicker.test.tsx.snap b/apps/davi/src/components/TokenPicker/__snapshots__/TokenPicker.test.tsx.snap index a437be06..02c2f73f 100644 --- a/apps/davi/src/components/TokenPicker/__snapshots__/TokenPicker.test.tsx.snap +++ b/apps/davi/src/components/TokenPicker/__snapshots__/TokenPicker.test.tsx.snap @@ -34,7 +34,7 @@ exports[`TokenPicker Should match snapshot 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -81,7 +81,7 @@ exports[`TokenPicker Should match snapshot 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c4 strong, diff --git a/apps/davi/src/components/Web3Modals/NetworkModal/__snapshots__/NetworkModal.test.tsx.snap b/apps/davi/src/components/Web3Modals/NetworkModal/__snapshots__/NetworkModal.test.tsx.snap index 1f9e67bd..4dc7aa81 100644 --- a/apps/davi/src/components/Web3Modals/NetworkModal/__snapshots__/NetworkModal.test.tsx.snap +++ b/apps/davi/src/components/Web3Modals/NetworkModal/__snapshots__/NetworkModal.test.tsx.snap @@ -48,7 +48,7 @@ exports[`NetworkModal Should match snapshot 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c4 strong, diff --git a/apps/davi/src/components/Web3Modals/TransactionModal/__snapshots__/TransactionModal.test.tsx.snap b/apps/davi/src/components/Web3Modals/TransactionModal/__snapshots__/TransactionModal.test.tsx.snap index fbb788e2..f02c6f90 100644 --- a/apps/davi/src/components/Web3Modals/TransactionModal/__snapshots__/TransactionModal.test.tsx.snap +++ b/apps/davi/src/components/Web3Modals/TransactionModal/__snapshots__/TransactionModal.test.tsx.snap @@ -110,7 +110,7 @@ exports[`TransactionModal Should match snapshot 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c5 strong, diff --git a/apps/davi/src/components/Web3Modals/WalletModal/__snapshots__/WalletModal.test.tsx.snap b/apps/davi/src/components/Web3Modals/WalletModal/__snapshots__/WalletModal.test.tsx.snap index c7f57008..cad1e5a9 100644 --- a/apps/davi/src/components/Web3Modals/WalletModal/__snapshots__/WalletModal.test.tsx.snap +++ b/apps/davi/src/components/Web3Modals/WalletModal/__snapshots__/WalletModal.test.tsx.snap @@ -5,7 +5,7 @@ exports[`WalletModal Should match snapshot 1`] = ` font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 16px; line-height: 1.5; - font-weight: 500; + font-weight: 400; } .c4 strong, diff --git a/apps/davi/src/components/primitives/Forms/AddressInput/__snapshots__/AddressInput.test.tsx.snap b/apps/davi/src/components/primitives/Forms/AddressInput/__snapshots__/AddressInput.test.tsx.snap index ed30fc79..da2ea6ad 100644 --- a/apps/davi/src/components/primitives/Forms/AddressInput/__snapshots__/AddressInput.test.tsx.snap +++ b/apps/davi/src/components/primitives/Forms/AddressInput/__snapshots__/AddressInput.test.tsx.snap @@ -34,7 +34,7 @@ exports[`AddressInput Snapshots should match snapshot isInvalid 1`] = ` color: #E75C5C; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -180,7 +180,7 @@ exports[`AddressInput Snapshots should match snapshot with ENS disabled 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } @@ -345,7 +345,7 @@ exports[`AddressInput Snapshots should match snapshot with address 1`] = ` color: #fff; font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 14px; - font-weight: 500; + font-weight: 400; text-align: left; } diff --git a/apps/davi/src/components/primitives/Typography/Heading.tsx b/apps/davi/src/components/primitives/Typography/Heading.tsx index 272b462d..cf93bdd1 100644 --- a/apps/davi/src/components/primitives/Typography/Heading.tsx +++ b/apps/davi/src/components/primitives/Typography/Heading.tsx @@ -13,13 +13,13 @@ const sizeStyles = (size = 1) => strong, b { - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; } `, 2: css` font-size: ${({ theme }) => theme.fontSizes.header2}; line-height: ${({ theme }) => theme.lineHeights.header2}; - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; `, }[size]); diff --git a/apps/davi/src/components/theme.tsx b/apps/davi/src/components/theme.tsx index 64f9f8b9..5111fb68 100644 --- a/apps/davi/src/components/theme.tsx +++ b/apps/davi/src/components/theme.tsx @@ -63,6 +63,7 @@ export interface GuildsTheme extends ThemeBase { label: string; mono: string; body: string; + bodyBig: string; header1: string; header2: string; }; diff --git a/apps/davi/src/theme/GlobalTheme.ts b/apps/davi/src/theme/GlobalTheme.ts index 900ddf2c..d0c77193 100644 --- a/apps/davi/src/theme/GlobalTheme.ts +++ b/apps/davi/src/theme/GlobalTheme.ts @@ -16,7 +16,7 @@ const GlobalStyle = createGlobalStyle<{ theme: GuildsTheme }>` } strong, b { - font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-weight: ${({ theme }) => theme.fontWeights.bold}; } code, pre { diff --git a/apps/davi/src/theme/dark.json b/apps/davi/src/theme/dark.json index a67cbe02..79fb9ecc 100644 --- a/apps/davi/src/theme/dark.json +++ b/apps/davi/src/theme/dark.json @@ -70,6 +70,7 @@ "label": "12px", "mono": "14px", "body": "14px", + "bodyBig": "16px", "header1": "16px", "header2": "20px" }, @@ -81,9 +82,9 @@ "header2": 1.2 }, "fontWeights": { - "regular": 500, - "medium": 600, - "bold": 700 + "regular": 400, + "medium": 500, + "bold": 600 }, "radii": { "curved": "10px", From 8cf2eb1b8130dd469eacabc2b65493b5c5accf41 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 17 Mar 2023 15:58:57 -0300 Subject: [PATCH 09/45] feat: added Text component --- .../components/primitives/Typography/Text.tsx | 52 +++++++++++++++++++ .../primitives/Typography/index.tsx | 1 + 2 files changed, 53 insertions(+) create mode 100644 apps/davi/src/components/primitives/Typography/Text.tsx diff --git a/apps/davi/src/components/primitives/Typography/Text.tsx b/apps/davi/src/components/primitives/Typography/Text.tsx new file mode 100644 index 00000000..99b68a00 --- /dev/null +++ b/apps/davi/src/components/primitives/Typography/Text.tsx @@ -0,0 +1,52 @@ +import styled, { css } from 'styled-components'; + +type TextAlignTypes = + | 'start' + | 'end' + | 'left' + | 'right' + | 'center' + | 'justify' + | 'justify-all' + | 'match-parent'; + +export const Text = styled.span<{ + bold?: boolean; + sizeVariant?: 'normal' | 'big' | 'small'; + colorVariant?: 'normal' | 'accentuated' | 'muted'; + color?: string; + textAlign?: TextAlignTypes; +}>` + font-size: ${ + ({ sizeVariant, theme }) => + sizeVariant === 'normal' || !sizeVariant + ? theme.fontSizes.body + : sizeVariant === 'big' + ? theme.fontSizes.bodyBig + : sizeVariant === 'small' + ? theme.fontSizes.label + : theme.fontSizes.body // default + }; + + font-weight: ${({ bold, theme }) => + bold ? theme.fontWeights.bold : theme.fontWeights.regular}; + + color: ${ + ({ color, colorVariant, theme }) => + color + ? color + : colorVariant === 'normal' || !colorVariant + ? theme.colors.text + : colorVariant === 'accentuated' + ? theme.colors.active + : colorVariant === 'muted' + ? theme.colors.grey + : theme.colors.text // default + }; + + ${({ textAlign }) => + textAlign && + css` + text-align: ${textAlign}; + `} +`; diff --git a/apps/davi/src/components/primitives/Typography/index.tsx b/apps/davi/src/components/primitives/Typography/index.tsx index ae368720..352dc869 100644 --- a/apps/davi/src/components/primitives/Typography/index.tsx +++ b/apps/davi/src/components/primitives/Typography/index.tsx @@ -1 +1,2 @@ export * from './Heading'; +export { Text } from './Text'; From a9c980b63ac73343b7bb8c07ed5a1c9c84b5e633 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 17 Mar 2023 16:01:51 -0300 Subject: [PATCH 10/45] feat: added modal --- .../HolographicConsensusCard.styled.tsx | 55 ++++--- .../HolographicConsensusCard.tsx | 42 +++-- .../HolographicConsensusModal.tsx | 144 ++++++++++++++++++ .../HolographicConsensusCard/StakeDetails.tsx | 10 +- 4 files changed, 213 insertions(+), 38 deletions(-) create mode 100644 apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx index 9d23e027..5fc33ea9 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx @@ -1,14 +1,8 @@ +import { Button } from 'components/primitives/Button'; import { SidebarCardContentWrapper } from 'components/SidebarCard/SidebarCard.styled'; import styled, { css } from 'styled-components'; import { StakeOptions } from './HolographicConsensusCard'; -export const BoostedStatePill = styled.div` - margin-top: -77px; - margin-bottom: 20px; - border-radius: ${({ theme }) => theme.radii.curved}; - font-size: 12px; -`; - export const StakeButtonsContainer = styled.div` display: flex; justify-content: space-around; @@ -44,7 +38,8 @@ export const StakeIconButton = styled.button<{ cursor: pointer; padding: 11px 43px; border-radius: ${({ theme }) => theme.radii.pill}; - background-color: ${({ theme }) => theme.colors.bg1}; + background-color: transparent; + width: 100%; border: 1px solid ${({ variant, theme }) => variant === 'for' ? theme.colors.yellow : theme.colors.votes[0]}; @@ -54,7 +49,7 @@ export const StakeIconButton = styled.button<{ css` ${variant === 'for' ? `background-color: ${theme.colors.yellow};` - : `background-color: ${theme.colors.votes[0]};`} + : `background-color: ${theme.colors.votes[0]};`}; `}; `; @@ -63,17 +58,6 @@ export const StakeDetailsContainer = styled(SidebarCardContentWrapper)` margin-top: 24px; `; -export const PredictionMessageSpan = styled.span` - margin: 24px 0px; - font-size: ${({ theme }) => theme.fontSizes.header1}; - font-weight: ${({ theme }) => theme.fontWeights.medium}; - text-align: center; -`; - -export const MutedText = styled.span` - color: ${({ theme }) => theme.colors.grey}; -`; - export const StakesAmount = styled.div` display: inline; border-radius: 8px; @@ -82,3 +66,34 @@ export const StakesAmount = styled.div` color: ${({ theme }) => theme.colors.grey}; background-color: ${({ theme }) => theme.colors.darkGreen1}; `; + +export const ModalContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + padding: 24px; +`; + +export const StakeSelectionContainer = styled.div` + width: 100%; + box-sizing: border-box; + margin: 32px 0px; + padding: 16px 20px; + border: 1px solid ${({ theme }) => theme.colors.border1}; + border-radius: ${({ theme }) => theme.radii.curved}; +`; + +export const LockButton = styled(Button)` + height: 2.5rem; + width: 100%; + font-weight: 600; + font-size: 16px; + background-color: ${({ theme }) => theme.colors.yellow}; + color: ${({ theme }) => theme.colors.bg4}; + :hover { + background-color: ${({ theme }) => theme.colors.darkGreen1}; + border: 1px solid ${({ theme }) => theme.colors.yellow}; + color: ${({ theme }) => theme.colors.yellow}; + opacity: 1; + } +`; diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index a9e472af..807f2925 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -1,8 +1,8 @@ +import { useState } from 'react'; import ReactSpeedometer from 'react-d3-speedometer'; import { useTheme } from 'styled-components'; import { lighten } from 'polished'; import { FiThumbsUp, FiThumbsDown } from 'react-icons/fi'; -import { useState } from 'react'; import { SidebarCard, @@ -11,16 +11,17 @@ import { } from 'components/SidebarCard'; import { CardDivider } from 'components/Card'; import { Flex } from 'components/primitives/Layout'; +import { Modal } from 'components/primitives/Modal'; +import { ExpandButton } from 'components/ExpandButton'; +import { HolographicConsensusModal } from './HolographicConsensusModal'; import { - BoostedStatePill, - PredictionMessageSpan, StakeButtonsContainer, StakeIconButton, StakeNumberButton, StakesAmount, } from './HolographicConsensusCard.styled'; import { StakeDetails } from './StakeDetails'; -import { ExpandButton } from 'components/ExpandButton'; +import { Text } from 'components/primitives/Typography'; export interface IStake { address: string; @@ -91,6 +92,7 @@ export type StakeOptions = 'for' | 'against'; export const HolographicConsensusCard = () => { const theme = useTheme(); + const [isModalOpen, setIsModalOpen] = useState(false); const [isStakeDetailsOpen, setIsStakeDetailsOpen] = useState(false); const [selectedStake, setSelectedStake] = useState('for'); @@ -127,7 +129,9 @@ export const HolographicConsensusCard = () => { currentValueText=" " needleColor={theme.colors.white} /> - Pending Boost + + Pending Boost + { )} - - Place your prediction to steer the proposal - + + + + Place your prediction to steer the proposal + + + - + setIsModalOpen(true)} + > - + setIsModalOpen(true)}> + setIsModalOpen(false)} + maxWidth={380} + header="Confirm prediction" + > + + ); }; -// TODO: Modal // TODO: Add translations // TODO: token icon -// TODO: add color to proposal state +// TODO: add color to proposal state pill // TODO: Logic! // ? border bottom of non-selected stake button? diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx new file mode 100644 index 00000000..7d710eac --- /dev/null +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -0,0 +1,144 @@ +import { useState } from 'react'; +import { lighten } from 'polished'; +import ReactSpeedometer from 'react-d3-speedometer'; +import { FiThumbsDown, FiThumbsUp, FiInfo } from 'react-icons/fi'; +import { useTheme } from 'styled-components'; + +import { Flex } from 'components/primitives/Layout'; +import { + LockButton, + ModalContainer, + StakeIconButton, + StakeSelectionContainer, +} from './HolographicConsensusCard.styled'; +import { Button } from 'components/primitives/Button'; +import { Slider } from 'components/primitives/Forms/Slider'; +import { StakeOptions } from './HolographicConsensusCard'; +import { Text } from 'components/primitives/Typography'; + +export const HolographicConsensusModal = () => { + const theme = useTheme(); + + const [selectedStake, setSelectedStake] = useState(null); + const [stakePercentage, setStakePercentage] = useState('0'); + + const handleSelectedStake = (option: StakeOptions) => { + if (selectedStake === option) setSelectedStake(null); + else setSelectedStake(option); + }; + + return ( + + + + + Pending Boost + + + + + + handleSelectedStake('against')} + active={selectedStake === 'against'} + > + + + handleSelectedStake('for')} + active={selectedStake === 'for'} + > + + + + + Balance: + + 10.00 + DXD + + + + + {((parseInt(stakePercentage) / 100) * 18).toFixed(2)} + + + + + + + Potential reward + + 1 + DXD + + + + Unlock time + March 13th + + +
+ +
+ + Your prediction will be locked until the proposal ends and you could + lose your DXD if your prediction is wrong. + +
+ + Lock DXD + +
+
+ ); +}; + +// For now, progress styling only works on Firefox diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx index 31657af8..1e1dfda9 100644 --- a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -1,10 +1,8 @@ import { Flex } from 'components/primitives/Layout'; +import { Text } from 'components/primitives/Typography'; import { shortenAddress } from 'utils'; import { IStake, IStakes, StakeOptions } from './HolographicConsensusCard'; -import { - MutedText, - StakeDetailsContainer, -} from './HolographicConsensusCard.styled'; +import { StakeDetailsContainer } from './HolographicConsensusCard.styled'; export const StakeDetails = ({ selectedStake, @@ -17,8 +15,8 @@ export const StakeDetails = ({ {stakeDetails[selectedStake].map((stake: IStake) => ( -
{shortenAddress(stake.address)}
- {stake.amount} + {shortenAddress(stake.address)} + {stake.amount} DXD
))}
From 11db169c826e611f47a7b14bf88a51cc4e3b209a Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 17 Mar 2023 16:26:00 -0300 Subject: [PATCH 11/45] feat: added translations and updated todo list --- apps/davi/public/locales/en/translation.json | 9 ++++++++ .../HolographicConsensusCard.tsx | 20 ++++++++++++------ .../HolographicConsensusModal.tsx | 21 ++++++++++++------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/apps/davi/public/locales/en/translation.json b/apps/davi/public/locales/en/translation.json index b9f0e595..8c2f657c 100644 --- a/apps/davi/public/locales/en/translation.json +++ b/apps/davi/public/locales/en/translation.json @@ -297,12 +297,14 @@ "increaseVotingPower": "Increase Voting Power", "locking": { "locked": "Locked", + "lock": "Lock", "unlocked": "Unlocked", "unlockedIn": "Unlocked in", "staked": "Staked", "withdraw": "Withdraw", "balance": "Balance", "unlockDate": "Unlock Date", + "unlockTime": "Unlock time", "spending": "Spending", "max": "Max", "stakeTokens": "Stake {{token}} tokens", @@ -401,6 +403,13 @@ "next": "Next", "errorFetchingSchemes": "Error while fetching schemes" }, + "holographicConsensus": { + "predictions": "Predictions", + "confirmPrediction": "Confirm prediction", + "placeYourPrediction": "Place your prediction to steer the proposal", + "potentialReward": "Potential reward", + "lockWarning": "Your prediction will be locked until the proposal ends and you could lose your DXD if your prediction is wrong" + }, "inputValidation": { "recipientAddressIsRequired": "Recipient address is required", "amountIsRequired": "Amount is required", diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 807f2925..5524de13 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -22,6 +22,7 @@ import { } from './HolographicConsensusCard.styled'; import { StakeDetails } from './StakeDetails'; import { Text } from 'components/primitives/Typography'; +import { useTranslation } from 'react-i18next'; export interface IStake { address: string; @@ -92,6 +93,8 @@ export type StakeOptions = 'for' | 'against'; export const HolographicConsensusCard = () => { const theme = useTheme(); + const { t } = useTranslation(); + const [isModalOpen, setIsModalOpen] = useState(false); const [isStakeDetailsOpen, setIsStakeDetailsOpen] = useState(false); const [selectedStake, setSelectedStake] = useState('for'); @@ -100,7 +103,7 @@ export const HolographicConsensusCard = () => { - Predictions + {t('holographicConsensus.predictions')} setIsStakeDetailsOpen(!isStakeDetailsOpen)} @@ -175,7 +178,7 @@ export const HolographicConsensusCard = () => { - Place your prediction to steer the proposal + {t('holographicConsensus.placeYourPrediction')} @@ -196,7 +199,7 @@ export const HolographicConsensusCard = () => { isOpen={isModalOpen} onDismiss={() => setIsModalOpen(false)} maxWidth={380} - header="Confirm prediction" + header={t('holographicConsensus.confirmPrediction')} > @@ -204,10 +207,15 @@ export const HolographicConsensusCard = () => { ); }; -// TODO: Add translations -// TODO: token icon +// TODO: fetch token icon +// TODO: fetch token symbol +// TODO: fetch user's token locked +// TODO: fetch current stakes in proposal +// TODO: maybe add stakes in the current dev scripts? +// TODO: make generic big button (like LOCK button) and change disabled&hover styles // TODO: add color to proposal state pill -// TODO: Logic! +// TODO: Proposal states: this is a whole implementation of the state logic that will include the hook useProposalState +// TODO: lock logic // ? border bottom of non-selected stake button? // maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index 7d710eac..4a8dc608 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -15,9 +15,11 @@ import { Button } from 'components/primitives/Button'; import { Slider } from 'components/primitives/Forms/Slider'; import { StakeOptions } from './HolographicConsensusCard'; import { Text } from 'components/primitives/Typography'; +import { useTranslation } from 'react-i18next'; export const HolographicConsensusModal = () => { const theme = useTheme(); + const { t } = useTranslation(); const [selectedStake, setSelectedStake] = useState(null); const [stakePercentage, setStakePercentage] = useState('0'); @@ -89,7 +91,7 @@ export const HolographicConsensusModal = () => { - Balance: + {t('members.locking.balance')}: 10.00 DXD @@ -103,13 +105,15 @@ export const HolographicConsensusModal = () => { /> {((parseInt(stakePercentage) / 100) * 18).toFixed(2)} - + - Potential reward + + {t('holographicConsensus.potentialReward')} + 1 DXD @@ -121,7 +125,7 @@ export const HolographicConsensusModal = () => { margin="12px 0px" fullWidth > - Unlock time + {t('members.locking.unlockTime')} March 13th @@ -129,12 +133,15 @@ export const HolographicConsensusModal = () => {
- Your prediction will be locked until the proposal ends and you could - lose your DXD if your prediction is wrong. + {t('holographicConsensus.lockWarning')}. - Lock DXD + + {t('members.locking.lock')} DXD + From 4c3b17a519b23a869ef32bd0909c3a62ba32f054 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 20 Mar 2023 13:52:18 -0300 Subject: [PATCH 12/45] feat: added subDAO property to Proposal type --- .../stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx | 2 ++ .../modules/1_5/fetchers/subgraph/useProposal/query.graphql | 3 +++ apps/davi/src/types/types.guilds.d.ts | 3 +++ 3 files changed, 8 insertions(+) diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx index 5fe0060f..4dc80b67 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx @@ -47,6 +47,7 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { descriptionHash, state, totalVotes, + scheme: { id: schemeId }, } = proposal; let mappedContractState: ContractState; @@ -86,6 +87,7 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { totalVotes: [noVotes, yesVotes], options: null, votes: null, + subDao: schemeId, totalOptions: null, // Not used in the codebase but in the deploy scripts }; }, [data]); diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql index eea505fd..0ab37f9c 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql @@ -25,6 +25,9 @@ query getDaoProposal($id: ID!, $proposalId: ID!) { votingMachineProposalState winningVote totalVotes + scheme { + id + } } } } diff --git a/apps/davi/src/types/types.guilds.d.ts b/apps/davi/src/types/types.guilds.d.ts index 0241f855..e363f9d2 100644 --- a/apps/davi/src/types/types.guilds.d.ts +++ b/apps/davi/src/types/types.guilds.d.ts @@ -23,6 +23,7 @@ export interface Proposal { options: Option[]; votes?: Vote[]; executionTransactionHash?: string; + subDao?: string; } export enum ProposalState { @@ -124,9 +125,11 @@ export interface SubDAO { voteGas: BigNumber; voteGasBalance: BigNumber; votingMachine: { + stakingTokenAddress: string; boostedVoteRequiredPercentage: BigNumber; preBoostedVotePeriodLimit: BigNumber; boostedVotePeriodLimit: BigNumber; quietEndingPeriod: BigNumber; }; } + From 42abc8df40f7f72714d0f4c6e75a0f31d1825450 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 20 Mar 2023 13:59:33 -0300 Subject: [PATCH 13/45] feat: added staking token address to voting machine schema --- apps/dao-subgraph/src/mappings/DAOController/mapping.ts | 3 +++ apps/dao-subgraph/src/mappings/DAOController/schema.graphql | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/dao-subgraph/src/mappings/DAOController/mapping.ts b/apps/dao-subgraph/src/mappings/DAOController/mapping.ts index 53287535..ebdd1c3e 100644 --- a/apps/dao-subgraph/src/mappings/DAOController/mapping.ts +++ b/apps/dao-subgraph/src/mappings/DAOController/mapping.ts @@ -66,6 +66,9 @@ export function handleRegisterScheme(event: RegisterScheme): void { votingMachine = new VotingMachine(votingMachineAddress.toHexString()); } + votingMachine.stakingTokenAddress = votingMachineContract + .stakingToken() + .toHexString(); votingMachine.queuedVoteRequiredPercentage = votingParams.getQueuedVoteRequiredPercentage(); votingMachine.queuedVotePeriodLimit = votingParams.getQueuedVotePeriodLimit(); diff --git a/apps/dao-subgraph/src/mappings/DAOController/schema.graphql b/apps/dao-subgraph/src/mappings/DAOController/schema.graphql index 5060cb51..440865c6 100644 --- a/apps/dao-subgraph/src/mappings/DAOController/schema.graphql +++ b/apps/dao-subgraph/src/mappings/DAOController/schema.graphql @@ -29,6 +29,7 @@ type Scheme @entity { type VotingMachine @entity { id: ID! + stakingTokenAddress: String! queuedVoteRequiredPercentage: BigInt queuedVotePeriodLimit: BigInt boostedVotePeriodLimit: BigInt From ccdffe3827fc6e77275ea099ae62b6d44cf0fcb7 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 20 Mar 2023 14:02:04 -0300 Subject: [PATCH 14/45] feat: added option to get data from only one scheme in useGetSubDAOs hook --- .../pages/SchemeSelection/SchemeInfo.tsx | 4 +-- .../fetchers/subgraph/useGetSubDAOs/index.tsx | 15 +++++--- .../subgraph/useGetSubDAOs/query.graphql | 36 ++++++++++++++++++- apps/davi/src/stores/types.ts | 5 ++- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/apps/davi/src/Modules/Guilds/pages/SchemeSelection/SchemeInfo.tsx b/apps/davi/src/Modules/Guilds/pages/SchemeSelection/SchemeInfo.tsx index 9607e9b1..d8aa6484 100644 --- a/apps/davi/src/Modules/Guilds/pages/SchemeSelection/SchemeInfo.tsx +++ b/apps/davi/src/Modules/Guilds/pages/SchemeSelection/SchemeInfo.tsx @@ -1,14 +1,14 @@ import moment from 'moment'; import { BigNumber } from 'ethers'; import { useTranslation } from 'react-i18next'; -import { getSchemesQuery } from '.graphclient'; +import { getAllSchemesQuery } from '.graphclient'; import { InfoDetail, InfoDetailMuted, } from 'components/ProposalInfoCard/ProposalInfoCard.styled'; import { CardBody, SchemePropertiesGrid } from './SchemeSelection.styled'; -type Scheme = getSchemesQuery['dao']['schemes'][0]; +type Scheme = getAllSchemesQuery['dao']['schemes'][0]; const humanizedTime = (time: string) => { const timeInSeconds = Number.parseInt(time); diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx index 98fbf156..81eea3a3 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx @@ -1,22 +1,28 @@ import { useNetwork } from 'wagmi'; import { useQuery } from '@apollo/client'; -import { getSchemesDocument, getSchemesQuery } from '.graphclient'; +import { + getAllSchemesDocument, + getSchemeDocument, + getAllSchemesQuery, +} from '.graphclient'; import { FetcherHooksInterface, SupportedSubgraph } from 'stores/types'; import { getApolloClient } from 'clients/apollo'; import { SubDAO } from 'types/types.guilds'; type IUseGetSubDAOs = FetcherHooksInterface['useGetSubDAOs']; -export const useGetSubDAOs: IUseGetSubDAOs = daoId => { +export const useGetSubDAOs: IUseGetSubDAOs = (daoId, schemeId) => { const { chain } = useNetwork(); + const queryToExecute = schemeId ? getSchemeDocument : getAllSchemesDocument; + const { data, loading: isLoading, error, - } = useQuery(getSchemesDocument, { + } = useQuery(queryToExecute, { client: getApolloClient(SupportedSubgraph.Governance1_5, chain?.id), - variables: { id: daoId?.toLowerCase() }, + variables: { id: daoId?.toLowerCase(), schemeId: schemeId?.toLowerCase() }, }); if (!data || !data.dao) { @@ -57,6 +63,7 @@ export const useGetSubDAOs: IUseGetSubDAOs = daoId => { voteGas: scheme.voteGas, voteGasBalance: scheme.voteGasBalance, votingMachine: { + stakingTokenAddress: scheme.votingMachine.stakingTokenAddress, boostedVoteRequiredPercentage: scheme.votingMachine.boostedVoteRequiredPercentage, preBoostedVotePeriodLimit: diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql index 61563b1e..9f9ab949 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql @@ -1,4 +1,4 @@ -query getSchemes($id: ID!) { +query getAllSchemes($id: ID!) { dao(id: $id) { schemes { # scheme data @@ -21,6 +21,40 @@ query getSchemes($id: ID!) { voteGas voteGasBalance votingMachine { + stakingTokenAddress + boostedVoteRequiredPercentage + preBoostedVotePeriodLimit + boostedVotePeriodLimit + quietEndingPeriod + } + } + } +} + +query getScheme($id: ID!, $schemeId: ID!) { + dao(id: $id) { + schemes(where: { id: $schemeId }) { + # scheme data + id + name + averagesDownstakesOfBoosted + controller + isRegistered + orgBoostedProposalsCnt + paramsHash + permissionRegistry + stakingTokenBalance + # capabilities + canChangeReputation + canMakeAvatarCalls + canManageSchemes + maxGasPrice + maxRepPercentageChange + type + voteGas + voteGasBalance + votingMachine { + stakingTokenAddress boostedVoteRequiredPercentage preBoostedVotePeriodLimit boostedVotePeriodLimit diff --git a/apps/davi/src/stores/types.ts b/apps/davi/src/stores/types.ts index 9520c55a..a049f62e 100644 --- a/apps/davi/src/stores/types.ts +++ b/apps/davi/src/stores/types.ts @@ -155,7 +155,10 @@ export interface FetcherHooksInterface { status: ProposalState, endTime: Moment ) => { detail: string; moment: Moment }; - useGetSubDAOs: (daoId: string) => { + useGetSubDAOs: ( + daoId: string, + schemeId?: string + ) => { data: SubDAO[]; isLoading: boolean; errorMessage: string; From 5268d44d3c532d5a6abcbbfac2cbdf7b76edba6e Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 20 Mar 2023 14:25:29 -0300 Subject: [PATCH 15/45] feat: added token symbol, and error and loading handlers for the component --- .../Guilds/pages/Proposal/Proposal.tsx | 4 +- .../HolographicConsensusCard.tsx | 308 +++++++++++------- 2 files changed, 200 insertions(+), 112 deletions(-) diff --git a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx index a207f03c..620d0f4c 100644 --- a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx +++ b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx @@ -204,7 +204,9 @@ const ProposalPage: React.FC = () => { guildConfig={guildConfig} quorum={quorum} /> - {consensus === 'holographic' && } + {consensus === 'holographic' && ( + + )} ); diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 5524de13..216f6890 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -3,16 +3,23 @@ import ReactSpeedometer from 'react-d3-speedometer'; import { useTheme } from 'styled-components'; import { lighten } from 'polished'; import { FiThumbsUp, FiThumbsDown } from 'react-icons/fi'; +import { useNetwork } from 'wagmi'; +import { useTranslation } from 'react-i18next'; +import { useHookStoreProvider } from 'stores'; import { SidebarCard, SidebarCardContent, SidebarCardHeaderSpaced, } from 'components/SidebarCard'; import { CardDivider } from 'components/Card'; +import { ExpandButton } from 'components/ExpandButton'; import { Flex } from 'components/primitives/Layout'; import { Modal } from 'components/primitives/Modal'; -import { ExpandButton } from 'components/ExpandButton'; +import { Text } from 'components/primitives/Typography'; +import { useTypedParams } from 'Modules/Guilds/Hooks/useTypedParams'; +import { useTokenList } from 'hooks/Guilds/tokens/useTokenList'; + import { HolographicConsensusModal } from './HolographicConsensusModal'; import { StakeButtonsContainer, @@ -21,8 +28,10 @@ import { StakesAmount, } from './HolographicConsensusCard.styled'; import { StakeDetails } from './StakeDetails'; -import { Text } from 'components/primitives/Typography'; -import { useTranslation } from 'react-i18next'; +import { Avatar } from 'components/Avatar'; +import { resolveUri } from 'utils'; +import { Loading } from 'components/primitives/Loading'; +import { Result, ResultState } from 'components/Result'; export interface IStake { address: string; @@ -91,131 +100,208 @@ const fakeStakes: IStakes = { export type StakeOptions = 'for' | 'against'; -export const HolographicConsensusCard = () => { +interface IHolographicConsensusCard { + schemeId: string; +} + +export const HolographicConsensusCard = ({ + schemeId, +}: IHolographicConsensusCard) => { const theme = useTheme(); const { t } = useTranslation(); + const { + hooks: { + fetchers: { useGetSubDAOs }, + }, + } = useHookStoreProvider(); + const { guildId: daoId } = useTypedParams(); + const { chain } = useNetwork(); const [isModalOpen, setIsModalOpen] = useState(false); const [isStakeDetailsOpen, setIsStakeDetailsOpen] = useState(false); const [selectedStake, setSelectedStake] = useState('for'); - return ( - - {t('holographicConsensus.predictions')} - setIsStakeDetailsOpen(!isStakeDetailsOpen)} - /> - - } - > - - - - - Pending Boost - - - - { - setSelectedStake('against'); - if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); - }} - > - {isStakeDetailsOpen && ( - {fakeStakes?.against?.length} - )} - 272.36 - - - { - setSelectedStake('for'); - if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); - }} - > - {isStakeDetailsOpen && ( - {fakeStakes?.for?.length} - )} - 314.15 - - - {isStakeDetailsOpen === true && ( - <> - - - - )} - - - - - {t('holographicConsensus.placeYourPrediction')} - - + const { + data: schemeData, + isLoading, + isError, + errorMessage, + } = useGetSubDAOs(daoId, schemeId); + const { tokens } = useTokenList(chain?.id); - - setIsModalOpen(true)} - > - - - setIsModalOpen(true)}> - - - - - - setIsModalOpen(false)} - maxWidth={380} - header={t('holographicConsensus.confirmPrediction')} + if (isLoading) { + return ( + + + + ); + } + + if (isError) { + return ( + + + + ); + } + + try { + const stakeTokenAddress = schemeData[0]?.votingMachine?.stakingTokenAddress; + const stakeTokenInfo = tokens.find(token => { + return token?.address?.toLowerCase() === stakeTokenAddress?.toLowerCase(); + }); + + return ( + + {t('holographicConsensus.predictions')} + setIsStakeDetailsOpen(!isStakeDetailsOpen)} + /> + + } > - - - - ); + + + + + Pending Boost + + + + { + setSelectedStake('against'); + if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); + }} + > + + {isStakeDetailsOpen === true && ( + {fakeStakes?.against?.length} + )} + + 272.36 + + + + { + setSelectedStake('for'); + if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); + }} + > + + {isStakeDetailsOpen === true && ( + {fakeStakes?.for?.length} + )} + + 314.15 + + + + {isStakeDetailsOpen === true && ( + <> + + + + )} + + + + + {t('holographicConsensus.placeYourPrediction')} + + + + + setIsModalOpen(true)} + > + + + setIsModalOpen(true)} + > + + + + + + setIsModalOpen(false)} + maxWidth={380} + header={t('holographicConsensus.confirmPrediction')} + > + + + + ); + } catch { + return ( + + + + ); + } }; -// TODO: fetch token icon // TODO: fetch token symbol // TODO: fetch user's token locked // TODO: fetch current stakes in proposal // TODO: maybe add stakes in the current dev scripts? +// TODO: lock logic // TODO: make generic big button (like LOCK button) and change disabled&hover styles // TODO: add color to proposal state pill -// TODO: Proposal states: this is a whole implementation of the state logic that will include the hook useProposalState -// TODO: lock logic +// TODO: fetch proposal state +// TODO: translations // ? border bottom of non-selected stake button? // maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 From b4b1c8716d046ea77732af1d29c567e474314798 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 20 Mar 2023 15:15:14 -0300 Subject: [PATCH 16/45] ci: added DXD token to localhost config --- .../dev-scripts/src/updateProjectsConfig.js | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/packages/dev-scripts/src/updateProjectsConfig.js b/packages/dev-scripts/src/updateProjectsConfig.js index ed83969b..10ba343a 100644 --- a/packages/dev-scripts/src/updateProjectsConfig.js +++ b/packages/dev-scripts/src/updateProjectsConfig.js @@ -1,51 +1,51 @@ -const fs = require("fs"); -const path = require("path"); +const fs = require('fs'); +const path = require('path'); /** * This script pull the latest deployment info and feed both davi, guild subgraph and 1.5 subgraph with necesary * development bytecodes and addresses created by the latest hardhat deployment */ -console.log("Executing apps/dev-scripts/src/updateProjectsConfig.js"); +console.log('Executing apps/dev-scripts/src/updateProjectsConfig.js'); -const bytecodesFilePath = path.resolve(__dirname, "../build/bytecodes.json"); -const addressesFilePath = path.resolve(__dirname, "../build/addresses.json"); +const bytecodesFilePath = path.resolve(__dirname, '../build/bytecodes.json'); +const addressesFilePath = path.resolve(__dirname, '../build/addresses.json'); if (fs.existsSync(bytecodesFilePath)) { const bytecodes = require(bytecodesFilePath); const stringBytecodes = JSON.stringify(bytecodes, null, 2); // Write bytecodes to davi - console.log("Writing davi local bytecodes"); + console.log('Writing davi local bytecodes'); fs.writeFileSync( - path.resolve(__dirname, "../../../apps/davi/src/bytecodes/local.json"), + path.resolve(__dirname, '../../../apps/davi/src/bytecodes/local.json'), JSON.stringify(bytecodes, null, 2) ); // Write bytecodes to subgraph - console.log("Writing subgraph local bytecodes"); + console.log('Writing subgraph local bytecodes'); fs.writeFileSync( path.resolve( __dirname, - "../../../apps/guilds-subgraph/src/mappings/Create2Deployer/local.ts" + '../../../apps/guilds-subgraph/src/mappings/Create2Deployer/local.ts' ), `export const local = ${JSON.stringify(stringBytecodes)};` ); } else { console.error( - "Error:: Missing file: dev-scripts/build/bytecodes.json. Do you forget to run compile script from dev-scripts?. Try with `pnpm run dev --force`" + 'Error:: Missing file: dev-scripts/build/bytecodes.json. Do you forget to run compile script from dev-scripts?. Try with `pnpm run dev --force`' ); process.exit(1); } if (fs.existsSync(addressesFilePath)) { const addresses = require(addressesFilePath); - console.log("Using deployed addresses:", addresses); + console.log('Using deployed addresses:', addresses); // Write addresses to guild subgraph - console.log("Writing guild subgraph local networks.json"); + console.log('Writing guild subgraph local networks.json'); fs.writeFileSync( - path.resolve(__dirname, "../../../apps/guilds-subgraph/networks.json"), + path.resolve(__dirname, '../../../apps/guilds-subgraph/networks.json'), JSON.stringify( { private: { @@ -69,9 +69,9 @@ if (fs.existsSync(addressesFilePath)) { ); // Write addresses to 1.5 subgraph - console.log("Writing 1.5 subgraph local networks.json"); + console.log('Writing 1.5 subgraph local networks.json'); fs.writeFileSync( - path.resolve(__dirname, "../../../apps/dao-subgraph/networks.json"), + path.resolve(__dirname, '../../../apps/dao-subgraph/networks.json'), JSON.stringify( { private: { @@ -99,10 +99,10 @@ if (fs.existsSync(addressesFilePath)) { ); // Write addresses to davi - console.log("Writing davi localhost config.json"); + console.log('Writing davi localhost config.json'); const localhostPath = path.resolve( __dirname, - "../../../apps/davi/src/configs/localhost" + '../../../apps/davi/src/configs/localhost' ); if (!fs.existsSync(localhostPath)) { fs.mkdirSync(localhostPath); @@ -110,7 +110,7 @@ if (fs.existsSync(addressesFilePath)) { fs.writeFileSync( path.resolve( __dirname, - "../../../apps/davi/src/configs/localhost/config.json" + '../../../apps/davi/src/configs/localhost/config.json' ), JSON.stringify( { @@ -120,6 +120,17 @@ if (fs.existsSync(addressesFilePath)) { }, votingMachines: {}, }, + tokens: [ + { + logoURI: + 'https://assets.coingecko.com/coins/images/11148/thumb/dxdao.png?1607999331', + chainId: 1337, + address: '0xc1f771042aa85ee9969f40a4e126786dd3e795c6', + name: 'DXdao', + symbol: 'DXD', + decimals: 18, + }, + ], }, null, 2 From a6af2c826f6902b054942b12bf13dde87d015242 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 20 Mar 2023 15:20:02 -0300 Subject: [PATCH 17/45] feat: fetch token symbol --- .../HolographicConsensusCard.tsx | 269 +++++++++--------- .../HolographicConsensusModal.tsx | 24 +- .../HolographicConsensusCard/StakeDetails.tsx | 16 +- 3 files changed, 155 insertions(+), 154 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 216f6890..6465e637 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -7,14 +7,18 @@ import { useNetwork } from 'wagmi'; import { useTranslation } from 'react-i18next'; import { useHookStoreProvider } from 'stores'; +import { resolveUri } from 'utils'; import { SidebarCard, SidebarCardContent, SidebarCardHeaderSpaced, } from 'components/SidebarCard'; +import { Avatar } from 'components/Avatar'; import { CardDivider } from 'components/Card'; import { ExpandButton } from 'components/ExpandButton'; import { Flex } from 'components/primitives/Layout'; +import { Result, ResultState } from 'components/Result'; +import { Loading } from 'components/primitives/Loading'; import { Modal } from 'components/primitives/Modal'; import { Text } from 'components/primitives/Typography'; import { useTypedParams } from 'Modules/Guilds/Hooks/useTypedParams'; @@ -28,10 +32,6 @@ import { StakesAmount, } from './HolographicConsensusCard.styled'; import { StakeDetails } from './StakeDetails'; -import { Avatar } from 'components/Avatar'; -import { resolveUri } from 'utils'; -import { Loading } from 'components/primitives/Loading'; -import { Result, ResultState } from 'components/Result'; export interface IStake { address: string; @@ -149,151 +149,138 @@ export const HolographicConsensusCard = ({ ); } - try { - const stakeTokenAddress = schemeData[0]?.votingMachine?.stakingTokenAddress; - const stakeTokenInfo = tokens.find(token => { - return token?.address?.toLowerCase() === stakeTokenAddress?.toLowerCase(); - }); + const stakeTokenAddress = schemeData[0]?.votingMachine?.stakingTokenAddress; + const stakeTokenInfo = tokens.find(token => { + return token?.address?.toLowerCase() === stakeTokenAddress?.toLowerCase(); + }); - return ( - - {t('holographicConsensus.predictions')} - setIsStakeDetailsOpen(!isStakeDetailsOpen)} - /> - - } - > - - - - - Pending Boost - - - - { - setSelectedStake('against'); - if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); - }} - > - - {isStakeDetailsOpen === true && ( - {fakeStakes?.against?.length} - )} - - 272.36 - - + if (!stakeTokenAddress) return <>; - { - setSelectedStake('for'); - if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); - }} - > - - {isStakeDetailsOpen === true && ( - {fakeStakes?.for?.length} - )} - - 314.15 - - - - {isStakeDetailsOpen === true && ( - <> - - + {t('holographicConsensus.predictions')} + setIsStakeDetailsOpen(!isStakeDetailsOpen)} + /> + + } + > + + + + + Pending Boost + + + + { + setSelectedStake('against'); + if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); + }} + > + + {isStakeDetailsOpen === true && ( + {fakeStakes?.against?.length} + )} + - - )} - + 272.36 + + - - - {t('holographicConsensus.placeYourPrediction')} - - + { + setSelectedStake('for'); + if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); + }} + > + + {isStakeDetailsOpen === true && ( + {fakeStakes?.for?.length} + )} + + 314.15 + + + + {isStakeDetailsOpen === true && ( + <> + + + + )} + - - setIsModalOpen(true)} - > - - - setIsModalOpen(true)} - > - - - + + + {t('holographicConsensus.placeYourPrediction')} + - - setIsModalOpen(false)} - maxWidth={380} - header={t('holographicConsensus.confirmPrediction')} - > - - - - ); - } catch { - return ( - - - - ); - } + + + setIsModalOpen(true)} + > + + + setIsModalOpen(true)}> + + + + + + setIsModalOpen(false)} + maxWidth={380} + header={t('holographicConsensus.confirmPrediction')} + > + + + + ); }; -// TODO: fetch token symbol // TODO: fetch user's token locked // TODO: fetch current stakes in proposal // TODO: maybe add stakes in the current dev scripts? diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index 4a8dc608..f9bc3bbd 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -3,21 +3,29 @@ import { lighten } from 'polished'; import ReactSpeedometer from 'react-d3-speedometer'; import { FiThumbsDown, FiThumbsUp, FiInfo } from 'react-icons/fi'; import { useTheme } from 'styled-components'; +import { useTranslation } from 'react-i18next'; +import { TokenInfoWithType } from 'types/types'; import { Flex } from 'components/primitives/Layout'; +import { Button } from 'components/primitives/Button'; +import { Slider } from 'components/primitives/Forms/Slider'; +import { Text } from 'components/primitives/Typography'; + import { LockButton, ModalContainer, StakeIconButton, StakeSelectionContainer, } from './HolographicConsensusCard.styled'; -import { Button } from 'components/primitives/Button'; -import { Slider } from 'components/primitives/Forms/Slider'; import { StakeOptions } from './HolographicConsensusCard'; -import { Text } from 'components/primitives/Typography'; -import { useTranslation } from 'react-i18next'; -export const HolographicConsensusModal = () => { +interface IHolographicConsensusModal { + tokenInfo: TokenInfoWithType; +} + +export const HolographicConsensusModal = ({ + tokenInfo, +}: IHolographicConsensusModal) => { const theme = useTheme(); const { t } = useTranslation(); @@ -94,7 +102,7 @@ export const HolographicConsensusModal = () => { {t('members.locking.balance')}: 10.00 - DXD + {tokenInfo?.symbol} { 1 - DXD + {tokenInfo?.symbol} { - {t('members.locking.lock')} DXD + {t('members.locking.lock')} {tokenInfo?.symbol} diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx index 1e1dfda9..cca17e3a 100644 --- a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -4,19 +4,25 @@ import { shortenAddress } from 'utils'; import { IStake, IStakes, StakeOptions } from './HolographicConsensusCard'; import { StakeDetailsContainer } from './HolographicConsensusCard.styled'; +interface IStakeDetails { + selectedStake: StakeOptions; + stakeDetails: IStakes; + tokenSymbol: string; +} + export const StakeDetails = ({ selectedStake, stakeDetails, -}: { - selectedStake: StakeOptions; - stakeDetails: IStakes; -}) => { + tokenSymbol, +}: IStakeDetails) => { return ( {stakeDetails[selectedStake].map((stake: IStake) => ( {shortenAddress(stake.address)} - {stake.amount} DXD + + {stake.amount} {tokenSymbol} + ))} From 9c56355a024cd2e4f8a2a3b9c71b4f03df40c6d3 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 20 Mar 2023 15:44:08 -0300 Subject: [PATCH 18/45] feat: token logo --- .../HolographicConsensusCard.tsx | 1 + .../HolographicConsensusModal.tsx | 16 ++++++++++++++-- .../HolographicConsensusCard/StakeDetails.tsx | 7 ++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 6465e637..8c3f318b 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -289,6 +289,7 @@ export const HolographicConsensusCard = ({ // TODO: add color to proposal state pill // TODO: fetch proposal state // TODO: translations +// TODO: stake: show ENS or address // ? border bottom of non-selected stake button? // maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index f9bc3bbd..fb56a6d5 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -18,6 +18,8 @@ import { StakeSelectionContainer, } from './HolographicConsensusCard.styled'; import { StakeOptions } from './HolographicConsensusCard'; +import { Avatar } from 'components/Avatar'; +import { resolveUri } from 'utils'; interface IHolographicConsensusModal { tokenInfo: TokenInfoWithType; @@ -100,8 +102,13 @@ export const HolographicConsensusModal = ({ {t('members.locking.balance')}: - + 10.00 + {tokenInfo?.symbol} @@ -122,8 +129,13 @@ export const HolographicConsensusModal = ({ {t('holographicConsensus.potentialReward')} - + 1 + {tokenInfo?.symbol} diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx index cca17e3a..1b2c1fc9 100644 --- a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -18,7 +18,12 @@ export const StakeDetails = ({ return ( {stakeDetails[selectedStake].map((stake: IStake) => ( - + {shortenAddress(stake.address)} {stake.amount} {tokenSymbol} From bbdc0223f8878630d311ef967ad9cedb70e3cd9d Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 20 Mar 2023 17:03:53 -0300 Subject: [PATCH 19/45] feat: fetch user balance, staking amount logic and conditional staking fetches the user staking token balance. If it has none, it won't show the option to open the stake modal. If it does, then the user can use the slider to choose a staking amount --- .../HolographicConsensusCard.tsx | 95 ++++++++++++------- .../HolographicConsensusModal.tsx | 24 ++++- 2 files changed, 80 insertions(+), 39 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 8c3f318b..c8979179 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -3,11 +3,12 @@ import ReactSpeedometer from 'react-d3-speedometer'; import { useTheme } from 'styled-components'; import { lighten } from 'polished'; import { FiThumbsUp, FiThumbsDown } from 'react-icons/fi'; -import { useNetwork } from 'wagmi'; +import { useAccount, useNetwork } from 'wagmi'; import { useTranslation } from 'react-i18next'; import { useHookStoreProvider } from 'stores'; import { resolveUri } from 'utils'; +import { TokenInfoWithType } from 'types/types'; import { SidebarCard, SidebarCardContent, @@ -23,6 +24,7 @@ import { Modal } from 'components/primitives/Modal'; import { Text } from 'components/primitives/Typography'; import { useTypedParams } from 'Modules/Guilds/Hooks/useTypedParams'; import { useTokenList } from 'hooks/Guilds/tokens/useTokenList'; +import { useERC20Balance } from 'hooks/Guilds/erc20/useERC20Balance'; import { HolographicConsensusModal } from './HolographicConsensusModal'; import { @@ -117,10 +119,6 @@ export const HolographicConsensusCard = ({ const { guildId: daoId } = useTypedParams(); const { chain } = useNetwork(); - const [isModalOpen, setIsModalOpen] = useState(false); - const [isStakeDetailsOpen, setIsStakeDetailsOpen] = useState(false); - const [selectedStake, setSelectedStake] = useState('for'); - const { data: schemeData, isLoading, @@ -129,6 +127,26 @@ export const HolographicConsensusCard = ({ } = useGetSubDAOs(daoId, schemeId); const { tokens } = useTokenList(chain?.id); + let stakeTokenAddress: string = null; + let stakeTokenInfo: TokenInfoWithType = null; + + try { + stakeTokenAddress = schemeData[0]?.votingMachine?.stakingTokenAddress; + stakeTokenInfo = tokens.find(token => { + return token?.address?.toLowerCase() === stakeTokenAddress?.toLowerCase(); + }); + } catch {} + + const { address: userAddress } = useAccount(); + const { data: userStakeTokenBalance } = useERC20Balance( + stakeTokenAddress, + userAddress + ); + + const [isModalOpen, setIsModalOpen] = useState(false); + const [isStakeDetailsOpen, setIsStakeDetailsOpen] = useState(false); + const [showStakeOption, setShowStakeOption] = useState('for'); + if (isLoading) { return ( @@ -149,11 +167,6 @@ export const HolographicConsensusCard = ({ ); } - const stakeTokenAddress = schemeData[0]?.votingMachine?.stakingTokenAddress; - const stakeTokenInfo = tokens.find(token => { - return token?.address?.toLowerCase() === stakeTokenAddress?.toLowerCase(); - }); - if (!stakeTokenAddress) return <>; return ( @@ -197,10 +210,10 @@ export const HolographicConsensusCard = ({ { - setSelectedStake('against'); + setShowStakeOption('against'); if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); }} > @@ -219,9 +232,9 @@ export const HolographicConsensusCard = ({ { - setSelectedStake('for'); + setShowStakeOption('for'); if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); }} > @@ -242,31 +255,38 @@ export const HolographicConsensusCard = ({ <> )} - - - - {t('holographicConsensus.placeYourPrediction')} - - + {userStakeTokenBalance?.isZero() === false && ( + <> + + + + {t('holographicConsensus.placeYourPrediction')} + + - - setIsModalOpen(true)} - > - - - setIsModalOpen(true)}> - - - + + setIsModalOpen(true)} + > + + + setIsModalOpen(true)} + > + + + + + )} - + ); }; +// TODO: maybe add stakes in the current dev scripts? +// TODO: add DAO staking token entity to subgraph // TODO: fetch user's token locked // TODO: fetch current stakes in proposal -// TODO: maybe add stakes in the current dev scripts? // TODO: lock logic // TODO: make generic big button (like LOCK button) and change disabled&hover styles // TODO: add color to proposal state pill // TODO: fetch proposal state // TODO: translations // TODO: stake: show ENS or address +// TODO: if a user staked, it can only increase its stake on the previous option +// TODO: calculate speedometer value +// TODO: decimals in token balance and total staked // ? border bottom of non-selected stake button? // maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index fb56a6d5..f1a623db 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -5,11 +5,13 @@ import { FiThumbsDown, FiThumbsUp, FiInfo } from 'react-icons/fi'; import { useTheme } from 'styled-components'; import { useTranslation } from 'react-i18next'; +import { resolveUri } from 'utils'; import { TokenInfoWithType } from 'types/types'; import { Flex } from 'components/primitives/Layout'; import { Button } from 'components/primitives/Button'; import { Slider } from 'components/primitives/Forms/Slider'; import { Text } from 'components/primitives/Typography'; +import { Avatar } from 'components/Avatar'; import { LockButton, @@ -18,15 +20,17 @@ import { StakeSelectionContainer, } from './HolographicConsensusCard.styled'; import { StakeOptions } from './HolographicConsensusCard'; -import { Avatar } from 'components/Avatar'; -import { resolveUri } from 'utils'; +import { BigNumber } from 'ethers'; +import useBigNumberToNumber from 'hooks/Guilds/conversions/useBigNumberToNumber'; interface IHolographicConsensusModal { tokenInfo: TokenInfoWithType; + userStakeTokenBalance: BigNumber; } export const HolographicConsensusModal = ({ tokenInfo, + userStakeTokenBalance, }: IHolographicConsensusModal) => { const theme = useTheme(); const { t } = useTranslation(); @@ -39,6 +43,11 @@ export const HolographicConsensusModal = ({ else setSelectedStake(option); }; + const roundedBalance = useBigNumberToNumber( + userStakeTokenBalance, + tokenInfo?.decimals + ); + return ( @@ -69,6 +78,7 @@ export const HolographicConsensusModal = ({ {t('members.locking.balance')}: - 10.00 + {roundedBalance} - {((parseInt(stakePercentage) / 100) * 18).toFixed(2)} - + + {roundedBalance * (Number(stakePercentage) / 100)} + + From 4302bab1f275df91239e8c0e9bc8f92cf0672b76 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Tue, 21 Mar 2023 13:48:06 -0300 Subject: [PATCH 20/45] fix(VotingMachine-mapping): fixed Voting Machine instance not being created --- apps/dao-subgraph/src/mappings/DAOController/mapping.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/dao-subgraph/src/mappings/DAOController/mapping.ts b/apps/dao-subgraph/src/mappings/DAOController/mapping.ts index ebdd1c3e..95c5ae7b 100644 --- a/apps/dao-subgraph/src/mappings/DAOController/mapping.ts +++ b/apps/dao-subgraph/src/mappings/DAOController/mapping.ts @@ -8,7 +8,10 @@ import { Scheme, VotingMachine } from '../../types/schema'; import { Scheme as SchemeContract } from '../../types/DAOController/Scheme'; import { VotingMachine as VotingMachineContract } from '../../types/DAOController/VotingMachine'; -import { Scheme as SchemeTemplate } from '../../types/templates'; +import { + Scheme as SchemeTemplate, + VotingMachine as VotingMachineTemplate, +} from '../../types/templates'; export function handleRegisterScheme(event: RegisterScheme): void { const controllerAddress = event.address; @@ -86,6 +89,7 @@ export function handleRegisterScheme(event: RegisterScheme): void { votingMachine.save(); SchemeTemplate.create(schemeAddress); + VotingMachineTemplate.create(votingMachineAddress); } export function handleUnregisterScheme(event: UnregisterScheme): void { From 2eb2d77d07e241f2363369973563f7b8494c0e29 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Tue, 21 Mar 2023 15:03:13 -0300 Subject: [PATCH 21/45] feat(useBigNumber): added non-hook version of useBigNumberToNumber and fixed bug then token had 0 decimals --- .../Guilds/pages/Treasury/Treasury.test.tsx | 25 ++- .../__snapshots__/Treasury.test.tsx.snap | 165 +++++++++++++++++- .../conversions/useBigNumberToNumber.test.tsx | 64 +++++++ .../conversions/useBigNumberToNumber.ts | 17 +- 4 files changed, 262 insertions(+), 9 deletions(-) create mode 100644 apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.test.tsx diff --git a/apps/davi/src/Modules/Guilds/pages/Treasury/Treasury.test.tsx b/apps/davi/src/Modules/Guilds/pages/Treasury/Treasury.test.tsx index bba43fd8..d789f7e8 100644 --- a/apps/davi/src/Modules/Guilds/pages/Treasury/Treasury.test.tsx +++ b/apps/davi/src/Modules/Guilds/pages/Treasury/Treasury.test.tsx @@ -9,16 +9,29 @@ jest.mock('Modules/Guilds/Hooks/useTypedParams', () => ({ }), })); +let mockHook; + jest.mock('hooks/Guilds/erc20/useAllERC20Balances', () => ({ - useAllERC20Balances: () => ({ - data: [MOCK_TOKEN_INFO], - isLoading: false, - isError: false, - }), + useAllERC20Balances: () => mockHook, })); describe('Treasury Page', () => { - it(`Should render without data`, async () => { + it(`Should render with token data`, async () => { + mockHook = { + data: [MOCK_TOKEN_INFO], + isLoading: false, + isError: false, + }; + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it(`Should render message when there are no tokens`, async () => { + mockHook = { + data: [], + isLoading: false, + isError: false, + }; const { container } = render(); expect(container).toMatchSnapshot(); }); diff --git a/apps/davi/src/Modules/Guilds/pages/Treasury/__snapshots__/Treasury.test.tsx.snap b/apps/davi/src/Modules/Guilds/pages/Treasury/__snapshots__/Treasury.test.tsx.snap index 115f0eb9..b88bf627 100644 --- a/apps/davi/src/Modules/Guilds/pages/Treasury/__snapshots__/Treasury.test.tsx.snap +++ b/apps/davi/src/Modules/Guilds/pages/Treasury/__snapshots__/Treasury.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Treasury Page Should render without data 1`] = ` +exports[`Treasury Page Should render message when there are no tokens 1`] = ` .c4 { width: 100%; min-width: 200px; @@ -35,6 +35,108 @@ exports[`Treasury Page Should render without data 1`] = ` padding: 1px 24px 8px 24px; } +.c6 { + margin-top: 1rem; + margin-bottom: 1rem; +} + +.c3 { + color: #DEFF4E; +} + +.c5 { + margin: 0; + margin-left: -24px; + width: calc(100% + 48px); +} + +
+ +
+

+ treasury.treasury +

+
+
+ treasury.noTreasuryAssets +
+
+ +
+`; + +exports[`Treasury Page Should render with token data 1`] = ` +.c4 { + width: 100%; + min-width: 200px; + height: 1px; + background-color: #303338; + margin: 0; + padding: 0; +} + +.c0 { + box-sizing: 'border-box'; + min-width: 0; + margin: 0; + padding: 0; +} + +.c2 { + font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; + font-size: 16px; + line-height: 1.5; + font-weight: 400; +} + +.c2 strong, +.c2 b { + font-weight: 600; +} + +.c13 { + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; +} + +.c13 > img, +.c13 span { + height: 24px; + width: 24px; +} + +.c1 { + border-radius: 10px; + background-color: #181B1B; + padding: 1px 24px 8px 24px; +} + +.c12 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + .c3 { color: #DEFF4E; } @@ -51,6 +153,10 @@ exports[`Treasury Page Should render without data 1`] = ` margin-top: 1rem; } +.c10 { + border-top: 1px solid #2F3533; +} + .c7 { border-bottom: 1px solid #2F3533; } @@ -71,6 +177,35 @@ exports[`Treasury Page Should render without data 1`] = ` color: #A1A6B0; } +.c11 { + height: 24px; + padding: 12px 0px; + font-weight: 400; + text-align: left; + width: auto; +} + +.c15 { + height: 24px; + padding: 12px 0px; + font-weight: 400; + text-align: right; + width: 20%; +} + +.c14 { + margin-right: 0.6rem; +} + +@media (max-width:960px) { + .c13 { + -webkit-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end; + } +} +
- + + + +
+
+ + WAGMI + +
+ + + 100 + + +
diff --git a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.test.tsx b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.test.tsx new file mode 100644 index 00000000..a6f0daa0 --- /dev/null +++ b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.test.tsx @@ -0,0 +1,64 @@ +import { renderHook } from '@testing-library/react'; +import { BigNumber } from 'ethers'; +import useBigNumberToNumber, { + bigNumberToNumber, +} from './useBigNumberToNumber'; + +const mockBigNumber = BigNumber.from('1000000000000000000'); + +describe('bigNumberToNumber', () => { + it('should return null if no number is provided', () => { + expect(bigNumberToNumber(undefined, 18)).toEqual(null); + }); + + it('should return null if no decimals are provided', () => { + expect(bigNumberToNumber(mockBigNumber, undefined)).toEqual(null); + }); + + it('should return a number if a number and decimals are provided', () => { + expect(bigNumberToNumber(mockBigNumber, 18)).toEqual(1); + }); + + it('should return zero if number is zero', () => { + expect(bigNumberToNumber(BigNumber.from(0), 18)).toEqual(0); + }); + + it('should return a number if decimals are zero', () => { + expect(bigNumberToNumber(BigNumber.from(1), 0)).toEqual(1); + }); +}); + +describe('useBigNumberToNumber', () => { + it('should return null if no number is provided', () => { + const { result } = renderHook(() => useBigNumberToNumber(undefined, 18)); + expect(result.current).toEqual(null); + }); + + it('should return null if no decimals are provided', () => { + const { result } = renderHook(() => + useBigNumberToNumber(mockBigNumber, undefined) + ); + expect(result.current).toEqual(null); + }); + + it('should return a number if a number and decimals are provided', () => { + const { result } = renderHook(() => + useBigNumberToNumber(mockBigNumber, 18) + ); + expect(result.current).toEqual(1); + }); + + it('should return zero if number is zero', () => { + const { result } = renderHook(() => + useBigNumberToNumber(BigNumber.from(0), 18) + ); + expect(result.current).toEqual(0); + }); + + it('should return a number if decimals are zero', () => { + const { result } = renderHook(() => + useBigNumberToNumber(BigNumber.from(1), 0) + ); + expect(result.current).toEqual(1); + }); +}); diff --git a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.ts b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.ts index 625d2331..2b75fe84 100644 --- a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.ts +++ b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.ts @@ -7,8 +7,10 @@ export default function useBigNumberToNumber( decimals: number, precision: number = 2 ) { + // I don't think we need to memoize this function + // TODO: check if this is true const stakeAmountParsed = useMemo(() => { - if (!number || !decimals) return null; + if (!number || decimals === null || decimals === undefined) return null; let formatted = Number.parseFloat(formatUnits(number, decimals)); return ( @@ -18,3 +20,16 @@ export default function useBigNumberToNumber( return stakeAmountParsed; } + +export function bigNumberToNumber( + number: BigNumber, + decimals: number, + precision: number = 2 +) { + if (!number || decimals === null || decimals === undefined) return null; + + let formatted = Number.parseFloat(formatUnits(number, decimals)); + return ( + Math.round(formatted * Math.pow(10, precision)) / Math.pow(10, precision) + ); +} From d655b362b758d26b130f9454a26ad67ebbb33575 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Tue, 21 Mar 2023 15:09:14 -0300 Subject: [PATCH 22/45] feat: added stakes and extracted types --- .../Guilds/pages/Proposal/Proposal.tsx | 5 +- .../HolographicConsensusCard.styled.tsx | 2 +- .../HolographicConsensusCard.tsx | 85 ++----------------- .../HolographicConsensusModal.tsx | 6 +- .../HolographicConsensusCard/StakeDetails.tsx | 42 ++++----- .../HolographicConsensusCard/types.ts | 25 ++++++ .../fetchers/subgraph/useProposal/index.tsx | 17 +++- .../subgraph/useProposal/query.graphql | 5 ++ apps/davi/src/types/types.guilds.d.ts | 3 + 9 files changed, 84 insertions(+), 106 deletions(-) create mode 100644 apps/davi/src/components/HolographicConsensusCard/types.ts diff --git a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx index 620d0f4c..92545efd 100644 --- a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx +++ b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx @@ -205,7 +205,10 @@ const ProposalPage: React.FC = () => { quorum={quorum} /> {consensus === 'holographic' && ( - + )} diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx index 5fc33ea9..236274ad 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx @@ -1,7 +1,7 @@ import { Button } from 'components/primitives/Button'; import { SidebarCardContentWrapper } from 'components/SidebarCard/SidebarCard.styled'; import styled, { css } from 'styled-components'; -import { StakeOptions } from './HolographicConsensusCard'; +import { StakeOptions } from './types'; export const StakeButtonsContainer = styled.div` display: flex; diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index c8979179..3fe0c26b 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -34,79 +34,10 @@ import { StakesAmount, } from './HolographicConsensusCard.styled'; import { StakeDetails } from './StakeDetails'; - -export interface IStake { - address: string; - amount: string; -} - -export interface IStakes { - for: IStake[]; - against: IStake[]; -} - -const fakeStakes: IStakes = { - for: [ - { - address: '0x9578e973bba0cc33bdbc93c7f77bb3fe6d47d68a', - amount: '121', - }, - { - address: '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f', - amount: '34', - }, - { - address: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', - amount: '4', - }, - { - address: '0xd507743abcdb265f5fcef125e3f6cf7250cfe9da', - amount: '21', - }, - { - address: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', - amount: '4', - }, - { - address: '0xd507743abcdb265f5fcef125e3f6cf7250cfe9da', - amount: '21', - }, - { - address: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', - amount: '4', - }, - { - address: '0xd507743abcdb265f5fcef125e3f6cf7250cfe9da', - amount: '21', - }, - { - address: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', - amount: '4', - }, - { - address: '0xd507743abcdb265f5fcef125e3f6cf7250cfe9da', - amount: '21', - }, - ], - against: [ - { - address: '0x84eeb305da0a4309a696d43de9f79f04e66eb4f8', - amount: '100', - }, - { - address: '0x1b929bdde0fb3b7b759696f23d6cac0963d326e6', - amount: '12.46', - }, - ], -}; - -export type StakeOptions = 'for' | 'against'; - -interface IHolographicConsensusCard { - schemeId: string; -} +import { IHolographicConsensusCard, StakeOptions } from './types'; export const HolographicConsensusCard = ({ + proposalStakes, schemeId, }: IHolographicConsensusCard) => { const theme = useTheme(); @@ -219,7 +150,7 @@ export const HolographicConsensusCard = ({ > {isStakeDetailsOpen === true && ( - {fakeStakes?.against?.length} + {proposalStakes?.against?.length} )} {isStakeDetailsOpen === true && ( - {fakeStakes?.for?.length} + {proposalStakes?.for?.length} )} )} @@ -304,10 +236,6 @@ export const HolographicConsensusCard = ({ ); }; -// TODO: maybe add stakes in the current dev scripts? -// TODO: add DAO staking token entity to subgraph -// TODO: fetch user's token locked -// TODO: fetch current stakes in proposal // TODO: lock logic // TODO: make generic big button (like LOCK button) and change disabled&hover styles // TODO: add color to proposal state pill @@ -317,6 +245,7 @@ export const HolographicConsensusCard = ({ // TODO: if a user staked, it can only increase its stake on the previous option // TODO: calculate speedometer value // TODO: decimals in token balance and total staked +// TODO: rename "for" and "against" to "yes" and "no" // ? border bottom of non-selected stake button? // maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index f1a623db..d6ebad8c 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -19,9 +19,9 @@ import { StakeIconButton, StakeSelectionContainer, } from './HolographicConsensusCard.styled'; -import { StakeOptions } from './HolographicConsensusCard'; +import { StakeOptions } from './types'; import { BigNumber } from 'ethers'; -import useBigNumberToNumber from 'hooks/Guilds/conversions/useBigNumberToNumber'; +import { bigNumberToNumber } from 'hooks/Guilds/conversions/useBigNumberToNumber'; interface IHolographicConsensusModal { tokenInfo: TokenInfoWithType; @@ -43,7 +43,7 @@ export const HolographicConsensusModal = ({ else setSelectedStake(option); }; - const roundedBalance = useBigNumberToNumber( + const roundedBalance = bigNumberToNumber( userStakeTokenBalance, tokenInfo?.decimals ); diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx index 1b2c1fc9..a4710bf9 100644 --- a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -1,35 +1,35 @@ +import { shortenAddress } from 'utils'; import { Flex } from 'components/primitives/Layout'; import { Text } from 'components/primitives/Typography'; -import { shortenAddress } from 'utils'; -import { IStake, IStakes, StakeOptions } from './HolographicConsensusCard'; +import { bigNumberToNumber } from 'hooks/Guilds/conversions/useBigNumberToNumber'; +import { IStake, IStakeDetails } from './types'; import { StakeDetailsContainer } from './HolographicConsensusCard.styled'; -interface IStakeDetails { - selectedStake: StakeOptions; - stakeDetails: IStakes; - tokenSymbol: string; -} - export const StakeDetails = ({ selectedStake, stakeDetails, tokenSymbol, + tokenDecimals, }: IStakeDetails) => { return ( - {stakeDetails[selectedStake].map((stake: IStake) => ( - - {shortenAddress(stake.address)} - - {stake.amount} {tokenSymbol} - - - ))} + {stakeDetails[selectedStake].map((stake: IStake) => { + const roundedBalance = bigNumberToNumber(stake.amount, tokenDecimals); + + return ( + + {shortenAddress(stake.staker)} + + {roundedBalance} {tokenSymbol} + + + ); + })} ); }; diff --git a/apps/davi/src/components/HolographicConsensusCard/types.ts b/apps/davi/src/components/HolographicConsensusCard/types.ts new file mode 100644 index 00000000..fef1bf77 --- /dev/null +++ b/apps/davi/src/components/HolographicConsensusCard/types.ts @@ -0,0 +1,25 @@ +import { BigNumber } from 'ethers'; + +export type StakeOptions = 'for' | 'against'; + +export interface IStake { + staker: string; + amount: BigNumber; +} + +export interface IStakes { + for: IStake[]; + against: IStake[]; +} + +export interface IHolographicConsensusCard { + proposalStakes: IStakes; + schemeId: string; +} + +export interface IStakeDetails { + selectedStake: StakeOptions; + stakeDetails: IStakes; + tokenSymbol: string; + tokenDecimals: number; +} diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx index 4dc80b67..dd07fb8c 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx @@ -2,13 +2,14 @@ import { useMemo } from 'react'; import { useNetwork } from 'wagmi'; import { unix } from 'moment'; import { useQuery } from '@apollo/client'; +import { BigNumber } from 'ethers'; import { getDaoProposalDocument, getDaoProposalQuery } from '.graphclient'; import { FetcherHooksInterface, SupportedSubgraph } from 'stores/types'; import { getApolloClient } from 'clients/apollo'; import { ContractState, Proposal } from 'types/types.guilds.d'; +import { IStakes } from 'components/HolographicConsensusCard/types'; import { useProposalCalls } from '../../rpc/useProposalCalls'; -import { BigNumber } from 'ethers'; type IUseProposal = FetcherHooksInterface['useProposal']; @@ -48,6 +49,8 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { state, totalVotes, scheme: { id: schemeId }, + stakes, + totalStakes, } = proposal; let mappedContractState: ContractState; @@ -73,6 +76,14 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { const noVotes = BigNumber.from(totalVotes[0]); const yesVotes = BigNumber.from(totalVotes[1]); + // Stakes processing + const noStakes = stakes.filter(stake => stake.option === '1'); + const yesStakes = stakes.filter(stake => stake.option === '2'); + const parsedStakes: IStakes = { + for: yesStakes, + against: noStakes, + }; + return { id: id as `0x${string}`, // typecast to comply with template literal type creator: proposer, @@ -87,8 +98,10 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { totalVotes: [noVotes, yesVotes], options: null, votes: null, - subDao: schemeId, totalOptions: null, // Not used in the codebase but in the deploy scripts + subDao: schemeId, + stakes: parsedStakes, + totalStakes, }; }, [data]); diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql index 0ab37f9c..c915a04f 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql @@ -28,6 +28,11 @@ query getDaoProposal($id: ID!, $proposalId: ID!) { scheme { id } + stakes { + staker + amount + option + } } } } diff --git a/apps/davi/src/types/types.guilds.d.ts b/apps/davi/src/types/types.guilds.d.ts index e363f9d2..b71e4407 100644 --- a/apps/davi/src/types/types.guilds.d.ts +++ b/apps/davi/src/types/types.guilds.d.ts @@ -1,6 +1,7 @@ import { Moment } from 'moment'; import { BigNumber } from 'ethers'; import { FetcherHooksInterface } from 'stores/types'; +import { IStakes } from 'components/HolographicConsensusCard/types'; type UseProposalVotesOfVoterReturn = ReturnType< FetcherHooksInterface['useProposalVotesOfVoter'] @@ -24,6 +25,8 @@ export interface Proposal { votes?: Vote[]; executionTransactionHash?: string; subDao?: string; + totalStakes?: BigNumber; + stakes?: IStakes; } export enum ProposalState { From 3c94e4d7caeb02bccf91462fbabdda6295d10b70 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Tue, 21 Mar 2023 15:39:44 -0300 Subject: [PATCH 23/45] feat: added non-hook version of useBigNumberToString --- .../conversions/useBigNumberToString.test.tsx | 65 +++++++++++++++++++ .../conversions/useBigNumberToString.ts | 6 ++ 2 files changed, 71 insertions(+) create mode 100644 apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.test.tsx diff --git a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.test.tsx b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.test.tsx new file mode 100644 index 00000000..20269e8d --- /dev/null +++ b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.test.tsx @@ -0,0 +1,65 @@ +import { renderHook } from '@testing-library/react'; +import { BigNumber } from 'ethers'; +import useBigNumberToString, { + bigNumberToString, +} from './useBigNumberToString'; + +const mockBigNumber = BigNumber.from(1); + +describe('bigNumberToString', () => { + it('should convert a BigNumber to a string', () => { + expect(bigNumberToString(mockBigNumber)).toEqual('1'); + }); + + it('should return the number if decimal places is zero', () => { + expect(bigNumberToString(mockBigNumber, 0)).toEqual('1'); + }); + + it('should return the number if decimal places are specified', () => { + expect(bigNumberToString(BigNumber.from(100), 2)).toEqual('1.0'); + }); + + it('should return zero if the number is zero', () => { + expect(bigNumberToString(BigNumber.from(0))).toEqual('0'); + }); + + it('should return null if the value is null', () => { + expect(bigNumberToString(null)).toEqual(null); + }); +}); + +describe('useBigNumberToString', () => { + it('should convert a BigNumber to a string', () => { + const { result } = renderHook(() => useBigNumberToString(mockBigNumber)); + + expect(result.current).toEqual('1'); + }); + + it('should return the number if decimal places is zero', () => { + const { result } = renderHook(() => useBigNumberToString(mockBigNumber, 0)); + + expect(result.current).toEqual('1'); + }); + + it('should return the number if decimal places are specified', () => { + const { result } = renderHook(() => + useBigNumberToString(BigNumber.from(100), 2) + ); + + expect(result.current).toEqual('1.0'); + }); + + it('should return zero if the number is zero', () => { + const { result } = renderHook(() => + useBigNumberToString(BigNumber.from(0)) + ); + + expect(result.current).toEqual('0'); + }); + + it('should return null if the value is null', () => { + const { result } = renderHook(() => useBigNumberToString(null)); + + expect(result.current).toEqual(null); + }); +}); diff --git a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.ts b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.ts index 425ecd09..9776ab71 100644 --- a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.ts +++ b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.ts @@ -15,3 +15,9 @@ export default function useBigNumberToString( return stakeAmountParsed; } + +export function bigNumberToString(number: BigNumber, decimals: number = 0) { + if (!number) return null; + let formatted = formatUnits(number, decimals); + return formatted; +} From 907dda11f44a30e344f9c106993866cf52c4b1c6 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Tue, 21 Mar 2023 15:41:30 -0300 Subject: [PATCH 24/45] feat: added totalStaked in proposal type and holographic consensus card --- .../Guilds/pages/Proposal/Proposal.tsx | 3 ++- .../HolographicConsensusCard.tsx | 27 ++++++++++++++----- .../HolographicConsensusCard/types.ts | 4 ++- .../fetchers/subgraph/useProposal/index.tsx | 13 +++++++-- apps/davi/src/types/types.guilds.d.ts | 2 +- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx index 92545efd..c2302261 100644 --- a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx +++ b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx @@ -206,7 +206,8 @@ const ProposalPage: React.FC = () => { /> {consensus === 'holographic' && ( )} diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 3fe0c26b..e3933ab6 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -25,6 +25,7 @@ import { Text } from 'components/primitives/Typography'; import { useTypedParams } from 'Modules/Guilds/Hooks/useTypedParams'; import { useTokenList } from 'hooks/Guilds/tokens/useTokenList'; import { useERC20Balance } from 'hooks/Guilds/erc20/useERC20Balance'; +import { bigNumberToString } from 'hooks/Guilds/conversions/useBigNumberToString'; import { HolographicConsensusModal } from './HolographicConsensusModal'; import { @@ -37,7 +38,8 @@ import { StakeDetails } from './StakeDetails'; import { IHolographicConsensusCard, StakeOptions } from './types'; export const HolographicConsensusCard = ({ - proposalStakes, + proposalStakeDetails, + proposalTotalStakes, schemeId, }: IHolographicConsensusCard) => { const theme = useTheme(); @@ -150,14 +152,19 @@ export const HolographicConsensusCard = ({ > {isStakeDetailsOpen === true && ( - {proposalStakes?.against?.length} + + {proposalStakeDetails?.against?.length} + )} - 272.36 + {bigNumberToString( + proposalTotalStakes[0], + stakeTokenInfo?.decimals + )} @@ -171,14 +178,19 @@ export const HolographicConsensusCard = ({ > {isStakeDetailsOpen === true && ( - {proposalStakes?.for?.length} + + {proposalStakeDetails?.for?.length} + )} - 314.15 + {bigNumberToString( + proposalTotalStakes[1], + stakeTokenInfo?.decimals + )} @@ -187,7 +199,7 @@ export const HolographicConsensusCard = ({ @@ -236,6 +248,8 @@ export const HolographicConsensusCard = ({ ); }; +// TODO: get totalStaked +// TODO: calculate speedometer value // TODO: lock logic // TODO: make generic big button (like LOCK button) and change disabled&hover styles // TODO: add color to proposal state pill @@ -243,7 +257,6 @@ export const HolographicConsensusCard = ({ // TODO: translations // TODO: stake: show ENS or address // TODO: if a user staked, it can only increase its stake on the previous option -// TODO: calculate speedometer value // TODO: decimals in token balance and total staked // TODO: rename "for" and "against" to "yes" and "no" // ? border bottom of non-selected stake button? diff --git a/apps/davi/src/components/HolographicConsensusCard/types.ts b/apps/davi/src/components/HolographicConsensusCard/types.ts index fef1bf77..92721c49 100644 --- a/apps/davi/src/components/HolographicConsensusCard/types.ts +++ b/apps/davi/src/components/HolographicConsensusCard/types.ts @@ -1,4 +1,5 @@ import { BigNumber } from 'ethers'; +import { Proposal } from 'types/types.guilds.d'; export type StakeOptions = 'for' | 'against'; @@ -13,7 +14,8 @@ export interface IStakes { } export interface IHolographicConsensusCard { - proposalStakes: IStakes; + proposalStakeDetails: IStakes; + proposalTotalStakes: Proposal['totalStaked']; schemeId: string; } diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx index dd07fb8c..5ea5840f 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx @@ -50,7 +50,6 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { totalVotes, scheme: { id: schemeId }, stakes, - totalStakes, } = proposal; let mappedContractState: ContractState; @@ -84,6 +83,16 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { against: noStakes, }; + // Total staked + const totalNoStakes = noStakes.reduce( + (acc, stake) => acc.add(stake.amount), + BigNumber.from(0) + ); + const totalYesStakes = yesStakes.reduce( + (acc, stake) => acc.add(stake.amount), + BigNumber.from(0) + ); + return { id: id as `0x${string}`, // typecast to comply with template literal type creator: proposer, @@ -101,7 +110,7 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { totalOptions: null, // Not used in the codebase but in the deploy scripts subDao: schemeId, stakes: parsedStakes, - totalStakes, + totalStaked: [totalNoStakes, totalYesStakes], }; }, [data]); diff --git a/apps/davi/src/types/types.guilds.d.ts b/apps/davi/src/types/types.guilds.d.ts index b71e4407..2cd247e7 100644 --- a/apps/davi/src/types/types.guilds.d.ts +++ b/apps/davi/src/types/types.guilds.d.ts @@ -25,7 +25,7 @@ export interface Proposal { votes?: Vote[]; executionTransactionHash?: string; subDao?: string; - totalStakes?: BigNumber; + totalStaked?: [BigNumber, BigNumber]; stakes?: IStakes; } From 5922d68dfba26c342a541c990532f1dab7ee09ef Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Tue, 21 Mar 2023 16:36:11 -0300 Subject: [PATCH 25/45] feat: speedometer value calculation --- .../HolographicConsensusCard.tsx | 7 +- .../HolographicConsensusModal.tsx | 15 ++--- .../HolographicConsensusCard/types.ts | 7 ++ .../HolographicConsensusCard/utils.test.tsx | 64 +++++++++++++++++++ .../HolographicConsensusCard/utils.ts | 22 +++++++ 5 files changed, 103 insertions(+), 12 deletions(-) create mode 100644 apps/davi/src/components/HolographicConsensusCard/utils.test.tsx create mode 100644 apps/davi/src/components/HolographicConsensusCard/utils.ts diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index e3933ab6..59c9925c 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -36,6 +36,7 @@ import { } from './HolographicConsensusCard.styled'; import { StakeDetails } from './StakeDetails'; import { IHolographicConsensusCard, StakeOptions } from './types'; +import { calculateSpeedometerValue } from './utils'; export const HolographicConsensusCard = ({ proposalStakeDetails, @@ -102,6 +103,8 @@ export const HolographicConsensusCard = ({ if (!stakeTokenAddress) return <>; + const speedometerValue = calculateSpeedometerValue(proposalTotalStakes); + return ( ); }; -// TODO: get totalStaked // TODO: calculate speedometer value // TODO: lock logic // TODO: make generic big button (like LOCK button) and change disabled&hover styles diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index d6ebad8c..029e7c95 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -6,12 +6,13 @@ import { useTheme } from 'styled-components'; import { useTranslation } from 'react-i18next'; import { resolveUri } from 'utils'; -import { TokenInfoWithType } from 'types/types'; + import { Flex } from 'components/primitives/Layout'; import { Button } from 'components/primitives/Button'; import { Slider } from 'components/primitives/Forms/Slider'; import { Text } from 'components/primitives/Typography'; import { Avatar } from 'components/Avatar'; +import { bigNumberToNumber } from 'hooks/Guilds/conversions/useBigNumberToNumber'; import { LockButton, @@ -19,18 +20,12 @@ import { StakeIconButton, StakeSelectionContainer, } from './HolographicConsensusCard.styled'; -import { StakeOptions } from './types'; -import { BigNumber } from 'ethers'; -import { bigNumberToNumber } from 'hooks/Guilds/conversions/useBigNumberToNumber'; - -interface IHolographicConsensusModal { - tokenInfo: TokenInfoWithType; - userStakeTokenBalance: BigNumber; -} +import { IHolographicConsensusModal, StakeOptions } from './types'; export const HolographicConsensusModal = ({ tokenInfo, userStakeTokenBalance, + speedometerValue, }: IHolographicConsensusModal) => { const theme = useTheme(); const { t } = useTranslation(); @@ -52,7 +47,7 @@ export const HolographicConsensusModal = ({ { + it('should return 0 when totalStaked is not provided', () => { + const totalStaked = null; + const result = calculateSpeedometerValue(totalStaked); + expect(result).toEqual(0); + }); + + it('should return 5000 when stakedFor and stakedAgainst are equal', () => { + const totalStaked: [BigNumber, BigNumber] = [ + BigNumber.from(100), + BigNumber.from(100), + ]; + const result = calculateSpeedometerValue(totalStaked); + expect(result).toEqual(5000); + }); + + it('should return 7500 when stakedFor is 2x stakedAgainst', () => { + const totalStaked: [BigNumber, BigNumber] = [ + BigNumber.from(100), + BigNumber.from(200), + ]; + const result = calculateSpeedometerValue(totalStaked); + expect(result).toEqual(7500); + }); + + it('should return 2500 when stakedAgainst is 2x stakedFor', () => { + const totalStaked: [BigNumber, BigNumber] = [ + BigNumber.from(200), + BigNumber.from(100), + ]; + const result = calculateSpeedometerValue(totalStaked); + expect(result).toEqual(2500); + }); + + it('should return 10000 when stakedAgainst is 0', () => { + const totalStaked: [BigNumber, BigNumber] = [ + BigNumber.from(0), + BigNumber.from(100), + ]; + const result = calculateSpeedometerValue(totalStaked); + expect(result).toEqual(10000); + }); + + it('should return 0 when stakedFor is 0', () => { + const totalStaked: [BigNumber, BigNumber] = [ + BigNumber.from(100), + BigNumber.from(0), + ]; + const result = calculateSpeedometerValue(totalStaked); + expect(result).toEqual(0); + }); + + it('should return 5650 if stakedAgainst is 272 and stakedFor is 314', () => { + const totalStaked: [BigNumber, BigNumber] = [ + BigNumber.from(272), + BigNumber.from(314), + ]; + const result = calculateSpeedometerValue(totalStaked); + expect(result).toEqual(5650); + }); +}); diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.ts b/apps/davi/src/components/HolographicConsensusCard/utils.ts new file mode 100644 index 00000000..d946a66c --- /dev/null +++ b/apps/davi/src/components/HolographicConsensusCard/utils.ts @@ -0,0 +1,22 @@ +import { Proposal } from 'types/types.guilds.d'; + +export const calculateSpeedometerValue = ( + totalStaked: Proposal['totalStaked'] +): number => { + if (!totalStaked) return 0; + + const stakedAgainst = totalStaked[0]; + const stakedFor = totalStaked[1]; + + const stakeDifference = stakedFor.sub(stakedAgainst); + let percentage: number; + + if (stakeDifference.gt(0)) { + percentage = stakeDifference.mul(100).div(stakedFor).toNumber(); + } else if (stakeDifference.eq(0)) { + percentage = 0; + } else { + percentage = stakeDifference.mul(100).div(stakedAgainst).toNumber(); + } + return 5000 + percentage * 50; +}; From fa4a183ee9d132f87f00c0b7fddb69eb64cbc68b Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 23 Mar 2023 09:45:04 -0300 Subject: [PATCH 26/45] feat: we have staking! --- apps/davi/public/locales/en/translation.json | 3 +- .../Guilds/pages/Proposal/Proposal.tsx | 1 + .../HolographicConsensusCard.tsx | 18 ++++--- .../HolographicConsensusModal.tsx | 48 ++++++++++++++----- .../HolographicConsensusCard/types.ts | 6 +++ .../HolographicConsensusCard/utils.test.tsx | 46 +++++++++++++++++- .../HolographicConsensusCard/utils.ts | 33 +++++++++++++ apps/davi/src/stores/modules/1_5/index.ts | 2 + .../src/stores/modules/1_5/writers/index.ts | 1 + .../1_5/writers/useStakeOnProposal/index.ts | 1 + .../useStakeOnProposal/useStakeOnProposal.tsx | 38 +++++++++++++++ .../guilds/SnapshotERC20Guild/index.ts | 2 + .../SnapshotERC20Guild/writers/index.ts | 1 + .../guilds/SnapshotRepERC20Guild/index.ts | 2 + .../SnapshotRepERC20Guild/writers/index.ts | 1 + .../modules/guilds/common/writers/index.ts | 1 + .../common/writers/useStakeOnProposal.tsx | 30 ++++++++++++ apps/davi/src/stores/types.ts | 10 ++++ 18 files changed, 224 insertions(+), 20 deletions(-) create mode 100644 apps/davi/src/stores/modules/1_5/writers/useStakeOnProposal/index.ts create mode 100644 apps/davi/src/stores/modules/1_5/writers/useStakeOnProposal/useStakeOnProposal.tsx create mode 100644 apps/davi/src/stores/modules/guilds/common/writers/useStakeOnProposal.tsx diff --git a/apps/davi/public/locales/en/translation.json b/apps/davi/public/locales/en/translation.json index f3259f28..fbf85f07 100644 --- a/apps/davi/public/locales/en/translation.json +++ b/apps/davi/public/locales/en/translation.json @@ -409,7 +409,8 @@ "confirmPrediction": "Confirm prediction", "placeYourPrediction": "Place your prediction to steer the proposal", "potentialReward": "Potential reward", - "lockWarning": "Your prediction will be locked until the proposal ends and you could lose your DXD if your prediction is wrong" + "lockWarning": "Your prediction will be locked until the proposal ends and you could lose your DXD if your prediction is wrong", + "stakeOnProposal": "Stake on proposal" }, "inputValidation": { "recipientAddressIsRequired": "Recipient address is required", diff --git a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx index c2302261..662d9d48 100644 --- a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx +++ b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx @@ -209,6 +209,7 @@ const ProposalPage: React.FC = () => { proposalStakeDetails={proposal?.stakes} proposalTotalStakes={proposal?.totalStaked} schemeId={proposal?.subDao} + proposalId={proposalId} /> )} diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 59c9925c..b56bd577 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -42,12 +42,14 @@ export const HolographicConsensusCard = ({ proposalStakeDetails, proposalTotalStakes, schemeId, + proposalId, }: IHolographicConsensusCard) => { const theme = useTheme(); const { t } = useTranslation(); const { hooks: { fetchers: { useGetSubDAOs }, + writers: { useStakeOnProposal }, }, } = useHookStoreProvider(); const { guildId: daoId } = useTypedParams(); @@ -61,6 +63,8 @@ export const HolographicConsensusCard = ({ } = useGetSubDAOs(daoId, schemeId); const { tokens } = useTokenList(chain?.id); + const stakeOnProposal = useStakeOnProposal(daoId, schemeId); + let stakeTokenAddress: string = null; let stakeTokenInfo: TokenInfoWithType = null; @@ -246,22 +250,24 @@ export const HolographicConsensusCard = ({ tokenInfo={stakeTokenInfo} userStakeTokenBalance={userStakeTokenBalance} speedometerValue={speedometerValue} + stakeOnProposal={stakeOnProposal} + proposalId={proposalId} /> ); }; -// TODO: calculate speedometer value -// TODO: lock logic -// TODO: make generic big button (like LOCK button) and change disabled&hover styles -// TODO: add color to proposal state pill +// TODO: stake logic +// TODO: if a user staked, it can only increase its stake on the previous option // TODO: fetch proposal state +// TODO: add color to proposal state pill // TODO: translations // TODO: stake: show ENS or address -// TODO: if a user staked, it can only increase its stake on the previous option // TODO: decimals in token balance and total staked -// TODO: rename "for" and "against" to "yes" and "no" +// TODO: make generic big button (like LOCK button) and change disabled&hover styles +// TODO: fix bug: using the slider sometimes causes the staking value to show a lot of decimals +// TODO: a way to show numbers with a fixed amount of decimals // ? border bottom of non-selected stake button? // maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index 029e7c95..bcadb460 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -4,9 +4,9 @@ import ReactSpeedometer from 'react-d3-speedometer'; import { FiThumbsDown, FiThumbsUp, FiInfo } from 'react-icons/fi'; import { useTheme } from 'styled-components'; import { useTranslation } from 'react-i18next'; +import { BigNumber } from 'ethers'; import { resolveUri } from 'utils'; - import { Flex } from 'components/primitives/Layout'; import { Button } from 'components/primitives/Button'; import { Slider } from 'components/primitives/Forms/Slider'; @@ -21,27 +21,48 @@ import { StakeSelectionContainer, } from './HolographicConsensusCard.styled'; import { IHolographicConsensusModal, StakeOptions } from './types'; +import { calculateBNPercentage } from './utils'; export const HolographicConsensusModal = ({ tokenInfo, userStakeTokenBalance, speedometerValue, + stakeOnProposal, + proposalId, }: IHolographicConsensusModal) => { const theme = useTheme(); const { t } = useTranslation(); - const [selectedStake, setSelectedStake] = useState(null); + const [staked, setStaked] = useState(BigNumber.from(0)); const [stakePercentage, setStakePercentage] = useState('0'); - const handleSelectedStake = (option: StakeOptions) => { - if (selectedStake === option) setSelectedStake(null); - else setSelectedStake(option); + const handleStakeChange = (value: string) => { + const stakedResult = calculateBNPercentage(userStakeTokenBalance, value); + setStakePercentage(value); + setStaked(stakedResult); + }; + + const [selectedOption, setSelectedOption] = useState(null); + const [selectedStake, setSelectedStake] = useState(null); + + const handleSelectOption = (option: StakeOptions) => { + const parsedOption = + option === 'for' ? BigNumber.from(2) : BigNumber.from(1); + + if (selectedStake === option) { + setSelectedOption(null); + setSelectedStake(null); + } else { + setSelectedOption(parsedOption); + setSelectedStake(option); + } }; - const roundedBalance = bigNumberToNumber( + const userStakeTokenBalanceNumber = bigNumberToNumber( userStakeTokenBalance, tokenInfo?.decimals ); + const stakedNumber = bigNumberToNumber(staked, tokenInfo?.decimals); return ( @@ -80,7 +101,7 @@ export const HolographicConsensusModal = ({ > handleSelectedStake('against')} + onClick={() => handleSelectOption('against')} active={selectedStake === 'against'} > handleSelectedStake('for')} + onClick={() => handleSelectOption('for')} active={selectedStake === 'for'} > {t('members.locking.balance')}: - {roundedBalance} + {userStakeTokenBalanceNumber} - {roundedBalance * (Number(stakePercentage) / 100)} + {stakedNumber} - @@ -167,6 +188,9 @@ export const HolographicConsensusModal = ({ { + stakeOnProposal(proposalId, selectedOption, staked); + }} disabled={selectedStake === null || stakePercentage === '0'} > {t('members.locking.lock')} {tokenInfo?.symbol} diff --git a/apps/davi/src/components/HolographicConsensusCard/types.ts b/apps/davi/src/components/HolographicConsensusCard/types.ts index dcbb23b7..5c9db9d4 100644 --- a/apps/davi/src/components/HolographicConsensusCard/types.ts +++ b/apps/davi/src/components/HolographicConsensusCard/types.ts @@ -1,6 +1,9 @@ import { BigNumber } from 'ethers'; import { Proposal } from 'types/types.guilds.d'; import { TokenInfoWithType } from 'types/types'; +import { WriterHooksInteface } from 'stores/types'; + +type IUseStakeOnProposal = WriterHooksInteface['useStakeOnProposal']; export type StakeOptions = 'for' | 'against'; @@ -18,6 +21,7 @@ export interface IHolographicConsensusCard { proposalStakeDetails: IStakes; proposalTotalStakes: Proposal['totalStaked']; schemeId: string; + proposalId: string; } export interface IStakeDetails { @@ -31,4 +35,6 @@ export interface IHolographicConsensusModal { tokenInfo: TokenInfoWithType; userStakeTokenBalance: BigNumber; speedometerValue: number; + stakeOnProposal: ReturnType; + proposalId: string; } diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx b/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx index 5c49d0fd..2371c2ce 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx @@ -1,5 +1,5 @@ import { BigNumber } from 'ethers'; -import { calculateSpeedometerValue } from './utils'; +import { calculateSpeedometerValue, calculateBNPercentage } from './utils'; describe('calculateSpeedometerValue', () => { it('should return 0 when totalStaked is not provided', () => { @@ -62,3 +62,47 @@ describe('calculateSpeedometerValue', () => { expect(result).toEqual(5650); }); }); + +describe('calculateBNPercentage', () => { + it('should return the percentage of a BigNumber when the percentage is a string', () => { + const value = BigNumber.from(100); + const percentage = '50'; + const result = calculateBNPercentage(value, percentage); + expect(result).toEqual(BigNumber.from(50)); + }); + + it('should return the percentage of a BigNumber when the percentage is a number', () => { + const value = BigNumber.from(100); + const percentage = 50; + const result = calculateBNPercentage(value, percentage); + expect(result).toEqual(BigNumber.from(50)); + }); + + it('should return 0 then the value is 0', () => { + const value = BigNumber.from(0); + const percentage = 50; + const result = calculateBNPercentage(value, percentage); + expect(result).toEqual(BigNumber.from(0)); + }); + + it('should return 0 when the percentage is 0', () => { + const value = BigNumber.from(100); + const percentage = 0; + const result = calculateBNPercentage(value, percentage); + expect(result).toEqual(BigNumber.from(0)); + }); + + it("should handle a percentage that's not a whole number", () => { + const value = BigNumber.from(100); + const percentage = 50.5; + const result = calculateBNPercentage(value, percentage); + expect(result).toEqual(BigNumber.from(50)); + }); + + it('should handle negative percentages', () => { + const value = BigNumber.from(100); + const percentage = -50; + const result = calculateBNPercentage(value, percentage); + expect(result).toEqual(BigNumber.from(-50)); + }); +}); diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.ts b/apps/davi/src/components/HolographicConsensusCard/utils.ts index d946a66c..0a14c546 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.ts +++ b/apps/davi/src/components/HolographicConsensusCard/utils.ts @@ -1,3 +1,4 @@ +import { BigNumber, FixedNumber } from 'ethers'; import { Proposal } from 'types/types.guilds.d'; export const calculateSpeedometerValue = ( @@ -20,3 +21,35 @@ export const calculateSpeedometerValue = ( } return 5000 + percentage * 50; }; + +export const calculateBNPercentage = ( + value: BigNumber, + percentage: string | number +) => { + // percentage should be an integer (before being divided by 100) + // if a percentage has decimals, it trims them + // TODO: handle decimals? + if (typeof percentage === 'string') { + if (percentage.includes('.')) { + const percentageSplit = percentage.split('.'); + percentage = percentageSplit[0]; + } + } + if (typeof percentage === 'number') { + if (percentage % 1 !== 0) { + percentage = Math.trunc(percentage); + } + } + + const valueFixed = FixedNumber.fromValue(value); + const percentageFixed = FixedNumber.fromValue(BigNumber.from(percentage)); + const hundredFixed = FixedNumber.fromValue(BigNumber.from(100)); + + const resultFixed = valueFixed + .mulUnsafe(percentageFixed) + .divUnsafe(hundredFixed); + + const resultFixedInteger = resultFixed.toString().split('.')[0]; + const resultBN = BigNumber.from(resultFixedInteger); + return resultBN; +}; diff --git a/apps/davi/src/stores/modules/1_5/index.ts b/apps/davi/src/stores/modules/1_5/index.ts index 36a408ab..cdb52b35 100644 --- a/apps/davi/src/stores/modules/1_5/index.ts +++ b/apps/davi/src/stores/modules/1_5/index.ts @@ -28,6 +28,7 @@ import { useExecuteProposal, useWithdrawTokens, useCreateProposal, + useStakeOnProposal, } from './writers'; import { useVoteOnProposal } from './writers/useVoteOnProposal/useVoteOnProposal'; @@ -93,6 +94,7 @@ export const governance1_5Implementation: Readonly useLockTokens: null, useVoteOnProposal, useWithdrawTokens, + useStakeOnProposal, }, }, capabilities: { diff --git a/apps/davi/src/stores/modules/1_5/writers/index.ts b/apps/davi/src/stores/modules/1_5/writers/index.ts index 32080288..10a1f4c2 100644 --- a/apps/davi/src/stores/modules/1_5/writers/index.ts +++ b/apps/davi/src/stores/modules/1_5/writers/index.ts @@ -2,3 +2,4 @@ export { useExecuteProposal } from './useExecuteProposal'; export { useWithdrawTokens } from './useWithdrawTokens'; export { useCreateProposal } from './useCreateProposal'; export { useVoteOnProposal } from './useVoteOnProposal'; +export { useStakeOnProposal } from './useStakeOnProposal'; diff --git a/apps/davi/src/stores/modules/1_5/writers/useStakeOnProposal/index.ts b/apps/davi/src/stores/modules/1_5/writers/useStakeOnProposal/index.ts new file mode 100644 index 00000000..43948470 --- /dev/null +++ b/apps/davi/src/stores/modules/1_5/writers/useStakeOnProposal/index.ts @@ -0,0 +1 @@ +export { useStakeOnProposal } from './useStakeOnProposal'; diff --git a/apps/davi/src/stores/modules/1_5/writers/useStakeOnProposal/useStakeOnProposal.tsx b/apps/davi/src/stores/modules/1_5/writers/useStakeOnProposal/useStakeOnProposal.tsx new file mode 100644 index 00000000..69fd1a9f --- /dev/null +++ b/apps/davi/src/stores/modules/1_5/writers/useStakeOnProposal/useStakeOnProposal.tsx @@ -0,0 +1,38 @@ +import { useTransactions } from 'contexts/Guilds'; +import { useVotingMachineContract } from 'hooks/Guilds/contracts/useContract'; +import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { WriterHooksInteface } from 'stores/types'; +import { useGetVotingMachineAddressBySchemeAddress } from '../../fetchers/subgraph/useGetVotingMachineAddressBySchemeAddress'; + +type IUseStakeOnProposal = WriterHooksInteface['useStakeOnProposal']; +type IHandleStakeOnProposal = ReturnType; + +export const useStakeOnProposal: IUseStakeOnProposal = ( + daoAddress, + schemeAddress +) => { + const { t } = useTranslation(); + const { createTransaction } = useTransactions(); + const votingMachineAddress = + useGetVotingMachineAddressBySchemeAddress(schemeAddress); + + const votingMachineContract = useVotingMachineContract( + votingMachineAddress?.votingMachineAddress + ); + + const handleStakeOnProposal: IHandleStakeOnProposal = useCallback( + async (proposalId, option, stakeAmount, title = '', cb = null) => { + createTransaction( + `${t('holographicConsensus.stakeOnProposal')}${` ${title}` ?? ''}`, + async () => + votingMachineContract.stake(proposalId, option, stakeAmount), + true, + cb + ); + }, + [createTransaction, t, votingMachineContract] + ); + + return handleStakeOnProposal; +}; diff --git a/apps/davi/src/stores/modules/guilds/SnapshotERC20Guild/index.ts b/apps/davi/src/stores/modules/guilds/SnapshotERC20Guild/index.ts index ff796fde..13262826 100644 --- a/apps/davi/src/stores/modules/guilds/SnapshotERC20Guild/index.ts +++ b/apps/davi/src/stores/modules/guilds/SnapshotERC20Guild/index.ts @@ -6,6 +6,7 @@ import { useLockTokens, useVoteOnProposal, useWithdrawTokens, + useStakeOnProposal, } from './writers'; import { useGuildConfig as useGuildConfigFromSubgraph, @@ -118,6 +119,7 @@ export const snapshotERC20GuildImplementation: Readonly; + +export const useStakeOnProposal: IUseStakeOnProposal = ( + daoAddress, + subDaoAddress +) => { + const { t } = useTranslation(); + + const methodNotSupported: IMethodNotSupported = useCallback( + async ( + proposalId, + option, + stakeAmount, + title = '', + cb = null + ): Promise => { + return new Promise((resolve, reject) => { + reject(t('hookStoreErrors.methodNotSupported')); + }); + }, + [t] + ); + + return methodNotSupported; +}; diff --git a/apps/davi/src/stores/types.ts b/apps/davi/src/stores/types.ts index a049f62e..1877f892 100644 --- a/apps/davi/src/stores/types.ts +++ b/apps/davi/src/stores/types.ts @@ -213,6 +213,16 @@ export interface WriterHooksInteface { tokenDecimals?: number, tokenSymbol?: string ) => Promise; + useStakeOnProposal: ( + daoAddress: string, + subDaoAddres?: string + ) => ( + proposalId: string, + option: BigNumber, + stakeAmount: BigNumber, + title?: string, + cb?: (error?: any, txtHash?: any) => void + ) => Promise; } interface HooksInterfaceWithFallback { From 06064f8577c64d2a982b82046df008fe9df9674c Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 23 Mar 2023 13:39:31 -0300 Subject: [PATCH 27/45] fix: fix stake detail with duplicated keys --- .../src/components/HolographicConsensusCard/StakeDetails.tsx | 2 +- apps/davi/src/components/HolographicConsensusCard/types.ts | 1 + .../modules/1_5/fetchers/subgraph/useProposal/query.graphql | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx index a4710bf9..770d4106 100644 --- a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -21,7 +21,7 @@ export const StakeDetails = ({ direction="row" justifyContent="space-between" margin="6px 0px" - key={stake.staker} + key={stake.id} > {shortenAddress(stake.staker)} diff --git a/apps/davi/src/components/HolographicConsensusCard/types.ts b/apps/davi/src/components/HolographicConsensusCard/types.ts index 5c9db9d4..9ce81040 100644 --- a/apps/davi/src/components/HolographicConsensusCard/types.ts +++ b/apps/davi/src/components/HolographicConsensusCard/types.ts @@ -8,6 +8,7 @@ type IUseStakeOnProposal = WriterHooksInteface['useStakeOnProposal']; export type StakeOptions = 'for' | 'against'; export interface IStake { + id: string; staker: string; amount: BigNumber; } diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql index c915a04f..5e0fc922 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/query.graphql @@ -29,6 +29,7 @@ query getDaoProposal($id: ID!, $proposalId: ID!) { id } stakes { + id staker amount option From e825516edcd55a4d6d7861361d33bd4337327770 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 23 Mar 2023 13:40:58 -0300 Subject: [PATCH 28/45] feat: added proposal state from voting machine --- .../Guilds/pages/Proposal/Proposal.tsx | 1 + .../HolographicConsensusCard.tsx | 31 ++++++------ .../HolographicConsensusModal.tsx | 30 +++++++++-- .../HolographicConsensusCard/fixtures.ts | 44 ++++++++++++++++ .../HolographicConsensusCard/types.ts | 6 ++- .../HolographicConsensusCard/utils.test.tsx | 50 ++++++++++++++++++- .../HolographicConsensusCard/utils.ts | 18 +++++++ .../fetchers/subgraph/useProposal/index.tsx | 43 +++++++++++++++- apps/davi/src/types/types.guilds.d.ts | 13 +++++ 9 files changed, 213 insertions(+), 23 deletions(-) create mode 100644 apps/davi/src/components/HolographicConsensusCard/fixtures.ts diff --git a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx index 662d9d48..ad3ebb43 100644 --- a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx +++ b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx @@ -210,6 +210,7 @@ const ProposalPage: React.FC = () => { proposalTotalStakes={proposal?.totalStaked} schemeId={proposal?.subDao} proposalId={proposalId} + proposalState={proposal?.holographicConsensusState} /> )} diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index b56bd577..cde52606 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -43,6 +43,7 @@ export const HolographicConsensusCard = ({ proposalTotalStakes, schemeId, proposalId, + proposalState, }: IHolographicConsensusCard) => { const theme = useTheme(); const { t } = useTranslation(); @@ -54,6 +55,7 @@ export const HolographicConsensusCard = ({ } = useHookStoreProvider(); const { guildId: daoId } = useTypedParams(); const { chain } = useNetwork(); + const { tokens } = useTokenList(chain?.id); const { data: schemeData, @@ -61,9 +63,6 @@ export const HolographicConsensusCard = ({ isError, errorMessage, } = useGetSubDAOs(daoId, schemeId); - const { tokens } = useTokenList(chain?.id); - - const stakeOnProposal = useStakeOnProposal(daoId, schemeId); let stakeTokenAddress: string = null; let stakeTokenInfo: TokenInfoWithType = null; @@ -80,12 +79,15 @@ export const HolographicConsensusCard = ({ stakeTokenAddress, userAddress ); + const stakeOnProposal = useStakeOnProposal(daoId, schemeId); const [isModalOpen, setIsModalOpen] = useState(false); const [isStakeDetailsOpen, setIsStakeDetailsOpen] = useState(false); const [showStakeOption, setShowStakeOption] = useState('for'); - if (isLoading) { + const speedometerValue = calculateSpeedometerValue(proposalTotalStakes); + + if (isLoading || !stakeTokenAddress) { return ( @@ -105,10 +107,6 @@ export const HolographicConsensusCard = ({ ); } - if (!stakeTokenAddress) return <>; - - const speedometerValue = calculateSpeedometerValue(proposalTotalStakes); - return ( - Pending Boost + {proposalState} @@ -252,22 +250,23 @@ export const HolographicConsensusCard = ({ speedometerValue={speedometerValue} stakeOnProposal={stakeOnProposal} proposalId={proposalId} + stakeDetails={proposalStakeDetails} + userAddress={userAddress} + proposalState={proposalState} /> ); }; -// TODO: stake logic -// TODO: if a user staked, it can only increase its stake on the previous option -// TODO: fetch proposal state // TODO: add color to proposal state pill // TODO: translations // TODO: stake: show ENS or address -// TODO: decimals in token balance and total staked -// TODO: make generic big button (like LOCK button) and change disabled&hover styles -// TODO: fix bug: using the slider sometimes causes the staking value to show a lot of decimals -// TODO: a way to show numbers with a fixed amount of decimals +// TODO: potential reward +// TODO: unlock time +// TODO: modal title styling +// TODO: clicking again in the staking details should close it +// TODO: check margins // ? border bottom of non-selected stake button? // maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index bcadb460..668d225d 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -21,7 +21,7 @@ import { StakeSelectionContainer, } from './HolographicConsensusCard.styled'; import { IHolographicConsensusModal, StakeOptions } from './types'; -import { calculateBNPercentage } from './utils'; +import { calculateBNPercentage, checkUserStakeOption } from './utils'; export const HolographicConsensusModal = ({ tokenInfo, @@ -29,10 +29,17 @@ export const HolographicConsensusModal = ({ speedometerValue, stakeOnProposal, proposalId, + stakeDetails, + userAddress, + proposalState, }: IHolographicConsensusModal) => { const theme = useTheme(); const { t } = useTranslation(); + const previousStake = checkUserStakeOption(userAddress, stakeDetails); + + // ? derive staked and selectedOption? + const [staked, setStaked] = useState(BigNumber.from(0)); const [stakePercentage, setStakePercentage] = useState('0'); @@ -42,8 +49,15 @@ export const HolographicConsensusModal = ({ setStaked(stakedResult); }; - const [selectedOption, setSelectedOption] = useState(null); - const [selectedStake, setSelectedStake] = useState(null); + const [selectedOption, setSelectedOption] = useState( + previousStake === 'for' + ? BigNumber.from(2) + : previousStake === 'against' + ? BigNumber.from(1) + : null + ); + const [selectedStake, setSelectedStake] = + useState(previousStake); const handleSelectOption = (option: StakeOptions) => { const parsedOption = @@ -87,7 +101,7 @@ export const HolographicConsensusModal = ({ needleColor={theme.colors.white} /> - Pending Boost + {proposalState} @@ -103,6 +117,7 @@ export const HolographicConsensusModal = ({ variant="against" onClick={() => handleSelectOption('against')} active={selectedStake === 'against'} + disabled={previousStake !== null} > handleSelectOption('for')} active={selectedStake === 'for'} + disabled={previousStake !== null} > + {previousStake && ( + + You cannot change your option since you already staked in this + proposal + + )} {t('members.locking.balance')}: diff --git a/apps/davi/src/components/HolographicConsensusCard/fixtures.ts b/apps/davi/src/components/HolographicConsensusCard/fixtures.ts new file mode 100644 index 00000000..8576622c --- /dev/null +++ b/apps/davi/src/components/HolographicConsensusCard/fixtures.ts @@ -0,0 +1,44 @@ +import { BigNumber } from 'ethers'; +import { IStakes } from './types'; + +export const mockProposalStakeDetails: IStakes = { + for: [ + { + id: '1', + staker: '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698', + amount: BigNumber.from('100000000000000000000'), + }, + { + id: '2', + staker: '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f', + amount: BigNumber.from('100000000000000000000'), + }, + { + id: '3', + staker: '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f', + amount: BigNumber.from('336000000000000000000'), + }, + { + id: '4', + staker: '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f', + amount: BigNumber.from('236600000000000000000'), + }, + { + id: '5', + staker: '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f', + amount: BigNumber.from('47138000000000000000'), + }, + ], + against: [ + { + id: '6', + staker: '0x84eeb305da0a4309a696d43de9f79f04e66eb4f8', + amount: BigNumber.from('100000000000000000000'), + }, + ], +}; + +export const mockProposalStakeDetailsEmpty = { + for: [], + against: [], +}; diff --git a/apps/davi/src/components/HolographicConsensusCard/types.ts b/apps/davi/src/components/HolographicConsensusCard/types.ts index 9ce81040..07b5da29 100644 --- a/apps/davi/src/components/HolographicConsensusCard/types.ts +++ b/apps/davi/src/components/HolographicConsensusCard/types.ts @@ -1,5 +1,5 @@ import { BigNumber } from 'ethers'; -import { Proposal } from 'types/types.guilds.d'; +import { HolographicConsensusState, Proposal } from 'types/types.guilds.d'; import { TokenInfoWithType } from 'types/types'; import { WriterHooksInteface } from 'stores/types'; @@ -23,6 +23,7 @@ export interface IHolographicConsensusCard { proposalTotalStakes: Proposal['totalStaked']; schemeId: string; proposalId: string; + proposalState: HolographicConsensusState; } export interface IStakeDetails { @@ -38,4 +39,7 @@ export interface IHolographicConsensusModal { speedometerValue: number; stakeOnProposal: ReturnType; proposalId: string; + stakeDetails: IStakes; + userAddress: string; + proposalState: HolographicConsensusState; } diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx b/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx index 2371c2ce..bc9f51d8 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx @@ -1,5 +1,13 @@ import { BigNumber } from 'ethers'; -import { calculateSpeedometerValue, calculateBNPercentage } from './utils'; +import { + mockProposalStakeDetails, + mockProposalStakeDetailsEmpty, +} from './fixtures'; +import { + calculateSpeedometerValue, + calculateBNPercentage, + checkUserStakeOption, +} from './utils'; describe('calculateSpeedometerValue', () => { it('should return 0 when totalStaked is not provided', () => { @@ -106,3 +114,43 @@ describe('calculateBNPercentage', () => { expect(result).toEqual(BigNumber.from(-50)); }); }); + +// write test cases for checkUserStakeOption +describe('checkUserStakeOption', () => { + it("should return 'for' if the user staked for the proposal", () => { + const userAddress = '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f'; + const result = checkUserStakeOption(userAddress, mockProposalStakeDetails); + expect(result).toEqual('for'); + }); + + it("should return 'against' if the user staked against the proposal", () => { + const userAddress = '0x84eeb305da0a4309a696d43de9f79f04e66eb4f8'; + const result = checkUserStakeOption(userAddress, mockProposalStakeDetails); + expect(result).toEqual('against'); + }); + + it('should return null if the user did not stake for the proposal', () => { + const userAddress = '0x9578e973bba0cc33bdbc93c7f77bb3fe6d47d68a'; + const result = checkUserStakeOption(userAddress, mockProposalStakeDetails); + expect(result).toEqual(null); + }); + + it('should handle an empty stakeDetails', () => { + const userAddress = '0x84eeb305da0a4309a696d43de9f79f04e66eb4f8'; + const result = checkUserStakeOption( + userAddress, + mockProposalStakeDetailsEmpty + ); + expect(result).toEqual(null); + }); + + it('should handle lower and upper case addresses', () => { + const userAddress = '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f'; + const userAddressUpper = userAddress.toUpperCase(); + const result = checkUserStakeOption( + userAddressUpper, + mockProposalStakeDetails + ); + expect(result).toEqual('for'); + }); +}); diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.ts b/apps/davi/src/components/HolographicConsensusCard/utils.ts index 0a14c546..c8ec25ef 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.ts +++ b/apps/davi/src/components/HolographicConsensusCard/utils.ts @@ -1,5 +1,6 @@ import { BigNumber, FixedNumber } from 'ethers'; import { Proposal } from 'types/types.guilds.d'; +import { IStakes } from './types'; export const calculateSpeedometerValue = ( totalStaked: Proposal['totalStaked'] @@ -53,3 +54,20 @@ export const calculateBNPercentage = ( const resultBN = BigNumber.from(resultFixedInteger); return resultBN; }; + +export const checkUserStakeOption = ( + userAddress: string, + stakeDetails: IStakes +) => { + const userStakeFor = stakeDetails.for.find( + stake => stake.staker.toLowerCase() === userAddress.toLowerCase() + ); + if (userStakeFor) return 'for'; + + const userStakeAgainst = stakeDetails.against.find( + stake => stake.staker.toLowerCase() === userAddress.toLowerCase() + ); + if (userStakeAgainst) return 'against'; + + return null; +}; diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx index 5ea5840f..f5cfd130 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx @@ -7,7 +7,11 @@ import { BigNumber } from 'ethers'; import { getDaoProposalDocument, getDaoProposalQuery } from '.graphclient'; import { FetcherHooksInterface, SupportedSubgraph } from 'stores/types'; import { getApolloClient } from 'clients/apollo'; -import { ContractState, Proposal } from 'types/types.guilds.d'; +import { + ContractState, + HolographicConsensusState, + Proposal, +} from 'types/types.guilds.d'; import { IStakes } from 'components/HolographicConsensusCard/types'; import { useProposalCalls } from '../../rpc/useProposalCalls'; @@ -50,6 +54,7 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { totalVotes, scheme: { id: schemeId }, stakes, + votingMachineProposalState, } = proposal; let mappedContractState: ContractState; @@ -72,6 +77,41 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { break; } + let mappedHolographicConsensusState: HolographicConsensusState; + + switch (votingMachineProposalState) { + case 'None': + mappedHolographicConsensusState = HolographicConsensusState.None; + break; + case 'Expired': + mappedHolographicConsensusState = HolographicConsensusState.Expired; + break; + case 'ExecutedInQueue': + mappedHolographicConsensusState = + HolographicConsensusState.ExecutedInQueue; + break; + case 'ExecutedInBoost': + mappedHolographicConsensusState = + HolographicConsensusState.ExecutedInBoost; + break; + case 'Queued': + mappedHolographicConsensusState = HolographicConsensusState.Queued; + break; + case 'PreBoosted': + mappedHolographicConsensusState = HolographicConsensusState.PreBoosted; + break; + case 'Boosted': + mappedHolographicConsensusState = HolographicConsensusState.Boosted; + break; + case 'QuietEndingPeriod': + mappedHolographicConsensusState = + HolographicConsensusState.QuietEndingPeriod; + break; + default: + mappedHolographicConsensusState = HolographicConsensusState.None; + break; + } + const noVotes = BigNumber.from(totalVotes[0]); const yesVotes = BigNumber.from(totalVotes[1]); @@ -111,6 +151,7 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { subDao: schemeId, stakes: parsedStakes, totalStaked: [totalNoStakes, totalYesStakes], + holographicConsensusState: mappedHolographicConsensusState, }; }, [data]); diff --git a/apps/davi/src/types/types.guilds.d.ts b/apps/davi/src/types/types.guilds.d.ts index 2cd247e7..5039938f 100644 --- a/apps/davi/src/types/types.guilds.d.ts +++ b/apps/davi/src/types/types.guilds.d.ts @@ -27,6 +27,7 @@ export interface Proposal { subDao?: string; totalStaked?: [BigNumber, BigNumber]; stakes?: IStakes; + holographicConsensusState?: HolographicConsensusState; // This is a very specific state for the holographic consensus, might be replaced for state } export enum ProposalState { @@ -44,6 +45,18 @@ export enum ContractState { Executed = 'Executed', Failed = 'Failed', } + +export enum HolographicConsensusState { + None = 'None', + Expired = 'Expired', + ExecutedInQueue = 'Executed in queue', + ExecutedInBoost = 'Executed in boost', + Queued = 'Queued', + PreBoosted = 'Pre-boosted', + Boosted = 'Boosted', + QuietEndingPeriod = 'Quiet ending period', +} + export interface ProposalMetadata { description: string; voteOptions: string[]; From a90a53968905cea75b6acca7334e093fecd98778 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 23 Mar 2023 13:59:56 -0300 Subject: [PATCH 29/45] feat: added colors to proposal state text --- .../HolographicConsensusCard.styled.tsx | 28 +++++++++++++++++++ .../HolographicConsensusCard.tsx | 9 ++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx index 236274ad..8024d56d 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx @@ -1,6 +1,7 @@ import { Button } from 'components/primitives/Button'; import { SidebarCardContentWrapper } from 'components/SidebarCard/SidebarCard.styled'; import styled, { css } from 'styled-components'; +import { HolographicConsensusState } from 'types/types.guilds.d'; import { StakeOptions } from './types'; export const StakeButtonsContainer = styled.div` @@ -97,3 +98,30 @@ export const LockButton = styled(Button)` opacity: 1; } `; + +export const ProposalStateSpan = styled.span<{ + state: HolographicConsensusState; +}>` + color: ${({ state, theme }) => { + switch (state) { + case HolographicConsensusState.None: + return theme.colors.grey; + case HolographicConsensusState.Expired: + return theme.colors.grey; + case HolographicConsensusState.ExecutedInQueue: + return theme.colors.grey; + case HolographicConsensusState.ExecutedInBoost: + return theme.colors.grey; + case HolographicConsensusState.Queued: + return theme.colors.text; + case HolographicConsensusState.PreBoosted: + return theme.colors.text; + case HolographicConsensusState.Boosted: + return theme.colors.active; + case HolographicConsensusState.QuietEndingPeriod: + return theme.colors.grey; + default: + return theme.colors.grey; + } + }}; +`; diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index cde52606..5c2b1192 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -29,6 +29,7 @@ import { bigNumberToString } from 'hooks/Guilds/conversions/useBigNumberToString import { HolographicConsensusModal } from './HolographicConsensusModal'; import { + ProposalStateSpan, StakeButtonsContainer, StakeIconButton, StakeNumberButton, @@ -141,7 +142,11 @@ export const HolographicConsensusCard = ({ needleColor={theme.colors.white} /> - {proposalState} + + + {proposalState} + + @@ -259,13 +264,13 @@ export const HolographicConsensusCard = ({ ); }; -// TODO: add color to proposal state pill // TODO: translations // TODO: stake: show ENS or address // TODO: potential reward // TODO: unlock time // TODO: modal title styling // TODO: clicking again in the staking details should close it +// TODO: fix: two children with the same key // TODO: check margins // ? border bottom of non-selected stake button? From 50a0c944b7a3574f2da12c8157c97ddc420ae942 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 23 Mar 2023 14:03:40 -0300 Subject: [PATCH 30/45] fix: translations --- apps/davi/public/locales/en/translation.json | 3 ++- .../HolographicConsensusCard/HolographicConsensusCard.tsx | 3 +-- .../HolographicConsensusCard/HolographicConsensusModal.tsx | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/davi/public/locales/en/translation.json b/apps/davi/public/locales/en/translation.json index fbf85f07..9f1c2b1e 100644 --- a/apps/davi/public/locales/en/translation.json +++ b/apps/davi/public/locales/en/translation.json @@ -410,7 +410,8 @@ "placeYourPrediction": "Place your prediction to steer the proposal", "potentialReward": "Potential reward", "lockWarning": "Your prediction will be locked until the proposal ends and you could lose your DXD if your prediction is wrong", - "stakeOnProposal": "Stake on proposal" + "stakeOnProposal": "Stake on proposal", + "youCannotChangeYourPrediction": "You cannot change your prediction since you already staked in this proposal" }, "inputValidation": { "recipientAddressIsRequired": "Recipient address is required", diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 5c2b1192..4589db1e 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -264,10 +264,9 @@ export const HolographicConsensusCard = ({ ); }; -// TODO: translations -// TODO: stake: show ENS or address // TODO: potential reward // TODO: unlock time +// TODO: stake: show ENS or address // TODO: modal title styling // TODO: clicking again in the staking details should close it // TODO: fix: two children with the same key diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index 668d225d..f910ec1e 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -144,8 +144,7 @@ export const HolographicConsensusModal = ({ {previousStake && ( - You cannot change your option since you already staked in this - proposal + {t('holographicConsensus.youCannotChangeYourPrediction')} )} @@ -222,5 +221,3 @@ export const HolographicConsensusModal = ({ ); }; - -// For now, progress styling only works on Firefox From e24c8af453b7d829a4c7348184c66a0f8f34bfef Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 23 Mar 2023 16:16:23 -0300 Subject: [PATCH 31/45] fix: fixed modal header and click toggles stake detail visibility --- .../HolographicConsensusCard.tsx | 29 ++++++++++++++----- .../HolographicConsensusModal.tsx | 5 +++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 4589db1e..6a7a44f0 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -157,7 +157,14 @@ export const HolographicConsensusCard = ({ } onClick={() => { setShowStakeOption('against'); - if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); + if (isStakeDetailsOpen === false) { + setIsStakeDetailsOpen(true); + } else if ( + isStakeDetailsOpen === true && + showStakeOption === 'against' + ) { + setIsStakeDetailsOpen(false); + } }} > @@ -183,7 +190,14 @@ export const HolographicConsensusCard = ({ active={isStakeDetailsOpen === true && showStakeOption === 'for'} onClick={() => { setShowStakeOption('for'); - if (isStakeDetailsOpen === false) setIsStakeDetailsOpen(true); + if (isStakeDetailsOpen === false) { + setIsStakeDetailsOpen(true); + } else if ( + isStakeDetailsOpen === true && + showStakeOption === 'for' + ) { + setIsStakeDetailsOpen(false); + } }} > @@ -247,7 +261,11 @@ export const HolographicConsensusCard = ({ isOpen={isModalOpen} onDismiss={() => setIsModalOpen(false)} maxWidth={380} - header={t('holographicConsensus.confirmPrediction')} + header={ + + {t('holographicConsensus.confirmPrediction')} + + } > {t('members.locking.unlockTime')} - March 13th + {/* + //! Unlock time is hardcoded untill we implement useTimeDetail hook + */} + March 14, 2023, 3:54pm UTC
From c287de80b70917b08452116a03c7ce36cadca116 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 24 Mar 2023 15:20:10 -0300 Subject: [PATCH 32/45] feat: potential reward calculation --- .../Guilds/pages/Proposal/Proposal.tsx | 1 + .../HolographicConsensusCard.tsx | 5 +- .../HolographicConsensusModal.tsx | 23 ++- .../HolographicConsensusCard/fixtures.ts | 59 +++++- .../HolographicConsensusCard/types.ts | 3 + .../HolographicConsensusCard/utils.test.tsx | 187 +++++++++++++++++- .../HolographicConsensusCard/utils.ts | 71 +++++++ .../fetchers/subgraph/useProposal/index.tsx | 2 + apps/davi/src/types/types.guilds.d.ts | 1 + 9 files changed, 339 insertions(+), 13 deletions(-) diff --git a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx index ad3ebb43..b2265e38 100644 --- a/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx +++ b/apps/davi/src/Modules/Guilds/pages/Proposal/Proposal.tsx @@ -211,6 +211,7 @@ const ProposalPage: React.FC = () => { schemeId={proposal?.subDao} proposalId={proposalId} proposalState={proposal?.holographicConsensusState} + daoBounty={proposal?.daoBounty} /> )} diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 6a7a44f0..88414f26 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -45,6 +45,7 @@ export const HolographicConsensusCard = ({ schemeId, proposalId, proposalState, + daoBounty, }: IHolographicConsensusCard) => { const theme = useTheme(); const { t } = useTranslation(); @@ -276,15 +277,17 @@ export const HolographicConsensusCard = ({ stakeDetails={proposalStakeDetails} userAddress={userAddress} proposalState={proposalState} + proposalTotalStakes={proposalTotalStakes} + daoBounty={daoBounty} /> ); }; -// TODO: potential reward // TODO: stake: show ENS or address // TODO: check margins +// TODO: fix dao bounty stake not showing on subgraph // TODO: unlock time: postponed untill useTimeDetail is implemented // ? border bottom of non-selected stake button? diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index bd01882f..b8c36388 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -21,7 +21,11 @@ import { StakeSelectionContainer, } from './HolographicConsensusCard.styled'; import { IHolographicConsensusModal, StakeOptions } from './types'; -import { calculateBNPercentage, checkUserStakeOption } from './utils'; +import { + calculateBNPercentage, + calculatePotentialReward, + checkUserStakeOption, +} from './utils'; export const HolographicConsensusModal = ({ tokenInfo, @@ -32,6 +36,8 @@ export const HolographicConsensusModal = ({ stakeDetails, userAddress, proposalState, + proposalTotalStakes, + daoBounty, }: IHolographicConsensusModal) => { const theme = useTheme(); const { t } = useTranslation(); @@ -78,6 +84,19 @@ export const HolographicConsensusModal = ({ ); const stakedNumber = bigNumberToNumber(staked, tokenInfo?.decimals); + const potentialReward = calculatePotentialReward( + stakeDetails, + staked, + userAddress, + selectedOption, + proposalTotalStakes, + daoBounty + ); + const potentialRewardNumber = bigNumberToNumber( + potentialReward, + tokenInfo?.decimals + ); + return ( @@ -181,7 +200,7 @@ export const HolographicConsensusModal = ({ {t('holographicConsensus.potentialReward')} - 1 + {potentialRewardNumber} { @@ -115,7 +121,6 @@ describe('calculateBNPercentage', () => { }); }); -// write test cases for checkUserStakeOption describe('checkUserStakeOption', () => { it("should return 'for' if the user staked for the proposal", () => { const userAddress = '0xc5b20ade9c9cd5e0cc087c62b26b815a4bc1881f'; @@ -154,3 +159,183 @@ describe('checkUserStakeOption', () => { expect(result).toEqual('for'); }); }); + +describe('calculatePotentialReward', () => { + describe('user staked for YES', () => { + it("if a user selected YES but has not staked and doesn't have any current stakes, the reward will be zero", () => { + const userAddress = ZERO_ADDRESS; + const currentStake = BigNumber.from(0); + const userOption = mockSelectedOption.yes; + + const result = calculatePotentialReward( + mockProposalStakeDetails, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(0).toString()); + }); + + it("should return the reward if the user has staked for YES but doesn't have any current stakes", () => { + const userAddress = '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698'; + const currentStake = BigNumber.from(0); + const userOption = mockSelectedOption.yes; + + const result = calculatePotentialReward( + mockProposalStakeDetails, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(124).toString()); + }); + + it('should return the reward if the user has not staked but has current stakes for YES', () => { + const userAddress = ZERO_ADDRESS; + const currentStake = BigNumber.from(100); + const userOption = mockSelectedOption.yes; + + const result = calculatePotentialReward( + mockProposalStakeDetails, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(120).toString()); + }); + + it('should return the reward if the user has staked for YES and has current stakes', () => { + const userAddress = '0xaf8eb8c3a5d9d900aa0b98e3df0bcc17d3c5f698'; + const currentStake = BigNumber.from('100'); + const userOption = mockSelectedOption.yes; + + const result = calculatePotentialReward( + mockProposalStakeDetails, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(242).toString()); + }); + + it('should handle if daoBounty is zero', () => {}); + }); + + describe('user staked for NO', () => { + it("if a user selected NO but has not staked and doesn't have any current stakes, the reward will be zero", () => { + const userAddress = ZERO_ADDRESS; + const currentStake = BigNumber.from(0); + const userOption = mockSelectedOption.no; + + const result = calculatePotentialReward( + mockProposalStakeDetails, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(0).toString()); + }); + + it("should return the reward if the user has staked for NO but doesn't have any current stakes", () => { + const userAddress = '0x84eeb305da0a4309a696d43de9f79f04e66eb4f8'; + const currentStake = BigNumber.from(0); + const userOption = mockSelectedOption.no; + + const result = calculatePotentialReward( + mockProposalStakeDetails, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(459).toString()); + }); + + it('should return the reward if the user has not staked but has current stakes for NO', () => { + const userAddress = ZERO_ADDRESS; + const currentStake = BigNumber.from(100); + const userOption = mockSelectedOption.no; + + const result = calculatePotentialReward( + mockProposalStakeDetails, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(339).toString()); + }); + + it('should return the reward if the user has staked for NO and has current stakes', () => { + const userAddress = '0x84eeb305da0a4309a696d43de9f79f04e66eb4f8'; + const currentStake = BigNumber.from(100); + const userOption = mockSelectedOption.no; + + const result = calculatePotentialReward( + mockProposalStakeDetails, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(679).toString()); + }); + }); + + describe('should handle empty stakes', () => { + it('should return zero if there are no stakes, user has not staked and no current staked', () => { + const userAddress = ZERO_ADDRESS; + const currentStake = BigNumber.from(0); + const userOption = mockSelectedOption.yes; + + const result = calculatePotentialReward( + mockProposalStakeDetailsEmpty, + currentStake, + userAddress, + userOption, + mockTotalStaked, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(0).toString()); + }); + + it('should return reward if there are no stakes, user has not staked and has current staked', () => { + const userAddress = ZERO_ADDRESS; + const currentStake = BigNumber.from(100); + const userOption = mockSelectedOption.yes; + + const result = calculatePotentialReward( + mockProposalStakeDetailsEmpty, + currentStake, + userAddress, + userOption, + mockTotalStakedEmpty, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(200).toString()); + }); + }); +}); diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.ts b/apps/davi/src/components/HolographicConsensusCard/utils.ts index c8ec25ef..6c320a91 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.ts +++ b/apps/davi/src/components/HolographicConsensusCard/utils.ts @@ -71,3 +71,74 @@ export const checkUserStakeOption = ( return null; }; + +export const calculatePotentialReward = ( + stakes: IStakes, + userCurrentStake: BigNumber, + userAddress: string, + userOption: BigNumber, + totalStaked: Proposal['totalStaked'], + daoBounty: BigNumber +) => { + const userStakedOptionIndex: number = userOption.toNumber() - 1; + let userStakedOptionString: string; + if (userStakedOptionIndex === 0) userStakedOptionString = 'against'; + if (userStakedOptionIndex === 1) userStakedOptionString = 'for'; + if (!userStakedOptionString) + throw new Error('Invalid userStakedOptionString'); + + const stakedInUserVote: BigNumber = + totalStaked[userStakedOptionIndex].add(userCurrentStake); + const stakedInUserVoteFixed: FixedNumber = + FixedNumber.fromValue(stakedInUserVote); + + const totalStakedWithoutDaoBounty = userCurrentStake + .add(totalStaked[0]) + .add(totalStaked[1]) + .sub(daoBounty); + + // Calculate what the user staked + const previouslyStakedByUser = stakes[userStakedOptionString].reduce( + (acc: BigNumber, cur) => { + if (cur.staker.toLowerCase() === userAddress.toLowerCase()) { + return acc.add(cur.amount); + } + return acc; + }, + BigNumber.from(0) + ); + + const totalUserStake = previouslyStakedByUser.add(userCurrentStake); + + // Calculate the coefficient for the base reward + + const initialRewardCoefficient = FixedNumber.fromValue( + totalStakedWithoutDaoBounty + ).divUnsafe(stakedInUserVoteFixed); + + const initialReward = FixedNumber.fromValue(totalUserStake).mulUnsafe( + initialRewardCoefficient + ); + + const initialRewardBN = BigNumber.from( + initialReward.toString().split('.')[0] + ); + + // If the user voted for "NO", then the reward is just the initial reward + if (userOption.eq(1)) return initialRewardBN; + + // If the user voted for "YES", then the reward is the initial reward + a percentage of the DAO bounty + const daoBountyRewardCoefficient = FixedNumber.fromValue(daoBounty).divUnsafe( + stakedInUserVoteFixed + ); + + const daoBountyReward = FixedNumber.fromValue(totalUserStake).mulUnsafe( + daoBountyRewardCoefficient + ); + + const daoBountyRewardBN = BigNumber.from( + daoBountyReward.toString().split('.')[0] + ); + + return initialRewardBN.add(daoBountyRewardBN); +}; diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx index f5cfd130..85d0ea36 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useProposal/index.tsx @@ -55,6 +55,7 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { scheme: { id: schemeId }, stakes, votingMachineProposalState, + daoBounty, } = proposal; let mappedContractState: ContractState; @@ -152,6 +153,7 @@ export const useProposal: IUseProposal = (daoId, proposalId) => { stakes: parsedStakes, totalStaked: [totalNoStakes, totalYesStakes], holographicConsensusState: mappedHolographicConsensusState, + daoBounty, }; }, [data]); diff --git a/apps/davi/src/types/types.guilds.d.ts b/apps/davi/src/types/types.guilds.d.ts index 5039938f..ed922d31 100644 --- a/apps/davi/src/types/types.guilds.d.ts +++ b/apps/davi/src/types/types.guilds.d.ts @@ -28,6 +28,7 @@ export interface Proposal { totalStaked?: [BigNumber, BigNumber]; stakes?: IStakes; holographicConsensusState?: HolographicConsensusState; // This is a very specific state for the holographic consensus, might be replaced for state + daoBounty?: BigNumber; } export enum ProposalState { From 0617140ffbdbb74c7e19b6b63b9dd098331431d9 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 24 Mar 2023 15:39:27 -0300 Subject: [PATCH 33/45] feat: show ENS or address in stake detail --- .../HolographicConsensusCard.tsx | 1 - .../HolographicConsensusCard/StakeDetails.tsx | 11 +++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 88414f26..7d620400 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -285,7 +285,6 @@ export const HolographicConsensusCard = ({ ); }; -// TODO: stake: show ENS or address // TODO: check margins // TODO: fix dao bounty stake not showing on subgraph // TODO: unlock time: postponed untill useTimeDetail is implemented diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx index 770d4106..160d6309 100644 --- a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -1,9 +1,15 @@ -import { shortenAddress } from 'utils'; import { Flex } from 'components/primitives/Layout'; import { Text } from 'components/primitives/Typography'; import { bigNumberToNumber } from 'hooks/Guilds/conversions/useBigNumberToNumber'; import { IStake, IStakeDetails } from './types'; import { StakeDetailsContainer } from './HolographicConsensusCard.styled'; +import { useEnsName } from 'wagmi'; +import { shortenAddress } from 'utils'; + +const Address = ({ address }: { address: `0x${string}` }) => { + const { data: ensName } = useEnsName({ address, chainId: 1 }); + return {ensName || shortenAddress(address)}; +}; export const StakeDetails = ({ selectedStake, @@ -15,6 +21,7 @@ export const StakeDetails = ({ {stakeDetails[selectedStake].map((stake: IStake) => { const roundedBalance = bigNumberToNumber(stake.amount, tokenDecimals); + const address = stake.staker as `0x${string}`; return ( - {shortenAddress(stake.staker)} +
{roundedBalance} {tokenSymbol} From 047ed74de80b743cc7e69daba23529a389121c1a Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 24 Mar 2023 15:54:30 -0300 Subject: [PATCH 34/45] feat: after proposal creation, it stakes daoBounty amount in "NO" option --- .../src/mappings/Scheme/mapping.ts | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/dao-subgraph/src/mappings/Scheme/mapping.ts b/apps/dao-subgraph/src/mappings/Scheme/mapping.ts index a8d34d01..d5c5fda7 100644 --- a/apps/dao-subgraph/src/mappings/Scheme/mapping.ts +++ b/apps/dao-subgraph/src/mappings/Scheme/mapping.ts @@ -1,7 +1,8 @@ -import { Address, Bytes } from '@graphprotocol/graph-ts'; +import { Address, Bytes, BigInt, log } from '@graphprotocol/graph-ts'; import { ProposalStateChange } from '../../types/DAOController/Scheme'; import { Proposal, + Stake, StateLog, VotingMachineProposalStateLog, } from '../../types/schema'; @@ -54,6 +55,24 @@ export function handleProposalStateChange(event: ProposalStateChange): void { let proposal = Proposal.load(proposalId.toHexString()); if (!proposal) { proposal = new Proposal(proposalId.toHexString()); + + // Every proposal starts with a stake on the "NO" option equal to daoBounty + const stakeId = `${proposalId.toHexString()}-${schemeAddress.toHexString()}-${ + event.block.timestamp + }-stake`; + + const stake = new Stake(stakeId); + stake.amount = new BigInt(0); + + stake.proposal = proposalId.toHexString(); + stake.avatar = schemeContract.avatar().toHexString(); + stake.staker = schemeAddress.toHexString(); + stake.option = BigInt.fromString('1'); // NO option + stake.amount = proposalDataFromVotingMachine.getDaoBounty(); + stake.timestamp = event.block.timestamp; + stake.txId = event.transaction.hash.toHexString(); + + stake.save(); } // Scheme data From a17dfc6b97126e5ef1c35d515d32cb2f564e5097 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Fri, 24 Mar 2023 16:19:45 -0300 Subject: [PATCH 35/45] fix: refactored styles and simplified logic --- .../HolographicConsensusCard.styled.tsx | 2 +- .../HolographicConsensusCard.tsx | 4 ++-- .../HolographicConsensusModal.tsx | 15 ++++----------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx index 8024d56d..a1a2eb3f 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx @@ -78,7 +78,7 @@ export const ModalContainer = styled.div` export const StakeSelectionContainer = styled.div` width: 100%; box-sizing: border-box; - margin: 32px 0px; + margin: 8px 0 32px 0; padding: 16px 20px; border: 1px solid ${({ theme }) => theme.colors.border1}; border-radius: ${({ theme }) => theme.radii.curved}; diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 7d620400..e3382e1d 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -285,8 +285,8 @@ export const HolographicConsensusCard = ({ ); }; -// TODO: check margins -// TODO: fix dao bounty stake not showing on subgraph +// TODO: merge develop +// TODO: move deploy scripts to davi // TODO: unlock time: postponed untill useTimeDetail is implemented // ? border bottom of non-selected stake button? diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index b8c36388..7b10cb68 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -44,16 +44,8 @@ export const HolographicConsensusModal = ({ const previousStake = checkUserStakeOption(userAddress, stakeDetails); - // ? derive staked and selectedOption? - - const [staked, setStaked] = useState(BigNumber.from(0)); const [stakePercentage, setStakePercentage] = useState('0'); - - const handleStakeChange = (value: string) => { - const stakedResult = calculateBNPercentage(userStakeTokenBalance, value); - setStakePercentage(value); - setStaked(stakedResult); - }; + const staked = calculateBNPercentage(userStakeTokenBalance, stakePercentage); const [selectedOption, setSelectedOption] = useState( previousStake === 'for' @@ -82,6 +74,7 @@ export const HolographicConsensusModal = ({ userStakeTokenBalance, tokenInfo?.decimals ); + const stakedNumber = bigNumberToNumber(staked, tokenInfo?.decimals); const potentialReward = calculatePotentialReward( @@ -180,7 +173,7 @@ export const HolographicConsensusModal = ({ @@ -188,7 +181,7 @@ export const HolographicConsensusModal = ({ {stakedNumber} - From 4cd1d93649c11d00041c05541829b470db894ab0 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 27 Mar 2023 13:43:30 -0300 Subject: [PATCH 36/45] feat: added voting machine ID to useGetSubDAO hook --- .../modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx | 1 + .../modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql | 2 ++ apps/davi/src/types/types.guilds.d.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx index 81eea3a3..248f5a91 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/index.tsx @@ -63,6 +63,7 @@ export const useGetSubDAOs: IUseGetSubDAOs = (daoId, schemeId) => { voteGas: scheme.voteGas, voteGasBalance: scheme.voteGasBalance, votingMachine: { + id: scheme.votingMachine.id, stakingTokenAddress: scheme.votingMachine.stakingTokenAddress, boostedVoteRequiredPercentage: scheme.votingMachine.boostedVoteRequiredPercentage, diff --git a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql index 9f9ab949..e9d262c0 100644 --- a/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql +++ b/apps/davi/src/stores/modules/1_5/fetchers/subgraph/useGetSubDAOs/query.graphql @@ -21,6 +21,7 @@ query getAllSchemes($id: ID!) { voteGas voteGasBalance votingMachine { + id stakingTokenAddress boostedVoteRequiredPercentage preBoostedVotePeriodLimit @@ -54,6 +55,7 @@ query getScheme($id: ID!, $schemeId: ID!) { voteGas voteGasBalance votingMachine { + id stakingTokenAddress boostedVoteRequiredPercentage preBoostedVotePeriodLimit diff --git a/apps/davi/src/types/types.guilds.d.ts b/apps/davi/src/types/types.guilds.d.ts index ed922d31..f6e0b51a 100644 --- a/apps/davi/src/types/types.guilds.d.ts +++ b/apps/davi/src/types/types.guilds.d.ts @@ -142,6 +142,7 @@ export interface SubDAO { voteGas: BigNumber; voteGasBalance: BigNumber; votingMachine: { + id: string; stakingTokenAddress: string; boostedVoteRequiredPercentage: BigNumber; preBoostedVotePeriodLimit: BigNumber; From be6eac35d8e08e85e7dedb0be727bc993c380d88 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 27 Mar 2023 13:47:48 -0300 Subject: [PATCH 37/45] feat: added useApproveTokens to hook store --- apps/davi/src/stores/modules/1_5/index.ts | 3 +- .../src/stores/modules/1_5/writers/index.ts | 1 + .../1_5/writers/useApproveTokens/index.ts | 1 + .../useApproveTokens/useApproveTokens.tsx | 31 +++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 apps/davi/src/stores/modules/1_5/writers/useApproveTokens/index.ts create mode 100644 apps/davi/src/stores/modules/1_5/writers/useApproveTokens/useApproveTokens.tsx diff --git a/apps/davi/src/stores/modules/1_5/index.ts b/apps/davi/src/stores/modules/1_5/index.ts index cdb52b35..a4af4ba3 100644 --- a/apps/davi/src/stores/modules/1_5/index.ts +++ b/apps/davi/src/stores/modules/1_5/index.ts @@ -29,6 +29,7 @@ import { useWithdrawTokens, useCreateProposal, useStakeOnProposal, + useApproveTokens, } from './writers'; import { useVoteOnProposal } from './writers/useVoteOnProposal/useVoteOnProposal'; @@ -88,7 +89,7 @@ export const governance1_5Implementation: Readonly }, }, writers: { - useApproveTokens: null, + useApproveTokens, useCreateProposal, useExecuteProposal, useLockTokens: null, diff --git a/apps/davi/src/stores/modules/1_5/writers/index.ts b/apps/davi/src/stores/modules/1_5/writers/index.ts index 10a1f4c2..b8f5abf8 100644 --- a/apps/davi/src/stores/modules/1_5/writers/index.ts +++ b/apps/davi/src/stores/modules/1_5/writers/index.ts @@ -3,3 +3,4 @@ export { useWithdrawTokens } from './useWithdrawTokens'; export { useCreateProposal } from './useCreateProposal'; export { useVoteOnProposal } from './useVoteOnProposal'; export { useStakeOnProposal } from './useStakeOnProposal'; +export { useApproveTokens } from './useApproveTokens'; diff --git a/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/index.ts b/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/index.ts new file mode 100644 index 00000000..1255f6c2 --- /dev/null +++ b/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/index.ts @@ -0,0 +1 @@ +export { useApproveTokens } from './useApproveTokens'; diff --git a/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/useApproveTokens.tsx b/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/useApproveTokens.tsx new file mode 100644 index 00000000..dc5692fc --- /dev/null +++ b/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/useApproveTokens.tsx @@ -0,0 +1,31 @@ +import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { MAX_UINT } from 'utils'; +import { WriterHooksInteface } from 'stores/types'; +import { useTransactions } from 'contexts/Guilds'; +import { useERC20 } from 'hooks/Guilds/contracts/useContract'; +import { useERC20Info } from 'hooks/Guilds/erc20/useERC20Info'; + +type IUseApproveTokens = WriterHooksInteface['useApproveTokens']; +type IHandleApproveTokens = ReturnType; + +export const useApproveTokens: IUseApproveTokens = tokenAddress => { + const { t } = useTranslation(); + const { createTransaction } = useTransactions(); + const tokenContract = useERC20(tokenAddress); + const { data: tokenInfo } = useERC20Info(tokenAddress); + + const handleApproveTokens: IHandleApproveTokens = useCallback( + async (daoTokenVault, amount = MAX_UINT) => { + createTransaction( + t('actionBuilder.approvals.approveTokenSpending', { + tokenSymbol: tokenInfo?.symbol, + }), + async () => tokenContract?.approve(daoTokenVault, amount) + ); + }, + [createTransaction, tokenContract, tokenInfo, t] + ); + + return handleApproveTokens; +}; From 8a139cfaaf5773c7d1d2db8a3b445fc5bf0681d9 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 27 Mar 2023 13:50:22 -0300 Subject: [PATCH 38/45] feat: added approve logic to staking --- .../HolographicConsensusCard.tsx | 10 ++++- .../HolographicConsensusModal.tsx | 45 +++++++++++++++---- .../HolographicConsensusCard/types.ts | 1 + 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index e3382e1d..502add8b 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -68,6 +68,12 @@ export const HolographicConsensusCard = ({ let stakeTokenAddress: string = null; let stakeTokenInfo: TokenInfoWithType = null; + let votingMachineAddress: string = null; + + if (schemeData && schemeData.length) { + const { votingMachine } = schemeData[0]; + votingMachineAddress = votingMachine?.id; + } try { stakeTokenAddress = schemeData[0]?.votingMachine?.stakingTokenAddress; @@ -279,14 +285,14 @@ export const HolographicConsensusCard = ({ proposalState={proposalState} proposalTotalStakes={proposalTotalStakes} daoBounty={daoBounty} + votingMachineAddress={votingMachineAddress} /> ); }; -// TODO: merge develop -// TODO: move deploy scripts to davi +// TODO: refactor scripts // TODO: unlock time: postponed untill useTimeDetail is implemented // ? border bottom of non-selected stake button? diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index 7b10cb68..2cfa96d0 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -15,7 +15,7 @@ import { Avatar } from 'components/Avatar'; import { bigNumberToNumber } from 'hooks/Guilds/conversions/useBigNumberToNumber'; import { - LockButton, + ConfirmStakeButton, ModalContainer, StakeIconButton, StakeSelectionContainer, @@ -26,6 +26,8 @@ import { calculatePotentialReward, checkUserStakeOption, } from './utils'; +import { useERC20Allowance } from 'hooks/Guilds/erc20/useERC20Allowance'; +import { useHookStoreProvider } from 'stores'; export const HolographicConsensusModal = ({ tokenInfo, @@ -38,15 +40,30 @@ export const HolographicConsensusModal = ({ proposalState, proposalTotalStakes, daoBounty, + votingMachineAddress, }: IHolographicConsensusModal) => { const theme = useTheme(); const { t } = useTranslation(); + const { + hooks: { + writers: { useApproveTokens }, + }, + } = useHookStoreProvider(); const previousStake = checkUserStakeOption(userAddress, stakeDetails); const [stakePercentage, setStakePercentage] = useState('0'); const staked = calculateBNPercentage(userStakeTokenBalance, stakePercentage); + const approveTokens = useApproveTokens(tokenInfo?.address as `0x${string}`); + + const { data: tokenAllowance } = useERC20Allowance( + tokenInfo?.address, + userAddress as `0x${string}`, + votingMachineAddress as `0x${string}` + ); + const isTokenAmountAllowed = tokenAllowance?.gte(staked); + const [selectedOption, setSelectedOption] = useState( previousStake === 'for' ? BigNumber.from(2) @@ -223,14 +240,24 @@ export const HolographicConsensusModal = ({ - { - stakeOnProposal(proposalId, selectedOption, staked); - }} - disabled={selectedStake === null || stakePercentage === '0'} - > - {t('members.locking.lock')} {tokenInfo?.symbol} - + {isTokenAmountAllowed === true ? ( + { + stakeOnProposal(proposalId, selectedOption, staked); + }} + disabled={selectedStake === null || stakePercentage === '0'} + > + {t('members.locking.lock')} {tokenInfo?.symbol} + + ) : ( + + approveTokens(votingMachineAddress, staked.toString()) + } + > + {t('actionBuilder.approval.approve')} {tokenInfo?.symbol} + + )} diff --git a/apps/davi/src/components/HolographicConsensusCard/types.ts b/apps/davi/src/components/HolographicConsensusCard/types.ts index 1db077ce..a737feaf 100644 --- a/apps/davi/src/components/HolographicConsensusCard/types.ts +++ b/apps/davi/src/components/HolographicConsensusCard/types.ts @@ -45,4 +45,5 @@ export interface IHolographicConsensusModal { proposalState: HolographicConsensusState; proposalTotalStakes: Proposal['totalStaked']; daoBounty: BigNumber; + votingMachineAddress: string; } From 73f90c88a7f460f513c0ee2c18ae8c72bac5488f Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 27 Mar 2023 13:50:59 -0300 Subject: [PATCH 39/45] fix: fix calculatePotentialReward bug and changed component name --- .../HolographicConsensusCard.styled.tsx | 2 +- .../HolographicConsensusCard/utils.test.tsx | 17 +++++++++++++++++ .../HolographicConsensusCard/utils.ts | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx index a1a2eb3f..c89e8b3a 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx @@ -84,7 +84,7 @@ export const StakeSelectionContainer = styled.div` border-radius: ${({ theme }) => theme.radii.curved}; `; -export const LockButton = styled(Button)` +export const ConfirmStakeButton = styled(Button)` height: 2.5rem; width: 100%; font-weight: 600; diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx b/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx index 8d43d4ff..b540d5a0 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx @@ -337,5 +337,22 @@ describe('calculatePotentialReward', () => { expect(result.toString()).toEqual(BigNumber.from(200).toString()); }); + + it('if the user selected no option, it should return zero', () => { + const userAddress = ZERO_ADDRESS; + const currentStake = BigNumber.from(0); + const userOption = null; + + const result = calculatePotentialReward( + mockProposalStakeDetailsEmpty, + currentStake, + userAddress, + userOption, + mockTotalStakedEmpty, + mockDaoBounty + ); + + expect(result.toString()).toEqual(BigNumber.from(0).toString()); + }); }); }); diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.ts b/apps/davi/src/components/HolographicConsensusCard/utils.ts index 6c320a91..03780e0d 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.ts +++ b/apps/davi/src/components/HolographicConsensusCard/utils.ts @@ -80,6 +80,7 @@ export const calculatePotentialReward = ( totalStaked: Proposal['totalStaked'], daoBounty: BigNumber ) => { + if (userOption === undefined || userOption === null) return BigNumber.from(0); const userStakedOptionIndex: number = userOption.toNumber() - 1; let userStakedOptionString: string; if (userStakedOptionIndex === 0) userStakedOptionString = 'against'; From 8eb7fce2b7aaca881519e0f2223928075c681385 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 27 Mar 2023 14:17:47 -0300 Subject: [PATCH 40/45] ci: moved DXD token transfer to development.js script on dev-scripts --- packages/dev-scripts/src/development.js | 34 +++++++++++++++++++------ 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/dev-scripts/src/development.js b/packages/dev-scripts/src/development.js index e2ca6312..501eaea5 100644 --- a/packages/dev-scripts/src/development.js +++ b/packages/dev-scripts/src/development.js @@ -1,4 +1,4 @@ -const hre = require("hardhat"); +const hre = require('hardhat'); /** * This script is intended to add custom actions to deployed contracts in @@ -6,17 +6,18 @@ const hre = require("hardhat"); */ async function main() { - console.log("Executing develoment scripts"); + console.log('Executing develoment scripts'); // Build develop-related actions here using hre.deployments await addDAOAvatarPermissions(); + await transferTokens(); } async function addDAOAvatarPermissions() { - const DAOAvatar = await hre.deployments.get("DAOAvatar"); + const DAOAvatar = await hre.deployments.get('DAOAvatar'); - const PermissionRegistry = await hre.artifacts.require("PermissionRegistry"); + const PermissionRegistry = await hre.artifacts.require('PermissionRegistry'); const permissionRegistryDeployed = await hre.deployments.get( - "PermissionRegistry" + 'PermissionRegistry' ); const permissionRegistry = await PermissionRegistry.at( permissionRegistryDeployed.address @@ -24,11 +25,28 @@ async function addDAOAvatarPermissions() { await permissionRegistry.setETHPermission( DAOAvatar.address, - "0x0000000000000000000000000000000000000000", - "0x00000000", + '0x0000000000000000000000000000000000000000', + '0x00000000', 0, true - ); + ); +} + +async function transferTokens() { + const { getNamedAccounts, deployments } = hre; + const { tokenHolder, tokenHolder2, tokenHolder3 } = await getNamedAccounts(); + + // DXDToken contract + const dxdTokenDeployed = await deployments.get('ERC20Mock'); + const DXDToken = await hre.artifacts.require('ERC20Mock'); + const dxdToken = await DXDToken.at(dxdTokenDeployed.address); + + await dxdToken.transfer(tokenHolder2, hre.web3.utils.toWei('100'), { + from: tokenHolder, + }); + await dxdToken.transfer(tokenHolder3, hre.web3.utils.toWei('100'), { + from: tokenHolder, + }); } main().catch((error) => { From 0db05c977b957555d8ac16e89a08548451480c9a Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 27 Mar 2023 14:27:24 -0300 Subject: [PATCH 41/45] fix: bug where it crashed because there were no stakes --- .../HolographicConsensusCard/HolographicConsensusCard.tsx | 3 ++- .../HolographicConsensusCard/HolographicConsensusModal.tsx | 1 + .../src/components/HolographicConsensusCard/utils.test.tsx | 2 +- apps/davi/src/components/HolographicConsensusCard/utils.ts | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 502add8b..d2675518 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -292,7 +292,8 @@ export const HolographicConsensusCard = ({ ); }; -// TODO: refactor scripts +// TODO: bug divide by zero +// TODO: message if there are no stakes // TODO: unlock time: postponed untill useTimeDetail is implemented // ? border bottom of non-selected stake button? diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index 2cfa96d0..7c4548b2 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -254,6 +254,7 @@ export const HolographicConsensusModal = ({ onClick={() => approveTokens(votingMachineAddress, staked.toString()) } + disabled={selectedStake === null || stakePercentage === '0'} > {t('actionBuilder.approval.approve')} {tokenInfo?.symbol} diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx b/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx index b540d5a0..5216cef5 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/utils.test.tsx @@ -314,7 +314,7 @@ describe('calculatePotentialReward', () => { currentStake, userAddress, userOption, - mockTotalStaked, + mockTotalStakedEmpty, mockDaoBounty ); diff --git a/apps/davi/src/components/HolographicConsensusCard/utils.ts b/apps/davi/src/components/HolographicConsensusCard/utils.ts index 03780e0d..1dc4d175 100644 --- a/apps/davi/src/components/HolographicConsensusCard/utils.ts +++ b/apps/davi/src/components/HolographicConsensusCard/utils.ts @@ -93,6 +93,8 @@ export const calculatePotentialReward = ( const stakedInUserVoteFixed: FixedNumber = FixedNumber.fromValue(stakedInUserVote); + if (stakedInUserVote.isZero()) return BigNumber.from(0); + const totalStakedWithoutDaoBounty = userCurrentStake .add(totalStaked[0]) .add(totalStaked[1]) From badccfb220694eda6fe301abf3c8312b3f1fdfa3 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 27 Mar 2023 14:34:05 -0300 Subject: [PATCH 42/45] fix: message if there are no stakes --- apps/davi/public/locales/en/translation.json | 3 +- .../HolographicConsensusCard.tsx | 2 - .../HolographicConsensusCard/StakeDetails.tsx | 43 +++++++++++-------- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/davi/public/locales/en/translation.json b/apps/davi/public/locales/en/translation.json index 9f1c2b1e..db911762 100644 --- a/apps/davi/public/locales/en/translation.json +++ b/apps/davi/public/locales/en/translation.json @@ -411,7 +411,8 @@ "potentialReward": "Potential reward", "lockWarning": "Your prediction will be locked until the proposal ends and you could lose your DXD if your prediction is wrong", "stakeOnProposal": "Stake on proposal", - "youCannotChangeYourPrediction": "You cannot change your prediction since you already staked in this proposal" + "youCannotChangeYourPrediction": "You cannot change your prediction since you already staked in this proposal", + "thereAreNoStakes": "There are no stakes for this option" }, "inputValidation": { "recipientAddressIsRequired": "Recipient address is required", diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index d2675518..40ed70e6 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -292,8 +292,6 @@ export const HolographicConsensusCard = ({ ); }; -// TODO: bug divide by zero -// TODO: message if there are no stakes // TODO: unlock time: postponed untill useTimeDetail is implemented // ? border bottom of non-selected stake button? diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx index 160d6309..8abb1784 100644 --- a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -5,6 +5,7 @@ import { IStake, IStakeDetails } from './types'; import { StakeDetailsContainer } from './HolographicConsensusCard.styled'; import { useEnsName } from 'wagmi'; import { shortenAddress } from 'utils'; +import { useTranslation } from 'react-i18next'; const Address = ({ address }: { address: `0x${string}` }) => { const { data: ensName } = useEnsName({ address, chainId: 1 }); @@ -17,26 +18,34 @@ export const StakeDetails = ({ tokenSymbol, tokenDecimals, }: IStakeDetails) => { + const { t } = useTranslation(); + return ( - {stakeDetails[selectedStake].map((stake: IStake) => { - const roundedBalance = bigNumberToNumber(stake.amount, tokenDecimals); - const address = stake.staker as `0x${string}`; + {stakeDetails[selectedStake].length === 0 ? ( + + {t('holographicConsensus.thereAreNoStakes')} + + ) : ( + stakeDetails[selectedStake].map((stake: IStake) => { + const roundedBalance = bigNumberToNumber(stake.amount, tokenDecimals); + const address = stake.staker as `0x${string}`; - return ( - -
- - {roundedBalance} {tokenSymbol} - - - ); - })} + return ( + +
+ + {roundedBalance} {tokenSymbol} + + + ); + }) + )} ); }; From ce54c4288975b9d4d1cf6263507216e3306f341d Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Mon, 27 Mar 2023 14:38:38 -0300 Subject: [PATCH 43/45] fix: minor changes --- .../HolographicConsensusCard/HolographicConsensusCard.tsx | 1 - .../HolographicConsensusCard/HolographicConsensusModal.tsx | 6 +++--- .../components/HolographicConsensusCard/StakeDetails.tsx | 6 +++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx index 40ed70e6..fe3c06eb 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.tsx @@ -293,6 +293,5 @@ export const HolographicConsensusCard = ({ }; // TODO: unlock time: postponed untill useTimeDetail is implemented -// ? border bottom of non-selected stake button? // maxValue of the speedometer is 10_000, so it's akin a 100% plus two decimal places. A value like 77,35% would be 7735 diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx index 7c4548b2..68f1c40f 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusModal.tsx @@ -7,12 +7,14 @@ import { useTranslation } from 'react-i18next'; import { BigNumber } from 'ethers'; import { resolveUri } from 'utils'; +import { useHookStoreProvider } from 'stores'; import { Flex } from 'components/primitives/Layout'; import { Button } from 'components/primitives/Button'; import { Slider } from 'components/primitives/Forms/Slider'; import { Text } from 'components/primitives/Typography'; import { Avatar } from 'components/Avatar'; import { bigNumberToNumber } from 'hooks/Guilds/conversions/useBigNumberToNumber'; +import { useERC20Allowance } from 'hooks/Guilds/erc20/useERC20Allowance'; import { ConfirmStakeButton, @@ -26,8 +28,6 @@ import { calculatePotentialReward, checkUserStakeOption, } from './utils'; -import { useERC20Allowance } from 'hooks/Guilds/erc20/useERC20Allowance'; -import { useHookStoreProvider } from 'stores'; export const HolographicConsensusModal = ({ tokenInfo, @@ -229,7 +229,7 @@ export const HolographicConsensusModal = ({ {/* //! Unlock time is hardcoded untill we implement useTimeDetail hook */} - March 14, 2023, 3:54pm UTC + March 14 (not implemented)
diff --git a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx index 8abb1784..59e2ccef 100644 --- a/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/StakeDetails.tsx @@ -1,11 +1,11 @@ +import { useEnsName } from 'wagmi'; +import { shortenAddress } from 'utils'; +import { useTranslation } from 'react-i18next'; import { Flex } from 'components/primitives/Layout'; import { Text } from 'components/primitives/Typography'; import { bigNumberToNumber } from 'hooks/Guilds/conversions/useBigNumberToNumber'; import { IStake, IStakeDetails } from './types'; import { StakeDetailsContainer } from './HolographicConsensusCard.styled'; -import { useEnsName } from 'wagmi'; -import { shortenAddress } from 'utils'; -import { useTranslation } from 'react-i18next'; const Address = ({ address }: { address: `0x${string}` }) => { const { data: ensName } = useEnsName({ address, chainId: 1 }); From 02e56740618fbce8ad4ce5b861224db22297034d Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 30 Mar 2023 09:37:20 -0300 Subject: [PATCH 44/45] fix: added spanish translations --- apps/davi/public/locales/es/translation.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/davi/public/locales/es/translation.json b/apps/davi/public/locales/es/translation.json index 35febdd3..3de4c4de 100644 --- a/apps/davi/public/locales/es/translation.json +++ b/apps/davi/public/locales/es/translation.json @@ -294,6 +294,7 @@ "yourVotingPower": "Tu Poder de Votación", "increaseVotingPower": "Incrementar Poder de Votación", "locking": { + "lock": "Bloquear", "locked": "Bloqueado", "unlocked": "Desbloqueado", "unlockedIn": "Desbloqueado en", @@ -301,6 +302,7 @@ "withdraw": "Retirar", "balance": "Balance", "unlockDate": "Fecha de desbloqueo", + "unlockTime": "Tiempo de desbloqueo", "spending": "Gasto", "max": "Max", "stakeTokens": "Invertir {{token}} tokens", @@ -431,5 +433,16 @@ }, "loading": "Cargando...", "showMore": "Mostrar más", - "showLess": "Mostrar menos" + "showLess": "Mostrar menos", + "holographicConsensus": { + "confirmPrediction": "Confirmar predicción", + "potentialReward": "Recompensa potencial", + "stakeOnProposal": "Apostar en la propuesta", + "predictions": "Predicciones", + "thereAreNoStakes": "No hay apuestas en esta opción", + "lockWarning": "Tu predicción estará bloqueada hasta que la propuesta termine y podrías perder tu DXD si tu predicción es incorrecta", + "placeYourPrediction": "Ingresa tu predicción para dirigir la propuesta", + "youCannotChangeYourPrediction": "No puedes cambiar tu predicción porque ya apostaste en esta propuesta" + } } + From ebcc56ad76beeb33dc6d81356f564fd6840eb9e1 Mon Sep 17 00:00:00 2001 From: dcrescimbeni Date: Thu, 30 Mar 2023 09:37:54 -0300 Subject: [PATCH 45/45] fix: refactored code to prevent duplication and fixed translation text --- .../HolographicConsensusCard.styled.tsx | 16 +++++----------- .../Guilds/conversions/useBigNumberToNumber.ts | 12 ++++-------- .../Guilds/conversions/useBigNumberToString.ts | 10 ++++------ .../useApproveTokens/useApproveTokens.tsx | 2 +- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx index c89e8b3a..1bd4dc4c 100644 --- a/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx +++ b/apps/davi/src/components/HolographicConsensusCard/HolographicConsensusCard.styled.tsx @@ -104,22 +104,16 @@ export const ProposalStateSpan = styled.span<{ }>` color: ${({ state, theme }) => { switch (state) { + case HolographicConsensusState.Boosted: + return theme.colors.active; + case HolographicConsensusState.Queued: + case HolographicConsensusState.PreBoosted: + return theme.colors.text; case HolographicConsensusState.None: - return theme.colors.grey; case HolographicConsensusState.Expired: - return theme.colors.grey; case HolographicConsensusState.ExecutedInQueue: - return theme.colors.grey; case HolographicConsensusState.ExecutedInBoost: - return theme.colors.grey; - case HolographicConsensusState.Queued: - return theme.colors.text; - case HolographicConsensusState.PreBoosted: - return theme.colors.text; - case HolographicConsensusState.Boosted: - return theme.colors.active; case HolographicConsensusState.QuietEndingPeriod: - return theme.colors.grey; default: return theme.colors.grey; } diff --git a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.ts b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.ts index 2b75fe84..78527131 100644 --- a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.ts +++ b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToNumber.ts @@ -9,14 +9,10 @@ export default function useBigNumberToNumber( ) { // I don't think we need to memoize this function // TODO: check if this is true - const stakeAmountParsed = useMemo(() => { - if (!number || decimals === null || decimals === undefined) return null; - - let formatted = Number.parseFloat(formatUnits(number, decimals)); - return ( - Math.round(formatted * Math.pow(10, precision)) / Math.pow(10, precision) - ); - }, [number, decimals, precision]); + const stakeAmountParsed = useMemo( + () => bigNumberToNumber(number, decimals, precision), + [number, decimals, precision] + ); return stakeAmountParsed; } diff --git a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.ts b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.ts index 9776ab71..f072d000 100644 --- a/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.ts +++ b/apps/davi/src/hooks/Guilds/conversions/useBigNumberToString.ts @@ -6,12 +6,10 @@ export default function useBigNumberToString( number: BigNumber, decimals: number = 0 ) { - const stakeAmountParsed = useMemo(() => { - if (!number) return null; - - let formatted = formatUnits(number, decimals); - return formatted; - }, [number, decimals]); + const stakeAmountParsed = useMemo( + () => bigNumberToString(number, decimals), + [number, decimals] + ); return stakeAmountParsed; } diff --git a/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/useApproveTokens.tsx b/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/useApproveTokens.tsx index dc5692fc..c38084fb 100644 --- a/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/useApproveTokens.tsx +++ b/apps/davi/src/stores/modules/1_5/writers/useApproveTokens/useApproveTokens.tsx @@ -18,7 +18,7 @@ export const useApproveTokens: IUseApproveTokens = tokenAddress => { const handleApproveTokens: IHandleApproveTokens = useCallback( async (daoTokenVault, amount = MAX_UINT) => { createTransaction( - t('actionBuilder.approvals.approveTokenSpending', { + t('actionBuilder.approval.approveTokenSpending', { tokenSymbol: tokenInfo?.symbol, }), async () => tokenContract?.approve(daoTokenVault, amount)