Skip to content

Commit

Permalink
Merge pull request #68 from oasisprotocol/ml/upcoming-vote
Browse files Browse the repository at this point in the history
Upcoming vote
  • Loading branch information
lubej authored Mar 28, 2024
2 parents ddae744 + a1ddc5d commit 5ee209e
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 16 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ different aspect of the Oasis Network as follows:
- Desert Owl represents _Knowledge_
- Fennec Fox stands for _Privacy_

The voting process is open to all Sapphire wallets holding a minimum of 100 ROSE tokens. The vote commences on _March
20, 2024, at 4:00:00 PM GMT+1_ and concludes on _March 27, 2024, at 4:00:00 PM GMT+1_. At the closure of the vote, the
results will be promptly available and no further voting will be permitted.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

<!-- ROADMAP -->
Expand Down
12 changes: 6 additions & 6 deletions frontend/.env.production
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
VITE_NETWORK=23294
VITE_WEB3_GATEWAY=https://sapphire.oasis.io
VITE_PROPOSAL_START_TIME=1710946800
VITE_PROPOSAL_START_TIME=0

VITE_CONTRACT_ACL_ALLOWALL=
VITE_CONTRACT_ACL_NATIVEBALANCE=
VITE_CONTRACT_POLLMANAGER=
VITE_CONTRACT_POLLMANAGER_ACL=
VITE_PROPOSAL_ID=
VITE_CONTRACT_ACL_ALLOWALL=0x0000000000000000000000000000000000000000
VITE_CONTRACT_ACL_NATIVEBALANCE=0x0000000000000000000000000000000000000000
VITE_CONTRACT_POLLMANAGER=0x0000000000000000000000000000000000000000
VITE_CONTRACT_POLLMANAGER_ACL=0x0000000000000000000000000000000000000000
VITE_PROPOSAL_ID=0x0000000000000000000000000000000000000000

VITE_REACT_APP_BUILD_VERSION=$REACT_APP_BUILD_SHA
VITE_REACT_APP_BUILD_DATETIME=$REACT_APP_BUILD_DATETIME
8 changes: 5 additions & 3 deletions frontend/src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import { Button } from '../Button'
import { StringUtils } from '../../utils/string.utils'
import { useInView } from 'react-intersection-observer'
import { LayoutBase } from '../LayoutBase'
import { UpcomingVotePage } from '../../pages/UpcomingVotePage'

export const Layout: FC = () => {
const {
state: { isInitialLoading, appError, isMobileScreen },
state: { isInitialLoading, appError, isMobileScreen, isUpcomingVote },
clearAppError,
} = useAppState()

Expand All @@ -32,7 +33,7 @@ export const Layout: FC = () => {
)}
>
<LogoIcon className={classes.logo} />
<ConnectWallet mobileSticky={isMobileScreen && !inView} />
{!isInitialLoading && !isUpcomingVote && <ConnectWallet mobileSticky={isMobileScreen && !inView} />}
</header>
<section className={classes.subHeader}>
<h1>Oasis Mascot</h1>
Expand All @@ -53,7 +54,8 @@ export const Layout: FC = () => {
{isInitialLoading && (
<Alert headerText="Please wait" type="loading" actions={<span>Fetching poll...</span>} />
)}
{!isInitialLoading && !appError && <Outlet />}
{!isInitialLoading && !appError && !isUpcomingVote && <Outlet />}
{!isInitialLoading && !appError && isUpcomingVote && <UpcomingVotePage />}
</section>
</LayoutBase>
</>
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/MascotCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface Props {
actions?: ReactElement
selected?: boolean
orientation?: MascotCardOrientation
className?: string
}

const orientationMap: Record<MascotCardOrientation, string> = {
Expand All @@ -27,6 +28,7 @@ export const MascotCard: FC<Props> = ({
actions,
selected,
orientation = 'vertical',
className,
}) => {
const {
state: { isDesktopScreen },
Expand All @@ -36,6 +38,7 @@ export const MascotCard: FC<Props> = ({
<Tilt tiltReverse tiltMaxAngleX={2} tiltMaxAngleY={10} {...(isDesktopScreen ? { scale: 1.05 } : {})}>
<div
className={StringUtils.clsx(
className,
classes.mascotCard,
selected ? classes.mascotCardSelected : undefined,
orientationMap[orientation]
Expand Down
81 changes: 81 additions & 0 deletions frontend/src/pages/UpcomingVotePage/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
.cardHeaderText {
font-size: 18px;
font-weight: 400;
line-height: 23px;
letter-spacing: 0;
text-align: center;
margin-bottom: 1.5625rem;
opacity: 0.8;
text-wrap: balance;
}

.mascotCards {
display: grid;
grid-template-columns: repeat(3, minmax(218px, 1fr));
grid-gap: 2.0625rem;
margin-bottom: 2.25rem;
}

.cardFooterText {
font-size: 14px;
font-weight: 500;
line-height: 21px;
letter-spacing: 0;
text-align: center;
color: var(--palatinate-blue);
text-wrap: balance;
}

.landingPageLink {
color: var(--dark-gunmetal);
}

@media screen and (max-width: 1000px) {
.mascotCards {
grid-template-columns: 1fr;
grid-auto-flow: row;
grid-gap: 1.25rem;
margin-bottom: 1.5rem;
}

.headerText {
font-size: 16px;
font-weight: 400;
line-height: 130%;
letter-spacing: 0;
text-align: left;
margin-top: 0.625rem;
margin-bottom: 2rem;
}

.landingPageLink {
color: var(--white);
}

.cardFooterText {
font-size: 16px;
font-weight: 400;
line-height: 130%;
letter-spacing: -0.03em;
}
}

@media screen and (min-width: 1000px) {
.mascotCard {
&.mascotCard {
&.mascotCard {
height: 368px;
}
}
}

.cardFooterText {
margin-top: auto;
}

.upcomingVotePageCard {
&.upcomingVotePageCard {
min-height: 450px;
}
}
}
52 changes: 52 additions & 0 deletions frontend/src/pages/UpcomingVotePage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { FC } from 'react'
import { Card } from '../../components/Card'
import classes from './index.module.css'
import { MascotCard } from '../../components/MascotCard'
import { POLL_CHOICES, VOTING_LANDING_PAGE_URL } from '../../constants/config'
import { useAppState } from '../../hooks/useAppState'

// TODO: Mark this page for removal
export const UpcomingVotePage: FC = () => {
const {
state: { isMobileScreen, isDesktopScreen },
} = useAppState()

const headerText = (
<>
Read more about the campaign&nbsp;
<a
className={classes.landingPageLink}
href={VOTING_LANDING_PAGE_URL}
target="_blank"
rel="noopener noreferrer"
>
on our website
</a>
.
</>
)

return (
<>
{isMobileScreen && <p className={classes.headerText}>{headerText}</p>}
<Card className={classes.upcomingVotePageCard}>
{isDesktopScreen && <p className={classes.cardHeaderText}>{headerText}</p>}
<div className={classes.mascotCards}>
{POLL_CHOICES.map(({ name, description, imagePath }) => (
<MascotCard
key={name}
title={name}
description={description}
image={<img alt={name} src={imagePath} />}
className={classes.mascotCard}
/>
))}
</div>
<p className={classes.cardFooterText}>
Thank you for your vote! We’re running a second ballot in April. Please stay tuned as we announce
the new voting period.
</p>
</Card>
</>
)
}
1 change: 1 addition & 0 deletions frontend/src/providers/AppStateContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface AppStateProviderState {
appError: string
isDesktopScreen: boolean
isMobileScreen: boolean
isUpcomingVote: boolean
}

export interface AppStateProviderContext {
Expand Down
13 changes: 11 additions & 2 deletions frontend/src/providers/AppStateProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { StorageKeys } from '../constants/storage-keys'
import { MascotChoices } from '../types'
import { NumberUtils } from '../utils/number.utils'
import { useMediaQuery } from 'react-responsive'
import { toErrorString } from '../utils/errors'
import { UpcomingPollError, toErrorString } from '../utils/errors'

const localStorageStore = storage()

Expand All @@ -18,6 +18,7 @@ const appStateProviderInitialState: AppStateProviderState = {
appError: '',
isMobileScreen: false,
isDesktopScreen: false,
isUpcomingVote: false,
}

export const AppStateContextProvider: FC<PropsWithChildren> = ({ children }) => {
Expand Down Expand Up @@ -81,7 +82,15 @@ export const AppStateContextProvider: FC<PropsWithChildren> = ({ children }) =>
}

init().catch(ex => {
setAppError(toErrorString(ex as Error))
if (ex instanceof UpcomingPollError) {
setState(prevState => ({
...prevState,
isInitialLoading: false,
isUpcomingVote: true,
}))
} else {
setAppError(toErrorString(ex as Error))
}
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isVoidSignerConnected])
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/providers/Web3Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import {
handleKnownContractCallExceptionErrors,
handleKnownErrors,
handleKnownEthersErrors,
UpcomingPollError,
UnknownNetworkError,
} from '../utils/errors'
import { Web3Context, Web3ProviderContext, Web3ProviderState } from './Web3Context'
import { useEIP1193 } from '../hooks/useEIP1193'
import { BigNumberish, BrowserProvider, JsonRpcProvider, toBeHex } from 'ethers'
import { BigNumberish, BrowserProvider, JsonRpcProvider, toBeHex, ZeroAddress } from 'ethers'
import { PollManager__factory } from '@oasisprotocol/dapp-voting-backend/src/contracts'

const EMPTY_IN_DATA = new Uint8Array([])
Expand Down Expand Up @@ -208,6 +209,11 @@ export const Web3ContextProvider: FC<PropsWithChildren> = ({ children }) => {
throw new Error('[pollManagerWithoutSigner] not initialized!')
}

// TODO: Special case for zero address proposalId
if (VITE_PROPOSAL_ID === ZeroAddress) {
throw new UpcomingPollError()
}

return await pollManagerVoidSigner.PROPOSALS(toBeHex(VITE_PROPOSAL_ID)).catch(handleKnownErrors)
}

Expand Down
6 changes: 6 additions & 0 deletions frontend/src/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ export class UnknownNetworkError extends Error {
}
}

export class UpcomingPollError extends Error {
constructor(message = '') {
super(message)
}
}

export interface EIP1193Error extends Error {
code: number
}
Expand Down

0 comments on commit 5ee209e

Please sign in to comment.