Skip to content

Commit

Permalink
Implement envelope (#197)
Browse files Browse the repository at this point in the history
* Implement envelope

* Add translations

* Update translation

* Export vote package type

* Minor fixes

* Refactor component name
  • Loading branch information
selankon authored Aug 9, 2024
1 parent 0863a41 commit 82afecb
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 1 deletion.
116 changes: 116 additions & 0 deletions packages/chakra-components/src/components/Election/Envelope.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { useDatesLocale, useElection } from '@vocdoni/react-providers'
import {
ElectionResultsTypeNames,
ElectionStatus,
IChoice,
IQuestion,
IVoteEncryptedPackage,
IVotePackage,
PublishedElection,
} from '@vocdoni/sdk'
import { Text } from '@chakra-ui/react'
import { chakra, ChakraProps, useMultiStyleConfig } from '@chakra-ui/system'
import { format } from 'date-fns'

export type VotePackageType = IVotePackage | IVoteEncryptedPackage

export const Envelope = ({
votePackage,
...props
}: {
votePackage: VotePackageType
} & ChakraProps) => {
const styles = useMultiStyleConfig('Envelope')
const { election, localize } = useElection()
const locale = useDatesLocale()

if (
!election ||
'encrypted' in votePackage ||
!(election instanceof PublishedElection) ||
election?.status === ElectionStatus.CANCELED
)
return null

if (election?.electionType.secretUntilTheEnd && election.status !== ElectionStatus.RESULTS) {
return (
<Text sx={styles.secret} {...props}>
{localize('results.secret_until_the_end', {
endDate: format(election.endDate, localize('results.date_format'), { locale }),
})}
</Text>
)
}

return (
<chakra.div sx={styles.wrapper} {...props}>
{election.questions.map((q, i) => {
return (
<chakra.div sx={styles.question}>
<Text sx={styles.title}>{localize('envelopes.question_title', { title: q.title.default })}</Text>
<SelectedOptions question={q} questionIndex={i} votes={votePackage.votes} />
</chakra.div>
)
})}
</chakra.div>
)
}

const SelectedOptions = ({
question,
questionIndex,
votes,
}: {
question: IQuestion
questionIndex: number
votes: number[]
}) => {
const { election, localize } = useElection()
const styles = useMultiStyleConfig('Envelope')

if (!election || !(election instanceof PublishedElection)) return null

const selectedOptions: IChoice[] = []
switch (election.resultsType.name) {
case ElectionResultsTypeNames.MULTIPLE_CHOICE:
const abstainValues = election.resultsType?.properties?.abstainValues ?? []
let abstainCount = 0
votes.forEach((v) => {
if (abstainValues.includes(v.toString())) {
abstainCount++
return
}
selectedOptions.push(question.choices[v])
})
if (abstainCount > 0) {
selectedOptions.push({
title: {
default: localize('envelopes.envelope_abstain_count', { count: abstainCount }),
},
results: abstainCount.toString(),
value: -1,
} as IChoice)
}
break
case ElectionResultsTypeNames.APPROVAL:
votes.forEach((v, i) => {
if (v > 0) selectedOptions.push(question.choices[i])
})
break
case ElectionResultsTypeNames.SINGLE_CHOICE_MULTIQUESTION:
selectedOptions.push(question.choices[votes[questionIndex]])
break
default:
selectedOptions.push(question.choices[votes[0]])
}

return (
<>
{selectedOptions.map((c, i) => (
<chakra.div key={i} sx={styles.choiceWrapper}>
<Text sx={styles.choiceTitle}>{c.title.default}</Text>
</chakra.div>
))}
</>
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './Actions'
export * from './Description'
export * from './Envelope'
export * from './Election'
export * from './Header'
export * from './Questions'
Expand Down
4 changes: 4 additions & 0 deletions packages/chakra-components/src/i18n/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export const locales = {
end_process_button: 'End process',
},
empty: 'Apparently this process has no questions 🤔',
envelopes: {
envelope_abstain_count: 'Abstained {{ count }} times',
question_title: 'Option/s selected in "{{ title }}":',
},
errors: {
wrong_data_title: 'Wrong data',
wrong_data_description: 'The specified data is not correct',
Expand Down
38 changes: 38 additions & 0 deletions packages/chakra-components/src/theme/envelope.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system'

export const envelopeAnatomy = [
// all questions wrapper
'wrapper',
// individual question wrapper
'question',
// question title
'title',
// choice wrapper
'choiceWrapper',
// choice title
'choiceTitle',
// secret envelope (no results until the end text)
'secret',
]

const { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(envelopeAnatomy)

const baseStyle = definePartsStyle({
wrapper: {
flexDirection: 'column',
gap: 2,
},
title: {
pb: 0,
fontWeight: 'bold',
},
secret: {
color: 'red.200',
textAlign: 'center',
fontWeight: 'bold',
},
})

export const EnvelopeTheme = defineMultiStyleConfig({
baseStyle,
})
5 changes: 4 additions & 1 deletion packages/chakra-components/src/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ import { ConfirmModalTheme } from './confirm'
import { ElectionScheduleTheme as ElectionSchedule, ElectionTitleTheme as ElectionTitle } from './election'
import { HorizontalRulerTheme } from './layout'
import {
QuestionsTheme as ElectionQuestions,
QuestionsConfirmationTheme,
QuestionsTheme as ElectionQuestions,
QuestionsTipTheme,
QuestionsTypeBadgeTheme,
} from './questions'
import { ResultsTheme as ElectionResults } from './results'
import { VoteWeightTheme } from './vote'
import { EnvelopeTheme } from './envelope'

export const theme = {
components: {
Envelope: EnvelopeTheme,
ElectionQuestions,
ElectionResults,
ElectionSchedule,
Expand All @@ -27,6 +29,7 @@ export const theme = {

export * from './actions'
export * from './confirm'
export * from './envelope'
export * from './election'
export * from './layout'
export * from './questions'
Expand Down

0 comments on commit 82afecb

Please sign in to comment.