Skip to content

Commit

Permalink
Adds teia polls page (#335)
Browse files Browse the repository at this point in the history
  • Loading branch information
jagracar authored Oct 17, 2023
1 parent 312938c commit 9f35b7d
Show file tree
Hide file tree
Showing 17 changed files with 744 additions and 21 deletions.
8 changes: 3 additions & 5 deletions src/atoms/input/TransferFields.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function TransferFields({
transfers,
onChange,
className,
round,
step,
children,
}) {
const handleChange = (index, parameter, value) => {
Expand Down Expand Up @@ -38,11 +38,9 @@ export default function TransferFields({
label={`${labels.amount} (${index + 1})`}
placeholder={placeholders?.amount ?? '0'}
min="0"
step={round ? 1 : 0.000001}
step={step}
value={transfer.amount}
onChange={(value) =>
handleChange(index, 'amount', round ? Math.round(value) : value)
}
onChange={(value) => handleChange(index, 'amount', value)}
className={className}
>
{children}
Expand Down
2 changes: 2 additions & 0 deletions src/components/header/main_menu/MainMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export const MainMenu = () => {
label="DAO governance"
route="dao"
/>

<MenuItem className={styles.menu_label} label="Polls" route="polls" />
<div className={styles.state_buttons}>
{/* <Toggle box onToggle={toggleTheme} toggled={theme === 'dark'} /> */}
<Toggle box label="ZEN" onToggle={setZen} toggled={zen} />
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const PATH = {
FAQ: '/faq',
CLAIM: '/claim',
DAO: '/dao',
POLLS: '/polls',
SYNC: '/sync',
MINT: '/mint',
OBJKT: '/objkt',
Expand Down Expand Up @@ -140,6 +141,7 @@ export const QUAKE_FUNDING_CONTRACT = 'KT1X1jyohFrZyDYWvCPXw9KvWxk2VDwxyg2g'
export const MOROCCO_QUAKE_FUNDING_CONTRACT =
'KT1RwXEP8Sj1UQDHPG4oEjRohBdzG2R7FCpA'

export const POLLS_CONTRACT = 'KT1NPELoSdKjKzfSs85hCTPcxWjuyJjoM4C5'
export const DAO_GOVERNANCE_CONTRACT = 'KT1VLLPBjSFFHMp9LxoRfA65cynkxeRDfQeX'
export const DAO_TOKEN_CONTRACT = 'KT1QrtA753MSv8VGxkDrKKyJniG5JtuHHbtV'
export const DAO_TOKEN_CLAIM_CONTRACT = 'KT1NrfV4e2qWqFrnrKyPTJth5wq2KP9VyBei'
Expand Down
111 changes: 111 additions & 0 deletions src/context/pollsStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { create } from 'zustand'
import {
persist,
createJSONStorage,
subscribeWithSelector,
} from 'zustand/middleware'
import { MichelsonMap } from '@taquito/taquito'
import { POLLS_CONTRACT} from '@constants'
import { Tezos, useUserStore } from './userStore'
import { useModalStore } from './modalStore'
import { stringToHex } from '@utils/string'

type OperationReturn = Promise<string | undefined>

interface PollsState {
/** Votes in an existing poll */
votePoll: (pollId: string, option: number, maxCheckpoints: number | null, callback?: any) => OperationReturn
/** Creates a new poll */
createPoll: (question: string, descriptionIpfsPath: string, voteWeightMethod: string, votePeriod: string, options: string[], callback?: any) => OperationReturn
}

export const usePollsStore = create<PollsState>()(
subscribeWithSelector(
persist(
(set, get) => ({
votePoll: async (pollId, option, maxCheckpoints, callback) => {
const handleOp = useUserStore.getState().handleOp
const showError = useModalStore.getState().showError
const step = useModalStore.getState().step

const modalTitle = 'Vote teia poll'
step(modalTitle, 'Waiting for confirmation', true)

try {
const contract = await Tezos.wallet.at(POLLS_CONTRACT)

const parameters = {
poll_id: parseInt(pollId),
option: option,
max_checkpoints: maxCheckpoints
}
const batch = contract.methodsObject.vote(parameters)
const opHash = await handleOp(batch, modalTitle)

callback?.()

return opHash
} catch (e) {
showError(modalTitle, e)
}
},
createPoll: async (question, descriptionIpfsPath, voteWeightMethod, votePeriod, options, callback) => {
const handleOp = useUserStore.getState().handleOp
const show = useModalStore.getState().show
const showError = useModalStore.getState().showError
const step = useModalStore.getState().step

const modalTitle = 'Create teia poll'

if (!question || question.length < 10) {
show(
modalTitle,
'The poll question must be at least 10 characters long'
)
return
}

if (options.length < 2) {
show(
modalTitle,
'The poll should have at least 2 options to vote'
)
return
}

step(modalTitle, 'Waiting for confirmation', true)

try {
const contract = await Tezos.wallet.at(POLLS_CONTRACT)

const parameters = {
question: stringToHex(question),
description: descriptionIpfsPath === ''
? stringToHex('')
: stringToHex(`ipfs://${descriptionIpfsPath}`),
options: MichelsonMap.fromLiteral(
Object.fromEntries(
options.map((option, index) => [index, stringToHex(option)])
)
),
vote_weight_method: { [voteWeightMethod]: [['unit']] },
vote_period: votePeriod
}
const batch = contract.methodsObject.create_poll(parameters)
const opHash = await handleOp(batch, modalTitle)

callback?.()

return opHash
} catch (e) {
showError(modalTitle, e)
}
},
}),
{
name: 'polls',
storage: createJSONStorage(() => localStorage), // or sessionStorage?
}
)
)
)
49 changes: 49 additions & 0 deletions src/data/swr.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,52 @@ export function useDaoMemberCount(minTokens) {

return [data ? parseInt(data) : 0, mutate]
}

export function usePolls(pollsStorage) {
const parameters = {
limit: 10000,
active: true,
select: 'key,value',
}
const { data, mutate } = useSWR(
pollsStorage?.polls
? [`/v1/bigmaps/${pollsStorage.polls}/keys`, parameters]
: null,
getTzktData
)

return [reorderBigmapData(data), mutate]
}

export function useUserPollVotes(address, pollsStorage) {
const parameters = {
'key.address': address,
limit: 10000,
active: true,
select: 'key,value',
}
const { data, mutate } = useSWR(
address && pollsStorage?.votes
? [`/v1/bigmaps/${pollsStorage.votes}/keys`, parameters]
: null,
getTzktData
)

return [reorderBigmapData(data, 'nat'), mutate]
}

export function usePollsUsersAliases(userAddress, polls) {
const addresses = new Set()

if (userAddress) {
addresses.add(userAddress)
}

if (polls) {
Object.values(polls).forEach((poll) => {
addresses.add(poll.issuer)
})
}

return useAliases(Array.from(addresses))
}
7 changes: 7 additions & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
DaoProposals,
SubmitDaoProposals,
} from '@pages/dao/tabs'
import { TeiaPolls } from '@pages/polls'
import { Polls, CreatePolls } from '@pages/polls/tabs'
import { FAQ } from '@pages/faq'
import { Home } from '@pages/home'
import FriendsFeed from '@pages/home/feeds/friends-feed'
Expand Down Expand Up @@ -148,6 +150,11 @@ const router = createBrowserRouter(
<Route path="submit" element={<SubmitDaoProposals />} />
<Route path="*" element={<DaoParameters />} />
</Route>
<Route path="polls/*" element={<TeiaPolls />}>
<Route index element={<Polls />} />
<Route path="create" element={<CreatePolls />} />
<Route path="*" element={<Polls />} />
</Route>
<Route path="tags/:tag" element={<Tags />} />
<Route path="tz/:address/*" element={<Display />}>
{display_routes}
Expand Down
1 change: 0 additions & 1 deletion src/pages/dao/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

.headline {
text-align: center;
margin-bottom: 1em 0;

> p {
margin: 1em 0;
Expand Down
10 changes: 4 additions & 6 deletions src/pages/dao/tabs/Proposals.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ function ProposalGroup({ status, proposals }) {
function ProposalList({ proposals, ...actions }) {
if (proposals.length !== 0) {
return (
<ul className={styles.proposal_list}>
<ul>
{proposals.map((proposal, index) => (
<li key={index}>
<div className={styles.proposal}>
Expand Down Expand Up @@ -278,12 +278,10 @@ function ProposalDescription({ proposal }) {

return (
<div>
<p>
<h3 className={styles.proposal_title}>
<span className={styles.proposal_id}>#{proposal.id}</span>
<span className={styles.proposal_title}>
{hexToString(proposal.title)}
</span>
</p>
{hexToString(proposal.title)}
</h3>

<p>
Proposed by{' '}
Expand Down
3 changes: 2 additions & 1 deletion src/pages/dao/tabs/Submit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ function TransferTezProposalForm({ callback }) {
}}
transfers={transfers}
onChange={setTransfers}
step="0.000001"
className={styles.proposal_form_field}
>
<Line />
Expand Down Expand Up @@ -349,8 +350,8 @@ function TransferTokenProposalForm({ callback }) {
}}
transfers={transfers}
onChange={setTransfers}
step="1"
className={styles.proposal_form_field}
round
>
<Line />
</TransferFields>
Expand Down
10 changes: 3 additions & 7 deletions src/pages/dao/tabs/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,8 @@
}
}

.proposal_list {
margin-top: 2em;
}

.proposal {
margin: 1em 0;
margin: 2em 0;

p {
margin: 0.5em 0;
Expand All @@ -51,14 +47,14 @@
}

.proposal_id {
margin-right: 0.5em;
margin-right: 1em;
padding: 0 1em;
text-align: center;
background-color: var(--gray-15);
}

.proposal_title {
font-weight: bold;
margin-bottom: 0.5em;
}

.user_vote {
Expand Down
29 changes: 29 additions & 0 deletions src/pages/polls/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Outlet } from 'react-router-dom'
import { Page } from '@atoms/layout'
import { Tabs } from '@atoms/tab'
import styles from '@style'

const TABS = [
{
title: 'Polls',
to: '',
},
{
title: 'Create',
to: 'create',
},
]

export function TeiaPolls() {
return (
<Page title="Teia polls">
<div className={styles.container}>
<h1 className={styles.headline}>Teia polls</h1>

<Tabs tabs={TABS} />

<Outlet />
</div>
</Page>
)
}
8 changes: 8 additions & 0 deletions src/pages/polls/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.container {
padding-bottom: 60px;
width: 100%;
}

.headline {
text-align: center;
}
Loading

0 comments on commit 9f35b7d

Please sign in to comment.