Skip to content

Commit

Permalink
Add feature flags for ALL_STATS
Browse files Browse the repository at this point in the history
  • Loading branch information
ArendPeter committed Dec 12, 2024
1 parent 5dd69e5 commit d80973c
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 31 deletions.
4 changes: 4 additions & 0 deletions packages/frontend/src/components/Election/Results/Results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import VoterIntentWidget from "./components/VoterIntentWidget";
import SupportBlurb from "../SupportBlurb";
import ColumnDistributionWidget from "./components/ColumnDistributionWidget";
import NameRecognitionWidget from "./components/NameRecognitionWidget";
import ScoreRangeWidget from "./components/ScoreRangeWidget";

function STARResultsViewer({ filterRandomFromLogs }: {filterRandomFromLogs: boolean }) {
let i = 0;
Expand Down Expand Up @@ -63,6 +64,7 @@ function STARResultsViewer({ filterRandomFromLogs }: {filterRandomFromLogs: bool
<VoterProfileWidget candidates={sortedCandidates} topScore={5} frontRunners={sortedCandidates.slice(0, 2) as [Candidate, Candidate]}/>
<ColumnDistributionWidget/>
<NameRecognitionWidget/>
<ScoreRangeWidget/>
</WidgetContainer>
</DetailExpander>
</DetailExpander>
Expand Down Expand Up @@ -401,6 +403,8 @@ function PRResultsViewer() {
</WidgetContainer>
<WidgetContainer>
<ColumnDistributionWidget/>
<NameRecognitionWidget/>
<ScoreRangeWidget/>
</WidgetContainer>
</DetailExpander>
</DetailExpander>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,38 +33,30 @@ const ViewElectionResults = () => {
</Typography>
{isPending && <div> {t('results.loading_election')} </div>}

{data?.results.map((results, race_index) => (
<Results
key={`results-${race_index}`}
race={election.races[race_index]}
results={results}
/>
))}
<hr/>
<Box sx={{width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', p: 2}}>
<Box sx={{ width: '100%', maxWidth: 750, display: 'flex', justifyContent: 'space-between', flexDirection: { xs: 'column', sm: 'row' } }} >
{(election.settings.public_results === true) &&
<Box sx={{ width: '100%', p: 1, px:{xs: 5, sm: 1} }}>
<BallotDataExport election={election}/>
</Box>
}

{election.settings.voter_access !== 'closed' &&
<Box sx={{ width: '100%', p: 1, px:{xs: 5, sm: 1} }}>
<ShareButton url={`${window.location.origin}/${election.election_id}`}/>
</Box>
{data?.results.map((results, race_index) => (
<Results
key={`results-${race_index}`}
race={election.races[race_index]}
results={results}
/>
))}
<hr/>
<Box sx={{width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', p: 2}}>
<Box sx={{ width: '100%', maxWidth: 750, display: 'flex', justifyContent: 'space-between', flexDirection: { xs: 'column', sm: 'row' } }} >
{(election.settings.public_results === true) &&
<Box sx={{ width: '100%', p: 1, px:{xs: 5, sm: 1} }}>
<BallotDataExport election={election}/>
</Box>
}
<Box sx={{ width: '100%', p: 1, px:{xs: 5, sm: 1} }}>
<StyledButton
type='button'
variant='contained'
fullwidth
href={'https://www.equal.vote/donate'} >
{t('ballot_submitted.donate')}
</StyledButton>

{election.settings.voter_access !== 'closed' &&
<Box sx={{ width: '100%', p: 1, px:{xs: 5, sm: 1} }}>
<ShareButton url={`${window.location.origin}/${election.election_id}`}/>
</Box>
}
</Box>
</Box>
<a href='https://www.equal.vote/donate'>{t('ballot_submitted.donate')}</a>
</Paper>
</Box>
<SupportBlurb/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import Widget from "./Widget";
import useRace from "~/components/RaceContextProvider";
import { Divider, Typography } from "@mui/material";
import ResultsBarChart from "./ResultsBarChart";
import useFeatureFlags from "~/components/FeatureFlagContextProvider";

// candidates helps define the order
export default () => {
const {ballotsForRace} = useAnonymizedBallots();
const {t, race} = useRace();

const flags = useFeatureFlags();
if(!flags.isSet('ALL_STATS')) return <></>

let numColumns = [];
let whichColumns = [];
let totalColumns = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import Widget from "./Widget";
import useRace from "~/components/RaceContextProvider";
import { Divider, Typography } from "@mui/material";
import ResultsBarChart from "./ResultsBarChart";
import useFeatureFlags from "~/components/FeatureFlagContextProvider";

// candidates helps define the order
export default () => {
const {ballotsForRace} = useAnonymizedBallots();
const {t, race} = useRace();

console.log(race.candidates)
const flags = useFeatureFlags();
if(!flags.isSet('ALL_STATS')) return <></>

let numActive = Object.fromEntries(race.candidates.map(c => [c.candidate_id, {
name: c.candidate_name,
count: 0,
Expand All @@ -25,7 +28,7 @@ export default () => {

return <Widget title={t(`results.name_recognition_title`)}>
<Typography variant='h6'>{t(`results.name_recognition_sub_title`)}</Typography>
<ResultsBarChart data={Object.values(numActive).sort((a, b) => -(a.count-b.count))} xKey='count' percentage={true} percentDenominator={b.length}/>
<ResultsBarChart data={Object.values(numActive)} xKey='count' percentage={true} percentDenominator={b.length}/>
<Typography>{t(`results.name_recognition_blank_warning`)}</Typography>
</Widget>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import useAnonymizedBallots from "~/components/AnonymizedBallotsContextProvider";
import Widget from "./Widget";
import useRace from "~/components/RaceContextProvider";
import { Divider, Typography } from "@mui/material";
import ResultsBarChart from "./ResultsBarChart";
import useFeatureFlags from "~/components/FeatureFlagContextProvider";

// candidates helps define the order
export default () => {
const {ballotsForRace} = useAnonymizedBallots();
const {t, race} = useRace();

const flags = useFeatureFlags();
if(!flags.isSet('ALL_STATS')) return <></>

let numAtDiff = [];

const incIndex = (arr, index) => {
while(index >= arr.length){
arr.push({
name: arr.length,
count: 0
});
}
arr[index].count++;
}

ballotsForRace().forEach((scores) => {
incIndex(numAtDiff,
scores.reduce((prev,score) => Math.max(prev, score.score), 0) -
scores.reduce((prev,score) => Math.min(prev, score.score), 20)
)
})

return <Widget title={t(`results.score_range_title`)}>
<Typography variant='h6'>{t(`results.score_range_sub_title`)}</Typography>
<ResultsBarChart data={numAtDiff.reverse()} xKey='count' percentage={true} sortFunc={false}/>
<Typography sx={{'textAlign': 'left'}}>{t(`results.score_range_warning`)}</Typography>
</Widget>
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const flagDefinitions = {
'ELECTION_TESTIMONIALS': 'Enables the election testimonials widget on the landing page',
'PRECINCTS': 'Allows elections to groups voters by precinct',
'THEMES': "Let's user pick a theme for their UI (temporarily via the top-right account button)",
'ALL_STATS': 'Show all work in progress widgets under "Stats for Nerds"',
'FORCE_DISABLE_RANDOM_CANDIDATES': '(testing only) Disables random candidate order on ballots',
'FORCE_DISABLE_INSTRUCTION_CONFIRMATION': '(testing only) Disables confirmation prompt on ballots',
};
Expand Down
24 changes: 23 additions & 1 deletion packages/frontend/src/i18n/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -446,12 +446,34 @@ results:
column_distribution_which_title: Which {{preferences}} were used? !tip(columns_used)

name_recognition_title: Name Recognition
name_recognition_sub_title: Percent of voters who listed a non-blank score for each candidate
name_recognition_sub_title: How many voters gave a non-blank score for the candidate
name_recognition_blank_warning: >
Choosing not to score a candidate is identical to giving that candidate a zero.
However the voter's decision still gives us sense for the candidates they're
most familiar with.
score_range_title: Range of Scores
score_range_sub_title: Difference between maximum and minimum score on ballots
score_range_warning: >
In order to have a maximum impact on the scoring round of STAR Voting, voters need to
follow the instructions on the ballot and indicate at at least one zero (or blank),
and at least one five. This would result in a range of 5 for the voters scores.
That said their ballot will still make a full impact during the automatic runoff where
the voter's full vote goes to whichever candidate they ranked higher.
Voters who didn't use the full range, either didn't understand the instructions or chose
to use a smaller range on purpose. This could be as a protest vote expressing that no candidates deserve 5 stars,
or it could be the opposite choosing to express that they have a postive opinion of everyone.
Note that not the consequences for not following the instructions are relatively minor, whereas failing to follow
the instructions in RCV could get your ballot thrown out (like giving multiple candidates your first choice). Voters
are also far more likely to use the full range in political elections where voters have a strong opinion.
candidate_selector: '{{capital_candidate}}'

win_count: '{{count}} Wins'
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/config/SharedConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export const sharedConfig = {
FF_VOTER_FLAGGING: 'false',
FF_ELECTION_TESTIMONIALS: 'false',
FF_PRECINCTS: 'false',
FF_ALL_STATS: 'false',
};

0 comments on commit d80973c

Please sign in to comment.