From e598d5a9f22e0107c462095874faa453c7e755ee Mon Sep 17 00:00:00 2001 From: stevepodell Date: Mon, 24 Feb 2025 16:26:57 -0800 Subject: [PATCH] Added reset password, which required a lot of changes and refactors This was a very messy merge... This is 95% done, but checking in so that we don't diverge so much again. We diverged a bit with admin rights for sessions. I left all the new stuff in parallel with the old stuff (server and client) and I'll migrate over to the new way represented as captureAccessRightsData on the client side. Still need to change over the MUI styles in the ResetYourPassword.jsx from MUI templates to our styles (they look different, and the difference does not add value). Navigating to /Tasks currently leaves the HeaderBar menu confused, will fix this. Spurious "Please sign in" after resetting password, will fix this. More testing needed -- the steps are pretty complex, with the need for immediate `useRef()` variables in some places to avoid (always losing) race conditions. --- src/js/common/utils/logging.js | 12 + src/js/components/Login/ResetYourPassword.jsx | 179 ++ src/js/components/Navigation/HeaderBar.jsx | 8 +- src/js/components/Person/PersonSummaryRow.jsx | 6 +- src/js/components/PrivateRoute.jsx | 9 +- src/js/components/Style/sharedStyles.js | 7 + src/js/components/Team/TeamHeader.jsx | 20 +- src/js/components/VerifySecretCodeModal.jsx | 82 +- src/js/config-template.js | 13 +- src/js/contexts/ConnectAppContext.jsx | 51 +- src/js/contexts/contextFunctions.jsx | 15 +- src/js/pages/Login.jsx | 152 +- .../PermissionsAdministration.jsx | 1 - src/js/pages/Teams.jsx | 2 +- src/js/react-query/WeConnectQuery.js | 7 +- src/js/react-query/mutations.jsx | 43 +- src/js/stores/VoterStore.js | 2682 ++++++++--------- src/js/utils/service.js | 212 +- 18 files changed, 1888 insertions(+), 1613 deletions(-) create mode 100644 src/js/components/Login/ResetYourPassword.jsx diff --git a/src/js/common/utils/logging.js b/src/js/common/utils/logging.js index b516f8c..31dc669 100644 --- a/src/js/common/utils/logging.js +++ b/src/js/common/utils/logging.js @@ -54,6 +54,18 @@ export function authLog (text, res) { } } +// Log reactQuery fetches and responses +export function reactQueryLog (text, res) { + if (webAppConfig.LOG_REACT_QUERY_EVENTS) { + if (res) { + console.log('>> reactQuery >> ', text, res); + } else { + console.log('>> reactQuery >> ', text); + } + } +} + + // Cordova offsets export function cordovaOffsetLog (text, res) { if (webAppConfig.LOG_CORDOVA_OFFSETS) { diff --git a/src/js/components/Login/ResetYourPassword.jsx b/src/js/components/Login/ResetYourPassword.jsx new file mode 100644 index 0000000..5f52dfd --- /dev/null +++ b/src/js/components/Login/ResetYourPassword.jsx @@ -0,0 +1,179 @@ +import { Modal } from '@mui/material'; +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import TextField from '@mui/material/TextField'; +import PropTypes from 'prop-types'; +import * as React from 'react'; +import { useEffect, useRef, useState } from 'react'; +import validator from 'validator'; +import { renderLog } from '../../common/utils/logging'; +import { useConnectAppContext } from '../../contexts/ConnectAppContext'; +import makeRequestParams from '../../react-query/makeRequestParams'; +import { useLogoutMutation, usePersonRetrieveByEmailMutation, usePersonSaveForAuthMutation } from '../../react-query/mutations'; +import weConnectQueryFn, { METHOD } from '../../react-query/WeConnectQuery'; +import { ErrorMessage } from '../Style/sharedStyles'; +import VerifySecretCodeModal from '../VerifySecretCodeModal'; + +const ResetYourPassword = ({ openDialog, closeDialog }) => { + renderLog('ResetYourPassword'); + const { mutate: mutateRetrievePersonByEmail } = usePersonRetrieveByEmailMutation(); + const { mutate: mutatePersonSaveForAuth } = usePersonSaveForAuthMutation(); + const { mutate: mutateLogout } = useLogoutMutation(); + const { getAppContextValue, setAppContextValue } = useConnectAppContext(); + + const [open, setOpen] = React.useState(openDialog); + const [displayEmailAddress, setDisplayEmailAddress] = useState(true); + const [warningLine, setWarningLine] = useState(''); + const [errorMessage, setErrorMessage] = useState(''); + + const emailRef = useRef(''); + const password1Ref = useRef(''); + const password2Ref = useRef(''); + const authPerson = useRef(undefined); + + useEffect(() => { + setOpen(openDialog); + }, [openDialog]); + + const secretCodeVerified = getAppContextValue('secretCodeVerifiedForReset') || false; + useEffect(() => { + if (secretCodeVerified === true) { + console.log('received new secretCodeVerifiedForReset', secretCodeVerified); + setDisplayEmailAddress(false); + emailRef.current = ''; + password1Ref.current = ''; + password2Ref.current = ''; + } + }, [secretCodeVerified]); + + const auth = getAppContextValue('authenticatedPerson'); + useEffect(() => { + const authP = getAppContextValue('authenticatedPerson'); + if (authP && open) { + console.log('received new authP', authP); + authPerson.current = authP; + console.log('authPerson.personId in Login useEffect [auth] id: ', authP.personId); + console.log('authPerson.personId in Login useEffect [auth] open: ', open); + weConnectQueryFn('send-email-code', { personId: authP.personId }, METHOD.POST) + .then(setAppContextValue('openVerifySecretCodeModalDialog', true)); + } + // eslint would have us add getAppContextValue and setAppContextValue, which causes and endless loop + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [auth]); + + const sendEmail = async () => { + const email = emailRef.current.value; + setAppContextValue('resetEmail', email); + console.log('email in sendEmail: ', emailRef.current.value); + if (!validator.isEmail(email)) { + setWarningLine('Please enter a valid email address.'); + return; + } + setWarningLine(''); + setAppContextValue('openVerifySecretCodeModalDialog', true); + // Logout so that the current sessionID will not be reused when resetting password for a potentially differnt staff member + await mutateLogout(); + // This retrieve will set the 'authenticatedPerson' app context value, and bring back a new sessionID (without touching the cookie) + await mutateRetrievePersonByEmail({ emailPersonal: email }); + }; + + const handleClose = () => { + setOpen(false); + closeDialog(false); + }; + + const changePassword = async () => { + const pass1 = password1Ref.current.value; + const pass2 = password2Ref.current.value; + const person = authPerson.current; + + console.log('password in changePassword: ', pass1, pass2); + if (pass1 !== pass2) { + setErrorMessage('Your password entries do not match.'); + } else { + setErrorMessage(''); + // const person = getAppContextValue('authenticatedPerson'); + await mutatePersonSaveForAuth(makeRequestParams({ id: person.id }, { password: pass1 })); + setAppContextValue('isAuthenticated', true); + console.log('ResetYourPassword changePassword pass1, pass2: ', pass1, pass2); + setAppContextValue('resetPassword', pass1); + handleClose(); + } + }; + + console.log('ResetYourPassword incoming authPerson: ', authPerson); + return ( + <> + + + Reset your Password +
{warningLine}
+ + + {displayEmailAddress ? 'Please enter your email address.' : 'Please enter your new password.'} + + {errorMessage} + { displayEmailAddress ? ( + + ) : ( +
+ + + + )} + +
+
+
+ + + ); +}; +ResetYourPassword.propTypes = { + openDialog: PropTypes.func, + closeDialog: PropTypes.func, +}; + +export default ResetYourPassword; diff --git a/src/js/components/Navigation/HeaderBar.jsx b/src/js/components/Navigation/HeaderBar.jsx index a5f663d..03c35fd 100644 --- a/src/js/components/Navigation/HeaderBar.jsx +++ b/src/js/components/Navigation/HeaderBar.jsx @@ -7,7 +7,7 @@ import styled from 'styled-components'; import standardBoxShadow from '../../common/components/Style/standardBoxShadow'; import { hasIPhoneNotch } from '../../common/utils/cordovaUtils'; import { normalizedHrefPage } from '../../common/utils/hrefUtils'; -import { renderLog } from '../../common/utils/logging'; +import { authLog, renderLog } from '../../common/utils/logging'; import { useConnectAppContext } from '../../contexts/ConnectAppContext'; import { clearSignedInGlobals } from '../../contexts/contextFunctions'; import { viewerCanSeeOrDo } from '../../models/AuthModel'; @@ -22,7 +22,7 @@ import HeaderBarLogo from './HeaderBarLogo'; const HeaderBar = ({ hideTabs }) => { renderLog('HeaderBar'); const navigate = useNavigate(); - const { apiDataCache, getAppContextValue, setAppContextValue } = useConnectAppContext(); + const { apiDataCache, getAppContextValue, setAppContextValue, getAppContextData } = useConnectAppContext(); const { viewerAccessRights } = apiDataCache; const { mutate: mutateLogout } = useLogoutMutation(); @@ -34,7 +34,7 @@ const HeaderBar = ({ hideTabs }) => { const isAuth = getAppContextValue('isAuthenticated'); useEffect(() => { if (isAuth !== null) { - console.log('----------- isAuthenticated changed =', isAuth); + authLog('HeaderBar isAuthenticated changed =', isAuth); setIsAuthenticated(isAuth); } }, [isAuth]); @@ -43,7 +43,7 @@ const HeaderBar = ({ hideTabs }) => { // I don't think we want to make the weConnectQueryFn call here since we are about to call mutateLogout const data = await weConnectQueryFn('logout', {}, METHOD.POST); console.log(`/logout response in HeaderBar -- status: '${'status'}', data: ${JSON.stringify(data)}`); - clearSignedInGlobals(setAppContextValue); + clearSignedInGlobals(setAppContextValue, getAppContextData); navigate('/login'); mutateLogout(); }; diff --git a/src/js/components/Person/PersonSummaryRow.jsx b/src/js/components/Person/PersonSummaryRow.jsx index ef04899..019c673 100644 --- a/src/js/components/Person/PersonSummaryRow.jsx +++ b/src/js/components/Person/PersonSummaryRow.jsx @@ -5,10 +5,7 @@ import styled from 'styled-components'; import DesignTokenColors from '../../common/components/Style/DesignTokenColors'; import { renderLog } from '../../common/utils/logging'; import { useConnectAppContext } from '../../contexts/ConnectAppContext'; -import { - getFullNamePreferredPerson, - // useGetFullNamePreferred, -} from '../../models/PersonModel'; +import { getFullNamePreferredPerson } from '../../models/PersonModel'; import { useRemoveTeamMemberMutation } from '../../react-query/mutations'; import { DeleteStyled, EditStyled } from '../Style/iconStyles'; import { viewerCanSeeOrDo, viewerCanSeeOrDoForThisTeam } from '../../models/AuthModel'; @@ -117,7 +114,6 @@ const PersonSummaryRow = ({ person, rowNumberForDisplay, teamId }) => { id={`removeMember-personId-${person.personId}`} onClick={() => removeTeamMemberClick(person)} style={{ cursor: 'pointer' }} - // cellwidth="20" cellwidth={20} > diff --git a/src/js/components/PrivateRoute.jsx b/src/js/components/PrivateRoute.jsx index be3736a..5a49563 100644 --- a/src/js/components/PrivateRoute.jsx +++ b/src/js/components/PrivateRoute.jsx @@ -7,7 +7,7 @@ import { captureAccessRightsData } from '../models/AuthModel'; const PrivateRoute = () => { const location = useLocation(); - const { apiDataCache, getAppContextValue } = useConnectAppContext(); + const { apiDataCache, getAppContextValue, setAppContextValue } = useConnectAppContext(); const dispatch = useConnectDispatch(); const [isAuthenticated, setIsAuthenticated] = useState(null); @@ -15,17 +15,16 @@ const PrivateRoute = () => { const { data: dataAuth, isSuccess: isSuccessAuth } = useFetchData(['get-auth'], {}, METHOD.POST); useEffect(() => { if (isSuccessAuth) { - // console.log('useFetchData in PrivateRoute useEffect dataAuth good:', dataAuth, isSuccessAuth); + authLog('useFetchData in PrivateRoute useEffect dataAuth good:', dataAuth, isSuccessAuth); setIsAuthenticated(dataAuth.isAuthenticated); - // setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin); + setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin); captureAccessRightsData(dataAuth, isSuccessAuth, apiDataCache, dispatch); - authLog('========= PrivateRoute =========== INNER isAuthenticated: ', dataAuth.isAuthenticated); } }, [dataAuth, isSuccessAuth]); const isAuth = getAppContextValue('isAuthenticated'); - authLog('========= PrivateRoute =========== OUTER isAuthenticated: ', isAuthenticated, ', isAuth: ', isAuth); + authLog('========= PrivateRoute =========== isAuthenticated: ', isAuthenticated); if (isAuthenticated || isAuth || isAuthenticated !== false) { return ; diff --git a/src/js/components/Style/sharedStyles.js b/src/js/components/Style/sharedStyles.js index c4fd278..fe94170 100644 --- a/src/js/components/Style/sharedStyles.js +++ b/src/js/components/Style/sharedStyles.js @@ -9,3 +9,10 @@ export const MatchingPerson = styled('div')` margin: 10px 0 0 10px; font-style: italic; `; + +export const ErrorMessage = styled('div')` + color: red; + margin-top: 50px; + text-align: center; + font-size: 18px; +`; diff --git a/src/js/components/Team/TeamHeader.jsx b/src/js/components/Team/TeamHeader.jsx index 00185c2..33348cf 100644 --- a/src/js/components/Team/TeamHeader.jsx +++ b/src/js/components/Team/TeamHeader.jsx @@ -30,7 +30,7 @@ const TeamHeader = ({ showHeaderLabels, showIcons, team }) => { return ( {/* Width (below) of this TeamHeaderCell comes from the combined widths of the first x columns in TeamMemberList */} - + {teamLocal && ( {teamLocal.teamName} @@ -85,19 +85,17 @@ const OneTeamHeader = styled('div')` margin-top: 10px; `; -const TeamHeaderCell = styled('div', { - shouldForwardProp: (prop) => !['largefont', 'titlecell', 'cellwidth'].includes(prop), -})(({ largefont, titlecell, cellwidth }) => (` +const TeamHeaderCell = styled.div` align-content: center; - ${(titlecell) ? '' : 'border-bottom: 1px solid #ccc;'} - ${(largefont) ? 'font-size: 1.1em;' : 'font-size: .8em;'} - ${(titlecell) ? '' : 'font-weight: 550;'} + border-bottom: ${(props) => (props?.$titleCell ? ';' : '1px solid #ccc;')} + font-size: ${(props) => (props?.$largefont ? '1.1em;' : '.8em;')}; + font-weight: ${(props) => (props?.$titleCell ? ';' : '550;')} height: 22px; - ${cellwidth ? `max-width: ${cellwidth}px;` : ''} - ${cellwidth ? `min-width: ${cellwidth}px;` : ''} + max-width: ${(props) => (props.cellwidth ? `${props.cellwidth}px;` : ';')}; + min-width: ${(props) => (props.cellwidth ? `${props.cellwidth}px;` : ';')}; + width: ${(props) => (props.cellwidth ? `${props.cellwidth}px;` : ';')}; overflow: hidden; white-space: nowrap; - ${cellwidth ? `width: ${cellwidth}px;` : ''} -`)); +`; export default withStyles(styles)(TeamHeader); diff --git a/src/js/components/VerifySecretCodeModal.jsx b/src/js/components/VerifySecretCodeModal.jsx index ed133be..bcdce62 100644 --- a/src/js/components/VerifySecretCodeModal.jsx +++ b/src/js/components/VerifySecretCodeModal.jsx @@ -9,13 +9,12 @@ import { isIPhone4in } from '../common/utils/cordovaUtils'; import { isCordova, isWebApp } from '../common/utils/isCordovaOrWebApp'; import { renderLog } from '../common/utils/logging'; import { useConnectAppContext } from '../contexts/ConnectAppContext'; -import { useGetAuthMutation } from '../react-query/mutations'; import weConnectQueryFn, { METHOD } from '../react-query/WeConnectQuery'; +import { ErrorMessage } from './Style/sharedStyles'; -const VerifySecretCodeModal = ({ classes, person, openVerifyModalDialog }) => { +const VerifySecretCodeModal = ({ classes, person }) => { renderLog('VerifySecretCodeModal'); - const { mutate: mutateAuth } = useGetAuthMutation(); - const { getAppContextValue } = useConnectAppContext(); + const { getAppContextValue, setAppContextValue } = useConnectAppContext(); const d1FldRef = useRef(''); const d2FldRef = useRef(''); @@ -29,21 +28,25 @@ const VerifySecretCodeModal = ({ classes, person, openVerifyModalDialog }) => { const [condensed] = useState(true); const [voterPhoneNumber] = useState(undefined); const [voterEmailAddress] = useState(true); - const [openDialog, setOpenDialog] = useState(true); + const [openDialogMutable, setOpenDialogMutable] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); const digits = [[1, 'd1Id', d1FldRef], [2, 'd2Id', d2FldRef], [3, 'd3Id', d3FldRef], [4, 'd4Id', d4FldRef], [5, 'd5Id', d5FldRef], [6, 'd6Id', d6FldRef]]; + const open = getAppContextValue('openVerifySecretCodeModalDialog'); useEffect(() => { - setOpenDialog(openVerifyModalDialog); - }, [openVerifyModalDialog]); + setOpenDialogMutable(getAppContextValue('openVerifySecretCodeModalDialog')); + setAppContextValue('secretCodeVerified', false); + }, [open]); const handleClose = () => { console.log('handleClose pressed'); - setOpenDialog(false); + setOpenDialogMutable(false); + setAppContextValue('openVerifySecretCodeModalDialog', false); }; - const voterVerifySecretCode = async () => { - console.log('voterVerifySecretCode pressed'); + const verifySecretCode = async () => { + console.log('verifySecretCode pressed'); let code = ''; for (let i = 0; i < digits.length; i++) { const digit = digits[i]; @@ -51,15 +54,19 @@ const VerifySecretCodeModal = ({ classes, person, openVerifyModalDialog }) => { code += refDigit.current.value.toString(); } - const newPersonId = getAppContextValue('authenticatedPersonId'); - const data = await weConnectQueryFn('verify-email-code', { personId: newPersonId, code }, METHOD.POST); + const data = await weConnectQueryFn('verify-email-code', { personId: person.personId, code }, METHOD.POST); console.log(`/verify-email-code response: data: ${JSON.stringify(data)}`); - await mutateAuth(); // to propagate the invalidation to HeaderBar and Login (might be a better way to do this) - setOpenDialog(false); + if (data.emailVerified) { + setAppContextValue('secretCodeVerified', true); + setAppContextValue('secretCodeVerifiedForReset', true); + setOpenDialogMutable(false); + } else { + setErrorMessage('Your code did not verify. Try again.'); + } }; useEffect(() => { - while (d1FldRef?.current) { + while (d1FldRef?.current && openDialogMutable) { setTimeout(() => { // See https://github.com/mui/material-ui/issues/33004#issuecomment-1455260156 d1FldRef.current?.focus(); @@ -80,11 +87,14 @@ const VerifySecretCodeModal = ({ classes, person, openVerifyModalDialog }) => { } }, [nextFocus]); + const extractDigits = (str) => { + const digitsLocal = str.match(/\d/g); + return digitsLocal?.length ? digitsLocal.join('') : ''; + }; + const onPaste = (event) => { - // console.log(ev.clipboardData.getData('Text')); - const clipboardData = event.clipboardData || window.clipboardData; - const pastedData = clipboardData.getData('text').trim(); - console.log(pastedData); + const clipboardData = (event.originalEvent || event).clipboardData.getData('text/plain'); + const pastedData = extractDigits(clipboardData); for (let i = 0; i < pastedData.length; i++) { const digit = digits[i]; @@ -97,8 +107,6 @@ const VerifySecretCodeModal = ({ classes, person, openVerifyModalDialog }) => { } }; - - const onDigitChange = (event) => { // eslint-disable-next-line no-unused-vars const [index, id, refThis] = digits.find((dig) => dig[1] === event.target.id); @@ -109,25 +117,23 @@ const VerifySecretCodeModal = ({ classes, person, openVerifyModalDialog }) => { refThis.current.blur(); setNextFocus(index + 1); } - + setErrorMessage(''); console.log(event); }; - if (!(openDialog)) { + if (!openDialogMutable || !person || Object.keys(person).length === 0) { return null; } return ( { Code Verification A 6-digit code has been sent to - {person?.email} + {person?.email} {(voterEmailAddress) ? ( If you haven't received the code in 30 seconds, please check your spam folder and mark the email as 'Not Spam'. @@ -159,6 +165,7 @@ const VerifySecretCodeModal = ({ classes, person, openVerifyModalDialog }) => { {digits.map((dig) => ( { label={false} notched={false} onChange={onDigitChange} + onPaste={onPaste} type="tel" - autoFocus={dig[0] === 0} // onFocus="this.select()" // maxLength={1} // value={this.state.digit1} // onBlur={this.handleBlur} - onPaste={onPaste} /> ))} + {errorMessage} @@ -201,7 +206,6 @@ const VerifySecretCodeModal = ({ classes, person, openVerifyModalDialog }) => { VerifySecretCodeModal.propTypes = { classes: PropTypes.object, person: PropTypes.object, - openVerifyModalDialog: PropTypes.bool, }; const styles = (theme) => ({ @@ -345,18 +349,10 @@ const Subtitle = styled('h4')` text-align: center; `; -const PhoneSubtitle = styled('h4')` +const EmailSubtitle = styled('h4')` color: black; font-weight: bold; text-align: center; `; -// const ErrorMessage = styled('div')` -// color: red; -// margin: 12px 0; -// text-align: center; -// font-size: 14px; -// `; - - export default withTheme(withStyles(styles)(VerifySecretCodeModal)); diff --git a/src/js/config-template.js b/src/js/config-template.js index 8074cc9..c771d6d 100644 --- a/src/js/config-template.js +++ b/src/js/config-template.js @@ -57,14 +57,15 @@ module.exports = { DEBUG_MODE: false, SHOW_TEST_OPTIONS: false, // On the DeviceDialog and elsewhere - LOG_RENDER_EVENTS: false, - LOG_ONLY_FIRST_RENDER_EVENTS: false, + ENABLE_REACT_QUERY_TOOLS: false, // Show ReactQueryDevtools icon/console + LOG_AUTHENTICATION: false, // authLog function prints to console + LOG_CORDOVA_OFFSETS: false, LOG_HTTP_REQUESTS: false, + LOG_RENDER_EVENTS__FIRST_ONLY: false, // Log the render event for a component, but only the first time + LOG_REACT_QUERY_EVENTS: false, // Log query requests/responses + LOG_RENDER_EVENTS: false, LOG_ROUTING: false, - LOG_AUTHENTICATION: false, // authLog function prints to console - LOG_CORDOVA_OFFSETS: false, - SHOW_CORDOVA_URL_FIELD: false, // Only needed for debugging in Cordova - ENABLE_REACT_QUERY_TOOLS: false, // Show ReactQueryDevtools icon/console + SHOW_CORDOVA_URL_FIELD: false, // Only needed for debugging in Cordova // Use 1 or 0 as opposed to true or false test: { diff --git a/src/js/contexts/ConnectAppContext.jsx b/src/js/contexts/ConnectAppContext.jsx index ac971c8..d24b74f 100644 --- a/src/js/contexts/ConnectAppContext.jsx +++ b/src/js/contexts/ConnectAppContext.jsx @@ -1,20 +1,15 @@ import PropTypes from 'prop-types'; import React, { createContext, useContext, useEffect, useReducer, useState } from 'react'; +import { authLog } from '../common/utils/logging'; import initialApiDataCache from '../models/initialApiDataCache'; // import capturePersonListRetrieveData from '../models/capturePersonListRetrieveData'; import { METHOD, useFetchData } from '../react-query/WeConnectQuery'; import { captureAccessRightsData } from '../models/AuthModel'; -// import { getInitialGlobalPersonVariables, PersonListRetrieveDataCapture } from '../models/PersonModel'; -// import { getInitialGlobalTaskVariables } from '../models/TaskModel'; -// import { getInitialGlobalTeamVariables } from '../models/TeamModel'; // Replaces AppObservableStore.js // Create the context const ConnectAppContext = createContext({}); const ConnectDispatch = createContext(null); -// const initialCachedApiPersonVariables = getInitialGlobalPersonVariables(); -// const initialCachedApiTaskVariables = getInitialGlobalTaskVariables(); -// const initialCachedApiTeamVariables = getInitialGlobalTeamVariables(); function apiDataCacheReducer (apiDataCache, action) { let revisedApiDataCache = { ...apiDataCache }; @@ -30,12 +25,6 @@ function apiDataCacheReducer (apiDataCache, action) { } } -// const initialApiDataCache = { -// ...initialCachedApiPersonVariables, -// ...initialCachedApiTaskVariables, -// ...initialCachedApiTeamVariables, -// }; - // Create the provider component // eslint-disable-next-line no-unused-vars export const ConnectAppContextProvider = ({ children }) => { @@ -67,16 +56,48 @@ export const ConnectAppContextProvider = ({ children }) => { } }; + // const { data: dataP, isSuccess: isSuccessP, isFetching: isFetchingP, isStale: isStaleP } = useFetchData(['person-list-retrieve'], {}, METHOD.GET); + // const personListRetrieveResults = useFetchData(['person-list-retrieve'], {}, METHOD.GET); + // This is not currently the right place to pass these values, but I'm saving these here for the next 30 days until we work out the correct place. + // { + // cacheTime: 0, + // networkMode: 'no-cache', <-- This is not a solution, it just covers up some problem in our code, while disabling the biggest benefit of ReactQueries. + // refetchOnMount: true, + // refetchOnWindowFocus: true, + // refetchInterval: 0, + // staleTime: 0, + // } + + // Moved to root pages: Teams, TeamHome, etc. + // useEffect(() => { + // // console.log('useFetchData person-list-retrieve in Teams useEffect:', personListRetrieveResults); + // if (personListRetrieveResults) { + // // console.log('In useEffect apiDataCache:', apiDataCache); + // // const changeResults = + // capturePersonListRetrieveData(personListRetrieveResults, apiDataCache, dispatch); + // // console.log('ConnectAppContext useEffect capturePersonListRetrieveData changeResults:', changeResults); + // } + // }, [personListRetrieveResults]); + + // const { data: dataP, isSuccess: isSuccessP, isFetching: isFetchingP } = personListRetrieveResults; + // useEffect(() => { + // // console.log('useFetchData in TeamHome (person-list-retrieve) useEffect:', dataP, isSuccessP, isFetchingP, isStaleP); + // if (isSuccessP) { + // // console.log('useFetchData in TeamHome (person-list-retrieve)useEffect data good:', dataP, isSuccessP, isFetchingP, isStaleP); + // setAppContextValue('allPeopleList', dataP ? dataP.personList : []); + // // console.log('ConnectAppContext useEffect allPeopleList fetched'); + // } + // }, [dataP, isSuccessP, isFetchingP]); + // The following prints console log errors const { data: dataAuth, isSuccess: isSuccessAuth, isFetching: isFetchingAuth } = useFetchData(['get-auth'], {}, METHOD.POST); useEffect(() => { if (isSuccessAuth) { - // console.log('useFetchData in ConnectAppContext useEffect dataAuth good:', dataAuth, isSuccessAuth, isFetchingAuth); + authLog('useFetchData in ConnectAppContext useEffect dataAuth good:', dataAuth, isSuccessAuth, isFetchingAuth); const { isAuthenticated } = dataAuth; setAppContextValue('authenticatedPerson', dataAuth.person); - setAppContextValue('authenticatedPersonId', dataAuth.personId); setAppContextValue('isAuthenticated', isAuthenticated); - // setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin); + setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin); captureAccessRightsData(dataAuth, isSuccessAuth, apiDataCache, dispatch); console.log('=============== ConnectAppContextProvider ======= isAuthenticated: ', isAuthenticated, ' ==========='); diff --git a/src/js/contexts/contextFunctions.jsx b/src/js/contexts/contextFunctions.jsx index 4e7671e..0a007f2 100644 --- a/src/js/contexts/contextFunctions.jsx +++ b/src/js/contexts/contextFunctions.jsx @@ -1,8 +1,11 @@ - -export const clearSignedInGlobals = (setAppContextValue) => { - setAppContextValue('authenticatedPerson', undefined); - setAppContextValue('authenticatedPersonId', -1); +const clearSignedInGlobals = (setAppContextValue, getAppContextData) => { + setAppContextValue('authenticatedPerson', {}); setAppContextValue('isAuthenticated', false); - // setAppContextValue('loggedInPersonIsAdmin', false); - setAppContextValue('personIsSignedIn', false); + setAppContextValue('loggedInPersonIsAdmin', false); + setAppContextValue('secretCodeVerifiedForReset', false); + setAppContextValue('secretCodeVerified', false); + console.log('appContextData in clearSignedInGlobals after clear: ', getAppContextData()); }; + +// eslint-disable-next-line import/prefer-default-export +export { clearSignedInGlobals }; diff --git a/src/js/pages/Login.jsx b/src/js/pages/Login.jsx index ac37928..3f4555e 100644 --- a/src/js/pages/Login.jsx +++ b/src/js/pages/Login.jsx @@ -1,6 +1,5 @@ import { Button, TextField } from '@mui/material'; import { withStyles } from '@mui/styles'; -import { useQueryClient } from '@tanstack/react-query'; import PropTypes from 'prop-types'; import React, { useEffect, useRef, useState } from 'react'; import { Helmet } from 'react-helmet-async'; @@ -9,23 +8,22 @@ import styled from 'styled-components'; import validator from 'validator'; import { renderLog } from '../common/utils/logging'; import compileDate from '../compileDate'; +import ResetYourPassword from '../components/Login/ResetYourPassword'; import { PageContentContainer } from '../components/Style/pageLayoutStyles'; import VerifySecretCodeModal from '../components/VerifySecretCodeModal'; import webAppConfig from '../config'; import { useConnectAppContext, useConnectDispatch } from '../contexts/ConnectAppContext'; -// import { clearSignedInGlobals } from '../contexts/contextFunctions'; +import { clearSignedInGlobals } from '../contexts/contextFunctions'; import { captureAccessRightsData } from '../models/AuthModel'; import { getFullNamePreferredPerson } from '../models/PersonModel'; import { useLogoutMutation } from '../react-query/mutations'; import weConnectQueryFn, { METHOD, useFetchData } from '../react-query/WeConnectQuery'; -import ReactQuerySaveReadTest from '../test/ReactQuerySaveReadTest'; const Login = ({ classes }) => { renderLog('Login'); const navigate = useNavigate(); - const queryClient = useQueryClient(); - const { apiDataCache, setAppContextValue } = useConnectAppContext(); + const { apiDataCache, getAppContextValue, setAppContextValue, getAppContextData } = useConnectAppContext(); const dispatch = useConnectDispatch(); const { mutate: mutateLogout } = useLogoutMutation(); @@ -38,10 +36,10 @@ const Login = ({ classes }) => { // const stateFldRef = useRef(''); const passwordFldRef = useRef(''); const confirmPasswordFldRef = useRef(''); + const authPerson = useRef(undefined); - const [authPerson, setAuthPerson] = useState({}); - const [openVerifyModalDialog, setOpenVerifyModalDialog] = useState(false); - const [returnFromLogin, setReturnFromLogin] = useState(false); + const [loginAttempted, setLoginAttempted] = useState(false); + const [openResetPasswordDialog, setOpenResetPasswordDialog] = useState(false); const [showCreateStuff, setShowCreateStuff] = useState(false); const [successLine, setSuccessLine] = useState(''); const [warningLine, setWarningLine] = useState(''); @@ -51,17 +49,24 @@ const Login = ({ classes }) => { if (isSuccessAuth) { console.log('useFetchData in Login useEffect dataAuth good:', dataAuth, isSuccessAuth, isFetchingAuth); - const { isAuthenticated } = dataAuth; - const authenticatedPerson = dataAuth.person; - setAuthPerson(authenticatedPerson); - const success = isAuthenticated && authenticatedPerson ? `Signed in as ${getFullNamePreferredPerson(authenticatedPerson)}` : 'Please sign in'; - setSuccessLine(success); - // setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin); + const { isAuthenticated, person: authenticatedPerson, emailVerified: emailVerifiedFromAPI, personId } = dataAuth; + authPerson.current = authenticatedPerson; captureAccessRightsData(dataAuth, isSuccessAuth, apiDataCache, dispatch); - if (isAuthenticated && returnFromLogin) { - setTimeout(() => { - navigate('/tasks'); - }, 2000); + console.log('appContextData in Login [dataAuth, isSuccessAuth]: ', getAppContextData()); + if (!emailVerifiedFromAPI && personId > 0) { + setWarningLine(''); + setSuccessLine('A verification email has been sent to your address'); + setAppContextValue('openVerifySecretCodeModalDialog', true); + } else if (isAuthenticated && authenticatedPerson) { + setSuccessLine(`Signed in as ${getFullNamePreferredPerson(authenticatedPerson)}`); + setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin); + if (loginAttempted) { // if we navigate to here directly, not as a result of a loginAPI + setTimeout(() => { + navigate('/tasks'); + }, 2000); + } + } else { + setSuccessLine('Please sign in'); } } }, [dataAuth, isSuccessAuth]); @@ -70,30 +75,56 @@ const Login = ({ classes }) => { if (!validator.isEmail(email)) { setWarningLine('Please enter a valid email address.'); return; - } - if (validator.isEmpty(password)) { + } else if (validator.isEmpty(password)) { setWarningLine('Password cannot be blank.'); return; + } else { + setSuccessLine(''); + setSuccessLine(''); } + setLoginAttempted(true); // so we know when to timeout to /tasks const data = await weConnectQueryFn('login', { email, password }, METHOD.POST); console.log(`/login response -- status: '${'status'}', data: ${JSON.stringify(data)}`); if (data.personId > 0) { - setWarningLine(''); - setSuccessLine(`Cheers person #${data.personId}! You are signed in!`); - setAppContextValue('isAuthenticated', true); - setAppContextValue('authenticatedPersonId', data.personId); - setReturnFromLogin(true); - if (!data.emailVerified) { - setOpenVerifyModalDialog(true); + setAppContextValue('isAuthenticated', data.emailVerified); + if (data.emailVerified) { + setWarningLine(''); + setSuccessLine(`${getFullNamePreferredPerson(data.person)}, you are signed in!`); + setAppContextValue('authenticatedPerson', data); + setTimeout(() => { + navigate('/tasks'); + }, 2000); + } else { + authPerson.current = { // just enough data for VerifySecretCodeModal + personId: data.personId, + personEmail: email.trim(), + }; + setAppContextValue('openVerifySecretCodeModalDialog', true); + setSuccessLine('A verification email has been sent to your address'); } - await queryClient.invalidateQueries('get-auth'); } else { setWarningLine(data.error.msg); setSuccessLine(''); } }; + const secretCodeVerified = getAppContextValue('secretCodeVerified'); + const resetPassword = getAppContextValue('resetPassword'); + useEffect(() => { + if (secretCodeVerified === true && resetPassword && resetPassword.length) { + loginApi(getAppContextValue('resetEmail'), getAppContextValue('resetPassword')).then(() => { + // console.log('--------- useEffect secretCodeVerified in Login, clearing resetEmail and resetPassword', e, p); + setAppContextValue('resetEmail', ''); + setAppContextValue('resetPassword', ''); + setAppContextValue('openVerifySecretCodeModalDialog', false); + setAppContextValue('secretCodeVerified', false); + setAppContextValue('secretCodeVerifiedForReset', false); + // console.log('appContextData in Login L124: ', getAppContextData()); + }); + } + }, [secretCodeVerified, resetPassword]); + const logoutApi = async () => { const data = await weConnectQueryFn('logout', {}, METHOD.POST); console.log(`/logout response -- status: '${'status'}', data: ${JSON.stringify(data)}`); @@ -130,12 +161,10 @@ const Login = ({ classes }) => { setWarningLine(errStr); if (data.personCreated) { setSuccessLine(`user # ${data.personId} created`); - // setAppContextValue('isAuthenticated', true); - setAppContextValue('authenticatedPersonId', data.personId); verifyYourEmail(data.personId).then(() => { setSuccessLine('A verification email has been sent to your address'); - console.log('verifyYourEmail in signupApi then clause , setOpenVerifyModalDialog true'); - setOpenVerifyModalDialog(true); + console.log('verifyYourEmail in signupApi then clause , openVerifySecretCodeModalDialog true'); + setAppContextValue('openVerifySecretCodeModalDialog', true); }); } } catch (e) { @@ -152,14 +181,14 @@ const Login = ({ classes }) => { setWarningLine('Enter a valid username and password'); } else { setWarningLine(''); - setAppContextValue('personIsSignedIn', true); loginApi(email, password).then(); } }; const useSignOutPressed = () => { // clearSignedInGlobals is also called in logoutApi, so isn't needed here - // clearSignedInGlobals(setAppContextValue); + // TODO 2/23/25: unfortunately there are two logoutApi(), consolidating them is high priority + clearSignedInGlobals(setAppContextValue, getAppContextData); logoutApi().then(); }; @@ -225,7 +254,7 @@ const Login = ({ classes }) => {
{warningLine}
{successLine}
- { paddingRight: '10px', display: showCreateStuff ? 'block' : 'none' }} /> - { display: showCreateStuff ? 'block' : 'none' }} /> - - { sx={{ paddingBottom: '15px', display: showCreateStuff ? 'block' : 'none' }} /> - { display: showCreateStuff ? 'block' : 'none' }} /> - - @@ -292,7 +321,14 @@ const Login = ({ classes }) => { > Sign In - Forgot your password? +
@@ -317,19 +354,16 @@ const Login = ({ classes }) => {
Compile Date:
{compileDate}
-
- + {authPerson.current && + Object.keys(authPerson.current).length > 0 && + getAppContextValue('secretCodeVerified') !== true && + getAppContextValue('openVerifySecretCodeModalDialog') && ( + + )} + {/* This following test can be deleted or converted to an automated test */} - + {/* */} ); @@ -350,14 +384,6 @@ const styles = (theme) => ({ }, }); -const AStyled = styled('a')` - font-weight: 400; - color: rgb(13, 110, 253); - text-decoration-color: rgb(13, 110, 253); - text-decoration-line: underline; - padding: 8px 0 0 25px; -`; - const DateDisplay = styled('div')` padding: 50px 0 50px 0; `; diff --git a/src/js/pages/SystemSettings/PermissionsAdministration.jsx b/src/js/pages/SystemSettings/PermissionsAdministration.jsx index 95dd65d..60fa972 100644 --- a/src/js/pages/SystemSettings/PermissionsAdministration.jsx +++ b/src/js/pages/SystemSettings/PermissionsAdministration.jsx @@ -65,7 +65,6 @@ const PermissionsAdministration = ({ classes }) => { const cancelClicked = (event) => { const pieces = event.target.id.split('-'); const personId = parseInt(pieces[2]); - // TODO change the data! const activePerson = peopleWorkingArray.find((p) => p.id === personId); const personCached = Object.values(allPeopleCache).find((p) => p.id === personId); Object.assign(activePerson, personCached); diff --git a/src/js/pages/Teams.jsx b/src/js/pages/Teams.jsx index 57401fe..2f273dc 100644 --- a/src/js/pages/Teams.jsx +++ b/src/js/pages/Teams.jsx @@ -210,7 +210,7 @@ const Teams = () => { })}
- Jump to the "Sign in" /login page (Temporary Link) + Sign in
diff --git a/src/js/react-query/WeConnectQuery.js b/src/js/react-query/WeConnectQuery.js index 8f0435f..f5dd9ed 100644 --- a/src/js/react-query/WeConnectQuery.js +++ b/src/js/react-query/WeConnectQuery.js @@ -1,6 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import axios from 'axios'; -import { httpLog } from '../common/utils/logging'; +import { reactQueryLog } from '../common/utils/logging'; import webAppConfig from '../config'; const METHOD = { @@ -16,8 +16,7 @@ const weConnectQueryFn = async (queryKey, params, isGet) => { if (isGet) { url.search = new URLSearchParams(params); } - // 2/12/24 temporarily replaced: httpLog(`weConnectQueryFn ${isGet ? 'GET' : 'POST'} url.href: ${url.href}`); // DO NOT REMOVE, this is the only way to see if we are hitting the API server unnecessarily - // console.log(`weConnectQueryFn ${isGet ? 'GET' : 'POST'} url.href: ${url.href}`); + reactQueryLog(`weConnectQueryFn ${isGet ? 'GET' : 'POST'} url.href: ${url.href}`); let response; try { @@ -38,7 +37,7 @@ const weConnectQueryFn = async (queryKey, params, isGet) => { }; const useFetchData = (queryKey, fetchParams, isGet) => { - httpLog('useFetchData queryKey, fetchParams before fetch: ', queryKey, ' fetchParams: ', fetchParams); + reactQueryLog('useFetchData queryKey, fetchParams before fetch: ', queryKey, ' fetchParams: ', fetchParams); const { data, isSuccess, isFetching, isStale, refetch, error } = useQuery({ queryKey, queryFn: () => weConnectQueryFn(queryKey, fetchParams, isGet), diff --git a/src/js/react-query/mutations.jsx b/src/js/react-query/mutations.jsx index 7510586..a8ac99b 100644 --- a/src/js/react-query/mutations.jsx +++ b/src/js/react-query/mutations.jsx @@ -1,4 +1,5 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useConnectAppContext } from '../contexts/ConnectAppContext'; import weConnectQueryFn, { METHOD } from './WeConnectQuery'; const useRemoveTeamMutation = () => { @@ -99,6 +100,16 @@ const usePersonSaveMutation = () => { }); }; +const usePersonSaveForAuthMutation = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (params) => weConnectQueryFn('person-save', params, METHOD.GET), + onError: (error) => console.log('error in personSaveMutation: ', error), + onSuccess: () => queryClient.invalidateQueries('get-auth'), + }); +}; + const useSaveTaskMutation = () => { const queryClient = useQueryClient(); @@ -127,10 +138,38 @@ const useGetAuthMutation = () => { }); }; +const usePersonRetrieveMutation = () => { + console.log('entry to useGetPersonMutation'); + const { setAppContextValue } = useConnectAppContext(); + + return useMutation({ + mutationFn: (params) => weConnectQueryFn('person-retrieve', params, METHOD.GET), + onError: (error) => console.log('error in usePersonRetrieveMutation: ', error), + onSuccess: (data, variables, context) => { + console.log('usePersonRetrieveMutation successful, returning', data, variables, context); + setAppContextValue('authenticatedPerson', data); + }, + }); +}; + +const usePersonRetrieveByEmailMutation = () => { + console.log('entry to useGetPersonMutation'); + const { setAppContextValue } = useConnectAppContext(); + + return useMutation({ + mutationFn: (params) => weConnectQueryFn('person-retrieve-by-email', params, METHOD.GET), + onError: (error) => console.log('error in usePersonRetrieveByEmailMutation: ', error), + onSuccess: (data, variables, context) => { + console.log('usePersonRetrieveByEmailMutation successful, returning', data, variables, context); + setAppContextValue('authenticatedPerson', data); + }, + }); +}; + export { useRemoveTeamMutation, useRemoveTeamMemberMutation, useAddPersonToTeamMutation, useQuestionnaireSaveMutation, useTaskDefinitionSaveMutation, useGroupSaveMutation, usePersonAwaySaveMutation, - useQuestionSaveMutation, usePersonSaveMutation, useSaveTaskMutation, useAnswerListSaveMutation, - useLogoutMutation, useGetAuthMutation }; + useQuestionSaveMutation, usePersonSaveMutation, usePersonSaveForAuthMutation, useSaveTaskMutation, useAnswerListSaveMutation, + useLogoutMutation, useGetAuthMutation, usePersonRetrieveMutation, usePersonRetrieveByEmailMutation }; diff --git a/src/js/stores/VoterStore.js b/src/js/stores/VoterStore.js index 0839752..48e07d6 100644 --- a/src/js/stores/VoterStore.js +++ b/src/js/stores/VoterStore.js @@ -1,1341 +1,1341 @@ -import { ReduceStore } from 'flux/utils'; -import VoterActions from '../actions/VoterActions'; // eslint-disable-line import/no-cycle -import Dispatcher from '../common/dispatcher/Dispatcher'; -import AppObservableStore from './AppObservableStore'; // eslint-disable-line import/no-cycle -import apiCalming from '../common/utils/apiCalming'; -import Cookies from '../common/utils/js-cookie/Cookies'; -import stringContains from '../common/utils/stringContains'; -import VoterConstants from '../constants/VoterConstants'; -import { dumpObjProps } from '../utils/appleSiliconUtils'; - -class VoterStore extends ReduceStore { - getInitialState () { - return { - voter: { - interface_status_flags: 0, - state_code_from_ip_address: '', - }, - address: {}, - emailAddressStatus: {}, - emailSignInStatus: {}, - emailAddressList: [], - externalVoterId: '', - facebookSignInStatus: {}, - facebookPhotoRetrieveLoopCount: 0, - latestGoogleCivicElectionId: 0, - secretCodeVerificationStatus: { - incorrectSecretCodeEntered: false, - numberOfTriesRemaining: 5, - secretCodeVerified: false, - voterMustRequestNewCode: false, - voterSecretCodeRequestsLocked: false, - }, - smsPhoneNumberStatus: { - sms_verify_attempted: false, - sms_phone_number_already_owned_by_other_voter: false, - sms_phone_number_already_owned_by_this_voter: false, - sms_phone_number_created: false, - sms_phone_number: '', - sms_phone_number_found: false, - sms_phone_number_deleted: false, - make_primary_sms: false, - sign_in_code_sms_sent: false, - verification_sms_sent: false, - }, - smsPhoneNumberList: [], - voterContactEmailGoogleCount: 0, - voterContactEmailList: [], - voterDeleted: false, - voterEmailQueuedToSave: '', - voterEmailQueuedToSaveSet: false, - voterFirstNameQueuedToSave: '', - voterFirstNameQueuedToSaveSet: false, - voterFirstRetrieveCompleted: false, // Has the first retrieve of the voter completed? - voterFound: false, - voterExternalIdHasBeenSavedOnce: {}, // Dict with externalVoterId and membershipOrganizationWeVoteId as keys, and true/false as value - voterLastNameQueuedToSave: '', - voterLastNameQueuedToSaveSet: false, - voterNotificationSettingsUpdateStatus: { - apiResponseReceived: false, - emailFound: false, - voterFound: false, - normalizedEmailAddress: '', - normalizedSmsPhoneNumber: '', - notificationSettingsFlags: false, - }, - voterPhotoQueuedToSave: '', - voterPhotoQueuedToSaveSet: false, - voterPhotoTooBig: false, - }; - } - - electionId () { - return this.getState().latestGoogleCivicElectionId || 0; - } - - resetState () { - return this.getInitialState(); - } - - getAddressObject () { - return this.getState().address || {}; - } - - getBallotLocationForVoter () { - // console.log('getBallotLocationForVoter this.getState().address:', this.getState().address); - if (this.getState().address) { - return { - text_for_map_search: this.getTextForMapSearch(), - ballot_returned_we_vote_id: this.getState().address.ballot_returned_we_vote_id, - polling_location_we_vote_id: '', - ballot_location_order: 0, - ballot_location_display_name: this.getState().address.ballot_location_display_name, - ballot_location_shortcut: '', - google_civic_election_id: this.getState().address.google_civic_election_id, - voter_entered_address: this.getState().address.voter_entered_address || false, // Did the voter save an address? - voter_specific_ballot_from_google_civic: this.getState().address.voter_specific_ballot_from_google_civic || false, // Did this ballot come back for this specific address? - }; - } - return null; - } - - getEmailAddressList () { - const { emailAddressList } = this.getState(); - return emailAddressList; - } - - getEmailAddressesVerifiedCount () { - const { emailAddressList } = this.getState(); - let oneEmail = {}; - let verifiedCount = 0; - for (let i = 0; i < emailAddressList.length; ++i) { - oneEmail = emailAddressList[i]; - if (oneEmail.email_ownership_is_verified === true) { - verifiedCount += 1; - } - } - return verifiedCount; - } - - getEmailAddressStatus () { - return this.getState().emailAddressStatus; - } - - getEmailSignInStatus () { - return this.getState().emailSignInStatus; - } - - getExternalVoterId () { - return this.getState().externalVoterId; - } - - getFacebookPhoto () { - return this.getState().voter.facebook_profile_image_url_https || ''; - } - - getFacebookSignInStatus () { - return this.getState().facebookSignInStatus; - } - - getFirstName () { - return this.getState().voter.first_name || ''; - } - - getFirstPlusLastName () { - const storedFirstName = this.getFirstName(); - const storedLastName = this.getLastName(); - let displayName = ''; - if (storedFirstName && String(storedFirstName) !== '') { - displayName = storedFirstName; - if (storedLastName && String(storedLastName) !== '') { - displayName += ' '; - } - } - if (storedLastName && String(storedLastName) !== '') { - displayName += storedLastName; - } - return displayName; - } - - getFullName () { - return this.getState().voter.full_name || ''; - } - - getLastName () { - return this.getState().voter.last_name || ''; - } - - getLinkedOrganizationWeVoteId () { - return this.getState().voter.linked_organization_we_vote_id || ''; - } - - getPrimaryEmailAddressDict () { - const { emailAddressList } = this.getState(); - let oneEmail = {}; - let primaryEmailAddress = {}; - for (let i = 0; i < emailAddressList.length; ++i) { - oneEmail = emailAddressList[i]; - // console.log('getPrimaryEmailAddressDict, oneEmail:', oneEmail); - if (oneEmail.primary_email_address === true && - oneEmail.email_permanent_bounce === false && - oneEmail.email_ownership_is_verified === true) { - primaryEmailAddress = oneEmail; - } - } - // console.log('getPrimaryEmailAddressDict, primaryEmailAddress:', primaryEmailAddress); - return primaryEmailAddress; - } - - getSecretCodeVerificationStatus () { - return this.getState().secretCodeVerificationStatus || {}; - } - - getSMSPhoneNumberStatus () { - return this.getState().smsPhoneNumberStatus; - } - - getSMSPhoneNumberList () { - const { smsPhoneNumberList } = this.getState(); - return smsPhoneNumberList; - } - - getSMSPhoneNumbersVerifiedCount () { - const { smsPhoneNumberList } = this.getState(); - let onePhoneNumber = {}; - let verifiedCount = 0; - for (let i = 0; i < smsPhoneNumberList.length; ++i) { - onePhoneNumber = smsPhoneNumberList[i]; - if (onePhoneNumber.sms_ownership_is_verified === true) { - verifiedCount += 1; - } - } - return verifiedCount; - } - - getStateCode () { - // This defaults to state_code_from_ip_address but is overridden by the address the voter defaults to, or enters in text_for_map_search - return this.getState().voter.state_code || ''; - } - - getStateCodeFromIPAddress () { - return this.getState().voter.state_code_from_ip_address || ''; - } - - getTextForMapSearch () { - let textForMapSearch = this.getState().address.text_for_map_search; - if (textForMapSearch === undefined) { - // Attaching full address object to voterRetrieve, so we can phase this out - textForMapSearch = this.getState().voter.text_for_map_search; - if (textForMapSearch === undefined) return ''; - } - if (Array.isArray(textForMapSearch)) return textForMapSearch[0] || ''; - return textForMapSearch; - } - - getTwitterHandle () { - return this.getState().voter.twitter_handle || ''; - } - - getTwitterSignInStatus () { - return this.getState().twitterSignInStatus || {}; - } - - getVoter () { - return this.getState().voter; - } - - getVoterContactEmailGoogleCount () { - return this.getState().voterContactEmailGoogleCount || 0; - } - - getVoterContactEmailList () { - return this.getState().voterContactEmailList || []; - } - - getVoterContactEmailListCount () { - const voterContactEmailList = this.getState().voterContactEmailList || []; - return voterContactEmailList.length; - } - - getVoterDeleted () { - return this.getState().voterDeleted || false; - } - - getVoterEmail () { - return this.getState().voter.email || ''; - } - - getVoterEmailQueuedToSave () { - return this.getState().voterEmailQueuedToSave; - } - - getVoterEmailQueuedToSaveSet () { - return this.getState().voterEmailQueuedToSaveSet; - } - - getVoterFirstName () { - if (this.getState().voter) { - return this.getState().voter.first_name || ''; - } - return ''; - } - - getVoterFirstNameQueuedToSave () { - return this.getState().voterFirstNameQueuedToSave; - } - - getVoterFirstNameQueuedToSaveSet () { - return this.getState().voterFirstNameQueuedToSaveSet; - } - - getVoterIsSignedIn () { - return this.getState().voter.is_signed_in || false; - } - - getVoterIsSignedInWithEmail () { - return this.getState().voter.signed_in_with_email || false; - } - - getVoterIsSignedInWithFacebook () { - return this.getState().voter.signed_in_facebook || false; - } - - getVoterIsSignedInWithTwitter () { - return this.getState().voter.signed_in_twitter || false; - } - - getVoterLastNameQueuedToSave () { - return this.getState().voterLastNameQueuedToSave; - } - - getVoterLastNameQueuedToSaveSet () { - return this.getState().voterLastNameQueuedToSaveSet; - } - - getVoterNotificationSettingsUpdateStatus () { - return this.getState().voterNotificationSettingsUpdateStatus || {}; - } - - getVoterPhotoQueuedToSave () { - return this.getState().voterPhotoQueuedToSave; - } - - getVoterPhotoQueuedToSaveSet () { - return this.getState().voterPhotoQueuedToSaveSet; - } - - getVoterPhotoTooBig () { - return this.getState().voterPhotoTooBig || false; - } - - // Could be either Facebook photo or Twitter photo - getVoterPhotoUrlLarge () { - return this.getState().voter.voter_photo_url_large || ''; - } - - // Could be either Facebook photo or Twitter photo - getVoterPhotoUrlMedium () { - return this.getState().voter.voter_photo_url_medium || ''; - } - - // Could be either Facebook photo or Twitter photo - getVoterPhotoUrlTiny () { - return this.getState().voter.voter_photo_url_tiny || ''; - } - - getVoterProfileUploadedImageUrlLarge () { - return this.getState().voter.we_vote_hosted_profile_uploaded_image_url_large || ''; - } - - getVoterSavedAddress () { - // console.log('VoterStore, getVoterSavedAddress: ', this.getState().address.voter_entered_address); - return this.getState().address.voter_entered_address || false; - } - - getVoterStateCode () { - // TODO in getVoterStateCode we check for normalized_state in the address object. We should be - // capturing the state when we call Google address Auto Complete (search for _placeChanged) - // and we should also figure out the state_code when we call API server voterAddressSave and put it in the "address" - // return data. - // console.log('this.getState().address:', this.getState().address); - // console.log('this.getState().voter:', this.getState().voter); - if (this.getState().address && this.getState().address.normalized_state) { - // console.log('normalized_state:', this.getState().address.normalized_state); - return this.getState().address.normalized_state; - } - if (this.getState().voter && this.getState().voter.state_code_from_ip_address) { - // console.log('state_code_from_ip_address:', this.getState().voter.state_code_from_ip_address); - return this.getState().voter.state_code_from_ip_address; - } - return ''; - } - - getVoterWeVoteId () { - return this.getState().voter.we_vote_id || ''; - } - - voterDeviceId () { - return this.getState().voter.voter_device_id || Cookies.get('voter_device_id'); - } - - setVoterDeviceIdCookie (id) { // eslint-disable-line - Cookies.remove('voter_device_id'); - Cookies.remove('voter_device_id', { path: '/' }); - Cookies.remove('voter_device_id', { path: '/', domain: 'wevote.us' }); - let { hostname } = window.location; - hostname = hostname || ''; - // console.log('setVoterDeviceIdCookie hostname:', hostname, 'cookie id:', id); - if (hostname && stringContains('wevote.us', hostname)) { - Cookies.set('voter_device_id', id, { expires: 10000, path: '/', domain: 'wevote.us' }); - } else { - Cookies.set('voter_device_id', id, { expires: 10000, path: '/' }); - } - } - - // Airbnb doesnt like bitwise operators in JavaScript - getInterfaceFlagState (flag) { - // Look in js/Constants/VoterConstants.js for list of flag constant definitions - // console.log('VoterStore getInterfaceFlagState flag: ', flag); - if (!this.getState().voter) { - return false; - } - - const interfaceStatusFlags = this.getState().voter.interface_status_flags || 0; - // console.log('VoterStore getInterfaceFlagState interfaceStatusFlags: ', interfaceStatusFlags); - // return True if bit specified by the flag is also set in interfaceStatusFlags (voter.interface_status_flags) - // Eg: if interfaceStatusFlags = 5, then we can confirm that bits representing 1 and 4 are set (i.e., 0101) - // so for value of flag = 1 and 4, we return a positive integer, - // but, the bit representing 2 and 8 are not set, so for flag = 2 and 8, we return zero - // const flagIsSet = interfaceStatusFlags & flag; // eslint-disable-line no-bitwise - // console.log('VoterStore getInterfaceFlagState flagIsSet: ', flagIsSet); - return interfaceStatusFlags & flag; // eslint-disable-line no-bitwise - } - - getNotificationSettingConstantFromUnsubscribeModifier (unsubscribeModifier) { - // New unsubscribe modifiers also need to be added in WeVoteServer - let notificationSettingConstant = 0; - // dailyfriendactivity, friendaccept, friendinvite, friendopinions, friendopinionsall, friendmessage, login, newsletter - // NOT IMPLEMENTED YET: suggestedfriend == NOTIFICATION_SUGGESTED_FRIENDS_EMAIL - if (unsubscribeModifier === 'dailyfriendactivity') { - notificationSettingConstant = VoterConstants.NOTIFICATION_VOTER_DAILY_SUMMARY_EMAIL; - } else if (unsubscribeModifier === 'friendaccept' || unsubscribeModifier === 'friendinvite') { - notificationSettingConstant = VoterConstants.NOTIFICATION_FRIEND_REQUESTS_EMAIL; // friendaccept: NOTIFICATION_FRIEND_REQUEST_RESPONSES_EMAIL - } else if (unsubscribeModifier === 'friendopinions' || unsubscribeModifier === 'friendopinionsall') { - notificationSettingConstant = VoterConstants.NOTIFICATION_FRIEND_OPINIONS_YOUR_BALLOT_EMAIL; // friendopinionsall: NOTIFICATION_FRIEND_OPINIONS_OTHER_REGIONS_EMAIL - } else if (unsubscribeModifier === 'friendmessage') { - notificationSettingConstant = VoterConstants.NOTIFICATION_FRIEND_MESSAGES_EMAIL; - } else if (unsubscribeModifier === 'login') { - notificationSettingConstant = VoterConstants.NOTIFICATION_LOGIN_EMAIL; - } else if (unsubscribeModifier === 'newsletter') { - notificationSettingConstant = VoterConstants.NOTIFICATION_NEWSLETTER_OPT_IN; - } - return notificationSettingConstant; - } - - getNotificationSettingsFlagState (flag) { - // Look in js/Constants/VoterConstants.js for list of flag constant definitions - if (!this.getState().voter) { - return false; - } - // Notification settings we haven't implemented yet which we show as still turned on - if ((flag === VoterConstants.NOTIFICATION_FRIEND_MESSAGES_EMAIL) || - (flag === VoterConstants.NOTIFICATION_FRIEND_OPINIONS_OTHER_REGIONS_EMAIL) || - (flag === VoterConstants.NOTIFICATION_LOGIN_EMAIL)) { - return true; - } - const notificationSettingsFlags = this.getState().voter.notification_settings_flags || 0; - // return True if bit specified by the flag is also set - // in notificationSettingsFlags (voter.notification_settings_flags) - // Eg: if interfaceStatusFlags = 5, then we can confirm that bits representing 1 and 4 are set (i.e., 0101) - // so for value of flag = 1 and 4, we return a positive integer, - // but, the bit representing 2 and 8 are not set, so for flag = 2 and 8, we return zero - return notificationSettingsFlags & flag; // eslint-disable-line no-bitwise - } - - getNotificationSettingsFlagStateFromSecretKey (flag) { - // Look in js/Constants/VoterConstants.js for list of flag constant definitions - if (!this.getState().voterNotificationSettingsUpdateStatus) { - return false; - } - // Notification settings we haven't implemented yet which we show as still turned on - if ((flag === VoterConstants.NOTIFICATION_FRIEND_MESSAGES_EMAIL) || - (flag === VoterConstants.NOTIFICATION_FRIEND_OPINIONS_OTHER_REGIONS_EMAIL) || - (flag === VoterConstants.NOTIFICATION_LOGIN_EMAIL)) { - return true; - } - const { notificationSettingsFlags } = this.getState().voterNotificationSettingsUpdateStatus; - // return True if bit specified by the flag is also set - // in notificationSettingsFlags (voter.notification_settings_flags) - // Eg: if interfaceStatusFlags = 5, then we can confirm that bits representing 1 and 4 are set (i.e., 0101) - // so for value of flag = 1 and 4, we return a positive integer, - // but, the bit representing 2 and 8 are not set, so for flag = 2 and 8, we return zero - return notificationSettingsFlags & flag; // eslint-disable-line no-bitwise - } - - getVoterContactEmailAugmentSequenceComplete () { - return this.getState().voterContactEmailAugmentSequenceComplete || false; - } - - getVoterContactEmailAugmentSequenceHasNextStep () { - return this.getState().voterContactEmailAugmentSequenceHasNextStep || false; - } // voterContactEmailAugmentWithWeVoteDataComplete - - getVoterContactEmailAugmentWithWeVoteDataComplete () { - return this.getState().voterContactEmailAugmentWithWeVoteDataComplete || false; - } - - isVoterFound () { - return this.getState().voterFound; - } - - voterFirstRetrieveCompleted () { - return this.getState().voterFirstRetrieveCompleted; - } - - voterExternalIdHasBeenSavedOnce (externalVoterId, membershipOrganizationWeVoteId) { - if (!externalVoterId || !membershipOrganizationWeVoteId) { - return false; - } - if (this.getState().voterExternalIdHasBeenSavedOnce[externalVoterId]) { - return this.getState().voterExternalIdHasBeenSavedOnce[externalVoterId][membershipOrganizationWeVoteId] || false; - } else { - return false; - } - } - - voterPhotoAndNameExist () { - const firstNameExists = !!(this.getState().voter.first_name && this.getState().voter.first_name !== ''); - const lastNameExists = !!(this.getState().voter.last_name && this.getState().voter.last_name !== ''); - const nameExists = firstNameExists || lastNameExists; - const photoExists = !!(this.getState().voter.voter_photo_url_large && this.getState().voter.voter_photo_url_large !== ''); - return !!(nameExists && photoExists); - } - - reduce (state, action) { - let facebookPhotoRetrieveLoopCount; - let address; - let currentVoterDeviceId; - // const delayBeforeApiCall = 3000; - let externalVoterId; - let googleCivicElectionId; - let incomingVoter; - let incorrectSecretCodeEntered; - let membershipOrganizationWeVoteId; - let mergeFromVoterWeVoteId; - let mergeToVoterWeVoteId; - let numberOfTriesRemaining; - let revisedState; - let secretCodeVerified; - let voterDeviceId; - let voterContactEmailAugmentWithWeVoteDataComplete; - let voterExternalIdHasBeenSavedOnce; - let voterFirstRetrieveCompleted; - let voterMustRequestNewCode; - let voterSecretCodeRequestsLocked; - - switch (action.type) { - case 'clearEmailAddressStatus': - // console.log('VoterStore clearEmailAddressStatus'); - return { ...state, emailAddressStatus: {} }; - case 'clearSecretCodeVerificationStatus': - // console.log('VoterStore clearSecretCodeVerificationStatus'); - return { - ...state, - secretCodeVerificationStatus: { - incorrectSecretCodeEntered: false, - numberOfTriesRemaining: 5, - secretCodeVerified: false, - voterMustRequestNewCode: false, - voterSecretCodeRequestsLocked: false, - }, - }; - case 'clearSecretCodeVerificationStatusAndEmail': - // Does both of the above steps in one call - // console.log('VoterStore clearSecretCodeVerificationStatusAndEmail'); - return { - ...state, - emailAddressStatus: {}, - secretCodeVerificationStatus: { - incorrectSecretCodeEntered: false, - numberOfTriesRemaining: 5, - secretCodeVerified: false, - voterMustRequestNewCode: false, - voterSecretCodeRequestsLocked: false, - }, - }; - case 'clearSMSPhoneNumberStatus': - // console.log('VoterStore clearSMSPhoneNumberStatus'); - return { - ...state, - smsPhoneNumberStatus: { - sms_verify_attempted: false, - sms_phone_number_already_owned_by_other_voter: false, - sms_phone_number_already_owned_by_this_voter: false, - sms_phone_number_created: false, - sms_phone_number: '', - sms_phone_number_found: false, - sms_phone_number_deleted: false, - make_primary_sms: false, - sign_in_code_sms_sent: false, - verification_sms_sent: false, - }, - }; - case 'clearSecretCodeVerificationStatusAndPhone': - // console.log('VoterStore clearSecretCodeVerificationStatusAndPhone'); - return { - ...state, - secretCodeVerificationStatus: { - incorrectSecretCodeEntered: false, - numberOfTriesRemaining: 5, - secretCodeVerified: false, - voterMustRequestNewCode: false, - voterSecretCodeRequestsLocked: false, - }, - smsPhoneNumberStatus: { - sms_verify_attempted: false, - sms_phone_number_already_owned_by_other_voter: false, - sms_phone_number_already_owned_by_this_voter: false, - sms_phone_number_created: false, - sms_phone_number: '', - sms_phone_number_found: false, - sms_phone_number_deleted: false, - make_primary_sms: false, - sign_in_code_sms_sent: false, - verification_sms_sent: false, - }, - }; - case 'clearVoterElectionId': - // console.log('VoterStore clearVoterElectionId'); - return { ...state, latestGoogleCivicElectionId: 0 }; - case 'clearVoterContactEmailImportVariables': - return { - ...state, - voterContactEmailAugmentWithWeVoteDataComplete: false, - voterContactEmailAugmentSequenceComplete: false, - voterContactEmailAugmentSequenceHasNextStep: false, - }; - case 'organizationSave': - // console.log('VoterStore organizationSave'); - // If an organization saves, we want to check to see if it is tied to this voter. If so, - // refresh the voter data so we have the value linked_organization_we_vote_id in the voter object. - if (action.res.success) { - if (action.res.facebook_id === state.voter.facebook_id) { - VoterActions.voterRetrieve(); - } else { - const organizationTwitterHandle = action.res.organization_twitter_handle || ''; - const twitterScreenName = state.voter.twitter_screen_name !== undefined ? state.voter.twitter_screen_name : ''; - if (organizationTwitterHandle && organizationTwitterHandle.toLowerCase() === twitterScreenName.toLowerCase()) { - VoterActions.voterRetrieve(); - } - } - } - return state; - - case 'positionListForVoter': - // console.log('VoterStore positionListForVoter'); - if (action.res.show_only_this_election) { - const positionListForOneElection = action.res.position_list; - return { - ...state, - voter: { - ...state.voter, - positionListForOneElection, - }, - }; - } else if (action.res.show_all_other_elections) { - const positionListForAllExceptOneElection = action.res.position_list; - return { - ...state, - voter: { - ...state.voter, - positionListForAllExceptOneElection, - }, - }; - } else { - const positionList = action.res.position_list; - return { - ...state, - voter: { - ...state.voter, - positionList, - }, - }; - } - - case 'setExternalVoterId': - externalVoterId = action.payload; - membershipOrganizationWeVoteId = AppObservableStore.getSiteOwnerOrganizationWeVoteId(); - ({ voterExternalIdHasBeenSavedOnce } = state); - // console.log('VoterStore externalVoterId:', externalVoterId, ', membershipOrganizationWeVoteId:', membershipOrganizationWeVoteId); - if (externalVoterId && membershipOrganizationWeVoteId) { - if (!this.voterExternalIdHasBeenSavedOnce(externalVoterId, membershipOrganizationWeVoteId)) { - // console.log('voterExternalIdHasBeenSavedOnce has NOT been saved before.'); - VoterActions.voterExternalIdSave(externalVoterId, membershipOrganizationWeVoteId); - if (!voterExternalIdHasBeenSavedOnce[externalVoterId]) { - voterExternalIdHasBeenSavedOnce[externalVoterId] = {}; - } - voterExternalIdHasBeenSavedOnce[externalVoterId][membershipOrganizationWeVoteId] = true; - // AnalyticsActions.saveActionBallotVisit(VoterStore.electionId()); - } else { - // console.log('voterExternalIdHasBeenSavedOnce has been saved before.'); - } - } - return { - ...state, - externalVoterId, - voterExternalIdHasBeenSavedOnce, - }; - - case 'twitterRetrieveIdsIFollow': - // console.log('VoterStore twitterRetrieveIdsIFollow'); - if (action.res.success) { - VoterActions.organizationSuggestionTasks('UPDATE_SUGGESTIONS_FROM_TWITTER_IDS_I_FOLLOW', - 'FOLLOW_SUGGESTIONS_FROM_TWITTER_IDS_I_FOLLOW'); - } - - return state; - - case 'voterAnalysisForJumpProcess': - // console.log('VoterStore, voterAnalysisForJumpProcess'); - VoterActions.voterRetrieve(); - return { - ...state, - emailAddressStatus: { - email_ownership_is_verified: action.res.email_ownership_is_verified, - email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, - email_verify_attempted: action.res.email_verify_attempted, - email_address_found: action.res.email_address_found, - }, - emailSignInStatus: { - email_ownership_is_verified: action.res.email_ownership_is_verified, - email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, - email_sign_in_attempted: action.res.email_verify_attempted, - email_address_found: action.res.email_address_found, - }, - }; - - case 'voterAddressRetrieve': - case 'voterAddressOnlyRetrieve': - // console.log('VoterStore, voterAddressRetrieve, address:', action.res); - address = action.res || {}; - return { - ...state, - address, - }; - - case 'voterAddressSave': - // console.log('VoterStore, voterAddressSave, action.res:', action.res); - revisedState = state; - if (action.res.status === 'SIMPLE_ADDRESS_SAVE') { - // Don't do any other refreshing - } else { - googleCivicElectionId = action.res.google_civic_election_id || 0; - if (googleCivicElectionId !== 0) { - revisedState = { ...revisedState, - latestGoogleCivicElectionId: googleCivicElectionId, - }; - } - } - ({ address } = action.res); - if (!address) { - address = { - text_for_map_search: '', - google_civic_election_id: 0, - ballot_returned_we_vote_id: '', - ballot_location_display_name: '', - voter_entered_address: '', - voter_specific_ballot_from_google_civic: null, - }; - } - - return { - ...revisedState, - address: { - text_for_map_search: address.text_for_map_search, - google_civic_election_id: address.google_civic_election_id, - ballot_returned_we_vote_id: address.ballot_returned_we_vote_id, - ballot_location_display_name: address.ballot_location_display_name, - voter_entered_address: address.voter_entered_address, - voter_specific_ballot_from_google_civic: address.voter_specific_ballot_from_google_civic, - }, - }; - - case 'voterBallotItemsRetrieve': - // console.log('VoterStore voterBallotItemsRetrieve latestGoogleCivicElectionId: ', action.res.google_civic_election_id); - googleCivicElectionId = action.res.google_civic_election_id || 0; - if (googleCivicElectionId !== 0) { - return { - ...state, - latestGoogleCivicElectionId: googleCivicElectionId, - }; - } - return state; - - case 'voterContactListRetrieve': - // console.log('VoterStore voterContactListRetrieve action:', action); - if (action.res.success) { - const { - voter_contact_email_google_count: voterContactEmailGoogleCount, - voter_contact_email_list: voterContactEmailList, - } = action.res; - return { - ...state, - voterContactEmailGoogleCount, - voterContactEmailList, - }; - } else { - console.log('response voterContactListRetrieve was not successful'); - return state; - } - - case 'voterContactListSave': - // console.log('VoterStore voterContactListSave action.res:', action.res); - if (action.res.success) { - ({ voterContactEmailAugmentWithWeVoteDataComplete } = state); - const { - augment_voter_contact_emails_with_location: justAugmentedWithLocation, - augment_voter_contact_emails_with_we_vote_data: justAugmentedWithWeVoteData, - contacts_stored: googleContactsStored, - delete_all_voter_contact_emails: voterContactEmailsJustDeleted, - voter_contact_email_augment_sequence_complete: voterContactEmailAugmentSequenceComplete, - voter_contact_email_augment_sequence_has_next_step: voterContactEmailAugmentSequenceHasNextStep, - voter_contact_email_google_count: voterContactEmailGoogleCount, - voter_contact_email_list: voterContactEmailList, - we_vote_id_for_google_contacts: weVoteIdForGoogleContacts, - } = action.res; - // console.log('googleContactsStored:', googleContactsStored, ', justAugmentedWithWeVoteData:', justAugmentedWithWeVoteData, ',justAugmentedWithLocation:', justAugmentedWithLocation); - if (voterContactEmailsJustDeleted || justAugmentedWithLocation) { - // Never call again - } else if (googleContactsStored && (googleContactsStored > 0)) { - // console.log('Calling VoterActions.voterContactListAugmentWithWeVoteData'); - VoterActions.voterContactListAugmentWithWeVoteData(true); - } else if (justAugmentedWithWeVoteData) { - // console.log('Calling VoterActions.voterContactListAugmentWithLocation'); - VoterActions.voterContactListAugmentWithLocation(true); - } - if (googleContactsStored) { - voterContactEmailAugmentWithWeVoteDataComplete = false; - } else if (justAugmentedWithWeVoteData) { - voterContactEmailAugmentWithWeVoteDataComplete = true; - } - return { - ...state, - weVoteIdForGoogleContacts, - googleContactsStored, - voterContactEmailAugmentWithWeVoteDataComplete, - voterContactEmailAugmentSequenceComplete, - voterContactEmailAugmentSequenceHasNextStep, - voterContactEmailGoogleCount, - voterContactEmailList, - }; - } else { - console.log('response voterContactListSave was not successful'); - return state; - } - - case 'voterEmailAddressRetrieve': - // console.log('VoterStore voterEmailAddressRetrieve: ', action.res.email_address_list); - return { - ...state, - emailAddressList: action.res.email_address_list, - }; - - case 'voterEmailAddressSave': - // console.log('VoterStore, voterEmailAddressSave'); - VoterActions.voterRetrieve(); - return { - ...state, - emailAddressList: action.res.email_address_list, - emailAddressStatus: { - email_verify_attempted: action.res.email_verify_attempted, - email_address_already_owned_by_other_voter: action.res.email_address_already_owned_by_other_voter, - email_address_already_owned_by_this_voter: action.res.email_address_already_owned_by_this_voter, - email_address_created: action.res.email_address_created, - email_address_deleted: action.res.email_address_deleted, - email_address_not_valid: action.res.email_address_not_valid, - from_voter_we_vote_id: action.res.from_voter_we_vote_id, - link_to_sign_in_email_sent: action.res.link_to_sign_in_email_sent, - make_primary_email: action.res.make_primary_email, - sign_in_code_email_sent: action.res.sign_in_code_email_sent, - secret_code_system_locked_for_this_voter_device_id: action.res.secret_code_system_locked_for_this_voter_device_id, - to_voter_we_vote_id: action.res.to_voter_we_vote_id, - verification_email_sent: action.res.verification_email_sent, - }, - }; - - case 'voterEmailAddressSignIn': - // console.log('VoterStore, voterEmailAddressSignIn'); - VoterActions.voterRetrieve(); - return { - ...state, - emailSignInStatus: { - email_sign_in_attempted: action.res.email_sign_in_attempted, - email_ownership_is_verified: action.res.email_ownership_is_verified, - email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, - email_address_found: action.res.email_address_found, - yes_please_merge_accounts: action.res.yes_please_merge_accounts, - voter_we_vote_id_from_secret_key: action.res.voter_we_vote_id_from_secret_key, - voter_merge_two_accounts_attempted: false, - }, - }; - - case 'voterEmailAddressVerify': - // console.log('VoterStore, voterEmailAddressVerify'); - VoterActions.voterRetrieve(); - return { - ...state, - emailAddressStatus: { - email_ownership_is_verified: action.res.email_ownership_is_verified, - email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, - email_verify_attempted: action.res.email_verify_attempted, - email_address_found: action.res.email_address_found, - }, - emailSignInStatus: { - email_ownership_is_verified: action.res.email_ownership_is_verified, - email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, - email_sign_in_attempted: action.res.email_verify_attempted, - email_address_found: action.res.email_address_found, - }, - }; - - case 'voterEmailQueuedToSave': - // console.log('VoterStore voterEmailQueuedToSave: ', action.payload); - if (action.payload === undefined) { - return { - ...state, - voterEmailQueuedToSave: '', - voterEmailQueuedToSaveSet: false, - }; - } else { - return { - ...state, - voterEmailQueuedToSave: action.payload, - voterEmailQueuedToSaveSet: true, - }; - } - - case 'voterFacebookSaveToCurrentAccount': - // console.log('VoterStore, voterFacebookSaveToCurrentAccount'); - VoterActions.voterRetrieve(); - return { - ...state, - facebookSignInStatus: { - facebook_account_created: action.res.facebook_account_created, - }, - }; - - case 'voterFirstNameQueuedToSave': - // console.log('VoterStore voterFirstNameQueuedToSave: ', action.payload); - if (action.payload === undefined) { - return { - ...state, - voterFirstNameQueuedToSave: '', - voterFirstNameQueuedToSaveSet: false, - }; - } else { - return { - ...state, - voterFirstNameQueuedToSave: action.payload, - voterFirstNameQueuedToSaveSet: true, - }; - } - - case 'voterLastNameQueuedToSave': - // console.log('VoterStore voterLastNameQueuedToSave: ', action.payload); - if (action.payload === undefined) { - return { - ...state, - voterLastNameQueuedToSave: '', - voterLastNameQueuedToSaveSet: false, - }; - } else { - return { - ...state, - voterLastNameQueuedToSave: action.payload, - voterLastNameQueuedToSaveSet: true, - }; - } - - case 'voterMergeTwoAccounts': - // console.log('VoterStore, voterMergeTwoAccounts'); - // On the server we just switched (linked) this voterDeviceId to a new voter record, so we want to the voter. - // refresh a lot of data -- December 2022, but as little as absolutely required, and no more - VoterActions.voterRetrieve(); - // // And set a timer for 3 seconds from now to refresh again - // this.timer = setTimeout(() => { - // VoterActions.voterRetrieve(); - // }, delayBeforeApiCall); - VoterActions.voterEmailAddressRetrieve(); // TODO: December 2022, Is this necessary? - VoterActions.voterSMSPhoneNumberRetrieve(); // TODO: December 2022, Is this necessary? - if (action.res.merge_from_voter_we_vote_id && action.res.merge_to_voter_we_vote_id) { - if (apiCalming('voterRetrieveMergeTwo', 3000)) { - // This completes the time-consuming process 'voter_merge_two_accounts_action' and then returns voter data - console.log('VoterStore: voterMergeTwoAccounts: Completing voterRetrieveMergeTwo process'); - VoterActions.voterRetrieve(action.res.merge_from_voter_we_vote_id, action.res.merge_to_voter_we_vote_id); - } - } - return { - ...state, - emailSignInStatus: { - email_ownership_is_verified: true, - email_secret_key_belongs_to_this_voter: true, - email_sign_in_attempted: true, - email_address_found: true, - yes_please_merge_accounts: false, - voter_we_vote_id_from_secret_key: '', - voter_merge_two_accounts_attempted: true, - }, - facebookSignInStatus: { - voter_merge_two_accounts_attempted: true, - }, - twitterSignInStatus: { - voter_merge_two_accounts_attempted: true, - }, - }; - - case 'voterNotificationSettingsUpdate': - // console.log('VoterStore, voterNotificationSettingsUpdate'); - if (!action.res) { - return { - ...state, - voterNotificationSettingsUpdateStatus: { - apiResponseReceived: true, - emailFound: false, - voterFound: false, - normalizedEmailAddress: '', - normalizedSmsPhoneNumber: '', - notificationSettingsFlags: false, - }, - }; - } - return { - ...state, - voterNotificationSettingsUpdateStatus: { - apiResponseReceived: true, - emailFound: action.res.email_found, - voterFound: action.res.voter_found, - normalizedEmailAddress: action.res.normalized_email_address, - normalizedSmsPhoneNumber: action.res.normalized_sms_phone_number, - notificationSettingsFlags: action.res.notification_settings_flags, - }, - }; - - case 'voterPhotoQueuedToSave': - // console.log('VoterStore voterPhotoQueuedToSave: ', action.payload); - if (action.payload === undefined) { - return { - ...state, - voterPhotoQueuedToSave: '', - voterPhotoQueuedToSaveSet: false, - }; - } else { - return { - ...state, - voterPhotoQueuedToSave: action.payload, - voterPhotoQueuedToSaveSet: true, - }; - } - - case 'voterPhotoSave': - // console.log('VoterStore, voterPhotoSave'); - return { - ...state, - voter: { ...state.voter, facebook_profile_image_url_https: action.res.facebook_profile_image_url_https }, - }; - - case 'voterPhotoTooBigReset': - // console.log('VoterStore, voterPhotoTooBigReset'); - return { - ...state, - voterPhotoTooBig: false, - }; - - case 'voterRetrieve': - // console.log('VoterStore, voterRetrieve state on entry: ', state); - // console.log('VoterStore, voterRetrieve state on entry: ', state.voter); - - // Preserve address within voter - incomingVoter = action.res; - ({ facebookPhotoRetrieveLoopCount, voterFirstRetrieveCompleted } = state); - if (!voterFirstRetrieveCompleted) { - voterFirstRetrieveCompleted = Boolean(action.res.success); - } - - currentVoterDeviceId = Cookies.get('voter_device_id'); - // console.log('VoterStore, voterRetrieve stored Cookie value for voter_device_id value on entry: ', currentVoterDeviceId); - if (!action.res.voter_found) { - console.log(`This voter_device_id is not in the db and is invalid, so delete it: ${currentVoterDeviceId}`); - - // Attempt to delete the voter_device_id cookie in a variety of ways - Cookies.remove('voter_device_id'); - Cookies.remove('voter_device_id', { path: '/' }); - Cookies.remove('voter_device_id', { path: '/', domain: 'wevote.us' }); - - // ...and then ask for a new voter. When it returns a voter with a new voter_device_id, we will set new cookie - if (!Cookies.get('voter_device_id')) { - console.log('voter_device_id gone -- calling voterRetrieve'); - VoterActions.voterRetrieve(); - } else { - // console.log('voter_device_id still exists -- did not call voterRetrieve'); - } - } else { - voterDeviceId = action.res.voter_device_id; - if (voterDeviceId) { - if (currentVoterDeviceId !== voterDeviceId) { - console.log('Setting new voter_device_id'); - this.setVoterDeviceIdCookie(voterDeviceId); - } - // FriendsInvitationList.jsx is choking on this because calling this - // results in an infinite loop cycling between voterRetrieve and getFaceProfilePicture which - // resolves to FACEBOOK_RECEIVED_PICTURE which then attempts to save using voterFacebookSignInPhoto - // which in turn resolves to voterFacebookSignInSave which finally attempts to call - // voterRetrieve again - // console.log('VoterStore, voterRetrieve, action.res: ', action.res); - } else { - // console.log('voter_device_id not returned by voterRetrieve'); - } - } - // April 29, 2021 TODO: We should make a combined Voter and Organization retrieve - // because this fires on the initial page load and takes almost a full second to return, blocking one of six available http channels - // Firing actions from stores should be avoided - // The following (new) condition blocks a organizationRetrieve on the first voterRetrieve - - // if (incomingVoter.signed_in_with_apple) { - // // Completing the logical OR that can't be conveniently made in the server, since Sign in with Apple is device_id specific - // incomingVoter.is_signed_in = incomingVoter.signed_in_with_apple; - // const { voter_photo_url_medium: statePhotoMed } = state.voter; - // const { voter_photo_url_medium: incomingPhotoMed } = incomingVoter; - // if (!statePhotoMed && !incomingPhotoMed) { - // incomingVoter.voter_photo_url_medium = 'https://wevote.us/img/global/logos/Apple_logo_grey.svg'; // TODO: Switch over to wevote.us once live server is updated - // } - // } - if (incomingVoter && incomingVoter.we_vote_id) { - if (incomingVoter.we_vote_id !== AppObservableStore.getOpenReplayVoterWeVoteId()) { - // console.log('tracker.setUserId:', incomingVoter.we_vote_id); - const tracker = AppObservableStore.getOpenReplayTracker(); - if (tracker) { - console.log('OpenReplay setting id: ', incomingVoter.we_vote_id); - AppObservableStore.setOpenReplayVoterWeVoteId(incomingVoter.we_vote_id); - tracker.setUserID(incomingVoter.we_vote_id); - } - } - if (incomingVoter.is_signed_in && !AppObservableStore.getOpenReplayVoterIsSignedIn()) { - const tracker = AppObservableStore.getOpenReplayTracker(); - if (tracker) { - console.log('OpenReplay setting voterIsSignedIn'); - AppObservableStore.setOpenReplayVoterIsSignedIn(true); - tracker.setMetadata('voterIsSignedIn', 'true'); - } - } - if (this.getStateCode() && !AppObservableStore.getOpenReplayStateCode()) { - // getStateCode defaults to state_code_from_ip_address but is overridden by the state in text_for_map_search - const tracker = AppObservableStore.getOpenReplayTracker(); - const stateCode = this.getStateCode().toUpperCase(); - if (tracker && stateCode) { - console.log('OpenReplay setting stateCode'); - AppObservableStore.setOpenReplayStateCode(stateCode); - tracker.setMetadata('stateCode', stateCode); - } - } - if (incomingVoter.state_code_from_ip_address && !AppObservableStore.getOpenReplayStateCodeFromIpAddress()) { - const tracker = AppObservableStore.getOpenReplayTracker(); - const stateCodeFromIpAddress = incomingVoter.state_code_from_ip_address.toUpperCase(); - if (tracker && stateCodeFromIpAddress) { - console.log('OpenReplay setting stateCodeFromIpAddress'); - AppObservableStore.setOpenReplayStateCodeFromIpAddress(stateCodeFromIpAddress); - tracker.setMetadata('stateCodeFromIpAddress', stateCodeFromIpAddress); - } - } - } - revisedState = state; - revisedState = { - ...revisedState, - facebookPhotoRetrieveLoopCount: facebookPhotoRetrieveLoopCount + 1, - voter: incomingVoter, - voterFirstRetrieveCompleted, - voterFound: action.res.voter_found, - }; - if (incomingVoter.address) { - // console.log('incomingVoter.address:', incomingVoter.address); - revisedState = { ...revisedState, address: incomingVoter.address }; - } - return revisedState; - - case 'voterSignOut': - // console.log('VoterStore resetting voterStore via voterSignOut'); - VoterActions.voterRetrieve(); - VoterActions.voterEmailAddressRetrieve(); - VoterActions.voterSMSPhoneNumberRetrieve(); - revisedState = state; - revisedState = { ...revisedState, ...this.getInitialState() }; - return revisedState; - - case 'voterSMSPhoneNumberRetrieve': - // console.log('VoterStore voterSMSPhoneNumberRetrieve: ', action.res.sms_phone_number_list); - return { - ...state, - smsPhoneNumberList: action.res.sms_phone_number_list, - }; - - case 'voterSMSPhoneNumberSave': - // console.log('VoterStore voterSMSPhoneNumberSave action.res:', action.res); - VoterActions.voterRetrieve(); - VoterActions.voterSMSPhoneNumberRetrieve(); - return { - ...state, - smsPhoneNumberList: action.res.sms_phone_number_list, - smsPhoneNumberStatus: { - sms_verify_attempted: action.res.sms_verify_attempted, - sms_phone_number_already_owned_by_other_voter: action.res.sms_phone_number_already_owned_by_other_voter, - sms_phone_number_already_owned_by_this_voter: action.res.sms_phone_number_already_owned_by_this_voter, - sms_phone_number_created: action.res.sms_phone_number_created, - sms_phone_number: action.res.sms_phone_number, - sms_phone_number_found: action.res.sms_phone_number_found, - sms_phone_number_deleted: action.res.sms_phone_number_deleted, - make_primary_sms: action.res.make_primary_sms, - secret_code_system_locked_for_this_voter_device_id: action.res.secret_code_system_locked_for_this_voter_device_id, - sign_in_code_sms_sent: action.res.sign_in_code_sms_sent, - verification_sms_sent: action.res.verification_sms_sent, - }, - }; - - case 'voterSplitIntoTwoAccounts': - // console.log('VoterStore voterSplitIntoTwoAccounts '); - VoterActions.voterRetrieve(); - return state; - - case 'voterTwitterSaveToCurrentAccount': - // console.log('VoterStore voterTwitterSaveToCurrentAccount '); - VoterActions.voterRetrieve(); - return { - ...state, - twitterSignInStatus: { - twitter_account_created: action.res.twitter_account_created, - }, - }; - - case 'voterUpdate': // Formerly voterDeleteAccount - if (action.res.success && action.res.voter_deleted) { - revisedState = state; - revisedState = { ...revisedState, - voterDeleted: true, - voterNotDeleted: false, - }; - return revisedState; - } else if (action.res.success && action.res.voter_not_deleted) { - revisedState = state; - revisedState = { ...revisedState, - voterDeleted: false, - voterNotDeleted: true, - }; - return revisedState; - } else if (action.res.success) { - let interfaceStatusFlags = action.res.interface_status_flags; - if (interfaceStatusFlags === undefined) { - interfaceStatusFlags = state.voter.interface_status_flags; - } - let notificationSettingsFlags = action.res.notification_settings_flags; - if (notificationSettingsFlags === undefined) { - notificationSettingsFlags = state.voter.notification_settings_flags; - } - return { - ...state, - voter: { - ...state.voter, - // With this we are only updating the values we change with a voterUpdate call. - facebook_email: action.res.email || state.voter.email, - first_name: action.res.first_name, - interface_status_flags: interfaceStatusFlags, - last_name: action.res.last_name, - notification_settings_flags: notificationSettingsFlags, - profile_image_type_currently_active: action.res.profile_image_type_currently_active || '', - voter_donation_history_list: action.res.voter_donation_history_list || state.voter.voter_donation_history_list, - voter_photo_url_large: action.res.we_vote_hosted_profile_image_url_large || '', - voter_photo_url_medium: action.res.we_vote_hosted_profile_image_url_medium || '', - voter_photo_url_tiny: action.res.we_vote_hosted_profile_image_url_tiny || '', - we_vote_hosted_profile_facebook_image_url_large: action.res.we_vote_hosted_profile_facebook_image_url_large || '', - we_vote_hosted_profile_twitter_image_url_large: action.res.we_vote_hosted_profile_twitter_image_url_large || '', - we_vote_hosted_profile_uploaded_image_url_large: action.res.we_vote_hosted_profile_uploaded_image_url_large || '', - }, - voterPhotoTooBig: action.res.voter_photo_too_big || false, - }; - } else { - return { - ...state, - voterPhotoTooBig: action.res.voter_photo_too_big || false, - }; - } - - case 'voterVerifySecretCode': - // console.log('VoterStore, voterVerifySecretCode, action.res:', action.res); - incorrectSecretCodeEntered = (action.res.incorrect_secret_code_entered && action.res.incorrect_secret_code_entered === true); - mergeFromVoterWeVoteId = action.res.merge_from_voter_we_vote_id; - mergeToVoterWeVoteId = action.res.merge_to_voter_we_vote_id; - numberOfTriesRemaining = action.res.number_of_tries_remaining_for_this_code; - secretCodeVerified = (action.res.secret_code_verified && action.res.secret_code_verified === true); - voterMustRequestNewCode = (action.res.voter_must_request_new_code && action.res.voter_must_request_new_code === true); - voterSecretCodeRequestsLocked = (action.res.secret_code_system_locked_for_this_voter_device_id && action.res.secret_code_system_locked_for_this_voter_device_id === true); - // console.log('onVoterStoreChange voterStore secretCodeVerified', secretCodeVerified); - // It is appropriate to keep this call within the Store because the components which trigger the voterVerifySecretCode - // get closed as soon as secretCodeVerified is true - if (mergeFromVoterWeVoteId && mergeToVoterWeVoteId) { - // console.log('VoterStore, voterVerifySecretCode: voterRetrieveMergeTwo mergeFromVoterWeVoteId:', mergeFromVoterWeVoteId, ', mergeToVoterWeVoteId:', mergeToVoterWeVoteId); - if (apiCalming('voterRetrieveMergeTwo', 3000)) { - // This completes the time-consuming process 'voter_merge_two_accounts_action' and then returns voter data - VoterActions.voterRetrieve(mergeFromVoterWeVoteId, mergeToVoterWeVoteId); - } - } - return { - ...state, - secretCodeVerificationStatus: { - incorrectSecretCodeEntered, - numberOfTriesRemaining, - secretCodeVerified, - voterMustRequestNewCode, - voterSecretCodeRequestsLocked, - }, - }; - - case 'appleSignInSave': - if (action.res.success) { - // eslint-disable-next-line camelcase - const { first_name, middle_name, last_name, email, user_code: appleUserCode } = action.res; - VoterActions.voterRetrieve(); - return { - ...state, - voter: { - first_name, - middle_name, - last_name, - email, - appleUserCode, - signed_in_with_apple: true, - }, - }; - } else { - console.log('Received a bad response from appleSignInSave API call'); - return state; - } - - case 'deviceStoreFirebaseCloudMessagingToken': - if (action.res.success) { - // console.log('Received success from deviceStoreFirebaseCloudMessagingToken API call'); - return state; - } else { - console.log('Received a bad response from deviceStoreFirebaseCloudMessagingToken API call, object properties follow:'); - dumpObjProps('action.res', action.res); - return state; - } - - - case 'error-voterRetrieve' || 'error-voterAddressRetrieve' || 'error-voterAddressSave': - // console.log('VoterStore action', action); - return state; - - default: - return state; - } - } -} - -export default new VoterStore(Dispatcher); +// import { ReduceStore } from 'flux/utils'; +// import VoterActions from '../actions/VoterActions'; // eslint-disable-line import/no-cycle +// import Dispatcher from '../common/dispatcher/Dispatcher'; +// import AppObservableStore from './AppObservableStore'; // eslint-disable-line import/no-cycle +// import apiCalming from '../common/utils/apiCalming'; +// import Cookies from '../common/utils/js-cookie/Cookies'; +// import stringContains from '../common/utils/stringContains'; +// import VoterConstants from '../constants/VoterConstants'; +// import { dumpObjProps } from '../utils/appleSiliconUtils'; +// +// class VoterStore extends ReduceStore { +// getInitialState () { +// return { +// voter: { +// interface_status_flags: 0, +// state_code_from_ip_address: '', +// }, +// address: {}, +// emailAddressStatus: {}, +// emailSignInStatus: {}, +// emailAddressList: [], +// externalVoterId: '', +// facebookSignInStatus: {}, +// facebookPhotoRetrieveLoopCount: 0, +// latestGoogleCivicElectionId: 0, +// secretCodeVerificationStatus: { +// incorrectSecretCodeEntered: false, +// numberOfTriesRemaining: 5, +// secretCodeVerified: false, +// voterMustRequestNewCode: false, +// voterSecretCodeRequestsLocked: false, +// }, +// smsPhoneNumberStatus: { +// sms_verify_attempted: false, +// sms_phone_number_already_owned_by_other_voter: false, +// sms_phone_number_already_owned_by_this_voter: false, +// sms_phone_number_created: false, +// sms_phone_number: '', +// sms_phone_number_found: false, +// sms_phone_number_deleted: false, +// make_primary_sms: false, +// sign_in_code_sms_sent: false, +// verification_sms_sent: false, +// }, +// smsPhoneNumberList: [], +// voterContactEmailGoogleCount: 0, +// voterContactEmailList: [], +// voterDeleted: false, +// voterEmailQueuedToSave: '', +// voterEmailQueuedToSaveSet: false, +// voterFirstNameQueuedToSave: '', +// voterFirstNameQueuedToSaveSet: false, +// voterFirstRetrieveCompleted: false, // Has the first retrieve of the voter completed? +// voterFound: false, +// voterExternalIdHasBeenSavedOnce: {}, // Dict with externalVoterId and membershipOrganizationWeVoteId as keys, and true/false as value +// voterLastNameQueuedToSave: '', +// voterLastNameQueuedToSaveSet: false, +// voterNotificationSettingsUpdateStatus: { +// apiResponseReceived: false, +// emailFound: false, +// voterFound: false, +// normalizedEmailAddress: '', +// normalizedSmsPhoneNumber: '', +// notificationSettingsFlags: false, +// }, +// voterPhotoQueuedToSave: '', +// voterPhotoQueuedToSaveSet: false, +// voterPhotoTooBig: false, +// }; +// } +// +// electionId () { +// return this.getState().latestGoogleCivicElectionId || 0; +// } +// +// resetState () { +// return this.getInitialState(); +// } +// +// getAddressObject () { +// return this.getState().address || {}; +// } +// +// getBallotLocationForVoter () { +// // console.log('getBallotLocationForVoter this.getState().address:', this.getState().address); +// if (this.getState().address) { +// return { +// text_for_map_search: this.getTextForMapSearch(), +// ballot_returned_we_vote_id: this.getState().address.ballot_returned_we_vote_id, +// polling_location_we_vote_id: '', +// ballot_location_order: 0, +// ballot_location_display_name: this.getState().address.ballot_location_display_name, +// ballot_location_shortcut: '', +// google_civic_election_id: this.getState().address.google_civic_election_id, +// voter_entered_address: this.getState().address.voter_entered_address || false, // Did the voter save an address? +// voter_specific_ballot_from_google_civic: this.getState().address.voter_specific_ballot_from_google_civic || false, // Did this ballot come back for this specific address? +// }; +// } +// return null; +// } +// +// getEmailAddressList () { +// const { emailAddressList } = this.getState(); +// return emailAddressList; +// } +// +// getEmailAddressesVerifiedCount () { +// const { emailAddressList } = this.getState(); +// let oneEmail = {}; +// let verifiedCount = 0; +// for (let i = 0; i < emailAddressList.length; ++i) { +// oneEmail = emailAddressList[i]; +// if (oneEmail.email_ownership_is_verified === true) { +// verifiedCount += 1; +// } +// } +// return verifiedCount; +// } +// +// getEmailAddressStatus () { +// return this.getState().emailAddressStatus; +// } +// +// getEmailSignInStatus () { +// return this.getState().emailSignInStatus; +// } +// +// getExternalVoterId () { +// return this.getState().externalVoterId; +// } +// +// getFacebookPhoto () { +// return this.getState().voter.facebook_profile_image_url_https || ''; +// } +// +// getFacebookSignInStatus () { +// return this.getState().facebookSignInStatus; +// } +// +// getFirstName () { +// return this.getState().voter.first_name || ''; +// } +// +// getFirstPlusLastName () { +// const storedFirstName = this.getFirstName(); +// const storedLastName = this.getLastName(); +// let displayName = ''; +// if (storedFirstName && String(storedFirstName) !== '') { +// displayName = storedFirstName; +// if (storedLastName && String(storedLastName) !== '') { +// displayName += ' '; +// } +// } +// if (storedLastName && String(storedLastName) !== '') { +// displayName += storedLastName; +// } +// return displayName; +// } +// +// getFullName () { +// return this.getState().voter.full_name || ''; +// } +// +// getLastName () { +// return this.getState().voter.last_name || ''; +// } +// +// getLinkedOrganizationWeVoteId () { +// return this.getState().voter.linked_organization_we_vote_id || ''; +// } +// +// getPrimaryEmailAddressDict () { +// const { emailAddressList } = this.getState(); +// let oneEmail = {}; +// let primaryEmailAddress = {}; +// for (let i = 0; i < emailAddressList.length; ++i) { +// oneEmail = emailAddressList[i]; +// // console.log('getPrimaryEmailAddressDict, oneEmail:', oneEmail); +// if (oneEmail.primary_email_address === true && +// oneEmail.email_permanent_bounce === false && +// oneEmail.email_ownership_is_verified === true) { +// primaryEmailAddress = oneEmail; +// } +// } +// // console.log('getPrimaryEmailAddressDict, primaryEmailAddress:', primaryEmailAddress); +// return primaryEmailAddress; +// } +// +// getSecretCodeVerificationStatus () { +// return this.getState().secretCodeVerificationStatus || {}; +// } +// +// getSMSPhoneNumberStatus () { +// return this.getState().smsPhoneNumberStatus; +// } +// +// getSMSPhoneNumberList () { +// const { smsPhoneNumberList } = this.getState(); +// return smsPhoneNumberList; +// } +// +// getSMSPhoneNumbersVerifiedCount () { +// const { smsPhoneNumberList } = this.getState(); +// let onePhoneNumber = {}; +// let verifiedCount = 0; +// for (let i = 0; i < smsPhoneNumberList.length; ++i) { +// onePhoneNumber = smsPhoneNumberList[i]; +// if (onePhoneNumber.sms_ownership_is_verified === true) { +// verifiedCount += 1; +// } +// } +// return verifiedCount; +// } +// +// getStateCode () { +// // This defaults to state_code_from_ip_address but is overridden by the address the voter defaults to, or enters in text_for_map_search +// return this.getState().voter.state_code || ''; +// } +// +// getStateCodeFromIPAddress () { +// return this.getState().voter.state_code_from_ip_address || ''; +// } +// +// getTextForMapSearch () { +// let textForMapSearch = this.getState().address.text_for_map_search; +// if (textForMapSearch === undefined) { +// // Attaching full address object to voterRetrieve, so we can phase this out +// textForMapSearch = this.getState().voter.text_for_map_search; +// if (textForMapSearch === undefined) return ''; +// } +// if (Array.isArray(textForMapSearch)) return textForMapSearch[0] || ''; +// return textForMapSearch; +// } +// +// getTwitterHandle () { +// return this.getState().voter.twitter_handle || ''; +// } +// +// getTwitterSignInStatus () { +// return this.getState().twitterSignInStatus || {}; +// } +// +// getVoter () { +// return this.getState().voter; +// } +// +// getVoterContactEmailGoogleCount () { +// return this.getState().voterContactEmailGoogleCount || 0; +// } +// +// getVoterContactEmailList () { +// return this.getState().voterContactEmailList || []; +// } +// +// getVoterContactEmailListCount () { +// const voterContactEmailList = this.getState().voterContactEmailList || []; +// return voterContactEmailList.length; +// } +// +// getVoterDeleted () { +// return this.getState().voterDeleted || false; +// } +// +// getVoterEmail () { +// return this.getState().voter.email || ''; +// } +// +// getVoterEmailQueuedToSave () { +// return this.getState().voterEmailQueuedToSave; +// } +// +// getVoterEmailQueuedToSaveSet () { +// return this.getState().voterEmailQueuedToSaveSet; +// } +// +// getVoterFirstName () { +// if (this.getState().voter) { +// return this.getState().voter.first_name || ''; +// } +// return ''; +// } +// +// getVoterFirstNameQueuedToSave () { +// return this.getState().voterFirstNameQueuedToSave; +// } +// +// getVoterFirstNameQueuedToSaveSet () { +// return this.getState().voterFirstNameQueuedToSaveSet; +// } +// +// getVoterIsSignedIn () { +// return this.getState().voter.is_signed_in || false; +// } +// +// getVoterIsSignedInWithEmail () { +// return this.getState().voter.signed_in_with_email || false; +// } +// +// getVoterIsSignedInWithFacebook () { +// return this.getState().voter.signed_in_facebook || false; +// } +// +// getVoterIsSignedInWithTwitter () { +// return this.getState().voter.signed_in_twitter || false; +// } +// +// getVoterLastNameQueuedToSave () { +// return this.getState().voterLastNameQueuedToSave; +// } +// +// getVoterLastNameQueuedToSaveSet () { +// return this.getState().voterLastNameQueuedToSaveSet; +// } +// +// getVoterNotificationSettingsUpdateStatus () { +// return this.getState().voterNotificationSettingsUpdateStatus || {}; +// } +// +// getVoterPhotoQueuedToSave () { +// return this.getState().voterPhotoQueuedToSave; +// } +// +// getVoterPhotoQueuedToSaveSet () { +// return this.getState().voterPhotoQueuedToSaveSet; +// } +// +// getVoterPhotoTooBig () { +// return this.getState().voterPhotoTooBig || false; +// } +// +// // Could be either Facebook photo or Twitter photo +// getVoterPhotoUrlLarge () { +// return this.getState().voter.voter_photo_url_large || ''; +// } +// +// // Could be either Facebook photo or Twitter photo +// getVoterPhotoUrlMedium () { +// return this.getState().voter.voter_photo_url_medium || ''; +// } +// +// // Could be either Facebook photo or Twitter photo +// getVoterPhotoUrlTiny () { +// return this.getState().voter.voter_photo_url_tiny || ''; +// } +// +// getVoterProfileUploadedImageUrlLarge () { +// return this.getState().voter.we_vote_hosted_profile_uploaded_image_url_large || ''; +// } +// +// getVoterSavedAddress () { +// // console.log('VoterStore, getVoterSavedAddress: ', this.getState().address.voter_entered_address); +// return this.getState().address.voter_entered_address || false; +// } +// +// getVoterStateCode () { +// // TODO in getVoterStateCode we check for normalized_state in the address object. We should be +// // capturing the state when we call Google address Auto Complete (search for _placeChanged) +// // and we should also figure out the state_code when we call API server voterAddressSave and put it in the "address" +// // return data. +// // console.log('this.getState().address:', this.getState().address); +// // console.log('this.getState().voter:', this.getState().voter); +// if (this.getState().address && this.getState().address.normalized_state) { +// // console.log('normalized_state:', this.getState().address.normalized_state); +// return this.getState().address.normalized_state; +// } +// if (this.getState().voter && this.getState().voter.state_code_from_ip_address) { +// // console.log('state_code_from_ip_address:', this.getState().voter.state_code_from_ip_address); +// return this.getState().voter.state_code_from_ip_address; +// } +// return ''; +// } +// +// getVoterWeVoteId () { +// return this.getState().voter.we_vote_id || ''; +// } +// +// voterDeviceId () { +// return this.getState().voter.voter_device_id || Cookies.get('voter_device_id'); +// } +// +// setVoterDeviceIdCookie (id) { // eslint-disable-line +// Cookies.remove('voter_device_id'); +// Cookies.remove('voter_device_id', { path: '/' }); +// Cookies.remove('voter_device_id', { path: '/', domain: 'wevote.us' }); +// let { hostname } = window.location; +// hostname = hostname || ''; +// // console.log('setVoterDeviceIdCookie hostname:', hostname, 'cookie id:', id); +// if (hostname && stringContains('wevote.us', hostname)) { +// Cookies.set('voter_device_id', id, { expires: 10000, path: '/', domain: 'wevote.us' }); +// } else { +// Cookies.set('voter_device_id', id, { expires: 10000, path: '/' }); +// } +// } +// +// // Airbnb doesnt like bitwise operators in JavaScript +// getInterfaceFlagState (flag) { +// // Look in js/Constants/VoterConstants.js for list of flag constant definitions +// // console.log('VoterStore getInterfaceFlagState flag: ', flag); +// if (!this.getState().voter) { +// return false; +// } +// +// const interfaceStatusFlags = this.getState().voter.interface_status_flags || 0; +// // console.log('VoterStore getInterfaceFlagState interfaceStatusFlags: ', interfaceStatusFlags); +// // return True if bit specified by the flag is also set in interfaceStatusFlags (voter.interface_status_flags) +// // Eg: if interfaceStatusFlags = 5, then we can confirm that bits representing 1 and 4 are set (i.e., 0101) +// // so for value of flag = 1 and 4, we return a positive integer, +// // but, the bit representing 2 and 8 are not set, so for flag = 2 and 8, we return zero +// // const flagIsSet = interfaceStatusFlags & flag; // eslint-disable-line no-bitwise +// // console.log('VoterStore getInterfaceFlagState flagIsSet: ', flagIsSet); +// return interfaceStatusFlags & flag; // eslint-disable-line no-bitwise +// } +// +// getNotificationSettingConstantFromUnsubscribeModifier (unsubscribeModifier) { +// // New unsubscribe modifiers also need to be added in WeVoteServer +// let notificationSettingConstant = 0; +// // dailyfriendactivity, friendaccept, friendinvite, friendopinions, friendopinionsall, friendmessage, login, newsletter +// // NOT IMPLEMENTED YET: suggestedfriend == NOTIFICATION_SUGGESTED_FRIENDS_EMAIL +// if (unsubscribeModifier === 'dailyfriendactivity') { +// notificationSettingConstant = VoterConstants.NOTIFICATION_VOTER_DAILY_SUMMARY_EMAIL; +// } else if (unsubscribeModifier === 'friendaccept' || unsubscribeModifier === 'friendinvite') { +// notificationSettingConstant = VoterConstants.NOTIFICATION_FRIEND_REQUESTS_EMAIL; // friendaccept: NOTIFICATION_FRIEND_REQUEST_RESPONSES_EMAIL +// } else if (unsubscribeModifier === 'friendopinions' || unsubscribeModifier === 'friendopinionsall') { +// notificationSettingConstant = VoterConstants.NOTIFICATION_FRIEND_OPINIONS_YOUR_BALLOT_EMAIL; // friendopinionsall: NOTIFICATION_FRIEND_OPINIONS_OTHER_REGIONS_EMAIL +// } else if (unsubscribeModifier === 'friendmessage') { +// notificationSettingConstant = VoterConstants.NOTIFICATION_FRIEND_MESSAGES_EMAIL; +// } else if (unsubscribeModifier === 'login') { +// notificationSettingConstant = VoterConstants.NOTIFICATION_LOGIN_EMAIL; +// } else if (unsubscribeModifier === 'newsletter') { +// notificationSettingConstant = VoterConstants.NOTIFICATION_NEWSLETTER_OPT_IN; +// } +// return notificationSettingConstant; +// } +// +// getNotificationSettingsFlagState (flag) { +// // Look in js/Constants/VoterConstants.js for list of flag constant definitions +// if (!this.getState().voter) { +// return false; +// } +// // Notification settings we haven't implemented yet which we show as still turned on +// if ((flag === VoterConstants.NOTIFICATION_FRIEND_MESSAGES_EMAIL) || +// (flag === VoterConstants.NOTIFICATION_FRIEND_OPINIONS_OTHER_REGIONS_EMAIL) || +// (flag === VoterConstants.NOTIFICATION_LOGIN_EMAIL)) { +// return true; +// } +// const notificationSettingsFlags = this.getState().voter.notification_settings_flags || 0; +// // return True if bit specified by the flag is also set +// // in notificationSettingsFlags (voter.notification_settings_flags) +// // Eg: if interfaceStatusFlags = 5, then we can confirm that bits representing 1 and 4 are set (i.e., 0101) +// // so for value of flag = 1 and 4, we return a positive integer, +// // but, the bit representing 2 and 8 are not set, so for flag = 2 and 8, we return zero +// return notificationSettingsFlags & flag; // eslint-disable-line no-bitwise +// } +// +// getNotificationSettingsFlagStateFromSecretKey (flag) { +// // Look in js/Constants/VoterConstants.js for list of flag constant definitions +// if (!this.getState().voterNotificationSettingsUpdateStatus) { +// return false; +// } +// // Notification settings we haven't implemented yet which we show as still turned on +// if ((flag === VoterConstants.NOTIFICATION_FRIEND_MESSAGES_EMAIL) || +// (flag === VoterConstants.NOTIFICATION_FRIEND_OPINIONS_OTHER_REGIONS_EMAIL) || +// (flag === VoterConstants.NOTIFICATION_LOGIN_EMAIL)) { +// return true; +// } +// const { notificationSettingsFlags } = this.getState().voterNotificationSettingsUpdateStatus; +// // return True if bit specified by the flag is also set +// // in notificationSettingsFlags (voter.notification_settings_flags) +// // Eg: if interfaceStatusFlags = 5, then we can confirm that bits representing 1 and 4 are set (i.e., 0101) +// // so for value of flag = 1 and 4, we return a positive integer, +// // but, the bit representing 2 and 8 are not set, so for flag = 2 and 8, we return zero +// return notificationSettingsFlags & flag; // eslint-disable-line no-bitwise +// } +// +// getVoterContactEmailAugmentSequenceComplete () { +// return this.getState().voterContactEmailAugmentSequenceComplete || false; +// } +// +// getVoterContactEmailAugmentSequenceHasNextStep () { +// return this.getState().voterContactEmailAugmentSequenceHasNextStep || false; +// } // voterContactEmailAugmentWithWeVoteDataComplete +// +// getVoterContactEmailAugmentWithWeVoteDataComplete () { +// return this.getState().voterContactEmailAugmentWithWeVoteDataComplete || false; +// } +// +// isVoterFound () { +// return this.getState().voterFound; +// } +// +// voterFirstRetrieveCompleted () { +// return this.getState().voterFirstRetrieveCompleted; +// } +// +// voterExternalIdHasBeenSavedOnce (externalVoterId, membershipOrganizationWeVoteId) { +// if (!externalVoterId || !membershipOrganizationWeVoteId) { +// return false; +// } +// if (this.getState().voterExternalIdHasBeenSavedOnce[externalVoterId]) { +// return this.getState().voterExternalIdHasBeenSavedOnce[externalVoterId][membershipOrganizationWeVoteId] || false; +// } else { +// return false; +// } +// } +// +// voterPhotoAndNameExist () { +// const firstNameExists = !!(this.getState().voter.first_name && this.getState().voter.first_name !== ''); +// const lastNameExists = !!(this.getState().voter.last_name && this.getState().voter.last_name !== ''); +// const nameExists = firstNameExists || lastNameExists; +// const photoExists = !!(this.getState().voter.voter_photo_url_large && this.getState().voter.voter_photo_url_large !== ''); +// return !!(nameExists && photoExists); +// } +// +// reduce (state, action) { +// let facebookPhotoRetrieveLoopCount; +// let address; +// let currentVoterDeviceId; +// // const delayBeforeApiCall = 3000; +// let externalVoterId; +// let googleCivicElectionId; +// let incomingVoter; +// let incorrectSecretCodeEntered; +// let membershipOrganizationWeVoteId; +// let mergeFromVoterWeVoteId; +// let mergeToVoterWeVoteId; +// let numberOfTriesRemaining; +// let revisedState; +// let secretCodeVerified; +// let voterDeviceId; +// let voterContactEmailAugmentWithWeVoteDataComplete; +// let voterExternalIdHasBeenSavedOnce; +// let voterFirstRetrieveCompleted; +// let voterMustRequestNewCode; +// let voterSecretCodeRequestsLocked; +// +// switch (action.type) { +// case 'clearEmailAddressStatus': +// // console.log('VoterStore clearEmailAddressStatus'); +// return { ...state, emailAddressStatus: {} }; +// case 'clearSecretCodeVerificationStatus': +// // console.log('VoterStore clearSecretCodeVerificationStatus'); +// return { +// ...state, +// secretCodeVerificationStatus: { +// incorrectSecretCodeEntered: false, +// numberOfTriesRemaining: 5, +// secretCodeVerified: false, +// voterMustRequestNewCode: false, +// voterSecretCodeRequestsLocked: false, +// }, +// }; +// case 'clearSecretCodeVerificationStatusAndEmail': +// // Does both of the above steps in one call +// // console.log('VoterStore clearSecretCodeVerificationStatusAndEmail'); +// return { +// ...state, +// emailAddressStatus: {}, +// secretCodeVerificationStatus: { +// incorrectSecretCodeEntered: false, +// numberOfTriesRemaining: 5, +// secretCodeVerified: false, +// voterMustRequestNewCode: false, +// voterSecretCodeRequestsLocked: false, +// }, +// }; +// case 'clearSMSPhoneNumberStatus': +// // console.log('VoterStore clearSMSPhoneNumberStatus'); +// return { +// ...state, +// smsPhoneNumberStatus: { +// sms_verify_attempted: false, +// sms_phone_number_already_owned_by_other_voter: false, +// sms_phone_number_already_owned_by_this_voter: false, +// sms_phone_number_created: false, +// sms_phone_number: '', +// sms_phone_number_found: false, +// sms_phone_number_deleted: false, +// make_primary_sms: false, +// sign_in_code_sms_sent: false, +// verification_sms_sent: false, +// }, +// }; +// case 'clearSecretCodeVerificationStatusAndPhone': +// // console.log('VoterStore clearSecretCodeVerificationStatusAndPhone'); +// return { +// ...state, +// secretCodeVerificationStatus: { +// incorrectSecretCodeEntered: false, +// numberOfTriesRemaining: 5, +// secretCodeVerified: false, +// voterMustRequestNewCode: false, +// voterSecretCodeRequestsLocked: false, +// }, +// smsPhoneNumberStatus: { +// sms_verify_attempted: false, +// sms_phone_number_already_owned_by_other_voter: false, +// sms_phone_number_already_owned_by_this_voter: false, +// sms_phone_number_created: false, +// sms_phone_number: '', +// sms_phone_number_found: false, +// sms_phone_number_deleted: false, +// make_primary_sms: false, +// sign_in_code_sms_sent: false, +// verification_sms_sent: false, +// }, +// }; +// case 'clearVoterElectionId': +// // console.log('VoterStore clearVoterElectionId'); +// return { ...state, latestGoogleCivicElectionId: 0 }; +// case 'clearVoterContactEmailImportVariables': +// return { +// ...state, +// voterContactEmailAugmentWithWeVoteDataComplete: false, +// voterContactEmailAugmentSequenceComplete: false, +// voterContactEmailAugmentSequenceHasNextStep: false, +// }; +// case 'organizationSave': +// // console.log('VoterStore organizationSave'); +// // If an organization saves, we want to check to see if it is tied to this voter. If so, +// // refresh the voter data so we have the value linked_organization_we_vote_id in the voter object. +// if (action.res.success) { +// if (action.res.facebook_id === state.voter.facebook_id) { +// VoterActions.voterRetrieve(); +// } else { +// const organizationTwitterHandle = action.res.organization_twitter_handle || ''; +// const twitterScreenName = state.voter.twitter_screen_name !== undefined ? state.voter.twitter_screen_name : ''; +// if (organizationTwitterHandle && organizationTwitterHandle.toLowerCase() === twitterScreenName.toLowerCase()) { +// VoterActions.voterRetrieve(); +// } +// } +// } +// return state; +// +// case 'positionListForVoter': +// // console.log('VoterStore positionListForVoter'); +// if (action.res.show_only_this_election) { +// const positionListForOneElection = action.res.position_list; +// return { +// ...state, +// voter: { +// ...state.voter, +// positionListForOneElection, +// }, +// }; +// } else if (action.res.show_all_other_elections) { +// const positionListForAllExceptOneElection = action.res.position_list; +// return { +// ...state, +// voter: { +// ...state.voter, +// positionListForAllExceptOneElection, +// }, +// }; +// } else { +// const positionList = action.res.position_list; +// return { +// ...state, +// voter: { +// ...state.voter, +// positionList, +// }, +// }; +// } +// +// case 'setExternalVoterId': +// externalVoterId = action.payload; +// membershipOrganizationWeVoteId = AppObservableStore.getSiteOwnerOrganizationWeVoteId(); +// ({ voterExternalIdHasBeenSavedOnce } = state); +// // console.log('VoterStore externalVoterId:', externalVoterId, ', membershipOrganizationWeVoteId:', membershipOrganizationWeVoteId); +// if (externalVoterId && membershipOrganizationWeVoteId) { +// if (!this.voterExternalIdHasBeenSavedOnce(externalVoterId, membershipOrganizationWeVoteId)) { +// // console.log('voterExternalIdHasBeenSavedOnce has NOT been saved before.'); +// VoterActions.voterExternalIdSave(externalVoterId, membershipOrganizationWeVoteId); +// if (!voterExternalIdHasBeenSavedOnce[externalVoterId]) { +// voterExternalIdHasBeenSavedOnce[externalVoterId] = {}; +// } +// voterExternalIdHasBeenSavedOnce[externalVoterId][membershipOrganizationWeVoteId] = true; +// // AnalyticsActions.saveActionBallotVisit(VoterStore.electionId()); +// } else { +// // console.log('voterExternalIdHasBeenSavedOnce has been saved before.'); +// } +// } +// return { +// ...state, +// externalVoterId, +// voterExternalIdHasBeenSavedOnce, +// }; +// +// case 'twitterRetrieveIdsIFollow': +// // console.log('VoterStore twitterRetrieveIdsIFollow'); +// if (action.res.success) { +// VoterActions.organizationSuggestionTasks('UPDATE_SUGGESTIONS_FROM_TWITTER_IDS_I_FOLLOW', +// 'FOLLOW_SUGGESTIONS_FROM_TWITTER_IDS_I_FOLLOW'); +// } +// +// return state; +// +// case 'voterAnalysisForJumpProcess': +// // console.log('VoterStore, voterAnalysisForJumpProcess'); +// VoterActions.voterRetrieve(); +// return { +// ...state, +// emailAddressStatus: { +// email_ownership_is_verified: action.res.email_ownership_is_verified, +// email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, +// email_verify_attempted: action.res.email_verify_attempted, +// email_address_found: action.res.email_address_found, +// }, +// emailSignInStatus: { +// email_ownership_is_verified: action.res.email_ownership_is_verified, +// email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, +// email_sign_in_attempted: action.res.email_verify_attempted, +// email_address_found: action.res.email_address_found, +// }, +// }; +// +// case 'voterAddressRetrieve': +// case 'voterAddressOnlyRetrieve': +// // console.log('VoterStore, voterAddressRetrieve, address:', action.res); +// address = action.res || {}; +// return { +// ...state, +// address, +// }; +// +// case 'voterAddressSave': +// // console.log('VoterStore, voterAddressSave, action.res:', action.res); +// revisedState = state; +// if (action.res.status === 'SIMPLE_ADDRESS_SAVE') { +// // Don't do any other refreshing +// } else { +// googleCivicElectionId = action.res.google_civic_election_id || 0; +// if (googleCivicElectionId !== 0) { +// revisedState = { ...revisedState, +// latestGoogleCivicElectionId: googleCivicElectionId, +// }; +// } +// } +// ({ address } = action.res); +// if (!address) { +// address = { +// text_for_map_search: '', +// google_civic_election_id: 0, +// ballot_returned_we_vote_id: '', +// ballot_location_display_name: '', +// voter_entered_address: '', +// voter_specific_ballot_from_google_civic: null, +// }; +// } +// +// return { +// ...revisedState, +// address: { +// text_for_map_search: address.text_for_map_search, +// google_civic_election_id: address.google_civic_election_id, +// ballot_returned_we_vote_id: address.ballot_returned_we_vote_id, +// ballot_location_display_name: address.ballot_location_display_name, +// voter_entered_address: address.voter_entered_address, +// voter_specific_ballot_from_google_civic: address.voter_specific_ballot_from_google_civic, +// }, +// }; +// +// case 'voterBallotItemsRetrieve': +// // console.log('VoterStore voterBallotItemsRetrieve latestGoogleCivicElectionId: ', action.res.google_civic_election_id); +// googleCivicElectionId = action.res.google_civic_election_id || 0; +// if (googleCivicElectionId !== 0) { +// return { +// ...state, +// latestGoogleCivicElectionId: googleCivicElectionId, +// }; +// } +// return state; +// +// case 'voterContactListRetrieve': +// // console.log('VoterStore voterContactListRetrieve action:', action); +// if (action.res.success) { +// const { +// voter_contact_email_google_count: voterContactEmailGoogleCount, +// voter_contact_email_list: voterContactEmailList, +// } = action.res; +// return { +// ...state, +// voterContactEmailGoogleCount, +// voterContactEmailList, +// }; +// } else { +// console.log('response voterContactListRetrieve was not successful'); +// return state; +// } +// +// case 'voterContactListSave': +// // console.log('VoterStore voterContactListSave action.res:', action.res); +// if (action.res.success) { +// ({ voterContactEmailAugmentWithWeVoteDataComplete } = state); +// const { +// augment_voter_contact_emails_with_location: justAugmentedWithLocation, +// augment_voter_contact_emails_with_we_vote_data: justAugmentedWithWeVoteData, +// contacts_stored: googleContactsStored, +// delete_all_voter_contact_emails: voterContactEmailsJustDeleted, +// voter_contact_email_augment_sequence_complete: voterContactEmailAugmentSequenceComplete, +// voter_contact_email_augment_sequence_has_next_step: voterContactEmailAugmentSequenceHasNextStep, +// voter_contact_email_google_count: voterContactEmailGoogleCount, +// voter_contact_email_list: voterContactEmailList, +// we_vote_id_for_google_contacts: weVoteIdForGoogleContacts, +// } = action.res; +// // console.log('googleContactsStored:', googleContactsStored, ', justAugmentedWithWeVoteData:', justAugmentedWithWeVoteData, ',justAugmentedWithLocation:', justAugmentedWithLocation); +// if (voterContactEmailsJustDeleted || justAugmentedWithLocation) { +// // Never call again +// } else if (googleContactsStored && (googleContactsStored > 0)) { +// // console.log('Calling VoterActions.voterContactListAugmentWithWeVoteData'); +// VoterActions.voterContactListAugmentWithWeVoteData(true); +// } else if (justAugmentedWithWeVoteData) { +// // console.log('Calling VoterActions.voterContactListAugmentWithLocation'); +// VoterActions.voterContactListAugmentWithLocation(true); +// } +// if (googleContactsStored) { +// voterContactEmailAugmentWithWeVoteDataComplete = false; +// } else if (justAugmentedWithWeVoteData) { +// voterContactEmailAugmentWithWeVoteDataComplete = true; +// } +// return { +// ...state, +// weVoteIdForGoogleContacts, +// googleContactsStored, +// voterContactEmailAugmentWithWeVoteDataComplete, +// voterContactEmailAugmentSequenceComplete, +// voterContactEmailAugmentSequenceHasNextStep, +// voterContactEmailGoogleCount, +// voterContactEmailList, +// }; +// } else { +// console.log('response voterContactListSave was not successful'); +// return state; +// } +// +// case 'voterEmailAddressRetrieve': +// // console.log('VoterStore voterEmailAddressRetrieve: ', action.res.email_address_list); +// return { +// ...state, +// emailAddressList: action.res.email_address_list, +// }; +// +// case 'voterEmailAddressSave': +// // console.log('VoterStore, voterEmailAddressSave'); +// VoterActions.voterRetrieve(); +// return { +// ...state, +// emailAddressList: action.res.email_address_list, +// emailAddressStatus: { +// email_verify_attempted: action.res.email_verify_attempted, +// email_address_already_owned_by_other_voter: action.res.email_address_already_owned_by_other_voter, +// email_address_already_owned_by_this_voter: action.res.email_address_already_owned_by_this_voter, +// email_address_created: action.res.email_address_created, +// email_address_deleted: action.res.email_address_deleted, +// email_address_not_valid: action.res.email_address_not_valid, +// from_voter_we_vote_id: action.res.from_voter_we_vote_id, +// link_to_sign_in_email_sent: action.res.link_to_sign_in_email_sent, +// make_primary_email: action.res.make_primary_email, +// sign_in_code_email_sent: action.res.sign_in_code_email_sent, +// secret_code_system_locked_for_this_voter_device_id: action.res.secret_code_system_locked_for_this_voter_device_id, +// to_voter_we_vote_id: action.res.to_voter_we_vote_id, +// verification_email_sent: action.res.verification_email_sent, +// }, +// }; +// +// case 'voterEmailAddressSignIn': +// // console.log('VoterStore, voterEmailAddressSignIn'); +// VoterActions.voterRetrieve(); +// return { +// ...state, +// emailSignInStatus: { +// email_sign_in_attempted: action.res.email_sign_in_attempted, +// email_ownership_is_verified: action.res.email_ownership_is_verified, +// email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, +// email_address_found: action.res.email_address_found, +// yes_please_merge_accounts: action.res.yes_please_merge_accounts, +// voter_we_vote_id_from_secret_key: action.res.voter_we_vote_id_from_secret_key, +// voter_merge_two_accounts_attempted: false, +// }, +// }; +// +// case 'voterEmailAddressVerify': +// // console.log('VoterStore, voterEmailAddressVerify'); +// VoterActions.voterRetrieve(); +// return { +// ...state, +// emailAddressStatus: { +// email_ownership_is_verified: action.res.email_ownership_is_verified, +// email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, +// email_verify_attempted: action.res.email_verify_attempted, +// email_address_found: action.res.email_address_found, +// }, +// emailSignInStatus: { +// email_ownership_is_verified: action.res.email_ownership_is_verified, +// email_secret_key_belongs_to_this_voter: action.res.email_secret_key_belongs_to_this_voter, +// email_sign_in_attempted: action.res.email_verify_attempted, +// email_address_found: action.res.email_address_found, +// }, +// }; +// +// case 'voterEmailQueuedToSave': +// // console.log('VoterStore voterEmailQueuedToSave: ', action.payload); +// if (action.payload === undefined) { +// return { +// ...state, +// voterEmailQueuedToSave: '', +// voterEmailQueuedToSaveSet: false, +// }; +// } else { +// return { +// ...state, +// voterEmailQueuedToSave: action.payload, +// voterEmailQueuedToSaveSet: true, +// }; +// } +// +// case 'voterFacebookSaveToCurrentAccount': +// // console.log('VoterStore, voterFacebookSaveToCurrentAccount'); +// VoterActions.voterRetrieve(); +// return { +// ...state, +// facebookSignInStatus: { +// facebook_account_created: action.res.facebook_account_created, +// }, +// }; +// +// case 'voterFirstNameQueuedToSave': +// // console.log('VoterStore voterFirstNameQueuedToSave: ', action.payload); +// if (action.payload === undefined) { +// return { +// ...state, +// voterFirstNameQueuedToSave: '', +// voterFirstNameQueuedToSaveSet: false, +// }; +// } else { +// return { +// ...state, +// voterFirstNameQueuedToSave: action.payload, +// voterFirstNameQueuedToSaveSet: true, +// }; +// } +// +// case 'voterLastNameQueuedToSave': +// // console.log('VoterStore voterLastNameQueuedToSave: ', action.payload); +// if (action.payload === undefined) { +// return { +// ...state, +// voterLastNameQueuedToSave: '', +// voterLastNameQueuedToSaveSet: false, +// }; +// } else { +// return { +// ...state, +// voterLastNameQueuedToSave: action.payload, +// voterLastNameQueuedToSaveSet: true, +// }; +// } +// +// case 'voterMergeTwoAccounts': +// // console.log('VoterStore, voterMergeTwoAccounts'); +// // On the server we just switched (linked) this voterDeviceId to a new voter record, so we want to the voter. +// // refresh a lot of data -- December 2022, but as little as absolutely required, and no more +// VoterActions.voterRetrieve(); +// // // And set a timer for 3 seconds from now to refresh again +// // this.timer = setTimeout(() => { +// // VoterActions.voterRetrieve(); +// // }, delayBeforeApiCall); +// VoterActions.voterEmailAddressRetrieve(); // TODO: December 2022, Is this necessary? +// VoterActions.voterSMSPhoneNumberRetrieve(); // TODO: December 2022, Is this necessary? +// if (action.res.merge_from_voter_we_vote_id && action.res.merge_to_voter_we_vote_id) { +// if (apiCalming('voterRetrieveMergeTwo', 3000)) { +// // This completes the time-consuming process 'voter_merge_two_accounts_action' and then returns voter data +// console.log('VoterStore: voterMergeTwoAccounts: Completing voterRetrieveMergeTwo process'); +// VoterActions.voterRetrieve(action.res.merge_from_voter_we_vote_id, action.res.merge_to_voter_we_vote_id); +// } +// } +// return { +// ...state, +// emailSignInStatus: { +// email_ownership_is_verified: true, +// email_secret_key_belongs_to_this_voter: true, +// email_sign_in_attempted: true, +// email_address_found: true, +// yes_please_merge_accounts: false, +// voter_we_vote_id_from_secret_key: '', +// voter_merge_two_accounts_attempted: true, +// }, +// facebookSignInStatus: { +// voter_merge_two_accounts_attempted: true, +// }, +// twitterSignInStatus: { +// voter_merge_two_accounts_attempted: true, +// }, +// }; +// +// case 'voterNotificationSettingsUpdate': +// // console.log('VoterStore, voterNotificationSettingsUpdate'); +// if (!action.res) { +// return { +// ...state, +// voterNotificationSettingsUpdateStatus: { +// apiResponseReceived: true, +// emailFound: false, +// voterFound: false, +// normalizedEmailAddress: '', +// normalizedSmsPhoneNumber: '', +// notificationSettingsFlags: false, +// }, +// }; +// } +// return { +// ...state, +// voterNotificationSettingsUpdateStatus: { +// apiResponseReceived: true, +// emailFound: action.res.email_found, +// voterFound: action.res.voter_found, +// normalizedEmailAddress: action.res.normalized_email_address, +// normalizedSmsPhoneNumber: action.res.normalized_sms_phone_number, +// notificationSettingsFlags: action.res.notification_settings_flags, +// }, +// }; +// +// case 'voterPhotoQueuedToSave': +// // console.log('VoterStore voterPhotoQueuedToSave: ', action.payload); +// if (action.payload === undefined) { +// return { +// ...state, +// voterPhotoQueuedToSave: '', +// voterPhotoQueuedToSaveSet: false, +// }; +// } else { +// return { +// ...state, +// voterPhotoQueuedToSave: action.payload, +// voterPhotoQueuedToSaveSet: true, +// }; +// } +// +// case 'voterPhotoSave': +// // console.log('VoterStore, voterPhotoSave'); +// return { +// ...state, +// voter: { ...state.voter, facebook_profile_image_url_https: action.res.facebook_profile_image_url_https }, +// }; +// +// case 'voterPhotoTooBigReset': +// // console.log('VoterStore, voterPhotoTooBigReset'); +// return { +// ...state, +// voterPhotoTooBig: false, +// }; +// +// case 'voterRetrieve': +// // console.log('VoterStore, voterRetrieve state on entry: ', state); +// // console.log('VoterStore, voterRetrieve state on entry: ', state.voter); +// +// // Preserve address within voter +// incomingVoter = action.res; +// ({ facebookPhotoRetrieveLoopCount, voterFirstRetrieveCompleted } = state); +// if (!voterFirstRetrieveCompleted) { +// voterFirstRetrieveCompleted = Boolean(action.res.success); +// } +// +// currentVoterDeviceId = Cookies.get('voter_device_id'); +// // console.log('VoterStore, voterRetrieve stored Cookie value for voter_device_id value on entry: ', currentVoterDeviceId); +// if (!action.res.voter_found) { +// console.log(`This voter_device_id is not in the db and is invalid, so delete it: ${currentVoterDeviceId}`); +// +// // Attempt to delete the voter_device_id cookie in a variety of ways +// Cookies.remove('voter_device_id'); +// Cookies.remove('voter_device_id', { path: '/' }); +// Cookies.remove('voter_device_id', { path: '/', domain: 'wevote.us' }); +// +// // ...and then ask for a new voter. When it returns a voter with a new voter_device_id, we will set new cookie +// if (!Cookies.get('voter_device_id')) { +// console.log('voter_device_id gone -- calling voterRetrieve'); +// VoterActions.voterRetrieve(); +// } else { +// // console.log('voter_device_id still exists -- did not call voterRetrieve'); +// } +// } else { +// voterDeviceId = action.res.voter_device_id; +// if (voterDeviceId) { +// if (currentVoterDeviceId !== voterDeviceId) { +// console.log('Setting new voter_device_id'); +// this.setVoterDeviceIdCookie(voterDeviceId); +// } +// // FriendsInvitationList.jsx is choking on this because calling this +// // results in an infinite loop cycling between voterRetrieve and getFaceProfilePicture which +// // resolves to FACEBOOK_RECEIVED_PICTURE which then attempts to save using voterFacebookSignInPhoto +// // which in turn resolves to voterFacebookSignInSave which finally attempts to call +// // voterRetrieve again +// // console.log('VoterStore, voterRetrieve, action.res: ', action.res); +// } else { +// // console.log('voter_device_id not returned by voterRetrieve'); +// } +// } +// // April 29, 2021 TODO: We should make a combined Voter and Organization retrieve +// // because this fires on the initial page load and takes almost a full second to return, blocking one of six available http channels +// // Firing actions from stores should be avoided +// // The following (new) condition blocks a organizationRetrieve on the first voterRetrieve +// +// // if (incomingVoter.signed_in_with_apple) { +// // // Completing the logical OR that can't be conveniently made in the server, since Sign in with Apple is device_id specific +// // incomingVoter.is_signed_in = incomingVoter.signed_in_with_apple; +// // const { voter_photo_url_medium: statePhotoMed } = state.voter; +// // const { voter_photo_url_medium: incomingPhotoMed } = incomingVoter; +// // if (!statePhotoMed && !incomingPhotoMed) { +// // incomingVoter.voter_photo_url_medium = 'https://wevote.us/img/global/logos/Apple_logo_grey.svg'; // TODO: Switch over to wevote.us once live server is updated +// // } +// // } +// if (incomingVoter && incomingVoter.we_vote_id) { +// if (incomingVoter.we_vote_id !== AppObservableStore.getOpenReplayVoterWeVoteId()) { +// // console.log('tracker.setUserId:', incomingVoter.we_vote_id); +// const tracker = AppObservableStore.getOpenReplayTracker(); +// if (tracker) { +// console.log('OpenReplay setting id: ', incomingVoter.we_vote_id); +// AppObservableStore.setOpenReplayVoterWeVoteId(incomingVoter.we_vote_id); +// tracker.setUserID(incomingVoter.we_vote_id); +// } +// } +// if (incomingVoter.is_signed_in && !AppObservableStore.getOpenReplayVoterIsSignedIn()) { +// const tracker = AppObservableStore.getOpenReplayTracker(); +// if (tracker) { +// console.log('OpenReplay setting voterIsSignedIn'); +// AppObservableStore.setOpenReplayVoterIsSignedIn(true); +// tracker.setMetadata('voterIsSignedIn', 'true'); +// } +// } +// if (this.getStateCode() && !AppObservableStore.getOpenReplayStateCode()) { +// // getStateCode defaults to state_code_from_ip_address but is overridden by the state in text_for_map_search +// const tracker = AppObservableStore.getOpenReplayTracker(); +// const stateCode = this.getStateCode().toUpperCase(); +// if (tracker && stateCode) { +// console.log('OpenReplay setting stateCode'); +// AppObservableStore.setOpenReplayStateCode(stateCode); +// tracker.setMetadata('stateCode', stateCode); +// } +// } +// if (incomingVoter.state_code_from_ip_address && !AppObservableStore.getOpenReplayStateCodeFromIpAddress()) { +// const tracker = AppObservableStore.getOpenReplayTracker(); +// const stateCodeFromIpAddress = incomingVoter.state_code_from_ip_address.toUpperCase(); +// if (tracker && stateCodeFromIpAddress) { +// console.log('OpenReplay setting stateCodeFromIpAddress'); +// AppObservableStore.setOpenReplayStateCodeFromIpAddress(stateCodeFromIpAddress); +// tracker.setMetadata('stateCodeFromIpAddress', stateCodeFromIpAddress); +// } +// } +// } +// revisedState = state; +// revisedState = { +// ...revisedState, +// facebookPhotoRetrieveLoopCount: facebookPhotoRetrieveLoopCount + 1, +// voter: incomingVoter, +// voterFirstRetrieveCompleted, +// voterFound: action.res.voter_found, +// }; +// if (incomingVoter.address) { +// // console.log('incomingVoter.address:', incomingVoter.address); +// revisedState = { ...revisedState, address: incomingVoter.address }; +// } +// return revisedState; +// +// case 'voterSignOut': +// // console.log('VoterStore resetting voterStore via voterSignOut'); +// VoterActions.voterRetrieve(); +// VoterActions.voterEmailAddressRetrieve(); +// VoterActions.voterSMSPhoneNumberRetrieve(); +// revisedState = state; +// revisedState = { ...revisedState, ...this.getInitialState() }; +// return revisedState; +// +// case 'voterSMSPhoneNumberRetrieve': +// // console.log('VoterStore voterSMSPhoneNumberRetrieve: ', action.res.sms_phone_number_list); +// return { +// ...state, +// smsPhoneNumberList: action.res.sms_phone_number_list, +// }; +// +// case 'voterSMSPhoneNumberSave': +// // console.log('VoterStore voterSMSPhoneNumberSave action.res:', action.res); +// VoterActions.voterRetrieve(); +// VoterActions.voterSMSPhoneNumberRetrieve(); +// return { +// ...state, +// smsPhoneNumberList: action.res.sms_phone_number_list, +// smsPhoneNumberStatus: { +// sms_verify_attempted: action.res.sms_verify_attempted, +// sms_phone_number_already_owned_by_other_voter: action.res.sms_phone_number_already_owned_by_other_voter, +// sms_phone_number_already_owned_by_this_voter: action.res.sms_phone_number_already_owned_by_this_voter, +// sms_phone_number_created: action.res.sms_phone_number_created, +// sms_phone_number: action.res.sms_phone_number, +// sms_phone_number_found: action.res.sms_phone_number_found, +// sms_phone_number_deleted: action.res.sms_phone_number_deleted, +// make_primary_sms: action.res.make_primary_sms, +// secret_code_system_locked_for_this_voter_device_id: action.res.secret_code_system_locked_for_this_voter_device_id, +// sign_in_code_sms_sent: action.res.sign_in_code_sms_sent, +// verification_sms_sent: action.res.verification_sms_sent, +// }, +// }; +// +// case 'voterSplitIntoTwoAccounts': +// // console.log('VoterStore voterSplitIntoTwoAccounts '); +// VoterActions.voterRetrieve(); +// return state; +// +// case 'voterTwitterSaveToCurrentAccount': +// // console.log('VoterStore voterTwitterSaveToCurrentAccount '); +// VoterActions.voterRetrieve(); +// return { +// ...state, +// twitterSignInStatus: { +// twitter_account_created: action.res.twitter_account_created, +// }, +// }; +// +// case 'voterUpdate': // Formerly voterDeleteAccount +// if (action.res.success && action.res.voter_deleted) { +// revisedState = state; +// revisedState = { ...revisedState, +// voterDeleted: true, +// voterNotDeleted: false, +// }; +// return revisedState; +// } else if (action.res.success && action.res.voter_not_deleted) { +// revisedState = state; +// revisedState = { ...revisedState, +// voterDeleted: false, +// voterNotDeleted: true, +// }; +// return revisedState; +// } else if (action.res.success) { +// let interfaceStatusFlags = action.res.interface_status_flags; +// if (interfaceStatusFlags === undefined) { +// interfaceStatusFlags = state.voter.interface_status_flags; +// } +// let notificationSettingsFlags = action.res.notification_settings_flags; +// if (notificationSettingsFlags === undefined) { +// notificationSettingsFlags = state.voter.notification_settings_flags; +// } +// return { +// ...state, +// voter: { +// ...state.voter, +// // With this we are only updating the values we change with a voterUpdate call. +// facebook_email: action.res.email || state.voter.email, +// first_name: action.res.first_name, +// interface_status_flags: interfaceStatusFlags, +// last_name: action.res.last_name, +// notification_settings_flags: notificationSettingsFlags, +// profile_image_type_currently_active: action.res.profile_image_type_currently_active || '', +// voter_donation_history_list: action.res.voter_donation_history_list || state.voter.voter_donation_history_list, +// voter_photo_url_large: action.res.we_vote_hosted_profile_image_url_large || '', +// voter_photo_url_medium: action.res.we_vote_hosted_profile_image_url_medium || '', +// voter_photo_url_tiny: action.res.we_vote_hosted_profile_image_url_tiny || '', +// we_vote_hosted_profile_facebook_image_url_large: action.res.we_vote_hosted_profile_facebook_image_url_large || '', +// we_vote_hosted_profile_twitter_image_url_large: action.res.we_vote_hosted_profile_twitter_image_url_large || '', +// we_vote_hosted_profile_uploaded_image_url_large: action.res.we_vote_hosted_profile_uploaded_image_url_large || '', +// }, +// voterPhotoTooBig: action.res.voter_photo_too_big || false, +// }; +// } else { +// return { +// ...state, +// voterPhotoTooBig: action.res.voter_photo_too_big || false, +// }; +// } +// +// case 'voterVerifySecretCode': +// // console.log('VoterStore, voterVerifySecretCode, action.res:', action.res); +// incorrectSecretCodeEntered = (action.res.incorrect_secret_code_entered && action.res.incorrect_secret_code_entered === true); +// mergeFromVoterWeVoteId = action.res.merge_from_voter_we_vote_id; +// mergeToVoterWeVoteId = action.res.merge_to_voter_we_vote_id; +// numberOfTriesRemaining = action.res.number_of_tries_remaining_for_this_code; +// secretCodeVerified = (action.res.secret_code_verified && action.res.secret_code_verified === true); +// voterMustRequestNewCode = (action.res.voter_must_request_new_code && action.res.voter_must_request_new_code === true); +// voterSecretCodeRequestsLocked = (action.res.secret_code_system_locked_for_this_voter_device_id && action.res.secret_code_system_locked_for_this_voter_device_id === true); +// // console.log('onVoterStoreChange voterStore secretCodeVerified', secretCodeVerified); +// // It is appropriate to keep this call within the Store because the components which trigger the voterVerifySecretCode +// // get closed as soon as secretCodeVerified is true +// if (mergeFromVoterWeVoteId && mergeToVoterWeVoteId) { +// // console.log('VoterStore, voterVerifySecretCode: voterRetrieveMergeTwo mergeFromVoterWeVoteId:', mergeFromVoterWeVoteId, ', mergeToVoterWeVoteId:', mergeToVoterWeVoteId); +// if (apiCalming('voterRetrieveMergeTwo', 3000)) { +// // This completes the time-consuming process 'voter_merge_two_accounts_action' and then returns voter data +// VoterActions.voterRetrieve(mergeFromVoterWeVoteId, mergeToVoterWeVoteId); +// } +// } +// return { +// ...state, +// secretCodeVerificationStatus: { +// incorrectSecretCodeEntered, +// numberOfTriesRemaining, +// secretCodeVerified, +// voterMustRequestNewCode, +// voterSecretCodeRequestsLocked, +// }, +// }; +// +// case 'appleSignInSave': +// if (action.res.success) { +// // eslint-disable-next-line camelcase +// const { first_name, middle_name, last_name, email, user_code: appleUserCode } = action.res; +// VoterActions.voterRetrieve(); +// return { +// ...state, +// voter: { +// first_name, +// middle_name, +// last_name, +// email, +// appleUserCode, +// signed_in_with_apple: true, +// }, +// }; +// } else { +// console.log('Received a bad response from appleSignInSave API call'); +// return state; +// } +// +// case 'deviceStoreFirebaseCloudMessagingToken': +// if (action.res.success) { +// // console.log('Received success from deviceStoreFirebaseCloudMessagingToken API call'); +// return state; +// } else { +// console.log('Received a bad response from deviceStoreFirebaseCloudMessagingToken API call, object properties follow:'); +// dumpObjProps('action.res', action.res); +// return state; +// } +// +// +// case 'error-voterRetrieve' || 'error-voterAddressRetrieve' || 'error-voterAddressSave': +// // console.log('VoterStore action', action); +// return state; +// +// default: +// return state; +// } +// } +// } +// +// export default new VoterStore(Dispatcher); diff --git a/src/js/utils/service.js b/src/js/utils/service.js index d970fc1..4885867 100644 --- a/src/js/utils/service.js +++ b/src/js/utils/service.js @@ -1,106 +1,106 @@ -import assign from 'object-assign'; -import webAppConfig from '../config'; -import Cookies from '../common/utils/js-cookie/Cookies'; -import { httpLog } from '../common/utils/logging'; -/* eslint no-param-reassign: 0 */ - - -const defaults = { - dataType: 'json', - baseUrl: webAppConfig.STAFF_API_SERVER_API_ROOT_URL, - baseCdnUrl: webAppConfig.STAFF_API_SERVER_API_CDN_ROOT_URL, - url: webAppConfig.STAFF_API_SERVER_API_ROOT_URL, - query: {}, - method: 'GET', - data () { - // console.log('----------- voter_device_id sent with request in service.js/data: ', Cookies.get('voter_device_id')); - return Cookies.get('voter_device_id') ? { - // csrfmiddlewaretoken: cookies.getItem('csrftoken'), - voter_device_id: Cookies.get('voter_device_id'), - } : {}; - }, - - success: (res) => console.warn('Success function not defined:', res), - error: (err) => console.error(`Ajax error: ${err.message}`), -}; - -/* - * 2021: This function uses jQuery, to do deferred fetches from endpoints, and is already loaded with React - * i.e. making sure jQuery is loaded right away becomes less important - * React fetch is a more up to date way of doing this: - * https://reactjs.org/docs/faq-ajax.html - * - * 2016: The idea of this APIS.js file is to abstract away the details - * of many repetitive service calls that we will be using. - * @author Nick Fiorini - */ - - -function innerAjax (options) { - const { $ } = window; - if (!options.endpoint) throw new Error('$ajax missing endpoint option'); - if (!defaults.baseCdnUrl) throw new Error('$ajax missing base CDN url option'); - if (!defaults.baseUrl) throw new Error('$ajax missing base url option'); - - options.crossDomain = true; - options.success = options.success || defaults.success; - options.error = options.error || defaults.error; - // console.log('service.js, options.endpoint: ', options.endpoint); - if (options.endpoint === 'campaignStartSave' || - // options.endpoint === 'challengeSave' || // TBD - options.endpoint === 'challengeStartSave' || - options.endpoint === 'organizationPhotosSave' || - options.endpoint === 'reactionLikeStatusRetrieve' || - options.endpoint === 'voterContactListSave' || - options.endpoint === 'voterUpdate') { - options.method = 'POST'; - } else { - options.method = 'GET'; - } - // Switch between master API server and CDN - if (options.endpoint === 'allBallotItemsRetrieve' || - options.endpoint === 'voterGuidesUpcomingRetrieve' || - options.endpoint === 'voterGuidesRetrieve' - ) { - // Retrieve API data from CDN - options.data = assign({}, options.data || {}); // Do not pass voter_device_id - if (options.endpoint && !options.endpoint.endsWith('/')) { - options.endpoint += '/'; - } - options.url = new URL(options.endpoint, defaults.baseCdnUrl); // `${URL.resolve(defaults.baseCdnUrl, options.endpoint)}/`; - } else { - // Retrieve API from API Server Pool - options.data = assign({}, options.data || {}, defaults.data()); - if (options.endpoint && !options.endpoint.endsWith('/')) { - options.endpoint += '/'; - } - options.url = new URL(options.endpoint, defaults.baseUrl); // `${URL.resolve(defaults.baseUrl, options.endpoint)}/`; - } - - httpLog(`AJAX URL: ${options.url} -- voter_device_id: ${Cookies.get('voter_device_id')}`); - if (options.method === 'POST') { - httpLog(JSON.stringify(options.data)); - } - if (['voterRetrieve', 'deviceStoreFirebaseCloudMessagingToken', 'siteConfigurationRetrieve'].includes(options.endpoint)) { - httpLog('AJAX voter_device_id: ', Cookies.get('voter_device_id')); - } - return $.ajax(options); -} - -export default function $ajax (options) { - if (typeof window.$ !== 'undefined') { - innerAjax(options); - } else { - let loop = 0; - // eslint-disable-next-line consistent-return - const waitForJQuery = setInterval(() => { - if (typeof window.$ !== 'undefined') { - clearInterval(waitForJQuery); - innerAjax(options); - } - if (loop++ > 400 && loop < 405) { - throw new Error('$ajax could not load jQuery within 20 seconds'); - } - }, 10); - } -} +// import assign from 'object-assign'; +// import webAppConfig from '../config'; +// import Cookies from '../common/utils/js-cookie/Cookies'; +// import { httpLog } from '../common/utils/logging'; +// /* eslint no-param-reassign: 0 */ +// +// +// const defaults = { +// dataType: 'json', +// baseUrl: webAppConfig.STAFF_API_SERVER_API_ROOT_URL, +// baseCdnUrl: webAppConfig.STAFF_API_SERVER_API_CDN_ROOT_URL, +// url: webAppConfig.STAFF_API_SERVER_API_ROOT_URL, +// query: {}, +// method: 'GET', +// data () { +// // console.log('----------- voter_device_id sent with request in service.js/data: ', Cookies.get('voter_device_id')); +// return Cookies.get('voter_device_id') ? { +// // csrfmiddlewaretoken: cookies.getItem('csrftoken'), +// voter_device_id: Cookies.get('voter_device_id'), +// } : {}; +// }, +// +// success: (res) => console.warn('Success function not defined:', res), +// error: (err) => console.error(`Ajax error: ${err.message}`), +// }; +// +// /* +// * 2021: This function uses jQuery, to do deferred fetches from endpoints, and is already loaded with React +// * i.e. making sure jQuery is loaded right away becomes less important +// * React fetch is a more up to date way of doing this: +// * https://reactjs.org/docs/faq-ajax.html +// * +// * 2016: The idea of this APIS.js file is to abstract away the details +// * of many repetitive service calls that we will be using. +// * @author Nick Fiorini +// */ +// +// +// function innerAjax (options) { +// const { $ } = window; +// if (!options.endpoint) throw new Error('$ajax missing endpoint option'); +// if (!defaults.baseCdnUrl) throw new Error('$ajax missing base CDN url option'); +// if (!defaults.baseUrl) throw new Error('$ajax missing base url option'); +// +// options.crossDomain = true; +// options.success = options.success || defaults.success; +// options.error = options.error || defaults.error; +// // console.log('service.js, options.endpoint: ', options.endpoint); +// if (options.endpoint === 'campaignStartSave' || +// // options.endpoint === 'challengeSave' || // TBD +// options.endpoint === 'challengeStartSave' || +// options.endpoint === 'organizationPhotosSave' || +// options.endpoint === 'reactionLikeStatusRetrieve' || +// options.endpoint === 'voterContactListSave' || +// options.endpoint === 'voterUpdate') { +// options.method = 'POST'; +// } else { +// options.method = 'GET'; +// } +// // Switch between master API server and CDN +// if (options.endpoint === 'allBallotItemsRetrieve' || +// options.endpoint === 'voterGuidesUpcomingRetrieve' || +// options.endpoint === 'voterGuidesRetrieve' +// ) { +// // Retrieve API data from CDN +// options.data = assign({}, options.data || {}); // Do not pass voter_device_id +// if (options.endpoint && !options.endpoint.endsWith('/')) { +// options.endpoint += '/'; +// } +// options.url = new URL(options.endpoint, defaults.baseCdnUrl); // `${URL.resolve(defaults.baseCdnUrl, options.endpoint)}/`; +// } else { +// // Retrieve API from API Server Pool +// options.data = assign({}, options.data || {}, defaults.data()); +// if (options.endpoint && !options.endpoint.endsWith('/')) { +// options.endpoint += '/'; +// } +// options.url = new URL(options.endpoint, defaults.baseUrl); // `${URL.resolve(defaults.baseUrl, options.endpoint)}/`; +// } +// +// httpLog(`AJAX URL: ${options.url} -- voter_device_id: ${Cookies.get('voter_device_id')}`); +// if (options.method === 'POST') { +// httpLog(JSON.stringify(options.data)); +// } +// if (['voterRetrieve', 'deviceStoreFirebaseCloudMessagingToken', 'siteConfigurationRetrieve'].includes(options.endpoint)) { +// httpLog('AJAX voter_device_id: ', Cookies.get('voter_device_id')); +// } +// return $.ajax(options); +// } +// +// export default function $ajax (options) { +// if (typeof window.$ !== 'undefined') { +// innerAjax(options); +// } else { +// let loop = 0; +// // eslint-disable-next-line consistent-return +// const waitForJQuery = setInterval(() => { +// if (typeof window.$ !== 'undefined') { +// clearInterval(waitForJQuery); +// innerAjax(options); +// } +// if (loop++ > 400 && loop < 405) { +// throw new Error('$ajax could not load jQuery within 20 seconds'); +// } +// }, 10); +// } +// }