diff --git a/src/js/common/stores/AppObservableStore.js b/src/js/common/stores/AppObservableStore.js index f7571507a..a2e75811e 100644 --- a/src/js/common/stores/AppObservableStore.js +++ b/src/js/common/stores/AppObservableStore.js @@ -69,6 +69,7 @@ const nonFluxState = { showClaimProfileWithOtherWaysModal: false, showCompleteYourProfileModal: false, showNotificationBannerAboveHeader: false, + showOfficeBannerAboveHeader: false, showEditAddressButton: false, showElectionsWithOrganizationVoterGuidesModal: false, showHeader: 0, @@ -296,6 +297,15 @@ export default { messageService.sendMessage('state updated showNotificationBannerAboveHeader'); }, + getShowOfficeBannerAboveHeader () { + return nonFluxState.showOfficeBannerAboveHeader; + }, + + setShowOfficeBannerAboveHeader (show) { + nonFluxState.showOfficeBannerAboveHeader = show; + messageService.sendMessage('state updated showOfficeBannerAboveHeader'); + }, + getWeVoteRootURL () { const { location: { hostname, origin } } = window; if (hostname === 'localhost' || hostname === 'quality.wevote.us' || hostname === 'wevotedeveloper.com') { diff --git a/src/js/components/Navigation/Header.jsx b/src/js/components/Navigation/Header.jsx index 893e6fde3..951375431 100644 --- a/src/js/components/Navigation/Header.jsx +++ b/src/js/components/Navigation/Header.jsx @@ -26,6 +26,7 @@ const HeaderBackToVoterGuides = React.lazy(() => import(/* webpackChunkName: 'He const HeaderBarModals = React.lazy(() => import(/* webpackChunkName: 'HeaderBarModals' */ './HeaderBarModals')); const HowItWorksModal = React.lazy(() => import(/* webpackChunkName: 'HowItWorksModal' */ '../CompleteYourProfile/HowItWorksModal')); const NotificationBannerAboveHeader = React.lazy(() => import(/* webpackChunkName: 'NotificationBannerAboveHeader' */ './NotificationBannerAboveHeader')); +const OfficeBannerAboveHeader = React.lazy(() => import(/* webpackChunkName: 'OfficeBannerAboveHeader' */ './OfficeBannerAboveHeader')); const OrganizationModal = React.lazy(() => import(/* webpackChunkName: 'OrganizationModal' */ '../VoterGuide/OrganizationModal')); const PositionDrawer = React.lazy(() => import(/* webpackChunkName: 'PositionDrawer' */ '../Ballot/PositionDrawer')); const SharedItemModal = React.lazy(() => import(/* webpackChunkName: 'SharedItemModal' */ '../Share/SharedItemModal')); @@ -43,6 +44,7 @@ export default class Header extends Component { sharedItemCode: '', showHowItWorksModal: false, showNotificationBannerAboveHeader: AppObservableStore.getShowNotificationBannerAboveHeader(), + showOfficeBannerAboveHeader: AppObservableStore.getShowOfficeBannerAboveHeader(), showVoterPlanModal: false, showOrganizationModal: false, showPositionDrawer: false, @@ -119,6 +121,7 @@ export default class Header extends Component { showPositionDrawer: AppObservableStore.showPositionDrawer(), showSharedItemModal: AppObservableStore.showSharedItemModal(), showNotificationBannerAboveHeader: AppObservableStore.getShowNotificationBannerAboveHeader(), + showOfficeBannerAboveHeader: AppObservableStore.getShowOfficeBannerAboveHeader(), }); } @@ -182,6 +185,7 @@ export default class Header extends Component { render () { renderLog('Header'); // Set LOG_RENDER_EVENTS to log all renders const { showNotificationBannerAboveHeader } = this.state; + const { showOfficeBannerAboveHeader } = this.state; if (this.hideHeader()) { renderLog('Header hidden'); @@ -189,6 +193,7 @@ export default class Header extends Component { } const pathname = normalizedHref(); const isCandidatePage = /^\/[-a-z0-9]+\/-\/?$/.test(pathname); + const isOfficePage = /^\/office\/[a-z0-9]+\/?$/.test(pathname); const { hideHeader, params } = this.props; // console.log('Header global.weVoteGlobalHistory', global.weVoteGlobalHistory); const { @@ -488,6 +493,13 @@ export default class Header extends Component { )} + {(showOfficeBannerAboveHeader && isOfficePage) && ( + + }> + + + + )} {(headerNotVisible || hideHeader) ? ( <> }> @@ -587,3 +599,8 @@ const NotificationBannerAboveHeaderWrapper = styled.div` justify-content: center; padding: 0 16px; `; +const OfficeBannerAboveHeaderWrapper = styled.div` + display: flex; + justify-content: center; + padding: 0 16px; +`; diff --git a/src/js/components/Navigation/OfficeBannerAboveHeader.jsx b/src/js/components/Navigation/OfficeBannerAboveHeader.jsx new file mode 100644 index 000000000..88610945c --- /dev/null +++ b/src/js/components/Navigation/OfficeBannerAboveHeader.jsx @@ -0,0 +1,189 @@ +import { Edit } from '@mui/icons-material'; +import React, { useCallback, useEffect, useState } from 'react'; +import TagManager from 'react-gtm-module'; +import { useHistory } from 'react-router-dom'; +import styled from 'styled-components'; +import lookupPageNameAndPageTypeDict, { getPageDetails } from '../../utils/lookupPageNameAndPageTypeDict'; +import normalizedImagePath from '../../common/utils/normalizedImagePath'; +import VoterStore from '../../stores/VoterStore'; +import AppObservableStore, { messageService } from '../../common/stores/AppObservableStore'; +import DesignTokenColors from '../../common/components/Style/DesignTokenColors'; +import useVoterCanEditPolitician from '../../hooks/useVoterCanEditPolitician'; +import PoliticianStore from '../../common/stores/PoliticianStore'; +import HeaderLogoImage from './HeaderLogoImage'; +import {WeVoteLogo} from '../Style/SimpleProcessStyles'; + +const chosenSiteLogoUrl = '../../../img/global/svg-icons/we-vote-icon-square-color.svg'; + +export default function OfficeBannerAboveHeader() { + const voterCanEditPoliticianProfile = useVoterCanEditPolitician(); + const [politicianWeVoteId, setPoliticianWeVoteId] = useState(AppObservableStore.getPoliticianWeVoteIdBeingViewed()); + + const history = useHistory(); + const handleBallotButtonClick = () => history.push('/ballot') + + const onAppObservableStoreChange = useCallback(() => { + if (AppObservableStore.getPoliticianWeVoteIdBeingViewed()) { + setPoliticianWeVoteId(AppObservableStore.getPoliticianWeVoteIdBeingViewed()); + // console.log('PoliticianSelfEditDrawer onAppObservableStoreChange politicianWeVoteId:', AppObservableStore.getPoliticianWeVoteIdBeingViewed()); + } + }, [setPoliticianWeVoteId]); + + const closeEditBar = (buttonId) => { + AppObservableStore.setShowOfficeBannerAboveHeader(false); + const dataLayerObject = { + actionDetails: { + actionType: 'closeModal', + buttonId, + }, + event: 'action', + pageDetails: getPageDetails(), + userDetails: VoterStore.getAnalyticsUserDetails(), + }; + TagManager.dataLayer({ dataLayer: dataLayerObject }); + }; + + useEffect(() => { + const appStateSubscription = messageService.getMessage().subscribe(onAppObservableStoreChange); + onAppObservableStoreChange(); + return () => { + setPoliticianWeVoteId(''); + appStateSubscription.unsubscribe(); + }; + }, [onAppObservableStoreChange]); + + return ( + + +
+ + Welcome to WeVote, your personalized voter guide! + Welcome to WeVote, your personalized voter guide: +
+ + {/*{' '}*/} + 🗳  VOTE YOUR VALUES + Get personalized ballot recommendations based on your interests and trusted connections. + + + 🤝  SHARE & MOBILIZE + Choose the candidates you support or oppose, and tell your friends. + + + 🔍  SIMPLIFY VOTING + Use clear, nonpartisan tools to understand your ballot and take action confidently. + +
+ + + + View your full ballot to get started + View your full ballot to get started + + + + closeEditBar('closeOfficeBanner')}>✕ + +
+ ); +} + +const VerticalCenter = styled.div` + margin-inline: 2%; + display: flex; + flex-direction: column; + justify-content: center; +`; + +const OfficeBannerAboveHeaderContainer = styled.div` + background: ${DesignTokenColors.secondary800}; + color: ${DesignTokenColors.whiteUI}; + display: flex; + font-size: 14px; +// flex-direction: column; // only on mobile! +// align-items: center; // only on mobile! + margin-left: -16px; + margin-right: -16px; + padding: 8px 16px; + width: 100vw; +`; + +const BannerTextContainer = styled.div` + display: flex; + gap: 12px; + flex-wrap: wrap; + flex-direction: column; + align-items: flex-start; + padding-bottom: 12px; +`; + +const BannerIntroTextDesktop = styled('span')` + font-size: 18px; + font-weight: 500; + margin-bottom: 8px; + margin-top: 8px; +`; + +const BannerIntroTextMobile = styled('span')` +`; + +const BannerElementTitle = styled.div` + font-weight: 500; + margin-bottom: 2px; + margin-left: 1em; +`; + +const BannerElementText = styled.div` + margin-left: 2.5em; +`; + +const BannerElement = styled('div')` +`; + +const VerticalLine = styled('div')` + border-left: 1px solid rgba(105, 105, 105, 0.6); + height: 90%; + margin-inline: 5%; + margin: 5px; +`; + +const ButtonHolder = styled.div` +`; + +const BallotButton = styled.button` + background: ${DesignTokenColors.whiteUI}; + border: none; + border-radius: 24px; + color: ${DesignTokenColors.secondary800}; + cursor: pointer; + font-weight: 500; + padding: 8px 16px; + margin-top: 32px; + + @media (max-width: 800px) { + margin-top: 8px; + } + @media (max-width: 600px) { + width: auto; + order: 1; + } +`; + +const CloseButton = styled.button` + background: transparent; + border: none; + color: ${DesignTokenColors.whiteUI}; + cursor: pointer; + font-size: 20px; + margin-left: 16px; + + display: flex; + flex-direction: row; + justify-content: center; + + @media (max-width: 600px) { + order: 2; + margin-left: 8px; + } +`; +