diff --git a/src/js/components/Drawers/HeaderProfileDrawer.jsx b/src/js/components/Drawers/HeaderProfileDrawer.jsx index 4cc04bea0..3a3b0616a 100644 --- a/src/js/components/Drawers/HeaderProfileDrawer.jsx +++ b/src/js/components/Drawers/HeaderProfileDrawer.jsx @@ -18,7 +18,7 @@ import AppObservableStore, { messageService } from '../../common/stores/AppObser import SettingsYourData from '../Settings/SettingsYourData'; import SettingsNotifications from '../Settings/SettingsNotifications'; import SettingsSectionFooter from '../Navigation/SettingsSectionFooter'; -import historyPush from "../../common/utils/historyPush"; +import historyPush from '../../common/utils/historyPush'; // const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite')); const SignInOptionsPanel = React.lazy(() => import(/* webpackChunkName: 'SignInOptionsPanel' */ '../../common/components/SignIn/SignInOptionsPanel')); diff --git a/src/js/components/Navigation/HeaderBar.jsx b/src/js/components/Navigation/HeaderBar.jsx index d5c09d63c..ae7db8cb2 100644 --- a/src/js/components/Navigation/HeaderBar.jsx +++ b/src/js/components/Navigation/HeaderBar.jsx @@ -367,7 +367,7 @@ class HeaderBar extends Component { more.css(highlight); break; case 'more/manage': - more.css(highlight); + more.css(highlight); break; default: break; diff --git a/src/js/components/Settings/SettingsYourData.jsx b/src/js/components/Settings/SettingsYourData.jsx index dab22debc..2e0495486 100644 --- a/src/js/components/Settings/SettingsYourData.jsx +++ b/src/js/components/Settings/SettingsYourData.jsx @@ -9,7 +9,7 @@ import DeleteYourAccountButton from './DeleteYourAccountButton'; import DeleteAllContactsButton from '../SetUpAccount/DeleteAllContactsButton'; import VoterStore from '../../stores/VoterStore'; import BrowserPushMessage from '../Widgets/BrowserPushMessage'; -import AppObservableStore from "../../common/stores/AppObservableStore"; +import AppObservableStore from '../../common/stores/AppObservableStore'; export default class SettingsYourData extends Component { constructor (props) { diff --git a/src/js/components/Settings/VoterEmailAddressEntry.jsx b/src/js/components/Settings/VoterEmailAddressEntry.jsx index 5892db594..d84cd2051 100644 --- a/src/js/components/Settings/VoterEmailAddressEntry.jsx +++ b/src/js/components/Settings/VoterEmailAddressEntry.jsx @@ -70,7 +70,7 @@ class VoterEmailAddressEntry extends Component { VoterActions.voterEmailAddressRetrieve(); if (this.emailInputRef && this.emailInputRef.current) { this.emailInputRef.current.blur(); - }; + } this._isMounted = true; } diff --git a/src/js/components/Share/shareButtonCommon.jsx b/src/js/components/Share/shareButtonCommon.jsx index bcfab1294..3dfff0ca8 100644 --- a/src/js/components/Share/shareButtonCommon.jsx +++ b/src/js/components/Share/shareButtonCommon.jsx @@ -465,7 +465,7 @@ export function ShareTwitter (props) { } const twitterRedirectUrl = `https://x.com/intent/post?url=${encodeURIComponent(linkToBeSharedTwitter)}&text=${encodeURIComponent('Please join me and vote.')}`; const buttonId = twitterButtonRef.current.id; - pushDataLayer(buttonId, 'x.com', 'externalShare', 'ballot', 'twitter',linkToBeSharedTwitter, twitterRedirectUrl); + pushDataLayer(buttonId, 'x.com', 'externalShare', 'ballot', 'twitter', linkToBeSharedTwitter, twitterRedirectUrl); }; return ( diff --git a/src/js/pages/Ballot/Ballot.jsx b/src/js/pages/Ballot/Ballot.jsx index 4803dbaed..3647a073a 100644 --- a/src/js/pages/Ballot/Ballot.jsx +++ b/src/js/pages/Ballot/Ballot.jsx @@ -55,7 +55,9 @@ import lazyPreloadPages from '../../utils/lazyPreloadPages'; import mapCategoryFilterType from '../../utils/map-category-filter-type'; import showBallotDecisionsTabs from '../../utilsApi/showBallotDecisionsTabs'; import { checkShouldUpdate, formatVoterBallotList } from './utils/ballotUtils'; -import lookupPageNameAndPageTypeDict from '../../utils/lookupPageNameAndPageTypeDict'; +import { getPageDetails } from '../../utils/lookupPageNameAndPageTypeDict'; + + const CompleteYourProfileOnBallot = React.lazy(() => import(/* webpackChunkName: 'CompleteYourProfile' */ '../../components/CompleteYourProfile/CompleteYourProfileOnBallot')); const DelayedLoad = React.lazy(() => import(/* webpackChunkName: 'DelayedLoad' */ '../../common/components/Widgets/DelayedLoad')); @@ -132,6 +134,7 @@ class Ballot extends Component { this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); // We need a ballotStoreListener here because we want the ballot to display before positions are received this.ballotStoreListener = BallotStore.addListener(this.onBallotStoreChange.bind(this)); + this.checkAndFireDataLayer(); this.campaignStoreListener = CampaignStore.addListener(this.onCampaignStoreChange.bind(this)); this.electionStoreListener = ElectionStore.addListener(this.onElectionStoreChange.bind(this)); this.issueStoreListener = IssueStore.addListener(this.onIssueStoreChange.bind(this)); @@ -363,18 +366,20 @@ class Ballot extends Component { navigator.serviceWorker.register('/sw.js'); window.serviceWorkerLoaded = true; } - const currentPage = lookupPageNameAndPageTypeDict(currentPathname); - const dataLayerObject = { - event: 'landing', - pageDetails: { - pageName: currentPage.pageName, - pageType: currentPage.pageType, - pathname: currentPathname, - }, - userDetails: VoterStore.getAnalyticsUserDetails(), - }; - TagManager.dataLayer({ dataLayer: dataLayerObject }); - } // end of componentDidMount + // const currentPage = lookupPageNameAndPageTypeDict(currentPathname); + // const dataLayerObject = { + // event: 'landing', + // pageDetails: { + // pageName: currentPage.pageName, + // pageType: currentPage.pageType, + // pathname: currentPathname, + // }, + // userDetails: VoterStore.getAnalyticsUserDetails(), + // }; + // TagManager.dataLayer({ dataLayer: dataLayerObject }); + } + + // eslint-disable-next-line camelcase,react/sort-comp UNSAFE_componentWillReceiveProps (nextProps) { @@ -446,6 +451,7 @@ class Ballot extends Component { componentDidUpdate (prevProps, prevState) { const { ballotWithAllItems, foundFirstRaceLevel, raceLevelFilterType } = this.state; + this.checkAndFireDataLayer(); // console.log('Ballot componentDidUpdate foundFirstRaceLevel: ', foundFirstRaceLevel); if (!foundFirstRaceLevel) { // We only need to be here if we haven't found the first Race level we are going to show, or we don't have a raceLevelFilterType identified @@ -1147,265 +1153,285 @@ class Ballot extends Component { }); } - render () { - renderLog('Ballot'); // Set LOG_RENDER_EVENTS to log all renders - // const ballotBaseUrl = '/ballot'; - const { classes, match: { params } } = this.props; - const googleCivicElectionIdFromUrl = params.google_civic_election_id || 0; - let ballotReturnedWeVoteIdFromUrl = params.ballot_returned_we_vote_id || ''; - ballotReturnedWeVoteIdFromUrl = ballotReturnedWeVoteIdFromUrl === 'none' ? '' : ballotReturnedWeVoteIdFromUrl; - const { location: { pathname } } = window; // search - let ballotLocationShortcutFromUrl = params.ballot_location_shortcut || ''; - ballotLocationShortcutFromUrl = ballotLocationShortcutFromUrl.trim(); - ballotLocationShortcutFromUrl = ballotLocationShortcutFromUrl === 'none' ? '' : ballotLocationShortcutFromUrl; + checkAndFireDataLayer = () => { + const { dataLayerFired } = this.state; + const voter = VoterStore.getVoter(); + + if (!dataLayerFired && voter && voter.we_voter_id) { + const dataLayerObject = { + event: 'landing', + pageDetails: getPageDetails(), + userDetalis: VoterStore.getAnalyticsUserDetails(), + }; + const electionDetails = BallotStore.getAnalyticsElectionDetails(); + if (electionDetails && electionDetails.electionDate) { + dataLayerObject.electionDetails = electionDetails; + } - const { - ballotSearchResults, ballotWithAllItems, ballotWithItemsFromCompletionFilterType, - completionLevelFilterType, doubleFilteredBallotItemsLength, - isSearching, loadingMoreItems, numberOfBallotItemsToDisplay, - scrolledDown, searchText, showFilterTabs, showLoadingBallotMessage, totalNumberOfBallotItems, - } = this.state; - let { raceLevelFilterType } = this.state; - if (!raceLevelFilterType) { - raceLevelFilterType = 'All'; // Make sure this is a string - } - // console.log(ballotWithAllItems); - // console.log('window.innerWidth:', window.innerWidth); - const textForMapSearch = VoterStore.getTextForMapSearch(); - // console.log('Ballot VoterStore.getTextForMapSearch(): ', textForMapSearch); + TagManager.dataLayer({ dataLayer: dataLayerObject }); + this.setState({ dataLayerFired: true}); + } + }; - if (showLoadingBallotMessage) { - return ( -
-
- - - - -
- Loading your ballot... -
-
- }> - - - Almost ready... - - - -
-
+ render () { + renderLog('Ballot'); // Set LOG_RENDER_EVENTS to log all renders + // const ballotBaseUrl = '/ballot'; + const { classes, match: { params } } = this.props; + const googleCivicElectionIdFromUrl = params.google_civic_election_id || 0; + let ballotReturnedWeVoteIdFromUrl = params.ballot_returned_we_vote_id || ''; + ballotReturnedWeVoteIdFromUrl = ballotReturnedWeVoteIdFromUrl === 'none' ? '' : ballotReturnedWeVoteIdFromUrl; + const { location: { pathname } } = window; // search + let ballotLocationShortcutFromUrl = params.ballot_location_shortcut || ''; + ballotLocationShortcutFromUrl = ballotLocationShortcutFromUrl.trim(); + ballotLocationShortcutFromUrl = ballotLocationShortcutFromUrl === 'none' ? '' : ballotLocationShortcutFromUrl; + + const { + ballotSearchResults, ballotWithAllItems, ballotWithItemsFromCompletionFilterType, + completionLevelFilterType, doubleFilteredBallotItemsLength, + isSearching, loadingMoreItems, numberOfBallotItemsToDisplay, + scrolledDown, searchText, showFilterTabs, showLoadingBallotMessage, totalNumberOfBallotItems, + } = this.state; + let { raceLevelFilterType } = this.state; + if (!raceLevelFilterType) { + raceLevelFilterType = 'All'; // Make sure this is a string + } + // console.log(ballotWithAllItems); + // console.log('window.innerWidth:', window.innerWidth); + const textForMapSearch = VoterStore.getTextForMapSearch(); + // console.log('Ballot VoterStore.getTextForMapSearch(): ', textForMapSearch); + + if (showLoadingBallotMessage) { + return ( +
+
+ + + + +
+ Loading your ballot... +
+
+ }> + + + Almost ready... + + + +
+
+
-
- ); - } + ); + } - let padBallotWindowBottomForCordova = ''; - if (isCordova()) { + let padBallotWindowBottomForCordova = ''; + if (isCordova()) { // If the previous render of the Ballot__Wrapper is less than the device height, pad it // temporarily for Cordova to stop the footer menu from bouncing when initially rendered - const { $, visualViewport: { height, scale } } = window; - const deviceHeight = height / scale; - const ballotWrapperHeight = $('[class^="class=Ballot__Wrapper"]').outerHeight() || 0; - if (ballotWrapperHeight < deviceHeight) { - padBallotWindowBottomForCordova = '625px'; // big enough for the largest phone with a footer menu + const { $, visualViewport: { height, scale } } = window; + const deviceHeight = height / scale; + const ballotWrapperHeight = $('[class^="class=Ballot__Wrapper"]').outerHeight() || 0; + if (ballotWrapperHeight < deviceHeight) { + padBallotWindowBottomForCordova = '625px'; // big enough for the largest phone with a footer menu + } } - } - const twoColumnDisplay = isIOSAppOnMac() || isIPadGiantSize(); - if (!ballotWithItemsFromCompletionFilterType) { - return ( - }> - -
-
- - If your ballot does not appear momentarily, - {' '} - {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} - }> + +
+
+ + If your ballot does not appear momentarily, + {' '} + {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} + this.toggleSelectBallotModal('', true, true)} style={{ color: 'rgb(6, 95, 212)' }} underline="hover" - > - please click here to enter an address - - {' '} - in the United States of America where you are registered to vote. - + > + please click here to enter an address + + {' '} + in the United States of America where you are registered to vote. + +
-
- - - ); - } + + + ); + } - // const voterAddressMissing = this.state.location === null; - - const sourcePollingLocationWeVoteId = BallotStore.currentBallotPollingLocationSource; - const ballotReturnedAdminEditUrl = `${webAppConfig.WE_VOTE_SERVER_ROOT_URL}b/${sourcePollingLocationWeVoteId}/list_edit_by_polling_location/?google_civic_election_id=${VoterStore.electionId()}&state_code=`; - // console.log('electionName: ', electionName, ', electionDayText: ', electionDayText); - - // const emptyBallotButton = completionLevelFilterType !== 'none' && !voterAddressMissing ? ( - // - // - // Ballot Not Released Yet - // - // - // Your next ballot isn't ready yet. Ballot data is usually available 45 days before each election. - // You can also - // {' '} - // AppObservableStore.setShowSelectBallotModalOnly(true)} - // > - // see what is on the ballot in other states - // - // . - // {!VoterStore.getVoterIsSignedIn() && ( - // <> - // {' '} - // Please sign in so we can notify you when your election data is available. - // - // )} - //
- //
- // WeVote uses ballot data aggregated from government, nonpartisan, and partisan sources. WeVote strives to provide a balanced selection of clearly identified voting guides from newspapers and media. Partisan voter guides are also provided from a diversity of sources and points-of-view. - //
- //
- // While you are waiting, connect with your friends who are already using WeVote. - //
- // - // }> - // - // - // - //
- // ) : ( - //
- // - //
- // - // Enter address where you are registered to vote - // - // )} - // // classes={this.props.classes} - // saveUrl={ballotBaseUrl} - // /> - //
- //
- // ); - - // console.log('ballotWithItemsFromCompletionFilterType: ', ballotWithItemsFromCompletionFilterType); - // Was: ballotWithItemsFromCompletionFilterType - const emptyBallot = ballotWithAllItems.length === 0 ? ( - - }> - -
- Connecting with our data providers... -
-
- -
- Requesting what is on your ballot... -
-
- -
- Waiting for response... -
-
- -
- Thank you for your patience... -
-
- {/* */} - {/*
*/} - {/*

{this.getEmptyMessageByFilterType(completionLevelFilterType)}

*/} - {/* {emptyBallotButton} */} - {/*
*/} - {/*
*/} -
-
- ) : null; - - const inRemainingDecisionsMode = completionLevelFilterType === 'filterRemaining'; - // console.log('inRemainingDecisionsMode: ', inRemainingDecisionsMode); - - if (ballotWithItemsFromCompletionFilterType.length === 0 && inRemainingDecisionsMode) { + // const voterAddressMissing = this.state.location === null; + + const sourcePollingLocationWeVoteId = BallotStore.currentBallotPollingLocationSource; + const ballotReturnedAdminEditUrl = `${webAppConfig.WE_VOTE_SERVER_ROOT_URL}b/${sourcePollingLocationWeVoteId}/list_edit_by_polling_location/?google_civic_election_id=${VoterStore.electionId()}&state_code=`; + // console.log('electionName: ', electionName, ', electionDayText: ', electionDayText); + + // const emptyBallotButton = completionLevelFilterType !== 'none' && !voterAddressMissing ? ( + // + // + // Ballot Not Released Yet + // + // + // Your next ballot isn't ready yet. Ballot data is usually available 45 days before each election. + // You can also + // {' '} + // AppObservableStore.setShowSelectBallotModalOnly(true)} + // > + // see what is on the ballot in other states + // + // . + // {!VoterStore.getVoterIsSignedIn() && ( + // <> + // {' '} + // Please sign in so we can notify you when your election data is available. + // + // )} + //
+ //
+ // WeVote uses ballot data aggregated from government, nonpartisan, and partisan sources. WeVote strives to provide a balanced selection of clearly identified voting guides from newspapers and media. Partisan voter guides are also provided from a diversity of sources and points-of-view. + //
+ //
+ // While you are waiting, connect with your friends who are already using WeVote. + //
+ // + // }> + // + // + // + //
+ // ) : ( + //
+ // + //
+ // + // Enter address where you are registered to vote + // + // )} + // // classes={this.props.classes} + // saveUrl={ballotBaseUrl} + // /> + //
+ //
+ // ); + + // console.log('ballotWithItemsFromCompletionFilterType: ', ballotWithItemsFromCompletionFilterType); + // Was: ballotWithItemsFromCompletionFilterType + const emptyBallot = ballotWithAllItems.length === 0 ? ( + + }> + +
+ Connecting with our data providers... +
+
+ +
+ Requesting what is on your ballot... +
+
+ +
+ Waiting for response... +
+
+ +
+ Thank you for your patience... +
+
+ {/* */} + {/*
*/} + {/*

{this.getEmptyMessageByFilterType(completionLevelFilterType)}

*/} + {/* {emptyBallotButton} */} + {/*
*/} + {/*
*/} +
+
+ ) : null; + + const inRemainingDecisionsMode = completionLevelFilterType === 'filterRemaining'; + // console.log('inRemainingDecisionsMode: ', inRemainingDecisionsMode); + + if (ballotWithItemsFromCompletionFilterType.length === 0 && inRemainingDecisionsMode) { // console.log('inRemainingDecisionsMode historyPush'); - historyPush(pathname); - } + historyPush(pathname); + } - let widthOverride = {}; - if (isAndroidSizeWide()) { - widthOverride = { width: '96px' }; - } - if (isSearching && isCordova()) { - widthOverride = { width: 'unset' }; - } + let widthOverride = {}; + if (isAndroidSizeWide()) { + widthOverride = { width: '96px' }; + } + if (isSearching && isCordova()) { + widthOverride = { width: 'unset' }; + } - let isFirstBallotItem = false; - let numberOfBallotItemsDisplayed = 0; - let showLoadingText = true; - let searchTextString = ''; - const showCompleteYourProfile = isWebApp(); - let paddingTop = ''; - if (isIPadMini()) { - paddingTop = '18%'; - } else if (isIPad11in()) { - paddingTop = '12%'; - } + let isFirstBallotItem = false; + let numberOfBallotItemsDisplayed = 0; + let showLoadingText = true; + let searchTextString = ''; + const showCompleteYourProfile = isWebApp(); + let paddingTop = ''; + if (isIPadMini()) { + paddingTop = '18%'; + } else if (isIPad11in()) { + paddingTop = '12%'; + } - return ( -
- }> - - - - -
-
-
- - Ballot - WeVote - {googleCivicElectionIdFromUrl ? ( - - ) : ( - <> - {ballotReturnedWeVoteIdFromUrl ? ( - - ) : ( - <> - {ballotLocationShortcutFromUrl ? ( - - ) : ( - - )} - - )} - - )} - -
- - + }> + + + + +
+
+
+ + Ballot - WeVote + {googleCivicElectionIdFromUrl ? ( + + ) : ( + <> + {ballotReturnedWeVoteIdFromUrl ? ( + + ) : ( + <> + {ballotLocationShortcutFromUrl ? ( + + ) : ( + + )} + + )} + + )} + +
+ + - -
- - { textForMapSearch || ballotWithItemsFromCompletionFilterType.length > 0 ? ( -
- { showBallotDecisionsTabs() && ( + /> + +
+ + { textForMapSearch || ballotWithItemsFromCompletionFilterType.length > 0 ? ( +
+ { showBallotDecisionsTabs() && ( <>

- )} - - { this.chipContainer = chips; }}> - { ballotWithItemsFromCompletionFilterType.length ? ( - <> - }> - + { this.chipContainer = chips; }}> + { ballotWithItemsFromCompletionFilterType.length ? ( + <> + }> + - - { showFilterTabs && ( + /> + + { showFilterTabs && (
this.setBallotItemFilterType('All', ballotWithItemsFromCompletionFilterType.length)} />
- )} - { showFilterTabs && ( - BALLOT_ITEM_FILTER_TYPES.map((oneTypeOfBallotItem) => { - const allBallotItemsByFilterType = this.state.ballotWithAllItems.filter((item) => { - if (oneTypeOfBallotItem === 'Measure') { - return item.kind_of_ballot_item === 'MEASURE'; - } else { - return oneTypeOfBallotItem === item.race_office_level; - } - }); - if (allBallotItemsByFilterType.length) { - const ballotItemsByFilterType = ballotWithItemsFromCompletionFilterType.filter((item) => { + )} + { showFilterTabs && ( + BALLOT_ITEM_FILTER_TYPES.map((oneTypeOfBallotItem) => { + const allBallotItemsByFilterType = this.state.ballotWithAllItems.filter((item) => { if (oneTypeOfBallotItem === 'Measure') { return item.kind_of_ballot_item === 'MEASURE'; } else { return oneTypeOfBallotItem === item.race_office_level; } }); - const ballotChip = ( - { + if (oneTypeOfBallotItem === 'Measure') { + return item.kind_of_ballot_item === 'MEASURE'; + } else { + return oneTypeOfBallotItem === item.race_office_level; + } + }); + const ballotChip = ( + this.setBallotItemFilterType(oneTypeOfBallotItem, ballotItemsByFilterType.length)} - /> - ); - return ( -
-
-
+ ); + return ( +
+
+
- {ballotChip} + > + {ballotChip} +
-
-
-
- +
+ { e.currentTarget.classList.remove(classes.badgeFocused); }} - > - {ballotChip} - + > + {ballotChip} + +
-
- ); - } else { - return null; - } - }) - )} - - ) : null} - - -
- ) : null} - + ); + } else { + return null; + } + }) + )} + + ) : null} + + +
+ ) : null} + +
-
- - -
- - - -
- - {/* eslint-disable-next-line no-nested-ternary */} - -
- {showCompleteYourProfile && ( + + +
+ + + +
+ + {/* eslint-disable-next-line no-nested-ternary */} + +
+ {showCompleteYourProfile && ( }> - )} - {emptyBallot} -
- {ballotWithItemsFromCompletionFilterType.length > 0 ? ( - + {ballotWithItemsFromCompletionFilterType.length > 0 ? ( + - ) : null} - - {(isSearching && searchText) && ( + /> + ) : null} + + {(isSearching && searchText) && ( Searching for " {searchText} " - )} - - {/* The rest of the ballot items */} -
- {(isSearching && ballotSearchResults && ballotSearchResults.length === 0) && ( + )} + + {/* The rest of the ballot items */} +
+ {(isSearching && ballotSearchResults && ballotSearchResults.length === 0) && ( Please enter new search terms to find results. - )} - {(isSearching ? ballotSearchResults : ballotWithItemsFromCompletionFilterType).map((item) => { + )} + {(isSearching ? ballotSearchResults : ballotWithItemsFromCompletionFilterType).map((item) => { // Ballot limited by items by race_office_level = (Federal, State, Local) or kind_of_ballot_item = (Measure) // console.log('raceLevelFilterType:', raceLevelFilterType, ', item:', item); - if ((raceLevelFilterType === 'All' || isSearching || + if ((raceLevelFilterType === 'All' || isSearching || (item.kind_of_ballot_item === raceLevelFilterType.toUpperCase()) || raceLevelFilterType === item.race_office_level)) { // console.log('Ballot item for BallotItemCompressed:', item); // {...item} - const key = item.we_vote_id; - // console.log('numberOfBallotItemsDisplayed:', numberOfBallotItemsDisplayed, ', numberOfBallotItemsToDisplay:', numberOfBallotItemsToDisplay); - if (numberOfBallotItemsDisplayed >= numberOfBallotItemsToDisplay) { - return null; - } - numberOfBallotItemsDisplayed += 1; - // console.log('numberOfBallotItemsDisplayed: ', numberOfBallotItemsDisplayed); - showLoadingText = numberOfBallotItemsDisplayed === 1; - // console.log('foundInArray:', item.foundInArray); - let foundInItemsAlreadyShown = 0; - let searchWordAlreadyShown = 0; - if (searchText) { - const wordsArray = searchText.split(' '); - searchTextString = wordsArray.map((oneItem) => { - const foundInStringItem = `${searchWordAlreadyShown ? ' or ' : ''}"${oneItem}"`; - searchWordAlreadyShown += 1; - return foundInStringItem; - }); - } - // console.log('-------- Ballot --------- numberOfBallotItemsDisplayed', numberOfBallotItemsDisplayed, item.we_vote_id); - isFirstBallotItem = numberOfBallotItemsDisplayed === 1; - return ( -
- }> - - <> - {!!(isSearching && searchTextString && item.foundInArray && item.foundInArray.length) && ( + const key = item.we_vote_id; + // console.log('numberOfBallotItemsDisplayed:', numberOfBallotItemsDisplayed, ', numberOfBallotItemsToDisplay:', numberOfBallotItemsToDisplay); + if (numberOfBallotItemsDisplayed >= numberOfBallotItemsToDisplay) { + return null; + } + numberOfBallotItemsDisplayed += 1; + // console.log('numberOfBallotItemsDisplayed: ', numberOfBallotItemsDisplayed); + showLoadingText = numberOfBallotItemsDisplayed === 1; + // console.log('foundInArray:', item.foundInArray); + let foundInItemsAlreadyShown = 0; + let searchWordAlreadyShown = 0; + if (searchText) { + const wordsArray = searchText.split(' '); + searchTextString = wordsArray.map((oneItem) => { + const foundInStringItem = `${searchWordAlreadyShown ? ' or ' : ''}"${oneItem}"`; + searchWordAlreadyShown += 1; + return foundInStringItem; + }); + } + // console.log('-------- Ballot --------- numberOfBallotItemsDisplayed', numberOfBallotItemsDisplayed, item.we_vote_id); + isFirstBallotItem = numberOfBallotItemsDisplayed === 1; + return ( +
+ }> + + <> + {!!(isSearching && searchTextString && item.foundInArray && item.foundInArray.length) && ( {searchTextString} {' '} @@ -1619,8 +1645,8 @@ class Ballot extends Component { return foundInStringItem; })} - )} - - - - -
- ); - } else { - return null; - } - })} - {doubleFilteredBallotItemsLength === 0 && + /> + +
+
+
+ ); + } else { + return null; + } + })} + {doubleFilteredBallotItemsLength === 0 && this.showUserEmptyOptions()} - {!!(totalNumberOfBallotItems) && ( + {!!(totalNumberOfBallotItems) && ( this.increaseNumberOfBallotItemsToDisplay()}> }> - )} - {!!(loadingMoreItems && totalNumberOfBallotItems && (numberOfBallotItemsToDisplay < totalNumberOfBallotItems)) && ( + )} + {!!(loadingMoreItems && totalNumberOfBallotItems && (numberOfBallotItemsToDisplay < totalNumberOfBallotItems)) && ( - )} - {(!isSearching && raceLevelFilterType !== 'All') && ( + )} + {(!isSearching && raceLevelFilterType !== 'All') && ( - )} -
-
- {/* Show links to this candidate in the admin tools */} - { (!twoColumnDisplay) && (this.state.voter && sourcePollingLocationWeVoteId) && (this.state.voter.is_admin || this.state.voter.is_verified_volunteer) ? ( - - Admin: - }> - + + {/* Show links to this candidate in the admin tools */} + { (!twoColumnDisplay) && (this.state.voter && sourcePollingLocationWeVoteId) && (this.state.voter.is_admin || this.state.voter.is_verified_volunteer) ? ( + + Admin: + }> + )} - /> - - - ) : null} - - - -
- - -
- ); - } + /> + + + ) : null} + + + +
+ + +
+ ); + } } Ballot.propTypes = { classes: PropTypes.object, diff --git a/src/js/pages/More/ManageMyCandidates.jsx b/src/js/pages/More/ManageMyCandidates.jsx index 607191083..1ff981635 100644 --- a/src/js/pages/More/ManageMyCandidates.jsx +++ b/src/js/pages/More/ManageMyCandidates.jsx @@ -26,11 +26,11 @@ export default function ManageMyCandidates () { // Selected candidate const [selectedId, setSelectedId] = useState(effectiveCandidates[0]?.id || ''); - const selected = effectiveCandidates.find(c => c.id === selectedId) || null; + const selected = effectiveCandidates.find((c) => c.id === selectedId) || null; // If the list ever changes (unlikely in demo), keep selection valid useEffect(() => { - if (!effectiveCandidates.find(c => c.id === selectedId)) { + if (!effectiveCandidates.find((c) => c.id === selectedId)) { setSelectedId(effectiveCandidates[0]?.id || ''); } }, [effectiveCandidates, selectedId]); @@ -112,18 +112,18 @@ Thanks for your help!`; } const text = await file.text(); const [headerLine, ...lines] = text.split(/\r?\n/).filter(Boolean); - const headers = headerLine.split(',').map(h => h.trim().toLowerCase()); + const headers = headerLine.split(',').map((h) => h.trim().toLowerCase()); const nameIdx = headers.indexOf('name'); const emailIdx = headers.indexOf('email'); const phoneIdx = headers.indexOf('phone'); - const rows = lines.map(line => { - const cols = line.split(',').map(c => c.trim()); + const rows = lines.map((line) => { + const cols = line.split(',').map((c) => c.trim()); return { name: nameIdx > -1 ? cols[nameIdx] : '', email: emailIdx > -1 ? cols[emailIdx] : '', phone: phoneIdx > -1 ? cols[phoneIdx] : '', }; - }).filter(r => r.name || r.email || r.phone); + }).filter((r) => r.name || r.email || r.phone); setImportedVoters(rows); alert(`Imported ${rows.length} voter(s) from CSV.`); e.target.value = ''; @@ -132,11 +132,12 @@ Thanks for your help!`; const handlePasteList = () => setShowPaste(true); const closePaste = () => setShowPaste(false); const handlePasteImport = () => { - const rows = pasteText.split(/\r?\n/).map(l => l.trim()).filter(Boolean).map(line => { - const parts = line.split(',').map(s => s.trim()); + const rows = pasteText.split(/\r?\n/).map((l) => l.trim()).filter(Boolean).map((line) => { + const parts = line.split(',').map((s) => s.trim()); return { name: parts[0] || '', email: parts[1] || '', phone: parts[2] || '' }; - }).filter(r => r.name || r.email || r.phone); - setImportedVoters(prev => [...prev, ...rows]); + }) + .filter((r) => r.name || r.email || r.phone); + setImportedVoters((prev) => [...prev, ...rows]); alert(`Imported ${rows.length} voter(s) from pasted list.`); setPasteText(''); setShowPaste(false); }; @@ -199,7 +200,9 @@ Thanks for your help!`; - Edit candidate profile + + {' '} + Edit candidate profile @@ -281,10 +284,14 @@ Thanks for your help!`; Preview invitation - Copy + + {' '} + Copy - Edit + + {' '} + Edit × @@ -321,7 +328,9 @@ Thanks for your help!`; Link will appear below text - Copy + + {' '} + Copy @@ -356,7 +365,12 @@ Thanks for your help!`; i - One person per line. Format: Name, Email, Phone (fields optional) + + One person per line. Format: + Name, Email, Phone + {' '} + (fields optional) +