Skip to content

Commit

Permalink
Merge pull request #11 from gnosisguild/web-feedback-2
Browse files Browse the repository at this point in the history
Feat: Enhance Poll UI and Functionality for Better User Experience
  • Loading branch information
auryn-macmillan authored May 15, 2024
2 parents f4a3650 + d80f22c commit 5153e7f
Show file tree
Hide file tree
Showing 18 changed files with 161 additions and 264 deletions.
2 changes: 1 addition & 1 deletion packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const App: React.FC = () => {
<Routes>
<Route path='/' element={<Landing />} />
<Route path='/about' element={<About />} />
<Route path='/daily' element={<DailyPoll />} />
<Route path='/current' element={<DailyPoll />} />
<Route path='/historic' element={<HistoricPoll />} />
<Route path='/result/:roundId/:type?' element={<PollResult />} />
<Route path='*' element={<Navigate to='/' replace />} />
Expand Down
9 changes: 8 additions & 1 deletion packages/client/src/components/Cards/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import React, { useEffect, useState } from 'react'
interface CardProps {
children: React.ReactNode
isDetails?: boolean
isActive?: boolean
checked?: boolean
onChecked?: (clicked: boolean) => void
}

const Card: React.FC<CardProps> = ({ children, isDetails, checked, onChecked }) => {
const Card: React.FC<CardProps> = ({ children, isActive, isDetails, checked, onChecked }) => {
const [isClicked, setIsClicked] = useState<boolean>(checked ?? false)

useEffect(() => {
Expand All @@ -20,6 +21,12 @@ const Card: React.FC<CardProps> = ({ children, isDetails, checked, onChecked })
setIsClicked(!isClicked)
}

useEffect(() => {
if (isActive) {
setIsClicked(false)
}
}, [isActive])

return (
<div
className={`
Expand Down
35 changes: 16 additions & 19 deletions packages/client/src/components/Cards/PollCard.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,40 @@
import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { PollOption } from '@/model/poll.model'
import { PollOption, PollResult } from '@/model/poll.model'
import VotesBadge from '@/components/VotesBadge'
import PollCardResult from '@/components/Cards/PollCardResult'
import { formatDate, markWinner } from '@/utils/methods'
import { formatDate, hasPollEndedByTimestamp, markWinner } from '@/utils/methods'

interface PollCardProps {
roundId: number
pollOptions: PollOption[]
totalVotes: number
date: string
}

const PollCard: React.FC<PollCardProps> = ({ roundId, pollOptions, totalVotes, date }) => {
const PollCard: React.FC<PollResult> = ({ roundId, options, totalVotes, date, endTime }) => {
const navigate = useNavigate()
const [results, setResults] = useState<PollOption[]>(pollOptions)
const [results, setResults] = useState<PollOption[]>(options)

const isActive = !hasPollEndedByTimestamp(endTime)

useEffect(() => {
const newPollOptions = markWinner(pollOptions)
const newPollOptions = markWinner(options)
setResults(newPollOptions)
}, [pollOptions])
}, [options])

const handleNavigation = () => {
navigate(`/result/${roundId}`)
isActive ? navigate('/current') : navigate(`/result/${roundId}`)
}

return (
<div
className='relative flex w-full cursor-pointer flex-col items-center justify-center space-y-4 rounded-3xl border-2 border-slate-600/20 bg-white/50 p-8 pt-2 shadow-lg md:max-w-[274px]'
className={`
${isActive ? 'scale-105 border-lime-400' : 'border-slate-600/20'}
relative flex min-h-[248px] w-full cursor-pointer flex-col items-center justify-center space-y-4 rounded-3xl border-2 bg-white/50 p-8 pt-2 shadow-lg md:max-w-[274px]`}
onClick={handleNavigation}
>
<div className='external-icon absolute right-4 top-4' />
<div className='external-icon absolute right-4 top-4' />
<div className='text-xs font-bold text-slate-600'>{formatDate(date)}</div>
<div className='flex space-x-8 '>
<PollCardResult results={results} totalVotes={totalVotes} />
<PollCardResult results={results} totalVotes={totalVotes} isActive={isActive} />
</div>

{isActive && <h2 className={`text-center text-2xl font-bold text-slate-600/50`}>Active</h2>}
<div className='absolute bottom-[-1rem] left-1/2 -translate-x-1/2 transform '>
<VotesBadge totalVotes={totalVotes} />
<VotesBadge totalVotes={totalVotes} isActive={isActive} />
</div>
</div>
)
Expand Down
28 changes: 16 additions & 12 deletions packages/client/src/components/Cards/PollCardResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ type PollCardResultProps = {
height?: number
width?: number
isResult?: boolean
isActive?: boolean
}
const PollCardResult: React.FC<PollCardResultProps> = ({ isResult, results, totalVotes }) => {
const PollCardResult: React.FC<PollCardResultProps> = ({ isResult, results, totalVotes, isActive }) => {
const calculatePercentage = (votes: number) => {
return ((votes / totalVotes) * 100).toFixed(0)
}
Expand All @@ -22,19 +23,22 @@ const PollCardResult: React.FC<PollCardResultProps> = ({ isResult, results, tota
<div
className={`flex w-full flex-col items-center justify-center ${isResult ? 'aspect-square space-y-6 max-sm:space-y-2' : 'space-y-4'}`}
>
<Card isDetails checked={poll.checked}>
<Card isDetails checked={totalVotes === 0 ? false : poll.checked} isActive={isActive}>
<p className={isResult ? 'text-8xl max-sm:p-5 max-sm:text-6xl' : 'text-5xl'}>{poll.label}</p>
</Card>
<div className={isResult ? 'space-y-2 max-sm:space-y-0' : ''}>
<h3
className={`text-center ${isResult ? 'text-h1' : 'text-h3'} font-bold ${poll.checked ? 'text-lime-400' : 'text-slate-600/50'}`}
>
{totalVotes ? calculatePercentage(poll.votes) : 0}%
</h3>
<p className={`text-center ${isResult ? 'text-2xl font-semibold' : 'text-xs font-bold'} text-slate-600/50`}>
{poll.votes} votes
</p>
</div>

{!isActive && (
<div className={isResult ? 'space-y-2 max-sm:space-y-0' : ''}>
<h3
className={`text-center ${isResult ? 'text-h1' : 'text-h3'} font-bold ${totalVotes > 0 && poll.checked ? 'text-lime-400' : 'text-slate-600/50'}`}
>
{totalVotes ? calculatePercentage(poll.votes) : 0}%
</h3>
<p className={`text-center ${isResult ? 'text-2xl font-semibold' : 'text-xs font-bold'} text-slate-600/50`}>
{poll.votes} votes
</p>
</div>
)}
</div>
</div>
))}
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/components/NavMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ interface NavMenuProps {}

const NAV_MENU_OPTIONS = [
{
name: 'Daily Poll',
name: 'Current Poll',
icon: <CalendarCheck />,
path: '/daily',
path: '/current',
},
{
name: 'Historic Polls',
Expand Down
7 changes: 5 additions & 2 deletions packages/client/src/components/VotesBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import React from 'react'

type VotesBadgeProps = {
totalVotes: number
isActive?: boolean
}

const VotesBadge: React.FC<VotesBadgeProps> = ({ totalVotes }) => {
const VotesBadge: React.FC<VotesBadgeProps> = ({ totalVotes, isActive }) => {
return (
<div className=' bg-white w-fit rounded-lg border-2 border-slate-600/20 p-2 py-1 text-center font-bold uppercase text-slate-800/50 shadow-md'>
<div
className={` ${isActive ? 'scale-105 border-lime-400' : 'border-slate-600/20'} w-fit rounded-lg border-2 bg-white p-2 py-1 text-center font-bold uppercase text-slate-800/50 shadow-md`}
>
{totalVotes} votes
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const VoteManagementProvider = ({ children }: VoteManagementProviderProps) => {
const [isLoading, setIsLoading] = useState<boolean>(false)
const [pollOptions, setPollOptions] = useState<Poll[]>([])
const [pastPolls, setPastPolls] = useState<PollResult[]>([])
const [txUrl, setTxUrl] = useState<string | undefined>(undefined)

/**
* Voting Management Methods
Expand Down Expand Up @@ -60,6 +61,13 @@ const VoteManagementProvider = ({ children }: VoteManagementProviderProps) => {

const getRoundStateLite = async (roundCount: number) => {
const roundState = await getRoundStateLiteRequest(roundCount)

if (roundState?.pk.length === 1 && roundState.pk[0] === 0) {
handleGenericError('getRoundStateLite', {
message: 'Enclave server failed generating the necessary pk bytes',
name: 'getRoundStateLite',
})
}
if (roundState) {
setRoundState(roundState)
setVotingRound({ round_id: roundState.id, pk_bytes: roundState.pk })
Expand All @@ -71,8 +79,8 @@ const VoteManagementProvider = ({ children }: VoteManagementProviderProps) => {
const getPastPolls = async (roundCount: number) => {
let results: PollResult[] = []
try {
for (let i = 0; i < roundCount; i++) {
const result = await getWebResult(i + 1)
for (let i = roundCount; i > 0; i--) {
const result = await getWebResult(i)
if (result) {
const convertedPoll = convertPollData(result)
results.push(convertedPoll)
Expand Down Expand Up @@ -104,6 +112,8 @@ const VoteManagementProvider = ({ children }: VoteManagementProviderProps) => {
pollOptions,
roundState,
pastPolls,
txUrl,
setTxUrl,
existNewRound,
getWebResult,
setPastPolls,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export type VoteManagementContextType = {
pollOptions: Poll[]
roundState: VoteStateLite | null
pastPolls: PollResult[]
txUrl: string | undefined
setTxUrl: React.Dispatch<React.SetStateAction<string | undefined>>
setPollOptions: React.Dispatch<React.SetStateAction<Poll[]>>
initialLoad: () => Promise<void>
existNewRound: () => Promise<void>
Expand Down
151 changes: 0 additions & 151 deletions packages/client/src/mocks/polls.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/client/src/model/poll.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface PollResult {
totalVotes: number
date: string
options: PollOption[]
endTime: number
}

export interface PollRequestResult {
Expand Down
Loading

0 comments on commit 5153e7f

Please sign in to comment.