Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/js/components/Ballot/BallotItemCompressed.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default class BallotItemCompressed extends PureComponent {
ballotItemDisplayName={ballotItemDisplayName}
candidateList={candidateList}
candidatesToShowForSearchResults={candidatesToShowForSearchResults}
disableAutoRollUp
// disableAutoRollUp
foundInSearchWords={foundInSearchWords}
isFirstBallotItem={isFirstBallotItem}
officeWeVoteId={weVoteId}
Expand Down
58 changes: 50 additions & 8 deletions src/js/components/Ballot/OfficeItemCompressed.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import OfficeHeaderTripleDotMenu from '../BallotItem/OfficeHeaderTripleDotMenu';

const ShowMoreButtons = React.lazy(() => import(/* webpackChunkName: 'ShowMoreButtons' */ '../Widgets/ShowMoreButtons'));
const OfficeInfoModal = React.lazy(() => import(/* webpackChunkName: 'OfficeInfoModal' */ './OfficeInfoModal'));
const NUMBER_OF_CANDIDATES_TO_DISPLAY = 5;
const NUMBER_OF_CANDIDATES_TO_DISPLAY = 4;

// This is related to components/VoterGuide/VoterGuideOfficeItemCompressed
class OfficeItemCompressed extends Component {
Expand All @@ -30,7 +30,6 @@ class OfficeItemCompressed extends Component {
super(props);
this.state = {
candidateListLength: 0,
candidateListForDisplay: [],
showAllCandidates: false,
totalNumberOfCandidates: 0,
officeInfoModalOpen: false,
Expand Down Expand Up @@ -63,11 +62,9 @@ class OfficeItemCompressed extends Component {
}

onCandidateStoreChange () {
const { candidateList, officeWeVoteId } = this.props;
const { officeWeVoteId } = this.props;
const totalNumberOfCandidates = officeWeVoteId ? CandidateStore.getNumberOfCandidatesRetrievedByOffice(officeWeVoteId) : 0;
// const sortedCandidateList = sortCandidateList(candidateList || []);
this.setState({
// candidateListForDisplay: sortedCandidateList,
totalNumberOfCandidates,
});
}
Expand All @@ -80,9 +77,40 @@ class OfficeItemCompressed extends Component {
if (showAllCandidates || disableAutoRollUp) {
return sortedCandidateList;
}
return sortedCandidateList.slice(0, NUMBER_OF_CANDIDATES_TO_DISPLAY);
const numberOfCandidatesToRender = this.getCandidatesToRenderCount();
// console.log('numberOfCandidatesToRender: ', numberOfCandidatesToRender);
return sortedCandidateList.slice(0, numberOfCandidatesToRender);
}

getCandidatesToRenderCount = () => {
// How many candidates should we render? If voter has chosen or opposed 1+ candidates, only show those
const { candidateList, disableAutoRollUp } = this.props;
if (!candidateList || candidateList.length === 0) {
return 0;
}
// Dale 2026-07-18 I want to leave candidatesToShowForSearchResults in place for the next year in case we need it again.
// let { candidatesToShowForSearchResults } = this.props;
// candidatesToShowForSearchResults = candidatesToShowForSearchResults || [];
const candidatesToShowForSearchResults = [];
const { showAllCandidates } = this.state;
const supportedCandidatesList = candidateList.filter((candidate) => candidatesToShowForSearchResults.includes(candidate.we_vote_id) || (SupportStore.getVoterSupportsByBallotItemWeVoteId(candidate.we_vote_id) && !candidate.withdrawn_from_election));
const opposedCandidatesList = candidateList.filter((candidate) => candidatesToShowForSearchResults.includes(candidate.we_vote_id) || (SupportStore.getVoterOpposesByBallotItemWeVoteId(candidate.we_vote_id) && !candidate.withdrawn_from_election));
const supportedAndOpposedCandidatesList = supportedCandidatesList.concat(opposedCandidatesList);
// console.log('OfficeItemCompressed getCandidatesToRenderCount showAllCandidates: ', showAllCandidates, ', disableAutoRollUp:', disableAutoRollUp, ', supportedAndOpposedCandidatesList:', supportedAndOpposedCandidatesList, ', candidateList:', candidateList);
if (showAllCandidates) {
return candidateList.length;
} else if (disableAutoRollUp) {
return NUMBER_OF_CANDIDATES_TO_DISPLAY;
} else if (supportedCandidatesList && supportedCandidatesList.length > 0) {
// Used to be:
// if (supportedAndOpposedCandidatesList && supportedAndOpposedCandidatesList.length > 0)
// But we don't want to roll-up until an option has been chosen/supported
return supportedAndOpposedCandidatesList.length;
} else {
return NUMBER_OF_CANDIDATES_TO_DISPLAY;
}
};

showAllCandidates = () => {
this.setState({ showAllCandidates: true });
};
Expand Down Expand Up @@ -125,7 +153,8 @@ class OfficeItemCompressed extends Component {
const { hideOfficeHeader, isFirstBallotItem, officeWeVoteId, primaryParty, useHelpDefeatOrHelpWin } = this.props;
const { candidateListLength, showAllCandidates, totalNumberOfCandidates, moreInfoIconHovered } = this.state;
ballotItemDisplayName = toTitleCase(ballotItemDisplayName).replace('(Unexpired)', '(Remainder)');
const moreCandidatesToDisplay = candidateListLength > NUMBER_OF_CANDIDATES_TO_DISPLAY;
const candidatesToRenderCount = this.getCandidatesToRenderCount();
const moreCandidatesToDisplay = candidatesToRenderCount < totalNumberOfCandidates;
const officeExplanationExists = false; // TODO: Add logic to check if officeExplanation exists

return (
Expand Down Expand Up @@ -177,7 +206,7 @@ class OfficeItemCompressed extends Component {
goToCandidateLink={(candidateWeVoteId) => this.goToCandidateLink(candidateWeVoteId)}
useHelpDefeatOrHelpWin={useHelpDefeatOrHelpWin}
/>
{moreCandidatesToDisplay && (
{(moreCandidatesToDisplay) ? (
<Suspense fallback={<></>}>
<ShowMoreButtons
showMoreId={`officeItemCompressedShowMoreFooter-${officeWeVoteId}`}
Expand All @@ -186,6 +215,19 @@ class OfficeItemCompressed extends Component {
officeWeVoteId={officeWeVoteId}
/>
</Suspense>
) : (
<>
{(showAllCandidates && candidateListLength >= totalNumberOfCandidates) && (
<Suspense fallback={<></>}>
<ShowMoreButtons
showMoreId={`officeItemCompressedShowLessFooter-${officeWeVoteId}`}
showMoreButtonsLink={() => this.showLessCandidates()}
showMoreButtonWasClicked
showLessCustomText="show fewer candidates"
/>
</Suspense>
)}
</>
)}
{this.state.officeInfoModalOpen && (
<Suspense fallback={<div>Loading...</div>}>
Expand Down
8 changes: 7 additions & 1 deletion src/js/utils/positionFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,17 +253,19 @@ export function sortCandidateList (newCandidateList) {
let candidateModified;
let numberOfOpposePositionsForScore = 0;
let numberOfSupportPositionsForScore = 0;
let voterOpposesBallotItem;
let voterSupportsBallotItem;

// Prepare an array of candidate names that are supported by voter
unsortedCandidateList.forEach((candidate) => {
ballotItemStatSheet = SupportStore.getBallotItemStatSheet(candidate.we_vote_id, candidate.politician_we_vote_id);
// console.log('ballotItemStatSheet:', ballotItemStatSheet);
if (ballotItemStatSheet) {
({ numberOfOpposePositionsForScore, numberOfSupportPositionsForScore, voterSupportsBallotItem } = ballotItemStatSheet);
({ numberOfOpposePositionsForScore, numberOfSupportPositionsForScore, voterOpposesBallotItem, voterSupportsBallotItem } = ballotItemStatSheet);
// voterIssuesScoreForCandidate = IssueStore.getIssuesScoreByBallotItemWeVoteId(candidate.we_vote_id);
candidateModified = { ...candidate };
candidateModified.voterNetworkScoreForCandidate = Math.abs(numberOfSupportPositionsForScore - numberOfOpposePositionsForScore);
candidateModified.voterOpposesBallotItem = voterOpposesBallotItem;
candidateModified.voterSupportsBallotItem = voterSupportsBallotItem;
// console.log('candidateModified:', candidateModified);
unsortedCandidateListModified.push(candidateModified);
Expand All @@ -275,8 +277,12 @@ export function sortCandidateList (newCandidateList) {
sortedCandidateList = unsortedCandidateListModified;
// Start by ordering by twitter_followers_count
sortedCandidateList.sort((optionA, optionB) => optionB.twitter_followers_count - optionA.twitter_followers_count);
// Move candidates with the highest supporters count to the top of the list
sortedCandidateList.sort((optionA, optionB) => optionB.supporters_count - optionA.supporters_count);
// Move candidates with the highest personalized score to the top of the list
sortedCandidateList.sort((optionA, optionB) => optionB.voterNetworkScoreForCandidate - optionA.voterNetworkScoreForCandidate);
// Move candidates opposed by the voter to the top of list
sortedCandidateList.sort((optionA, optionB) => (optionB.voterOpposesBallotItem ? 1 : 0) - (optionA.voterOpposesBallotItem ? 1 : 0));
// Move candidates supported by the voter to the top of list
sortedCandidateList.sort((optionA, optionB) => (optionB.voterSupportsBallotItem ? 1 : 0) - (optionA.voterSupportsBallotItem ? 1 : 0));
// Move withdrawn candidates to the bottom of list
Expand Down
8 changes: 6 additions & 2 deletions src/js/utilsApi/showBallotDecisionsTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import { isWebApp } from '../common/utils/isCordovaOrWebApp';
import BallotStore from '../stores/BallotStore'; // eslint-disable-line import/no-cycle

export default function showBallotDecisionsTabs () {
// Dale 2026-07-18 I would like showBallotDecisionsTabs to not be based on mobile vs. desktop, but only based on if ballot choices have been made.
// WV-679 is the ticket where the UX team is reworking the design for in all screen sizes.

// src/js/common/utils/isMobileScreenSize.js should be used to avoid problems, 500 is an imperfect criteria
const isMobileScreenSizeForShowBallotDecisionsTabs = window.innerWidth < 500;
// const isMobileScreenSizeForShowBallotDecisionsTabs = window.innerWidth < 500;
// console.log('window.innerWidth:', window.innerWidth, ', isMobileScreenSizeForShowBallotDecisionsTabs:', isMobileScreenSizeForShowBallotDecisionsTabs);
return (BallotStore.ballotLength !== BallotStore.ballotRemainingChoicesLength) &&
(BallotStore.ballotRemainingChoicesLength > 0) &&
!isMobileScreenSizeForShowBallotDecisionsTabs &&
// !isMobileScreenSizeForShowBallotDecisionsTabs &&
isWebApp(); // November 2025: Disabled for Cordova until the feature is finished and released to production
}
Loading