Skip to content

Commit

Permalink
Add an election progress bar (#4556)
Browse files Browse the repository at this point in the history
* Fix 4006: ElectionProgressBar.tsx

* Fix 4006: adjusting the tooltip's arrow to progress

* Fix 4006 : fix lint issue

* Fix 4006 : Fixed test.tsx

* Fix 4006 : Updted the progress bar description by following figma

* Fix 4006: updated the code by Thesan's suggestion

* Updated progress bar to remove idle block and fix comment issue

* Added storybook and removed idle section since idlePeriod == 1

* adjust sample value for currentBlock in stories.tsx

* moved the idle period to the first

* Updated the changes for UI

* Updated the suggestion

* refactored stage parameters calculation

* Refactoerd description update code

* Merge dev into branch

* Fixed the issue after merged dev

* yarn lint:fix

* Updated the code by following Thesan's

* added useCouncilPeriodInformation

* updated the election.tsx

* updated the code

* lint issue

* Remove `remainingPeriod` check

* Updated for responsive layout

* updated responsive card & added genersis block timestamp

* updated date calculation

---------

Co-authored-by: Mark Gui <[email protected]>
Co-authored-by: Theophile Sandoz <[email protected]>
  • Loading branch information
3 people authored Dec 19, 2023
1 parent 4b9a450 commit 1267cf9
Show file tree
Hide file tree
Showing 7 changed files with 789 additions and 27 deletions.
163 changes: 163 additions & 0 deletions packages/ui/src/app/pages/Election/Election.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { Meta, StoryContext, StoryObj } from '@storybook/react'
import { FC } from 'react'

import { GetCurrentElectionDocument } from '@/council/queries'
import { joy } from '@/mocks/helpers'
import { MocksParameters } from '@/mocks/providers'

import { Election } from './Election'

type Args = {
electionStage: 'announcing' | 'revealing' | 'voting' | 'inactive'
remainingPeriod: number
}

type Story = StoryObj<FC<Args>>

export default {
title: 'Pages/Election/Election',
component: Election,
argTypes: {
electionStage: {
control: { type: 'radio' },
options: ['inactive', 'announcing', 'voting', 'revealing'],
},
},
args: {
electionStage: 'announcing',
remainingPeriod: 10000,
},
parameters: {
currentBlock: 480_2561,
idlePeriodDuration: 14400,
budgetRefillPeriod: 14400,
announcingPeriodDuration: 129600,
voteStageDuration: 43200,
revealStageDuration: 43200,
mocks: ({ args, parameters }: StoryContext<Args>): MocksParameters => {
const councilStageDuration =
parameters[args.electionStage === 'inactive' ? 'idlePeriodDuration' : 'announcingPeriodDuration']
return {
chain: {
consts: {
council: {
councilSize: 3,
idlePeriodDuration: parameters.idlePeriodDuration,
announcingPeriodDuration: parameters.announcingPeriodDuration,
budgetRefillPeriod: parameters.budgetRefillPeriod,
minCandidateStake: joy(166_666.666666),
},
referendum: {
voteStageDuration: parameters.voteStageDuration,
revealStageDuration: parameters.revealStageDuration,
minimumStake: joy(166.666666666),
},
},
rpc: {
chain: {
subscribeNewHeads: {
number: parameters.currentBlock,
},
},
},
query: {
council: {
stage: {
stage: {
isIdle: args.electionStage === 'inactive',
isAnnouncing: args.electionStage === 'announcing',
},
changedAt: Math.max(0, parameters.currentBlock - councilStageDuration + args.remainingPeriod),
},
},
referendum: {
stage: {
isVoting: args.electionStage === 'voting',
isRevealing: args.electionStage === 'revealing',
asVoting: {
started: Math.max(0, parameters.currentBlock - parameters.voteStageDuration + args.remainingPeriod),
},
asRevealing: {
started: Math.max(0, parameters.currentBlock - parameters.revealStageDuration + args.remainingPeriod),
},
},
},
},
},
gql: {
queries: [
{
query: GetCurrentElectionDocument,
data: {
electionRounds: [
{
__typename: 'ElectionRound',
cycleId: 23,
candidates: [
{
id: '0000003s',
member: {
id: '0',
name: 'Jennifer_123',
rootAccount: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
controllerAccount: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
handle: 'Jennifer_123',
isVerified: true,
isFoundingMember: true,
isCouncilMember: false,
roles: [
{
__typename: 'Worker',
id: 'membershipWorkingGroup-0',
createdAt: '2021',
isLead: true,
group: {
__typename: 'WorkingGroup',
name: 'Jennifer_123',
},
},
],
boundAccounts: [],
inviteCount: 0,
createdAt: '',
metadata: {
name: 'Jennifer_123',
},
},
noteMetadata: {
header: 'Jennifer_123',
bannerUri:
'https://upload.wikimedia.org/wikipedia/commons/b/be/Bliss_location%2C_Sonoma_Valley_in_2006.jpg',
bulletPoints: [
'Amet minim mollit non deserunt ullamco est sit liqua dolor',
'Amet minim mollit non deserunt ullamco est sit liqua dolor',
'Amet minim mollit non deserunt ullamco est sit liqua dolor Amet minim mollit non deserunt ullamco est sit liqua dolor Amet minim mollit non deserunt ullamco est sit liqua dolor Amet minim mollit non deserunt ullamco est sit liqua dolor',
],
description: 'Test member',
},
stake: '16660000000000',
stakingAccountId: 'j4Sba211111111',
status: 'ACTIVE',
votesReceived: [],
},
],
},
],
},
},
],
},
}
},
},
} satisfies Meta<Args>

export const Announcing: Story = {
args: { electionStage: 'announcing' },
}
export const Voting: Story = {
args: { electionStage: 'voting' },
}
export const Revealing: Story = {
args: { electionStage: 'revealing' },
}
42 changes: 22 additions & 20 deletions packages/ui/src/app/pages/Election/Election.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import React, { useEffect } from 'react'
import { useHistory } from 'react-router-dom'
import styled from 'styled-components'

import { PageHeaderWithButtons, PageHeaderWrapper, PageLayout } from '@/app/components/PageLayout'
import { ButtonsGroup, CopyButtonTemplate } from '@/common/components/buttons'
import { LinkIcon } from '@/common/components/icons'
import { Loading } from '@/common/components/Loading'
import { MainPanel } from '@/common/components/page/PageContent'
import { PageTitle } from '@/common/components/page/PageTitle'
import { BlockDurationStatistics, StatisticItem, Statistics } from '@/common/components/statistics'
import { StatisticItem, Statistics } from '@/common/components/statistics'
import { TextHuge } from '@/common/components/typography'
import { camelCaseToText } from '@/common/helpers'
import { useRefetchQueries } from '@/common/hooks/useRefetchQueries'
import { useResponsive } from '@/common/hooks/useResponsive'
import { MILLISECONDS_PER_BLOCK } from '@/common/model/formatters'
import { getUrl } from '@/common/utils/getUrl'
import { AnnounceCandidacyButton } from '@/council/components/election/announcing/AnnounceCandidacyButton'
Expand All @@ -21,11 +22,11 @@ import { RevealingStage } from '@/council/components/election/revealing/Revealin
import { VotingStage } from '@/council/components/election/voting/VotingStage'
import { ElectionRoutes } from '@/council/constants'
import { useCandidatePreviewViaUrlParameter } from '@/council/hooks/useCandidatePreviewViaUrlParameter'
import { useCouncilRemainingPeriod } from '@/council/hooks/useCouncilRemainingPeriod'
import { useCurrentElection } from '@/council/hooks/useCurrentElection'
import { useElectionStage } from '@/council/hooks/useElectionStage'
import { Election as ElectionType } from '@/council/types/Election'

import { ElectionProgressBar } from './components/ElectionProgressBar'
import { ElectionTabs } from './components/ElectionTabs'

const displayElectionRound = (election: ElectionType | undefined): string => {
Expand All @@ -37,10 +38,10 @@ const displayElectionRound = (election: ElectionType | undefined): string => {
}

export const Election = () => {
const { size } = useResponsive()
const { isLoading: isLoadingElection, election } = useCurrentElection()

const { isLoading: isLoadingElectionStage, stage: electionStage } = useElectionStage()
const remainingPeriod = useCouncilRemainingPeriod()
const history = useHistory()
useCandidatePreviewViaUrlParameter()

Expand Down Expand Up @@ -87,29 +88,21 @@ export const Election = () => {

const main = (
<MainPanel>
<Statistics>
<StyledStatistics size={size}>
<StatisticItem
title="Stage"
tooltipText="Elections occur periodically. Each has a sequence of stages referred to as the election cycle. Stages are: announcing period, voting period and revealing period."
tooltipLinkURL="https://joystream.gitbook.io/testnet-workspace/system/council#election"
>
<TextHuge bold>{camelCaseToText(electionStage)} Period</TextHuge>
</StatisticItem>
<BlockDurationStatistics
title="Period remaining length"
value={remainingPeriod}
tooltipText="Remaining length of current period before the next one starts."
tooltipLinkURL="https://joystream.gitbook.io/testnet-workspace/system/council#election"
/>
<StatisticItem
title="Election round"
title="Round"
tooltipText="Elections are held in consecutive rounds. This is the number of current election."
>
<TextHuge id="election-round-value" bold>
{displayElectionRound(election)}
</TextHuge>
</StatisticItem>
</Statistics>
<ElectionProgressBar
electionStage={electionStage}
title="Election Progress"
tooltipText="Elections occur periodically. Each has a sequence of stages referred to as the election cycle. Stages are: announcing period, voting period and revealing period."
/>
</StyledStatistics>
{electionStage === 'announcing' && (
<AnnouncingStage election={election} isLoading={!isRefetched && isLoadingElection} />
)}
Expand All @@ -120,3 +113,12 @@ export const Election = () => {

return <PageLayout header={header} main={main} />
}

const StyledStatistics = styled(Statistics)<{ size: string }>`
grid-template-columns: ${({ size }) =>
size === 'xxs'
? 'repeat(auto-fit, minmax(238px, 1fr))'
: size === 'xs'
? 'repeat(auto-fit, minmax(400px, 1fr))'
: '200px minmax(400px, 1fr)'};
`
Loading

2 comments on commit 1267cf9

@vercel
Copy link

@vercel vercel bot commented on 1267cf9 Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 1267cf9 Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

pioneer-2 – ./

pioneer-2-joystream.vercel.app
pioneer-2.vercel.app
pioneer-2-git-dev-joystream.vercel.app

Please sign in to comment.