From 7dc7b4cf1ad2eba05ec6a323569acd57b08fc611 Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Thu, 29 Aug 2024 17:35:45 -0700 Subject: [PATCH] Added first versions of Challenge files. Added some CampaignX files. --- src/App.jsx | 14 + src/js/common/actions/CampaignStartActions.js | 121 ++++++ .../common/actions/ChallengeStartActions.js | 121 ++++++ .../CampaignDescriptionInputField.jsx | 147 +++++++ .../CampaignStart/CampaignPhotoUpload.jsx | 226 ++++++++++ .../CampaignStart/CampaignTitleInputField.jsx | 147 +++++++ .../ChallengeDescriptionInputField.jsx | 147 +++++++ .../ChallengeStart/ChallengePhotoUpload.jsx | 226 ++++++++++ .../ChallengeTitleInputField.jsx | 147 +++++++ .../Navigation/CampaignStartSteps.jsx | 135 ++++++ .../Navigation/ChallengeStartSteps.jsx | 134 ++++++ .../components/Style/CampaignStartStyles.jsx | 38 ++ .../components/Style/commonMuiStyles.js | 2 +- .../CampaignStartAddDescription.jsx | 163 ++++++++ .../CampaignStart/CampaignStartAddPhoto.jsx | 154 +++++++ .../CampaignStart/CampaignStartAddTitle.jsx | 140 +++++++ .../CampaignStart/CampaignStartEditAll.jsx | 388 +++++++++++++++++ .../CampaignStart/CampaignStartPreview.jsx | 392 ++++++++++++++++++ .../ChallengeStartAddDescription.jsx | 163 ++++++++ .../ChallengeStart/ChallengeStartAddPhoto.jsx | 154 +++++++ .../ChallengeStart/ChallengeStartAddTitle.jsx | 140 +++++++ .../ChallengeStart/ChallengeStartEditAll.jsx | 380 +++++++++++++++++ .../ChallengeStart/ChallengeStartIntro.jsx | 321 ++++++++++++++ .../ChallengeStart/ChallengeStartPreview.jsx | 350 ++++++++++++++++ src/js/common/stores/AppObservableStore.js | 4 + src/js/common/stores/CampaignStartStore.js | 314 ++++++++++++++ src/js/common/stores/ChallengeStartStore.js | 314 ++++++++++++++ src/js/components/Navigation/Header.jsx | 4 +- src/js/utils/applicationUtils.js | 5 +- src/js/utils/service.js | 4 +- 30 files changed, 4991 insertions(+), 4 deletions(-) create mode 100644 src/js/common/actions/CampaignStartActions.js create mode 100644 src/js/common/actions/ChallengeStartActions.js create mode 100755 src/js/common/components/CampaignStart/CampaignDescriptionInputField.jsx create mode 100644 src/js/common/components/CampaignStart/CampaignPhotoUpload.jsx create mode 100755 src/js/common/components/CampaignStart/CampaignTitleInputField.jsx create mode 100755 src/js/common/components/ChallengeStart/ChallengeDescriptionInputField.jsx create mode 100644 src/js/common/components/ChallengeStart/ChallengePhotoUpload.jsx create mode 100755 src/js/common/components/ChallengeStart/ChallengeTitleInputField.jsx create mode 100644 src/js/common/components/Navigation/CampaignStartSteps.jsx create mode 100644 src/js/common/components/Navigation/ChallengeStartSteps.jsx create mode 100644 src/js/common/components/Style/CampaignStartStyles.jsx create mode 100644 src/js/common/pages/CampaignStart/CampaignStartAddDescription.jsx create mode 100644 src/js/common/pages/CampaignStart/CampaignStartAddPhoto.jsx create mode 100644 src/js/common/pages/CampaignStart/CampaignStartAddTitle.jsx create mode 100644 src/js/common/pages/CampaignStart/CampaignStartEditAll.jsx create mode 100644 src/js/common/pages/CampaignStart/CampaignStartPreview.jsx create mode 100644 src/js/common/pages/ChallengeStart/ChallengeStartAddDescription.jsx create mode 100644 src/js/common/pages/ChallengeStart/ChallengeStartAddPhoto.jsx create mode 100644 src/js/common/pages/ChallengeStart/ChallengeStartAddTitle.jsx create mode 100644 src/js/common/pages/ChallengeStart/ChallengeStartEditAll.jsx create mode 100644 src/js/common/pages/ChallengeStart/ChallengeStartIntro.jsx create mode 100644 src/js/common/pages/ChallengeStart/ChallengeStartPreview.jsx create mode 100644 src/js/common/stores/CampaignStartStore.js create mode 100644 src/js/common/stores/ChallengeStartStore.js diff --git a/src/App.jsx b/src/App.jsx index 6ceea3c56..b2588f48d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -48,6 +48,12 @@ const CampaignUpdatesPage = React.lazy(() => import(/* webpackChunkName: 'Campai const Candidate = React.lazy(() => import(/* webpackChunkName: 'Candidate' */ './js/pages/Ballot/Candidate')); const CandidateForExtension = React.lazy(() => import(/* webpackChunkName: 'EditCandidateForExtension' */ './js/pages/Ballot/EditCandidateForExtension/EditCandidateForExtension')); const ChallengeHomePage = React.lazy(() => import(/* webpackChunkName: 'ChallengeHomePage' */ './js/common/pages/Challenge/ChallengeHomePage')); +const ChallengeStartAddDescription = React.lazy(() => import(/* webpackChunkName: 'ChallengeStartAddDescription' */ './js/common/pages/ChallengeStart/ChallengeStartAddDescription')); +const ChallengeStartAddPhoto = React.lazy(() => import(/* webpackChunkName: 'ChallengeStartAddPhoto' */ './js/common/pages/ChallengeStart/ChallengeStartAddPhoto')); +const ChallengeStartAddTitle = React.lazy(() => import(/* webpackChunkName: 'ChallengeStartAddTitle' */ './js/common/pages/ChallengeStart/ChallengeStartAddTitle')); +const ChallengeStartEditAll = React.lazy(() => import(/* webpackChunkName: 'ChallengeStartEditAll' */ './js/common/pages/ChallengeStart/ChallengeStartEditAll')); +const ChallengeStartIntro = React.lazy(() => import(/* webpackChunkName: 'ChallengeStartIntro' */ './js/common/pages/ChallengeStart/ChallengeStartIntro')); +const ChallengeStartPreview = React.lazy(() => import(/* webpackChunkName: 'ChallengeStartPreview' */ './js/common/pages/ChallengeStart/ChallengeStartPreview')); const ChallengeSupportJoin = React.lazy(() => import(/* webpackChunkName: 'ChallengeSupportJoin' */ './js/common/pages/ChallengeSupport/ChallengeSupportJoin')); const ClaimYourPage = React.lazy(() => import(/* webpackChunkName: 'ClaimYourPage' */ './js/pages/Settings/ClaimYourPage')); const CompleteYourProfileMobile = React.lazy(() => import(/* webpackChunkName: 'CompleteYourProfileMobile' */ './js/common/pages/Settings/CompleteYourProfileMobile')); @@ -402,6 +408,7 @@ class App extends Component { } /> } /> + } /> } /> } /> } /> @@ -568,6 +575,13 @@ class App extends Component { + + + + + } /> + + diff --git a/src/js/common/actions/CampaignStartActions.js b/src/js/common/actions/CampaignStartActions.js new file mode 100644 index 000000000..f428d71f4 --- /dev/null +++ b/src/js/common/actions/CampaignStartActions.js @@ -0,0 +1,121 @@ +import Dispatcher from '../dispatcher/Dispatcher'; + +export default { + campaignDescriptionQueuedToSave (campaignDescription) { + Dispatcher.dispatch({ type: 'campaignDescriptionQueuedToSave', payload: campaignDescription }); + }, + + campaignDescriptionSave (campaignWeVoteId, campaignDescription) { + // console.log('campaignDescriptionSave: ', campaignDescription); + Dispatcher.loadEndpoint('campaignStartSave', + { + campaign_description: campaignDescription, + campaign_description_changed: true, + campaignx_we_vote_id: campaignWeVoteId, + }); + }, + + campaignEditAllReset () { + Dispatcher.dispatch({ type: 'campaignEditAllReset', payload: true }); + }, + + campaignEditAllSave ( + campaignXWeVoteId, + campaignDescriptionQueuedToSave, campaignDescriptionQueuedToSaveSet, + campaignPhotoQueuedToDelete, campaignPhotoQueuedToDeleteSet, + campaignPhotoQueuedToSave, campaignPhotoQueuedToSaveSet, + campaignPoliticianDeleteListJson, + campaignPoliticianStarterListQueuedToSave, campaignPoliticianStarterListQueuedToSaveSet, + campaignTitleQueuedToSave, campaignTitleQueuedToSaveSet, + ) { + Dispatcher.loadEndpoint('campaignStartSave', + { + campaign_description: campaignDescriptionQueuedToSave, + campaign_description_changed: campaignDescriptionQueuedToSaveSet, + campaign_photo_from_file_reader: campaignPhotoQueuedToSave, + campaign_photo_changed: campaignPhotoQueuedToSaveSet, + campaign_photo_delete: campaignPhotoQueuedToDelete, + campaign_photo_delete_changed: campaignPhotoQueuedToDeleteSet, + campaign_title: campaignTitleQueuedToSave, + campaign_title_changed: campaignTitleQueuedToSaveSet, + campaignx_we_vote_id: campaignXWeVoteId, + politician_delete_list: campaignPoliticianDeleteListJson, + politician_starter_list: campaignPoliticianStarterListQueuedToSave, + politician_starter_list_changed: campaignPoliticianStarterListQueuedToSaveSet, + }); + }, + + campaignPhotoQueuedToDelete (deleteCampaignPhoto = true) { + Dispatcher.dispatch({ type: 'campaignPhotoQueuedToDelete', payload: deleteCampaignPhoto }); + }, + + campaignPhotoQueuedToSave (campaignPhotoFromFileReader) { + Dispatcher.dispatch({ type: 'campaignPhotoQueuedToSave', payload: campaignPhotoFromFileReader }); + }, + + campaignPhotoSave (campaignWeVoteId, campaignPhotoFromFileReader) { + Dispatcher.loadEndpoint('campaignStartSave', + { + campaign_photo_from_file_reader: campaignPhotoFromFileReader, + campaign_photo_changed: true, + campaignx_we_vote_id: campaignWeVoteId, + }); + }, + + campaignPoliticianDeleteAddQueuedToSave (campaignXPoliticianId) { + Dispatcher.dispatch({ type: 'campaignPoliticianDeleteAddQueuedToSave', payload: campaignXPoliticianId }); + }, + + campaignPoliticianDeleteRemoveQueuedToSave (campaignXPoliticianId) { + Dispatcher.dispatch({ type: 'campaignPoliticianDeleteRemoveQueuedToSave', payload: campaignXPoliticianId }); + }, + + campaignPoliticianStarterListQueuedToSave (campaignPoliticianStarterList) { + Dispatcher.dispatch({ type: 'campaignPoliticianStarterListQueuedToSave', payload: campaignPoliticianStarterList }); + }, + + campaignPoliticianStarterListSave (campaignWeVoteId, campaignPoliticianStarterListQueuedToSaveJson, campaignPoliticianDeleteListJson) { + // console.log('campaignPoliticianStarterListQueuedToSaveJson: ', campaignPoliticianStarterListQueuedToSaveJson); + Dispatcher.loadEndpoint('campaignStartSave', + { + politician_delete_list: campaignPoliticianDeleteListJson, + politician_starter_list: campaignPoliticianStarterListQueuedToSaveJson, + politician_starter_list_changed: true, + campaignx_we_vote_id: campaignWeVoteId, + }); + }, + + campaignRetrieveAsOwner (campaignWeVoteId) { + let { hostname } = window.location; + hostname = hostname || ''; + Dispatcher.loadEndpoint('campaignRetrieveAsOwner', + { + campaignx_we_vote_id: campaignWeVoteId, + hostname, + }); + }, + + campaignTitleQueuedToSave (campaignTitle) { + Dispatcher.dispatch({ type: 'campaignTitleQueuedToSave', payload: campaignTitle }); + }, + + campaignTitleSave (campaignWeVoteId, campaignTitle) { + // console.log('campaignTitleSave: ', campaignTitle); + Dispatcher.loadEndpoint('campaignStartSave', + { + campaign_title: campaignTitle, + campaign_title_changed: true, + campaignx_we_vote_id: campaignWeVoteId, + }); + }, + + inDraftModeSave (campaignWeVoteId, inDraftMode) { + // console.log('campaignDescriptionSave: ', campaignDescription); + Dispatcher.loadEndpoint('campaignStartSave', + { + in_draft_mode: inDraftMode, + in_draft_mode_changed: true, + campaignx_we_vote_id: campaignWeVoteId, + }); + }, +}; diff --git a/src/js/common/actions/ChallengeStartActions.js b/src/js/common/actions/ChallengeStartActions.js new file mode 100644 index 000000000..8af8d9328 --- /dev/null +++ b/src/js/common/actions/ChallengeStartActions.js @@ -0,0 +1,121 @@ +import Dispatcher from '../dispatcher/Dispatcher'; + +export default { + challengeDescriptionQueuedToSave (challengeDescription) { + Dispatcher.dispatch({ type: 'challengeDescriptionQueuedToSave', payload: challengeDescription }); + }, + + challengeDescriptionSave (challengeWeVoteId, challengeDescription) { + // console.log('challengeDescriptionSave: ', challengeDescription); + Dispatcher.loadEndpoint('challengeStartSave', + { + challenge_description: challengeDescription, + challenge_description_changed: true, + challenge_we_vote_id: challengeWeVoteId, + }); + }, + + challengeEditAllReset () { + Dispatcher.dispatch({ type: 'challengeEditAllReset', payload: true }); + }, + + challengeEditAllSave ( + challengeWeVoteId, + challengeDescriptionQueuedToSave, challengeDescriptionQueuedToSaveSet, + challengePhotoQueuedToDelete, challengePhotoQueuedToDeleteSet, + challengePhotoQueuedToSave, challengePhotoQueuedToSaveSet, + challengePoliticianDeleteListJson, + challengePoliticianStarterListQueuedToSave, challengePoliticianStarterListQueuedToSaveSet, + challengeTitleQueuedToSave, challengeTitleQueuedToSaveSet, + ) { + Dispatcher.loadEndpoint('challengeStartSave', + { + challenge_description: challengeDescriptionQueuedToSave, + challenge_description_changed: challengeDescriptionQueuedToSaveSet, + challenge_photo_from_file_reader: challengePhotoQueuedToSave, + challenge_photo_changed: challengePhotoQueuedToSaveSet, + challenge_photo_delete: challengePhotoQueuedToDelete, + challenge_photo_delete_changed: challengePhotoQueuedToDeleteSet, + challenge_title: challengeTitleQueuedToSave, + challenge_title_changed: challengeTitleQueuedToSaveSet, + challenge_we_vote_id: challengeWeVoteId, + politician_delete_list: challengePoliticianDeleteListJson, + politician_starter_list: challengePoliticianStarterListQueuedToSave, + politician_starter_list_changed: challengePoliticianStarterListQueuedToSaveSet, + }); + }, + + challengePhotoQueuedToDelete (deleteChallengePhoto = true) { + Dispatcher.dispatch({ type: 'challengePhotoQueuedToDelete', payload: deleteChallengePhoto }); + }, + + challengePhotoQueuedToSave (challengePhotoFromFileReader) { + Dispatcher.dispatch({ type: 'challengePhotoQueuedToSave', payload: challengePhotoFromFileReader }); + }, + + challengePhotoSave (challengeWeVoteId, challengePhotoFromFileReader) { + Dispatcher.loadEndpoint('challengeStartSave', + { + challenge_photo_from_file_reader: challengePhotoFromFileReader, + challenge_photo_changed: true, + challenge_we_vote_id: challengeWeVoteId, + }); + }, + + challengePoliticianDeleteAddQueuedToSave (challengePoliticianId) { + Dispatcher.dispatch({ type: 'challengePoliticianDeleteAddQueuedToSave', payload: challengePoliticianId }); + }, + + challengePoliticianDeleteRemoveQueuedToSave (challengePoliticianId) { + Dispatcher.dispatch({ type: 'challengePoliticianDeleteRemoveQueuedToSave', payload: challengePoliticianId }); + }, + + challengePoliticianStarterListQueuedToSave (challengePoliticianStarterList) { + Dispatcher.dispatch({ type: 'challengePoliticianStarterListQueuedToSave', payload: challengePoliticianStarterList }); + }, + + challengePoliticianStarterListSave (challengeWeVoteId, challengePoliticianStarterListQueuedToSaveJson, challengePoliticianDeleteListJson) { + // console.log('challengePoliticianStarterListQueuedToSaveJson: ', challengePoliticianStarterListQueuedToSaveJson); + Dispatcher.loadEndpoint('challengeStartSave', + { + politician_delete_list: challengePoliticianDeleteListJson, + politician_starter_list: challengePoliticianStarterListQueuedToSaveJson, + politician_starter_list_changed: true, + challenge_we_vote_id: challengeWeVoteId, + }); + }, + + challengeRetrieveAsOwner (challengeWeVoteId) { + let { hostname } = window.location; + hostname = hostname || ''; + Dispatcher.loadEndpoint('challengeRetrieveAsOwner', + { + challenge_we_vote_id: challengeWeVoteId, + hostname, + }); + }, + + challengeTitleQueuedToSave (challengeTitle) { + Dispatcher.dispatch({ type: 'challengeTitleQueuedToSave', payload: challengeTitle }); + }, + + challengeTitleSave (challengeWeVoteId, challengeTitle) { + console.log('challengeTitleSave: ', challengeTitle, ', challengeWeVoteId: ', challengeWeVoteId); + Dispatcher.loadEndpoint('challengeStartSave', + { + challenge_title: challengeTitle, + challenge_title_changed: true, + challenge_we_vote_id: challengeWeVoteId, + }); + }, + + inDraftModeSave (challengeWeVoteId, inDraftMode) { + // console.log('challengeDescriptionSave: ', challengeDescription); + Dispatcher.loadEndpoint('challengeStartSave', + { + in_draft_mode: inDraftMode, + in_draft_mode_changed: true, + challenge_we_vote_id: challengeWeVoteId, + }); + }, +}; diff --git a/src/js/common/components/CampaignStart/CampaignDescriptionInputField.jsx b/src/js/common/components/CampaignStart/CampaignDescriptionInputField.jsx new file mode 100755 index 000000000..1e073df04 --- /dev/null +++ b/src/js/common/components/CampaignStart/CampaignDescriptionInputField.jsx @@ -0,0 +1,147 @@ +import { FormControl, TextField } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import CampaignStartActions from '../../actions/CampaignStartActions'; +import { renderLog } from '../../utils/logging'; +import CampaignStartStore from '../../stores/CampaignStartStore'; +import CampaignStore from '../../stores/CampaignStore'; + +class CampaignDescriptionInputField extends Component { + constructor (props) { + super(props); + this.state = { + campaignDescription: '', + }; + + this.handleKeyPress = this.handleKeyPress.bind(this); + this.updateCampaignDescription = this.updateCampaignDescription.bind(this); + } + + componentDidMount () { + // console.log('CampaignDescriptionInputField, componentDidMount'); + this.campaignStartStoreListener = CampaignStartStore.addListener(this.onCampaignStartStoreChange.bind(this)); + this.campaignStoreListener = CampaignStore.addListener(this.onCampaignStartStoreChange.bind(this)); + this.onCampaignStartStoreChange(); + } + + componentDidUpdate (prevProps) { + // console.log('CampaignDescriptionInputField componentDidUpdate'); + const { + campaignXWeVoteId: campaignXWeVoteIdPrevious, + } = prevProps; + const { + campaignXWeVoteId, + } = this.props; + if (campaignXWeVoteId) { + if (campaignXWeVoteId !== campaignXWeVoteIdPrevious) { + this.onCampaignStartStoreChange(); + } + } + } + + componentWillUnmount () { + this.campaignStartStoreListener.remove(); + this.campaignStoreListener.remove(); + } + + handleKeyPress () { + // + } + + onCampaignStartStoreChange () { + const { campaignXWeVoteId, editExistingCampaign } = this.props; + let campaignDescription = ''; + if (editExistingCampaign) { + const campaignX = CampaignStore.getCampaignXByWeVoteId(campaignXWeVoteId); + if (campaignX && campaignX.campaignx_we_vote_id) { + campaignDescription = campaignX.campaign_description; + } + } else { + campaignDescription = CampaignStartStore.getCampaignDescription(); + } + const campaignDescriptionQueuedToSave = CampaignStartStore.getCampaignDescriptionQueuedToSave(); + const campaignDescriptionQueuedToSaveSet = CampaignStartStore.getCampaignDescriptionQueuedToSaveSet(); + let campaignDescriptionAdjusted = campaignDescription; + if (campaignDescriptionQueuedToSaveSet) { + campaignDescriptionAdjusted = campaignDescriptionQueuedToSave; + } + // console.log('onCampaignStartStoreChange campaignDescription: ', campaignDescription, ', campaignDescriptionQueuedToSave: ', campaignDescriptionQueuedToSave, ', campaignDescriptionAdjusted:', campaignDescriptionAdjusted); + this.setState({ + campaignDescription: campaignDescriptionAdjusted, + }); + } + + updateCampaignDescription (event) { + if (event.target.name === 'campaignDescription') { + CampaignStartActions.campaignDescriptionQueuedToSave(event.target.value); + this.setState({ + campaignDescription: event.target.value, + }); + } + } + + render () { + renderLog('CampaignDescriptionInputField'); // Set LOG_RENDER_EVENTS to log all renders + + const { classes, externalUniqueId } = this.props; + const { campaignDescription } = this.state; + + return ( +
+
{ e.preventDefault(); }}> + + + + + + + +
+
+ ); + } +} +CampaignDescriptionInputField.propTypes = { + campaignXWeVoteId: PropTypes.string, + classes: PropTypes.object, + editExistingCampaign: PropTypes.bool, + externalUniqueId: PropTypes.string, +}; + +const styles = () => ({ + formControl: { + width: '100%', + }, + // TODO: Figure out how to apply to TextField + textField: { + fontSize: '22px', + }, +}); + +const ColumnFullWidth = styled('div')` + padding: 8px 12px; + width: 100%; +`; + +const Wrapper = styled('div')` + display: flex; + justify-content: space-between; + margin-left: -12px; + width: calc(100% + 24px); +`; + +export default withStyles(styles)(CampaignDescriptionInputField); diff --git a/src/js/common/components/CampaignStart/CampaignPhotoUpload.jsx b/src/js/common/components/CampaignStart/CampaignPhotoUpload.jsx new file mode 100644 index 000000000..b348cf8a1 --- /dev/null +++ b/src/js/common/components/CampaignStart/CampaignPhotoUpload.jsx @@ -0,0 +1,226 @@ +import { Button } from '@mui/material'; +import withStyles from '@mui/styles/withStyles'; +import { DropzoneArea } from 'mui-file-dropzone'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import styled from 'styled-components'; +import CampaignStartActions from '../../actions/CampaignStartActions'; +import isMobileScreenSize from '../../utils/isMobileScreenSize'; +import { renderLog } from '../../utils/logging'; +import CampaignStartStore from '../../stores/CampaignStartStore'; +import CampaignStore from '../../stores/CampaignStore'; + + +class CampaignPhotoUpload extends Component { + constructor (props) { + super(props); + this.state = { + }; + + this.handleDrop = this.handleDrop.bind(this); + } + + componentDidMount () { + // console.log('CampaignPhotoUpload, componentDidMount'); + this.campaignStartStoreListener = CampaignStartStore.addListener(this.onCampaignStartStoreChange.bind(this)); + this.campaignStoreListener = CampaignStore.addListener(this.onCampaignStartStoreChange.bind(this)); + this.onCampaignStartStoreChange(); + } + + componentDidUpdate (prevProps) { + // console.log('CampaignPhotoUpload componentDidUpdate'); + const { + campaignXWeVoteId: campaignXWeVoteIdPrevious, + } = prevProps; + const { + campaignXWeVoteId, + } = this.props; + if (campaignXWeVoteId) { + if (campaignXWeVoteId !== campaignXWeVoteIdPrevious) { + this.onCampaignStartStoreChange(); + } + } + } + + componentWillUnmount () { + this.campaignStartStoreListener.remove(); + this.campaignStoreListener.remove(); + } + + handleDrop (files) { + if (files && files[0]) { + const fileFromDropzone = files[0]; + if (!fileFromDropzone) return; + const fileReader = new FileReader(); + // No need to 'remove' this type of event listener + fileReader.addEventListener('load', () => { + const photoFromFileReader = fileReader.result; + // console.log('photoFromFileReader:', photoFromFileReader); + CampaignStartActions.campaignPhotoQueuedToSave(photoFromFileReader); + }); + fileReader.readAsDataURL(fileFromDropzone); + } + } + + onCampaignStartStoreChange () { + const { campaignXWeVoteId, editExistingCampaign } = this.props; + let campaignPhotoLargeUrl = ''; + if (editExistingCampaign) { + const campaignX = CampaignStore.getCampaignXByWeVoteId(campaignXWeVoteId); + if (campaignX && campaignX.campaignx_we_vote_id) { + campaignPhotoLargeUrl = campaignX.we_vote_hosted_campaign_photo_large_url; + } + } else { + campaignPhotoLargeUrl = CampaignStartStore.getCampaignPhotoLargeUrl(); + } + const campaignPhotoQueuedToDelete = CampaignStartStore.getCampaignPhotoQueuedToDelete(); + const campaignPhotoQueuedToDeleteSet = CampaignStartStore.getCampaignPhotoQueuedToDeleteSet(); + this.setState({ + campaignPhotoLargeUrl, + campaignPhotoQueuedToDelete, + campaignPhotoQueuedToDeleteSet, + }); + } + + markCampaignImageForDelete = () => { + CampaignStartActions.campaignPhotoQueuedToDelete(true); + } + + render () { + renderLog('CampaignPhotoUpload'); // Set LOG_RENDER_EVENTS to log all renders + + const { classes } = this.props; + const { campaignPhotoLargeUrl, campaignPhotoQueuedToDelete, campaignPhotoQueuedToDeleteSet } = this.state; + let campaignPhotoExists = false; + let dropzoneText = isMobileScreenSize() ? 'Upload campaign photo' : 'Drag campaign photo here (or click to find file)'; + if (campaignPhotoLargeUrl) { + campaignPhotoExists = true; + dropzoneText = isMobileScreenSize() ? 'Upload new photo' : 'Drag new photo here (or click to find file)'; + } + const campaignPhotoMarkedForDeletion = Boolean(campaignPhotoQueuedToDelete && campaignPhotoQueuedToDeleteSet); + // console.log('campaignPhotoMarkedForDeletion:', campaignPhotoMarkedForDeletion); + return ( +
+
{ e.preventDefault(); }}> + + + {(campaignPhotoExists && !campaignPhotoMarkedForDeletion) ? ( + + + + + + + + + + + + + ) : ( + + )} + + +
+
+ ); + } +} +CampaignPhotoUpload.propTypes = { + campaignXWeVoteId: PropTypes.string, + classes: PropTypes.object, + editExistingCampaign: PropTypes.bool, +}; + +const styles = (theme) => ({ + buttonDelete: { + backgroundColor: '#f44336', + boxShadow: 'none !important', + fontSize: '18px', + height: '35px !important', + '&:hover': { + backgroundColor: '#8C001A', + }, + marginLeft: 10, + padding: '0 30px', + textTransform: 'none', + width: 100, + }, + dropzoneIcon: { + color: '#999', + }, + dropzoneRoot: { + color: '#999', + [theme.breakpoints.down('sm')]: { + minHeight: '160px', + }, + }, +}); + +const CampaignImage = styled('img')` + width: 100%; +`; + +const CampaignImageWrapper = styled('div')` + margin-top: -44px; +`; + +const CampaignImageDeleteButtonOuterWrapper = styled('div')` + display: flex; + justify-content: flex-end; + width: 100%; + position: relative; + z-index: 1; +`; + +const CampaignImageDeleteButtonInnerWrapper = styled('div')` + margin-right: 8px; + z-index: 2; +`; + +const ColumnFullWidth = styled('div')` + padding: 8px 12px; + width: 100%; +`; + +const OverlayOuterWrapper = styled('div')` + align-self: flex-end; + // width: 640px; + display: flex; + // padding: 0 15px; +`; + +const OverlayInnerWrapper = styled('div')` + min-height: 37px; + width: 100%; +`; + +const Wrapper = styled('div')` + display: flex; + justify-content: space-between; + margin-left: -12px; + margin-top: 10px; + width: calc(100% + 24px); +`; + +export default withStyles(styles)(CampaignPhotoUpload); diff --git a/src/js/common/components/CampaignStart/CampaignTitleInputField.jsx b/src/js/common/components/CampaignStart/CampaignTitleInputField.jsx new file mode 100755 index 000000000..72c626812 --- /dev/null +++ b/src/js/common/components/CampaignStart/CampaignTitleInputField.jsx @@ -0,0 +1,147 @@ +import { FormControl, TextField } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import CampaignStartActions from '../../actions/CampaignStartActions'; +import { renderLog } from '../../utils/logging'; +import CampaignStartStore from '../../stores/CampaignStartStore'; +import CampaignStore from '../../stores/CampaignStore'; + +class CampaignTitleInputField extends Component { + constructor (props) { + super(props); + this.state = { + campaignTitle: '', + }; + + this.handleKeyPress = this.handleKeyPress.bind(this); + this.updateCampaignTitle = this.updateCampaignTitle.bind(this); + } + + componentDidMount () { + // console.log('CampaignTitleInputField, componentDidMount'); + this.campaignStartStoreListener = CampaignStartStore.addListener(this.onCampaignStartStoreChange.bind(this)); + this.campaignStoreListener = CampaignStore.addListener(this.onCampaignStartStoreChange.bind(this)); + this.onCampaignStartStoreChange(); + } + + componentDidUpdate (prevProps) { + // console.log('CampaignTitleInputField componentDidUpdate'); + const { + campaignXWeVoteId: campaignXWeVoteIdPrevious, + } = prevProps; + const { + campaignXWeVoteId, + } = this.props; + if (campaignXWeVoteId) { + if (campaignXWeVoteId !== campaignXWeVoteIdPrevious) { + this.onCampaignStartStoreChange(); + } + } + } + + componentWillUnmount () { + this.campaignStartStoreListener.remove(); + this.campaignStoreListener.remove(); + } + + handleKeyPress () { + // + } + + onCampaignStartStoreChange () { + const { campaignXWeVoteId, editExistingCampaign } = this.props; + // console.log('CampaignTitleInputField campaignXWeVoteId:', campaignXWeVoteId); + let campaignTitle = ''; + if (editExistingCampaign) { + const campaignX = CampaignStore.getCampaignXByWeVoteId(campaignXWeVoteId); + if (campaignX && campaignX.campaignx_we_vote_id) { + campaignTitle = campaignX.campaign_title; + } + } else { + campaignTitle = CampaignStartStore.getCampaignTitle(); + } + // console.log('CampaignTitleInputField campaignTitle:', campaignTitle); + const campaignTitleQueuedToSave = CampaignStartStore.getCampaignTitleQueuedToSave(); + const campaignTitleQueuedToSaveSet = CampaignStartStore.getCampaignTitleQueuedToSaveSet(); + let campaignTitleAdjusted = campaignTitle; + if (campaignTitleQueuedToSaveSet) { + campaignTitleAdjusted = campaignTitleQueuedToSave; + } + // console.log('onCampaignStartStoreChange campaignTitle: ', campaignTitle, ', campaignTitleQueuedToSave: ', campaignTitleQueuedToSave, ', campaignTitleAdjusted:', campaignTitleAdjusted); + this.setState({ + campaignTitle: campaignTitleAdjusted, + }); + } + + updateCampaignTitle (event) { + if (event.target.name === 'campaignTitle') { + CampaignStartActions.campaignTitleQueuedToSave(event.target.value); + this.setState({ + campaignTitle: event.target.value, + }); + } + } + + render () { + renderLog('CampaignTitleInputField'); // Set LOG_RENDER_EVENTS to log all renders + + const { campaignTitlePlaceholder, classes, externalUniqueId } = this.props; + const { campaignTitle } = this.state; + return ( +
+
{ e.preventDefault(); }}> + + + + + + + +
+
+ ); + } +} +CampaignTitleInputField.propTypes = { + campaignTitlePlaceholder: PropTypes.string, + campaignXWeVoteId: PropTypes.string, + classes: PropTypes.object, + editExistingCampaign: PropTypes.bool, + externalUniqueId: PropTypes.string, +}; + +const styles = () => ({ + formControl: { + width: '100%', + }, + // TODO: Figure out how to apply to TextField + textField: { + fontSize: '22px', + }, +}); + +const ColumnFullWidth = styled('div')` + padding: 8px 12px; + width: 100%; +`; + +const Wrapper = styled('div')` + display: flex; + justify-content: space-between; + margin-left: -12px; + width: calc(100% + 24px); +`; + +export default withStyles(styles)(CampaignTitleInputField); diff --git a/src/js/common/components/ChallengeStart/ChallengeDescriptionInputField.jsx b/src/js/common/components/ChallengeStart/ChallengeDescriptionInputField.jsx new file mode 100755 index 000000000..7ee4e40cb --- /dev/null +++ b/src/js/common/components/ChallengeStart/ChallengeDescriptionInputField.jsx @@ -0,0 +1,147 @@ +import { FormControl, TextField } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import ChallengeStartActions from '../../actions/ChallengeStartActions'; +import { renderLog } from '../../utils/logging'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; +import ChallengeStore from '../../stores/ChallengeStore'; + +class ChallengeDescriptionInputField extends Component { + constructor (props) { + super(props); + this.state = { + challengeDescription: '', + }; + + this.handleKeyPress = this.handleKeyPress.bind(this); + this.updateChallengeDescription = this.updateChallengeDescription.bind(this); + } + + componentDidMount () { + // console.log('ChallengeDescriptionInputField, componentDidMount'); + this.challengeStartStoreListener = ChallengeStartStore.addListener(this.onChallengeStartStoreChange.bind(this)); + this.challengeStoreListener = ChallengeStore.addListener(this.onChallengeStartStoreChange.bind(this)); + this.onChallengeStartStoreChange(); + } + + componentDidUpdate (prevProps) { + // console.log('ChallengeDescriptionInputField componentDidUpdate'); + const { + challengeWeVoteId: challengeWeVoteIdPrevious, + } = prevProps; + const { + challengeWeVoteId, + } = this.props; + if (challengeWeVoteId) { + if (challengeWeVoteId !== challengeWeVoteIdPrevious) { + this.onChallengeStartStoreChange(); + } + } + } + + componentWillUnmount () { + this.challengeStartStoreListener.remove(); + this.challengeStoreListener.remove(); + } + + handleKeyPress () { + // + } + + onChallengeStartStoreChange () { + const { challengeWeVoteId, editExistingChallenge } = this.props; + let challengeDescription = ''; + if (editExistingChallenge) { + const challenge = ChallengeStore.getChallengeByWeVoteId(challengeWeVoteId); + if (challenge && challenge.challenge_we_vote_id) { + challengeDescription = challenge.challenge_description; + } + } else { + challengeDescription = ChallengeStartStore.getChallengeDescription(); + } + const challengeDescriptionQueuedToSave = ChallengeStartStore.getChallengeDescriptionQueuedToSave(); + const challengeDescriptionQueuedToSaveSet = ChallengeStartStore.getChallengeDescriptionQueuedToSaveSet(); + let challengeDescriptionAdjusted = challengeDescription; + if (challengeDescriptionQueuedToSaveSet) { + challengeDescriptionAdjusted = challengeDescriptionQueuedToSave; + } + // console.log('onChallengeStartStoreChange challengeDescription: ', challengeDescription, ', challengeDescriptionQueuedToSave: ', challengeDescriptionQueuedToSave, ', challengeDescriptionAdjusted:', challengeDescriptionAdjusted); + this.setState({ + challengeDescription: challengeDescriptionAdjusted, + }); + } + + updateChallengeDescription (event) { + if (event.target.name === 'challengeDescription') { + ChallengeStartActions.challengeDescriptionQueuedToSave(event.target.value); + this.setState({ + challengeDescription: event.target.value, + }); + } + } + + render () { + renderLog('ChallengeDescriptionInputField'); // Set LOG_RENDER_EVENTS to log all renders + + const { classes, externalUniqueId } = this.props; + const { challengeDescription } = this.state; + + return ( +
+
{ e.preventDefault(); }}> + + + + + + + +
+
+ ); + } +} +ChallengeDescriptionInputField.propTypes = { + challengeWeVoteId: PropTypes.string, + classes: PropTypes.object, + editExistingChallenge: PropTypes.bool, + externalUniqueId: PropTypes.string, +}; + +const styles = () => ({ + formControl: { + width: '100%', + }, + // TODO: Figure out how to apply to TextField + textField: { + fontSize: '22px', + }, +}); + +const ColumnFullWidth = styled('div')` + padding: 8px 12px; + width: 100%; +`; + +const Wrapper = styled('div')` + display: flex; + justify-content: space-between; + margin-left: -12px; + width: calc(100% + 24px); +`; + +export default withStyles(styles)(ChallengeDescriptionInputField); diff --git a/src/js/common/components/ChallengeStart/ChallengePhotoUpload.jsx b/src/js/common/components/ChallengeStart/ChallengePhotoUpload.jsx new file mode 100644 index 000000000..4ee543cdc --- /dev/null +++ b/src/js/common/components/ChallengeStart/ChallengePhotoUpload.jsx @@ -0,0 +1,226 @@ +import { Button } from '@mui/material'; +import withStyles from '@mui/styles/withStyles'; +import { DropzoneArea } from 'mui-file-dropzone'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import styled from 'styled-components'; +import ChallengeStartActions from '../../actions/ChallengeStartActions'; +import isMobileScreenSize from '../../utils/isMobileScreenSize'; +import { renderLog } from '../../utils/logging'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; +import ChallengeStore from '../../stores/ChallengeStore'; + + +class ChallengePhotoUpload extends Component { + constructor (props) { + super(props); + this.state = { + }; + + this.handleDrop = this.handleDrop.bind(this); + } + + componentDidMount () { + // console.log('ChallengePhotoUpload, componentDidMount'); + this.challengeStartStoreListener = ChallengeStartStore.addListener(this.onChallengeStartStoreChange.bind(this)); + this.challengeStoreListener = ChallengeStore.addListener(this.onChallengeStartStoreChange.bind(this)); + this.onChallengeStartStoreChange(); + } + + componentDidUpdate (prevProps) { + // console.log('ChallengePhotoUpload componentDidUpdate'); + const { + challengeWeVoteId: challengeWeVoteIdPrevious, + } = prevProps; + const { + challengeWeVoteId, + } = this.props; + if (challengeWeVoteId) { + if (challengeWeVoteId !== challengeWeVoteIdPrevious) { + this.onChallengeStartStoreChange(); + } + } + } + + componentWillUnmount () { + this.challengeStartStoreListener.remove(); + this.challengeStoreListener.remove(); + } + + handleDrop (files) { + if (files && files[0]) { + const fileFromDropzone = files[0]; + if (!fileFromDropzone) return; + const fileReader = new FileReader(); + // No need to 'remove' this type of event listener + fileReader.addEventListener('load', () => { + const photoFromFileReader = fileReader.result; + // console.log('photoFromFileReader:', photoFromFileReader); + ChallengeStartActions.challengePhotoQueuedToSave(photoFromFileReader); + }); + fileReader.readAsDataURL(fileFromDropzone); + } + } + + onChallengeStartStoreChange () { + const { challengeWeVoteId, editExistingChallenge } = this.props; + let challengePhotoLargeUrl = ''; + if (editExistingChallenge) { + const challenge = ChallengeStore.getChallengeByWeVoteId(challengeWeVoteId); + if (challenge && challenge.challengex_we_vote_id) { + challengePhotoLargeUrl = challenge.we_vote_hosted_challenge_photo_large_url; + } + } else { + challengePhotoLargeUrl = ChallengeStartStore.getChallengePhotoLargeUrl(); + } + const challengePhotoQueuedToDelete = ChallengeStartStore.getChallengePhotoQueuedToDelete(); + const challengePhotoQueuedToDeleteSet = ChallengeStartStore.getChallengePhotoQueuedToDeleteSet(); + this.setState({ + challengePhotoLargeUrl, + challengePhotoQueuedToDelete, + challengePhotoQueuedToDeleteSet, + }); + } + + markChallengeImageForDelete = () => { + ChallengeStartActions.challengePhotoQueuedToDelete(true); + } + + render () { + renderLog('ChallengePhotoUpload'); // Set LOG_RENDER_EVENTS to log all renders + + const { classes } = this.props; + const { challengePhotoLargeUrl, challengePhotoQueuedToDelete, challengePhotoQueuedToDeleteSet } = this.state; + let challengePhotoExists = false; + let dropzoneText = isMobileScreenSize() ? 'Upload challenge photo' : 'Drag challenge photo here (or click to find file)'; + if (challengePhotoLargeUrl) { + challengePhotoExists = true; + dropzoneText = isMobileScreenSize() ? 'Upload new photo' : 'Drag new photo here (or click to find file)'; + } + const challengePhotoMarkedForDeletion = Boolean(challengePhotoQueuedToDelete && challengePhotoQueuedToDeleteSet); + // console.log('challengePhotoMarkedForDeletion:', challengePhotoMarkedForDeletion); + return ( +
+
{ e.preventDefault(); }}> + + + {(challengePhotoExists && !challengePhotoMarkedForDeletion) ? ( + + + + + + + + + + + + + ) : ( + + )} + + +
+
+ ); + } +} +ChallengePhotoUpload.propTypes = { + challengeWeVoteId: PropTypes.string, + classes: PropTypes.object, + editExistingChallenge: PropTypes.bool, +}; + +const styles = (theme) => ({ + buttonDelete: { + backgroundColor: '#f44336', + boxShadow: 'none !important', + fontSize: '18px', + height: '35px !important', + '&:hover': { + backgroundColor: '#8C001A', + }, + marginLeft: 10, + padding: '0 30px', + textTransform: 'none', + width: 100, + }, + dropzoneIcon: { + color: '#999', + }, + dropzoneRoot: { + color: '#999', + [theme.breakpoints.down('sm')]: { + minHeight: '160px', + }, + }, +}); + +const ChallengeImage = styled('img')` + width: 100%; +`; + +const ChallengeImageWrapper = styled('div')` + margin-top: -44px; +`; + +const ChallengeImageDeleteButtonOuterWrapper = styled('div')` + display: flex; + justify-content: flex-end; + width: 100%; + position: relative; + z-index: 1; +`; + +const ChallengeImageDeleteButtonInnerWrapper = styled('div')` + margin-right: 8px; + z-index: 2; +`; + +const ColumnFullWidth = styled('div')` + padding: 8px 12px; + width: 100%; +`; + +const OverlayOuterWrapper = styled('div')` + align-self: flex-end; + // width: 640px; + display: flex; + // padding: 0 15px; +`; + +const OverlayInnerWrapper = styled('div')` + min-height: 37px; + width: 100%; +`; + +const Wrapper = styled('div')` + display: flex; + justify-content: space-between; + margin-left: -12px; + margin-top: 10px; + width: calc(100% + 24px); +`; + +export default withStyles(styles)(ChallengePhotoUpload); diff --git a/src/js/common/components/ChallengeStart/ChallengeTitleInputField.jsx b/src/js/common/components/ChallengeStart/ChallengeTitleInputField.jsx new file mode 100755 index 000000000..2924221f5 --- /dev/null +++ b/src/js/common/components/ChallengeStart/ChallengeTitleInputField.jsx @@ -0,0 +1,147 @@ +import { FormControl, TextField } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import ChallengeStartActions from '../../actions/ChallengeStartActions'; +import { renderLog } from '../../utils/logging'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; +import ChallengeStore from '../../stores/ChallengeStore'; + +class ChallengeTitleInputField extends Component { + constructor (props) { + super(props); + this.state = { + challengeTitle: '', + }; + + this.handleKeyPress = this.handleKeyPress.bind(this); + this.updateChallengeTitle = this.updateChallengeTitle.bind(this); + } + + componentDidMount () { + // console.log('ChallengeTitleInputField, componentDidMount'); + this.challengeStartStoreListener = ChallengeStartStore.addListener(this.onChallengeStartStoreChange.bind(this)); + this.challengeStoreListener = ChallengeStore.addListener(this.onChallengeStartStoreChange.bind(this)); + this.onChallengeStartStoreChange(); + } + + componentDidUpdate (prevProps) { + // console.log('ChallengeTitleInputField componentDidUpdate'); + const { + challengeWeVoteId: challengeWeVoteIdPrevious, + } = prevProps; + const { + challengeWeVoteId, + } = this.props; + if (challengeWeVoteId) { + if (challengeWeVoteId !== challengeWeVoteIdPrevious) { + this.onChallengeStartStoreChange(); + } + } + } + + componentWillUnmount () { + this.challengeStartStoreListener.remove(); + this.challengeStoreListener.remove(); + } + + handleKeyPress () { + // + } + + onChallengeStartStoreChange () { + const { challengeWeVoteId, editExistingChallenge } = this.props; + console.log('ChallengeTitleInputField challengeWeVoteId:', challengeWeVoteId); + let challengeTitle = ''; + if (editExistingChallenge) { + const challenge = ChallengeStore.getChallengeByWeVoteId(challengeWeVoteId); + if (challenge && challenge.challenge_we_vote_id) { + challengeTitle = challenge.challenge_title; + } + } else { + challengeTitle = ChallengeStartStore.getChallengeTitle(); + } + console.log('ChallengeTitleInputField challengeTitle:', challengeTitle); + const challengeTitleQueuedToSave = ChallengeStartStore.getChallengeTitleQueuedToSave(); + const challengeTitleQueuedToSaveSet = ChallengeStartStore.getChallengeTitleQueuedToSaveSet(); + let challengeTitleAdjusted = challengeTitle; + if (challengeTitleQueuedToSaveSet) { + challengeTitleAdjusted = challengeTitleQueuedToSave; + } + console.log('onChallengeStartStoreChange challengeTitle: ', challengeTitle, ', challengeTitleQueuedToSave: ', challengeTitleQueuedToSave, ', challengeTitleAdjusted:', challengeTitleAdjusted); + this.setState({ + challengeTitle: challengeTitleAdjusted, + }); + } + + updateChallengeTitle (event) { + if (event.target.name === 'challengeTitle') { + ChallengeStartActions.challengeTitleQueuedToSave(event.target.value); + this.setState({ + challengeTitle: event.target.value, + }); + } + } + + render () { + renderLog('ChallengeTitleInputField'); // Set LOG_RENDER_EVENTS to log all renders + + const { challengeTitlePlaceholder, classes, externalUniqueId } = this.props; + const { challengeTitle } = this.state; + return ( +
+
{ e.preventDefault(); }}> + + + + + + + +
+
+ ); + } +} +ChallengeTitleInputField.propTypes = { + challengeTitlePlaceholder: PropTypes.string, + challengeWeVoteId: PropTypes.string, + classes: PropTypes.object, + editExistingChallenge: PropTypes.bool, + externalUniqueId: PropTypes.string, +}; + +const styles = () => ({ + formControl: { + width: '100%', + }, + // TODO: Figure out how to apply to TextField + textField: { + fontSize: '22px', + }, +}); + +const ColumnFullWidth = styled('div')` + padding: 8px 12px; + width: 100%; +`; + +const Wrapper = styled('div')` + display: flex; + justify-content: space-between; + margin-left: -12px; + width: calc(100% + 24px); +`; + +export default withStyles(styles)(ChallengeTitleInputField); diff --git a/src/js/common/components/Navigation/CampaignStartSteps.jsx b/src/js/common/components/Navigation/CampaignStartSteps.jsx new file mode 100644 index 000000000..fb74066fe --- /dev/null +++ b/src/js/common/components/Navigation/CampaignStartSteps.jsx @@ -0,0 +1,135 @@ +import withStyles from '@mui/styles/withStyles'; +import { Done } from '@mui/icons-material'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import commonMuiStyles from '../Style/commonMuiStyles'; +import { InnerWrapper, OuterWrapper, StepCircle, StepNumber, StepWrapper } from '../Style/stepDisplayStyles'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import CampaignStartStore from '../../stores/CampaignStartStore'; + + +class CampaignStartSteps extends Component { + constructor (props) { + super(props); + this.state = { + step1Completed: false, + step2Completed: false, + step3Completed: false, + step4Completed: false, + }; + } + + componentDidMount () { + // console.log('CampaignStartSteps, componentDidMount'); + this.campaignStartStoreListener = CampaignStartStore.addListener(this.onCampaignStartStoreChange.bind(this)); + const step1Completed = CampaignStartStore.campaignTitleExists(); + const step2Completed = CampaignStartStore.campaignPoliticianListExists(); + const step3Completed = CampaignStartStore.campaignDescriptionExists(); + const step4Completed = CampaignStartStore.campaignPhotoExists(); + this.setState({ + step1Completed, + step2Completed, + step3Completed, + step4Completed, + }); + } + + componentWillUnmount () { + this.campaignStartStoreListener.remove(); + } + + onCampaignStartStoreChange () { + const step1Completed = CampaignStartStore.campaignTitleExists(); + const step2Completed = CampaignStartStore.campaignPoliticianListExists(); + const step3Completed = CampaignStartStore.campaignDescriptionExists(); + const step4Completed = CampaignStartStore.campaignPhotoExists(); + // console.log('onCampaignStartStoreChange step1Completed: ', step1Completed, ', step2Completed: ', step2Completed, ', step3Completed:', step3Completed); + this.setState({ + step1Completed, + step2Completed, + step3Completed, + step4Completed, + }); + } + + render () { + renderLog('CampaignStartSteps'); // Set LOG_RENDER_EVENTS to log all renders + const { + atStepNumber1, atStepNumber2, atStepNumber3, atStepNumber4, + classes, + } = this.props; + const { + step1Completed, step2Completed, step3Completed, step4Completed, + } = this.state; + return ( +
+ + + + {step1Completed ? ( + historyPush('/start-a-campaign-add-title')}> + + + + + ) : ( + historyPush('/start-a-campaign-add-title')}> + 1 + + )} + + + {step2Completed ? ( + historyPush('/who-do-you-want-to-see-elected')}> + + + + + ) : ( + historyPush('/who-do-you-want-to-see-elected')}> + 2 + + )} + + + {step3Completed ? ( + historyPush('/start-a-campaign-why-winning-matters')}> + + + + + ) : ( + historyPush('/start-a-campaign-why-winning-matters')}> + 3 + + )} + + + {step4Completed ? ( + historyPush('/start-a-campaign-add-photo')}> + + + + + ) : ( + historyPush('/start-a-campaign-add-photo')}> + 4 + + )} + + + +
+ ); + } +} +CampaignStartSteps.propTypes = { + classes: PropTypes.object, + atStepNumber1: PropTypes.bool, + atStepNumber2: PropTypes.bool, + atStepNumber3: PropTypes.bool, + atStepNumber4: PropTypes.bool, +}; + +export default withStyles(commonMuiStyles)(CampaignStartSteps); diff --git a/src/js/common/components/Navigation/ChallengeStartSteps.jsx b/src/js/common/components/Navigation/ChallengeStartSteps.jsx new file mode 100644 index 000000000..9d4f70a27 --- /dev/null +++ b/src/js/common/components/Navigation/ChallengeStartSteps.jsx @@ -0,0 +1,134 @@ +import withStyles from '@mui/styles/withStyles'; +import { Done } from '@mui/icons-material'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import commonMuiStyles from '../Style/commonMuiStyles'; +import { InnerWrapper, OuterWrapper, StepCircle, StepNumber, StepWrapper } from '../Style/stepDisplayStyles'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; + +const STEP1_URL = '/start-a-challenge-add-title'; +const STEP2_URL = '/start-a-challenge-why-winning-matters'; +const STEP3_URL = '/start-a-challenge-add-photo'; +// const STEP4_URL = '/who-do-you-want-to-see-elected'; + +class ChallengeStartSteps extends Component { + constructor (props) { + super(props); + this.state = { + step1Completed: false, + step2Completed: false, + step3Completed: false, + }; + } + + componentDidMount () { + // console.log('ChallengeStartSteps, componentDidMount'); + this.challengeStartStoreListener = ChallengeStartStore.addListener(this.onChallengeStartStoreChange.bind(this)); + const step1Completed = ChallengeStartStore.challengeTitleExists(); + const step2Completed = ChallengeStartStore.challengeDescriptionExists(); + const step3Completed = ChallengeStartStore.challengePhotoExists(); + this.setState({ + step1Completed, + step2Completed, + step3Completed, + }); + } + + componentWillUnmount () { + this.challengeStartStoreListener.remove(); + } + + onChallengeStartStoreChange () { + const step1Completed = ChallengeStartStore.challengeTitleExists(); + const step2Completed = ChallengeStartStore.challengeDescriptionExists(); + const step3Completed = ChallengeStartStore.challengePhotoExists(); + // console.log('onChallengeStartStoreChange step1Completed: ', step1Completed, ', step2Completed: ', step2Completed, ', step3Completed:', step3Completed); + this.setState({ + step1Completed, + step2Completed, + step3Completed, + }); + } + + render () { + renderLog('ChallengeStartSteps'); // Set LOG_RENDER_EVENTS to log all renders + const { + atStepNumber1, atStepNumber2, atStepNumber3, + classes, + } = this.props; + const { + step1Completed, step2Completed, step3Completed, + } = this.state; + return ( +
+ + + + {step1Completed ? ( + historyPush(STEP1_URL)}> + + + + + ) : ( + historyPush(STEP1_URL)}> + 1 + + )} + + + {step2Completed ? ( + historyPush(STEP2_URL)}> + + + + + ) : ( + historyPush(STEP2_URL)}> + 2 + + )} + + + {step3Completed ? ( + historyPush(STEP3_URL)}> + + + + + ) : ( + historyPush(STEP3_URL)}> + 3 + + )} + + {/* */} + {/* {step4Completed ? ( */} + {/* historyPush(STEP4_URL)}> */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* ) : ( */} + {/* historyPush(STEP4_URL)}> */} + {/* 4 */} + {/* */} + {/* )} */} + {/* */} + + +
+ ); + } +} +ChallengeStartSteps.propTypes = { + classes: PropTypes.object, + atStepNumber1: PropTypes.bool, + atStepNumber2: PropTypes.bool, + atStepNumber3: PropTypes.bool, + // atStepNumber4: PropTypes.bool, +}; + +export default withStyles(commonMuiStyles)(ChallengeStartSteps); diff --git a/src/js/common/components/Style/CampaignStartStyles.jsx b/src/js/common/components/Style/CampaignStartStyles.jsx new file mode 100644 index 000000000..c86677ad2 --- /dev/null +++ b/src/js/common/components/Style/CampaignStartStyles.jsx @@ -0,0 +1,38 @@ +import styled from 'styled-components'; + +export const CampaignStartDesktopButtonPanel = styled('div')` + background-color: #fff; + padding: 10px 0; + // width: 100%; +`; + +export const CampaignStartDesktopButtonWrapper = styled('div')` + display: flex; + justify-content: center; + margin: 20px 0 0 0; + width: 100%; +`; + +export const CampaignStartMobileButtonPanel = styled('div')` + background-color: #fff; + border-top: 1px solid #ddd; + padding: 10px; +`; + +export const CampaignStartMobileButtonWrapper = styled('div')` + position: fixed; + width: 100%; + bottom: 0; + display: block; +`; + +export const CampaignStartSection = styled('div')` + margin-bottom: 60px !important; + max-width: 620px; + width: 100%; +`; + +export const CampaignStartSectionWrapper = styled('div')` + display: flex; + justify-content: center; +`; diff --git a/src/js/common/components/Style/commonMuiStyles.js b/src/js/common/components/Style/commonMuiStyles.js index 09f24f11e..325a59dcf 100644 --- a/src/js/common/components/Style/commonMuiStyles.js +++ b/src/js/common/components/Style/commonMuiStyles.js @@ -71,7 +71,7 @@ const commonMuiStyles = { [theme.breakpoints.down('lg')]: { fontSize: 28, }, - paddingTop: '5px', + paddingTop: '1px', }, }; diff --git a/src/js/common/pages/CampaignStart/CampaignStartAddDescription.jsx b/src/js/common/pages/CampaignStart/CampaignStartAddDescription.jsx new file mode 100644 index 000000000..e16ad8c06 --- /dev/null +++ b/src/js/common/pages/CampaignStart/CampaignStartAddDescription.jsx @@ -0,0 +1,163 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import CampaignStartActions from '../../actions/CampaignStartActions'; +import { AdviceBox, AdviceBoxText, AdviceBoxTitle, AdviceBoxWrapper } from '../../components/Style/adviceBoxStyles'; +import commonMuiStyles from '../../components/Style/commonMuiStyles'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import CampaignDescriptionInputField from '../../components/CampaignStart/CampaignDescriptionInputField'; +import CampaignStartSteps from '../../components/Navigation/CampaignStartSteps'; +import { CampaignProcessStepIntroductionText, CampaignProcessStepTitle } from '../../components/Style/CampaignProcessStyles'; +import { CampaignStartDesktopButtonPanel, CampaignStartDesktopButtonWrapper, CampaignStartMobileButtonPanel, CampaignStartMobileButtonWrapper, CampaignStartSection, CampaignStartSectionWrapper } from '../../components/Style/CampaignStartStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import CampaignStartStore from '../../stores/CampaignStartStore'; +import initializejQuery from '../../utils/initializejQuery'; + + +class CampaignStartAddDescription extends Component { + constructor (props) { + super(props); + this.state = { + }; + } + + componentDidMount () { + // console.log('CampaignStartAddDescription, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + initializejQuery(() => { + CampaignStartActions.campaignRetrieveAsOwner(''); + }); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + submitCampaignDescription = () => { + const campaignDescriptionQueuedToSave = CampaignStartStore.getCampaignDescriptionQueuedToSave(); + const campaignDescriptionQueuedToSaveSet = CampaignStartStore.getCampaignDescriptionQueuedToSaveSet(); + if (campaignDescriptionQueuedToSaveSet) { + // console.log('CampaignStartAddDescription, campaignDescriptionQueuedToSave:', campaignDescriptionQueuedToSave); + const campaignWeVoteId = ''; + CampaignStartActions.campaignDescriptionSave(campaignWeVoteId, campaignDescriptionQueuedToSave); + CampaignStartActions.campaignDescriptionQueuedToSave(undefined); + } + historyPush('/start-a-campaign-add-photo'); + } + + render () { + renderLog('CampaignStartAddDescription'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { chosenWebsiteName } = this.state; + const mobileButtonClasses = classes.buttonDefault; // isWebApp() ? classes.buttonDefault : classes.buttonDefaultCordova; + return ( +
+ + + + + + + Explain why winning matters + + + People are more likely to support your campaign if it’s clear why you care. Explain how this candidate winning will impact you, your family, or your community. + + + + + + + + + + + + + Describe the people who will be affected if this candidate loses + + + People are most likely to vote when they understand the consequences of this candidate not being elected, described in terms of the people impacted. + + +   + + + Describe the benefits of this candidate winning + + + Explain why this candidate or candidates winning will bring positive change. + + +   + + + Make it personal + + + Voters are more likely to sign and support your campaign if it’s clear why you care. + + +   + + + Respect others + + + Don’t bully, use hate speech, threaten violence or make things up. + + + + + + + + + + + + + +
+ ); + } +} +CampaignStartAddDescription.propTypes = { + classes: PropTypes.object, +}; + +const InnerWrapper = styled('div')` +`; + + +export default withStyles(commonMuiStyles)(CampaignStartAddDescription); diff --git a/src/js/common/pages/CampaignStart/CampaignStartAddPhoto.jsx b/src/js/common/pages/CampaignStart/CampaignStartAddPhoto.jsx new file mode 100644 index 000000000..1aaf635c6 --- /dev/null +++ b/src/js/common/pages/CampaignStart/CampaignStartAddPhoto.jsx @@ -0,0 +1,154 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import CampaignStartActions from '../../actions/CampaignStartActions'; +import { AdviceBox, AdviceBoxText, AdviceBoxTitle, AdviceBoxWrapper } from '../../components/Style/adviceBoxStyles'; +import commonMuiStyles from '../../components/Style/commonMuiStyles'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import CampaignPhotoUpload from '../../components/CampaignStart/CampaignPhotoUpload'; +import CampaignStartSteps from '../../components/Navigation/CampaignStartSteps'; +import { CampaignProcessStepIntroductionText, CampaignProcessStepTitle } from '../../components/Style/CampaignProcessStyles'; +import { CampaignStartDesktopButtonPanel, CampaignStartDesktopButtonWrapper, CampaignStartMobileButtonPanel, CampaignStartMobileButtonWrapper, CampaignStartSection, CampaignStartSectionWrapper } from '../../components/Style/CampaignStartStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import CampaignStartStore from '../../stores/CampaignStartStore'; +import initializejQuery from '../../utils/initializejQuery'; + + +class CampaignStartAddPhoto extends Component { + constructor (props) { + super(props); + this.state = { + }; + } + + componentDidMount () { + // console.log('CampaignStartAddPhoto, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + initializejQuery(() => { + CampaignStartActions.campaignRetrieveAsOwner(''); + }); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + submitCampaignPhoto = () => { + const campaignPhotoQueuedToSave = CampaignStartStore.getCampaignPhotoQueuedToSave(); + const campaignPhotoQueuedToSaveSet = CampaignStartStore.getCampaignPhotoQueuedToSaveSet(); + if (campaignPhotoQueuedToSaveSet) { + // console.log('CampaignStartAddPhoto, campaignPhotoQueuedToSave:', campaignPhotoQueuedToSave); + const campaignWeVoteId = ''; + CampaignStartActions.campaignPhotoSave(campaignWeVoteId, campaignPhotoQueuedToSave); + CampaignStartActions.campaignPhotoQueuedToSave(undefined); + } + historyPush('/start-a-campaign-preview'); + } + + render () { + renderLog('CampaignStartAddPhoto'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { chosenWebsiteName } = this.state; + const mobileButtonClasses = classes.buttonDefault; // isWebApp() ? classes.buttonDefault : classes.buttonDefaultCordova; + return ( +
+ + + + + + + Add a photo + + + Campaigns with a photo receive six times more supporters than those without. Include one that captures the emotion of your story. + + + + + + + + + + + + + Choose a photo that captures the emotion of your campaign + + + A photo of people with your candidate(s) works well. + + +   + + + Try to upload a photo that is 1200 x 628 pixels or larger + + + A large photo will look good on all screen sizes. We can accept one photo up to 5 megabytes in size. + + +   + + + Keep it friendly for all audiences + + + Make sure your photo doesn't include graphic violence or sexual content. + + + + + + + + + + + + + +
+ ); + } +} +CampaignStartAddPhoto.propTypes = { + classes: PropTypes.object, +}; + + +const InnerWrapper = styled('div')` +`; + +export default withStyles(commonMuiStyles)(CampaignStartAddPhoto); diff --git a/src/js/common/pages/CampaignStart/CampaignStartAddTitle.jsx b/src/js/common/pages/CampaignStart/CampaignStartAddTitle.jsx new file mode 100644 index 000000000..e0abc3f3a --- /dev/null +++ b/src/js/common/pages/CampaignStart/CampaignStartAddTitle.jsx @@ -0,0 +1,140 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import CampaignStartActions from '../../actions/CampaignStartActions'; +import { AdviceBox, AdviceBoxText, AdviceBoxTitle, AdviceBoxWrapper } from '../../components/Style/adviceBoxStyles'; +import commonMuiStyles from '../../components/Style/commonMuiStyles'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import CampaignTitleInputField from '../../components/CampaignStart/CampaignTitleInputField'; +import CampaignStartSteps from '../../components/Navigation/CampaignStartSteps'; +import { CampaignProcessStepIntroductionText, CampaignProcessStepTitle } from '../../components/Style/CampaignProcessStyles'; +import { CampaignStartDesktopButtonPanel, CampaignStartDesktopButtonWrapper, CampaignStartMobileButtonPanel, CampaignStartMobileButtonWrapper, CampaignStartSection, CampaignStartSectionWrapper } from '../../components/Style/CampaignStartStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import CampaignStartStore from '../../stores/CampaignStartStore'; +import initializejQuery from '../../utils/initializejQuery'; + + +class CampaignStartAddTitle extends Component { + constructor (props) { + super(props); + this.state = { + }; + } + + componentDidMount () { + // console.log('CampaignStartAddTitle, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + initializejQuery(() => { + CampaignStartActions.campaignRetrieveAsOwner(''); + }); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + submitCampaignTitle = () => { + const campaignTitleQueuedToSave = CampaignStartStore.getCampaignTitleQueuedToSave(); + const campaignTitleQueuedToSaveSet = CampaignStartStore.getCampaignTitleQueuedToSaveSet(); + if (campaignTitleQueuedToSaveSet) { + // console.log('CampaignStartAddTitle, campaignTitleQueuedToSave:', campaignTitleQueuedToSave); + const campaignWeVoteId = ''; + CampaignStartActions.campaignTitleSave(campaignWeVoteId, campaignTitleQueuedToSave); + CampaignStartActions.campaignTitleQueuedToSave(''); + } + historyPush('/who-do-you-want-to-see-elected'); + } + + render () { + renderLog('CampaignStartAddTitle'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { chosenWebsiteName } = this.state; + const mobileButtonClasses = classes.buttonDefault; // isWebApp() ? classes.buttonDefault : classes.buttonDefaultCordova; + return ( +
+ + + + + + + Write your campaign title + + + This is the first thing people will see about your campaign. Get their attention with a short title that focuses on what the candidate(s) you support will do to improve people's lives. + + + + + + + + + + + + + Keep it short and to the point + + + Example: "Sam Davis for Oakland School Board" + + + Not: "If you want to have your kids be more engaged at school, vote for Sam Davis for Oakland School Board" + + + + + + + + + + + + + +
+ ); + } +} +CampaignStartAddTitle.propTypes = { + classes: PropTypes.object, +}; + + +const InnerWrapper = styled('div')` +`; + + +export default withStyles(commonMuiStyles)(CampaignStartAddTitle); diff --git a/src/js/common/pages/CampaignStart/CampaignStartEditAll.jsx b/src/js/common/pages/CampaignStart/CampaignStartEditAll.jsx new file mode 100644 index 000000000..803c41b82 --- /dev/null +++ b/src/js/common/pages/CampaignStart/CampaignStartEditAll.jsx @@ -0,0 +1,388 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component, Suspense } from 'react'; +import { Helmet } from 'react-helmet-async'; +import CampaignStartActions from '../../actions/CampaignStartActions'; +import commonMuiStyles from '../../components/Style/commonMuiStyles'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import OpenExternalWebSite from '../../components/Widgets/OpenExternalWebSite'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import AddCandidateInputField from '../../components/CampaignStart/AddPoliticianInputField'; +import CampaignDescriptionInputField from '../../components/CampaignStart/CampaignDescriptionInputField'; +import CampaignPhotoUpload from '../../components/CampaignStart/CampaignPhotoUpload'; +import CampaignTitleInputField from '../../components/CampaignStart/CampaignTitleInputField'; +import EditPoliticianList from '../../components/CampaignStart/EditPoliticianList'; +import { BlockedReason } from '../../components/Style/CampaignIndicatorStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import CampaignStartStore from '../../stores/CampaignStartStore'; +import CampaignStore from '../../stores/CampaignStore'; +import { getCampaignXValuesFromIdentifiers, retrieveCampaignXFromIdentifiersIfNeeded } from '../../utils/campaignUtils'; +import initializejQuery from '../../utils/initializejQuery'; + + +const CampaignRetrieveController = React.lazy(() => import(/* webpackChunkName: 'CampaignRetrieveController' */ '../../components/Campaign/CampaignRetrieveController')); + + +class CampaignStartEditAll extends Component { + constructor (props) { + super(props); + this.state = { + campaignSEOFriendlyPath: '', + campaignXWeVoteId: '', + chosenWebsiteName: '', + isBlockedByWeVote: false, + isBlockedByWeVoteReason: false, + voterIsCampaignXOwner: true, // Start by assuming true + }; + } + + componentDidMount () { + // console.log('CampaignStartEditAll, componentDidMount'); + const { editExistingCampaign } = this.props; + if (this.props.setShowHeaderFooter) { + this.props.setShowHeaderFooter(false); + } + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + this.campaignStoreListener = CampaignStore.addListener(this.onCampaignStoreChange.bind(this)); + if (editExistingCampaign) { + const { match: { params } } = this.props; + const { + campaignSEOFriendlyPath: campaignSEOFriendlyPathFromParams, + campaignXWeVoteId: campaignXWeVoteIdFromParams, + } = params; + // console.log('componentDidMount campaignSEOFriendlyPathFromParams: ', campaignSEOFriendlyPathFromParams, ', campaignXWeVoteIdFromParams: ', campaignXWeVoteIdFromParams); + const { + campaignSEOFriendlyPath, + campaignXWeVoteId, + isBlockedByWeVote, + isBlockedByWeVoteReason, + voterIsCampaignXOwner, + } = getCampaignXValuesFromIdentifiers(campaignSEOFriendlyPathFromParams, campaignXWeVoteIdFromParams); + this.setState({ + isBlockedByWeVote, + isBlockedByWeVoteReason, + voterIsCampaignXOwner, + }); + if (campaignSEOFriendlyPath) { + this.setState({ + campaignSEOFriendlyPath, + }); + } else if (campaignSEOFriendlyPathFromParams) { + this.setState({ + campaignSEOFriendlyPath: campaignSEOFriendlyPathFromParams, + }); + } + if (campaignXWeVoteId) { + this.setState({ + campaignXWeVoteId, + }); + } else if (campaignXWeVoteIdFromParams) { + this.setState({ + campaignXWeVoteId: campaignXWeVoteIdFromParams, + }); + } + // Take the "calculated" identifiers and retrieve if missing + retrieveCampaignXFromIdentifiersIfNeeded(campaignSEOFriendlyPath, campaignXWeVoteId); + } else { + initializejQuery(() => { + CampaignStartActions.campaignRetrieveAsOwner(''); + CampaignStartActions.campaignEditAllReset(); + }); + } + window.scrollTo(0, 0); + } + + componentWillUnmount () { + if (this.props.setShowHeaderFooter) { + this.props.setShowHeaderFooter(true); + } + this.appStateSubscription.unsubscribe(); + this.campaignStoreListener.remove(); + if (this.timer) { + clearTimeout(this.timer); + } + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + onCampaignStoreChange () { + const { editExistingCampaign } = this.props; + // console.log('onCampaignStoreChange campaignSEOFriendlyPathFromParams: ', campaignSEOFriendlyPathFromParams, ', campaignXWeVoteIdFromParams: ', campaignXWeVoteIdFromParams); + if (editExistingCampaign) { + const { match: { params } } = this.props; + const { + campaignSEOFriendlyPath: campaignSEOFriendlyPathFromParams, + campaignXWeVoteId: campaignXWeVoteIdFromParams, + } = params; + // console.log('componentDidMount campaignSEOFriendlyPathFromParams: ', campaignSEOFriendlyPathFromParams, ', campaignXWeVoteIdFromParams: ', campaignXWeVoteIdFromParams); + const { + campaignSEOFriendlyPath, + campaignXWeVoteId, + isBlockedByWeVote, + isBlockedByWeVoteReason, + voterIsCampaignXOwner, + } = getCampaignXValuesFromIdentifiers(campaignSEOFriendlyPathFromParams, campaignXWeVoteIdFromParams); + this.setState({ + isBlockedByWeVote, + isBlockedByWeVoteReason, + voterIsCampaignXOwner, + }); + if (campaignSEOFriendlyPath) { + this.setState({ + campaignSEOFriendlyPath, + }); + } else if (campaignSEOFriendlyPathFromParams) { + this.setState({ + campaignSEOFriendlyPath: campaignSEOFriendlyPathFromParams, + }); + } + if (campaignXWeVoteId) { + this.setState({ + campaignXWeVoteId, + }); + } else if (campaignXWeVoteIdFromParams) { + this.setState({ + campaignXWeVoteId: campaignXWeVoteIdFromParams, + }); + } + } + } + + cancelEditAll = () => { + const { editExistingCampaign } = this.props; + if (editExistingCampaign) { + CampaignStartActions.campaignEditAllReset(); + const { campaignXWeVoteId, campaignSEOFriendlyPath } = this.state; + if (campaignSEOFriendlyPath) { + historyPush(`/c/${campaignSEOFriendlyPath}`); + } else { + historyPush(`/id/${campaignXWeVoteId}`); + } + } else { + historyPush('/start-a-campaign-preview'); + } + } + + submitCampaignEditAll = () => { + const { editExistingCampaign } = this.props; + const { campaignXWeVoteId, voterIsCampaignXOwner } = this.state; + const campaignDescriptionQueuedToSave = CampaignStartStore.getCampaignDescriptionQueuedToSave(); + const campaignDescriptionQueuedToSaveSet = CampaignStartStore.getCampaignDescriptionQueuedToSaveSet(); + const campaignPhotoQueuedToDelete = CampaignStartStore.getCampaignPhotoQueuedToDelete(); + const campaignPhotoQueuedToDeleteSet = CampaignStartStore.getCampaignPhotoQueuedToDeleteSet(); + const campaignPhotoQueuedToSave = CampaignStartStore.getCampaignPhotoQueuedToSave(); + const campaignPhotoQueuedToSaveSet = CampaignStartStore.getCampaignPhotoQueuedToSaveSet(); + const campaignPoliticianDeleteList = CampaignStartStore.getCampaignPoliticianDeleteList(); + const campaignPoliticianStarterListQueuedToSave = CampaignStartStore.getCampaignPoliticianStarterListQueuedToSave(); + const campaignPoliticianStarterListQueuedToSaveSet = CampaignStartStore.getCampaignPoliticianStarterListQueuedToSaveSet(); + const campaignTitleQueuedToSave = CampaignStartStore.getCampaignTitleQueuedToSave(); + const campaignTitleQueuedToSaveSet = CampaignStartStore.getCampaignTitleQueuedToSaveSet(); + // console.log('CampaignStartEditAll campaignPoliticianStarterListQueuedToSaveSet:', campaignPoliticianStarterListQueuedToSaveSet); + if (voterIsCampaignXOwner && (campaignDescriptionQueuedToSaveSet || campaignPhotoQueuedToDeleteSet || campaignPhotoQueuedToSaveSet || campaignPoliticianDeleteList || campaignPoliticianStarterListQueuedToSaveSet || campaignTitleQueuedToSaveSet)) { + const campaignPoliticianDeleteListJson = JSON.stringify(campaignPoliticianDeleteList); + const campaignPoliticianStarterListQueuedToSaveJson = JSON.stringify(campaignPoliticianStarterListQueuedToSave); + // console.log('CampaignStartEditAll campaignPoliticianStarterListQueuedToSaveJson:', campaignPoliticianStarterListQueuedToSaveJson); + CampaignStartActions.campaignEditAllSave( + campaignXWeVoteId, + campaignDescriptionQueuedToSave, campaignDescriptionQueuedToSaveSet, + campaignPhotoQueuedToDelete, campaignPhotoQueuedToDeleteSet, + campaignPhotoQueuedToSave, campaignPhotoQueuedToSaveSet, + campaignPoliticianDeleteListJson, + campaignPoliticianStarterListQueuedToSaveJson, campaignPoliticianStarterListQueuedToSaveSet, + campaignTitleQueuedToSave, campaignTitleQueuedToSaveSet, + ); + CampaignStartActions.campaignEditAllReset(); + } + // We want to wait 1 second before redirecting, so the save has a chance to execute + this.timer = setTimeout(() => { + if (editExistingCampaign) { + const { campaignSEOFriendlyPath } = this.state; + if (campaignSEOFriendlyPath) { + historyPush(`/c/${campaignSEOFriendlyPath}`); + } else { + historyPush(`/id/${campaignXWeVoteId}`); + } + } else { + historyPush('/start-a-campaign-preview'); + } + }, 750); + } + + render () { + renderLog('CampaignStartEditAll'); // Set LOG_RENDER_EVENTS to log all renders + const { classes, editExistingCampaign } = this.props; + const { + campaignSEOFriendlyPath, campaignXWeVoteId, chosenWebsiteName, + isBlockedByWeVote, isBlockedByWeVoteReason, voterIsCampaignXOwner, + } = this.state; + return ( +
+  }> + + + + + + + + {voterIsCampaignXOwner && ( + + )} + + + + + + {voterIsCampaignXOwner ? ( + + {isBlockedByWeVote && ( + + + + Your campaign has been blocked by moderators from We Vote. Please make any requested modifications so you are in compliance with our terms of service and + {' '} + contact We Vote support for help.} + /> + {isBlockedByWeVoteReason && ( + <> +
+
+ " + {isBlockedByWeVoteReason} + " + + )} +
+
+
+ )} + + + + + + + We recommend you use a photo that is 1200 x 628 pixels or larger. We can accept one photo up to 5 megabytes in size. + + + + + +
+ ) : ( + + + + + You do not have permission to edit this campaign. + + + + + )} +
+
+
+ ); + } +} +CampaignStartEditAll.propTypes = { + classes: PropTypes.object, + editExistingCampaign: PropTypes.bool, + match: PropTypes.object, + setShowHeaderFooter: PropTypes.func, +}; + + +const CampaignStartSection = styled('div')` + margin-bottom: 60px !important; + max-width: 620px; + width: 100%; +`; + +const CampaignStartSectionWrapper = styled('div')` + display: flex; + justify-content: center; +`; + +const SaveCancelButtonsWrapper = styled('div')` + display: flex; +`; + +const SaveCancelInnerWrapper = styled('div')` + align-items: center; + display: flex; + justify-content: flex-end; + margin: 0 auto; + max-width: 960px; + padding: 8px 0; + @media (max-width: 1005px) { + // Switch to 15px left/right margin when auto is too small + margin: 0 15px; + } +`; + +const SaveCancelOuterWrapper = styled('div')` + background-color: #f6f4f6; + border-bottom: 1px solid #ddd; + margin-top: 0; + position: fixed; + width: 100%; + z-index: 2; +`; + +const InnerWrapper = styled('div')` + margin-top: 75px; + width: 100%; +`; + +const PhotoUploadWrapper = styled('div')` + margin-top: 32px; +`; + +export default withStyles(commonMuiStyles)(CampaignStartEditAll); diff --git a/src/js/common/pages/CampaignStart/CampaignStartPreview.jsx b/src/js/common/pages/CampaignStart/CampaignStartPreview.jsx new file mode 100644 index 000000000..82cd7a05c --- /dev/null +++ b/src/js/common/pages/CampaignStart/CampaignStartPreview.jsx @@ -0,0 +1,392 @@ +import { Button } from '@mui/material'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import styled from 'styled-components'; +import CampaignStartActions from '../../actions/CampaignStartActions'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import DelayedLoad from '../../components/Widgets/DelayedLoad'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import CompleteYourProfileModalController from '../../components/Settings/CompleteYourProfileModalController'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import CampaignStartStore from '../../stores/CampaignStartStore'; +import VoterStore from '../../../stores/VoterStore'; +import initializejQuery from '../../utils/initializejQuery'; + + +class CampaignStartPreview extends Component { + constructor (props) { + super(props); + this.state = { + campaignDescription: '', + campaignPhotoLargeUrl: '', + campaignPoliticianList: [], + campaignTitle: '', + readyToPublish: false, + voterFirstName: '', + voterLastName: '', + voterSignedInWithEmail: false, + }; + } + + componentDidMount () { + // console.log('CampaignStartPreview, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + this.onCampaignStartStoreChange(); + this.onVoterStoreChange(); + this.campaignStartStoreListener = CampaignStartStore.addListener(this.onCampaignStartStoreChange.bind(this)); + this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this)); + initializejQuery(() => { + CampaignStartActions.campaignRetrieveAsOwner(''); + CampaignStartActions.campaignEditAllReset(); + }); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + this.campaignStartStoreListener.remove(); + this.voterStoreListener.remove(); + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + onCampaignStartStoreChange () { + const campaignDescription = CampaignStartStore.getCampaignDescription(); + const campaignPhotoLargeUrl = CampaignStartStore.getCampaignPhotoLargeUrl(); + const campaignPoliticianList = CampaignStartStore.getCampaignPoliticianList(); + const campaignTitle = CampaignStartStore.getCampaignTitle(); + const step1Completed = CampaignStartStore.campaignTitleExists(); + const step2Completed = CampaignStartStore.campaignPoliticianListExists(); + const step3Completed = CampaignStartStore.campaignDescriptionExists(); + const readyToPublish = step1Completed && step2Completed && step3Completed; + const voterSignedInWithEmail = CampaignStartStore.getVoterSignedInWithEmail(); + this.setState({ + campaignDescription, + campaignPhotoLargeUrl, + campaignPoliticianList, + campaignTitle, + readyToPublish, + voterSignedInWithEmail, + }); + } + + onVoterStoreChange () { + const voterFirstName = VoterStore.getFirstName(); + const voterLastName = VoterStore.getLastName(); + const voterSignedInWithEmail = VoterStore.getVoterIsSignedInWithEmail(); + this.setState({ + voterFirstName, + voterLastName, + voterSignedInWithEmail, + }); + } + + campaignEditAll = () => { + historyPush('/start-a-campaign-edit-all'); + } + + submitPublishNowDesktop = () => { + const { voterFirstName, voterLastName, voterSignedInWithEmail } = this.state; + if (!voterFirstName || !voterLastName || !voterSignedInWithEmail) { + // Open complete your profile modal + AppObservableStore.setShowCompleteYourProfileModal(true); + } else { + // Mark the campaign as published + const campaignWeVoteId = ''; + CampaignStartActions.inDraftModeSave(campaignWeVoteId, false); + historyPush('/profile/started'); + } + } + + submitPublishNowMobile = () => { + const { voterFirstName, voterLastName, voterSignedInWithEmail } = this.state; + // console.log('CampaignStartPreview submitPublishNowMobile'); + if (!voterFirstName || !voterLastName || !voterSignedInWithEmail) { + // Navigate to the mobile complete your profile page + historyPush('/start-a-campaign-complete-your-profile'); + } else { + this.functionToUseWhenProfileComplete(); + } + } + + functionToUseWhenProfileComplete = () => { + // Mark the campaign as published + const campaignWeVoteId = ''; + CampaignStartActions.inDraftModeSave(campaignWeVoteId, false); + historyPush('/profile/started'); + } + + render () { + renderLog('CampaignStartPreview'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { + campaignDescription, campaignPhotoLargeUrl, campaignPoliticianList, + campaignTitle, chosenWebsiteName, readyToPublish, + } = this.state; + let campaignPoliticianNumber = 0; + let commaOrNot = ''; + return ( +
+ + + + + +
+ +
+
+ +
+
+
+
+ + + + + + + {campaignTitle || Title Required} + + + {campaignTitle || Title Required} + + {(campaignPoliticianList && campaignPoliticianList.length > 0) ? ( + + {campaignPoliticianList.length === 1 ? ( + <> + Politician this campaign is about: + {' '} + {campaignPoliticianList[0].politician_name} + + ) : ( + <> + Politicians this campaign is about: + { campaignPoliticianList.map((campaignPolitician) => { + campaignPoliticianNumber += 1; + if (campaignPoliticianNumber >= campaignPoliticianList.length) { + return ( + + {' '} + and + {' '} + {campaignPolitician.politician_name} + + ); + } else { + commaOrNot = (campaignPoliticianNumber === campaignPoliticianList.length - 1) ? '' : ','; + return ( + + {' '} + {campaignPolitician.politician_name} + {commaOrNot} + + ); + } + })} + + )} + + ) : ( + Politician Missing + )} +
+ {campaignPhotoLargeUrl ? ( + + ) : ( + + + + <> + Photo Missing + + + + + )} + {campaignDescription ? ( + {campaignDescription} + ) : ( + Description Required + )} +
+
+
+
+
+ +
+ ); + } +} +CampaignStartPreview.propTypes = { + classes: PropTypes.object, +}; + +const styles = (theme) => ({ + buttonEdit: { + boxShadow: 'none !important', + fontSize: '18px', + height: '45px !important', + padding: '0 30px', + textTransform: 'none', + width: 100, + }, + buttonSave: { + boxShadow: 'none !important', + fontSize: '18px', + height: '45px !important', + marginLeft: 10, + textTransform: 'none', + width: 200, + [theme.breakpoints.down('sm')]: { + width: 150, + }, + }, + buttonRoot: { + width: 250, + }, +}); + +const CampaignDescription = styled('div')` + font-size: 15px; + margin: 10px 0; + white-space: pre-wrap; +`; + +const CampaignDescriptionMissing = styled('div')` + color: red; + font-size: 18px; + margin: 10px 0; +`; + +const CampaignImage = styled('img')` + width: 100%; +`; + +const CampaignImageMissing = styled('div')` + color: red; + font-size: 18px; + font-weight: 600; +`; + +const CampaignImageMissingWrapper = styled('div')` + display: flex; + justify-content: flex-start; +`; + +const CampaignPoliticianList = styled('div')` + font-size: 17px; + margin: 10px 0; +`; + +const CampaignPoliticianListMissing = styled('div')` + color: red; + font-size: 18px; + margin: 10px 0; +`; + +const CampaignStartSection = styled('div')` + margin-bottom: 60px !important; + max-width: 620px; + width: 100%; +`; + +const CampaignStartSectionWrapper = styled('div')` + display: flex; + justify-content: center; +`; + +const CampaignTitleDesktop = styled('h1')(({ theme }) => (` + font-size: 28px; + text-align: center; + margin: 30px 20px 40px 20px; + ${theme.breakpoints.down('md')} { + font-size: 24px; + } +`)); + +const CampaignTitleMissing = styled('div')` + color: red; +`; + +const CampaignTitleMobile = styled('h1')` + font-size: 18px; + text-align: left; + margin: 0; +`; + +const DesktopDisplayWrapper = styled('div')` +`; + +const InnerWrapper = styled('div')` + width: 100%; +`; + +const MobileDisplayWrapper = styled('div')` +`; + +const SaveCancelButtonsWrapper = styled('div')` + display: flex; +`; + +const SaveCancelInnerWrapper = styled('div')` + align-items: center; + display: flex; + justify-content: flex-end; + margin: 0 auto; + max-width: 960px; + padding: 8px 0; + @media (max-width: 1005px) { + // Switch to 15px left/right margin when auto is too small + margin: 0 15px; + } +`; + +const SaveCancelOuterWrapper = styled('div')` + background-color: #f6f4f6; + border-bottom: 1px solid #ddd; + // margin: 10px 0; + width: 100%; +`; + +export default withStyles(styles)(CampaignStartPreview); diff --git a/src/js/common/pages/ChallengeStart/ChallengeStartAddDescription.jsx b/src/js/common/pages/ChallengeStart/ChallengeStartAddDescription.jsx new file mode 100644 index 000000000..d6a1da6ed --- /dev/null +++ b/src/js/common/pages/ChallengeStart/ChallengeStartAddDescription.jsx @@ -0,0 +1,163 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import ChallengeStartActions from '../../actions/ChallengeStartActions'; +import { AdviceBox, AdviceBoxText, AdviceBoxTitle, AdviceBoxWrapper } from '../../components/Style/adviceBoxStyles'; +import commonMuiStyles from '../../components/Style/commonMuiStyles'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import ChallengeDescriptionInputField from '../../components/ChallengeStart/ChallengeDescriptionInputField'; +import ChallengeStartSteps from '../../components/Navigation/ChallengeStartSteps'; +import { CampaignProcessStepIntroductionText, CampaignProcessStepTitle } from '../../components/Style/CampaignProcessStyles'; +import { CampaignStartDesktopButtonPanel, CampaignStartDesktopButtonWrapper, CampaignStartMobileButtonPanel, CampaignStartMobileButtonWrapper, CampaignStartSection, CampaignStartSectionWrapper } from '../../components/Style/CampaignStartStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; +import initializejQuery from '../../utils/initializejQuery'; + + +class ChallengeStartAddDescription extends Component { + constructor (props) { + super(props); + this.state = { + }; + } + + componentDidMount () { + // console.log('ChallengeStartAddDescription, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + initializejQuery(() => { + ChallengeStartActions.challengeRetrieveAsOwner(''); + }); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + submitChallengeDescription = () => { + const challengeDescriptionQueuedToSave = ChallengeStartStore.getChallengeDescriptionQueuedToSave(); + const challengeDescriptionQueuedToSaveSet = ChallengeStartStore.getChallengeDescriptionQueuedToSaveSet(); + if (challengeDescriptionQueuedToSaveSet) { + // console.log('ChallengeStartAddDescription, challengeDescriptionQueuedToSave:', challengeDescriptionQueuedToSave); + const challengeWeVoteId = ''; + ChallengeStartActions.challengeDescriptionSave(challengeWeVoteId, challengeDescriptionQueuedToSave); + ChallengeStartActions.challengeDescriptionQueuedToSave(undefined); + } + historyPush('/start-a-challenge-add-photo'); + } + + render () { + renderLog('ChallengeStartAddDescription'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { chosenWebsiteName } = this.state; + const mobileButtonClasses = classes.buttonDefault; // isWebApp() ? classes.buttonDefault : classes.buttonDefaultCordova; + return ( +
+ + + + + + + Explain why voting matters to you + + + People are more likely to join your challenge if it’s clear why you care. Explain how voting will impact you, your family, or your community. + + + + + + + + + + + + + Describe the people who will be affected if this candidate loses + + + People are most likely to vote when they understand the consequences of this candidate not being elected, described in terms of the people impacted. + + +   + + + Describe the benefits of this candidate winning + + + Explain why this candidate or candidates winning will bring positive change. + + +   + + + Make it personal + + + Voters are more likely to sign and support your challenge if it’s clear why you care. + + +   + + + Respect others + + + Don’t bully, use hate speech, threaten violence or make things up. + + + + + + + + + + + + + +
+ ); + } +} +ChallengeStartAddDescription.propTypes = { + classes: PropTypes.object, +}; + +const InnerWrapper = styled('div')` +`; + + +export default withStyles(commonMuiStyles)(ChallengeStartAddDescription); diff --git a/src/js/common/pages/ChallengeStart/ChallengeStartAddPhoto.jsx b/src/js/common/pages/ChallengeStart/ChallengeStartAddPhoto.jsx new file mode 100644 index 000000000..e3ae5a162 --- /dev/null +++ b/src/js/common/pages/ChallengeStart/ChallengeStartAddPhoto.jsx @@ -0,0 +1,154 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import ChallengeStartActions from '../../actions/ChallengeStartActions'; +import { AdviceBox, AdviceBoxText, AdviceBoxTitle, AdviceBoxWrapper } from '../../components/Style/adviceBoxStyles'; +import commonMuiStyles from '../../components/Style/commonMuiStyles'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import ChallengePhotoUpload from '../../components/ChallengeStart/ChallengePhotoUpload'; +import ChallengeStartSteps from '../../components/Navigation/ChallengeStartSteps'; +import { CampaignProcessStepIntroductionText, CampaignProcessStepTitle } from '../../components/Style/CampaignProcessStyles'; +import { CampaignStartDesktopButtonPanel, CampaignStartDesktopButtonWrapper, CampaignStartMobileButtonPanel, CampaignStartMobileButtonWrapper, CampaignStartSection, CampaignStartSectionWrapper } from '../../components/Style/CampaignStartStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; +import initializejQuery from '../../utils/initializejQuery'; + + +class ChallengeStartAddPhoto extends Component { + constructor (props) { + super(props); + this.state = { + }; + } + + componentDidMount () { + // console.log('ChallengeStartAddPhoto, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + initializejQuery(() => { + ChallengeStartActions.challengeRetrieveAsOwner(''); + }); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + submitChallengePhoto = () => { + const challengePhotoQueuedToSave = ChallengeStartStore.getChallengePhotoQueuedToSave(); + const challengePhotoQueuedToSaveSet = ChallengeStartStore.getChallengePhotoQueuedToSaveSet(); + if (challengePhotoQueuedToSaveSet) { + // console.log('ChallengeStartAddPhoto, challengePhotoQueuedToSave:', challengePhotoQueuedToSave); + const challengeWeVoteId = ''; + ChallengeStartActions.challengePhotoSave(challengeWeVoteId, challengePhotoQueuedToSave); + ChallengeStartActions.challengePhotoQueuedToSave(undefined); + } + historyPush('/start-a-challenge-preview'); + } + + render () { + renderLog('ChallengeStartAddPhoto'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { chosenWebsiteName } = this.state; + const mobileButtonClasses = classes.buttonDefault; // isWebApp() ? classes.buttonDefault : classes.buttonDefaultCordova; + return ( +
+ + + + + + + Add a photo + + + Campaigns with a photo receive six times more supporters than those without. Include one that captures the emotion of your story. + + + + + + + + + + + + + Choose a photo that captures the emotion of your challenge + + + A photo of people with your candidate(s) works well. + + +   + + + Try to upload a photo that is 1200 x 628 pixels or larger + + + A large photo will look good on all screen sizes. We can accept one photo up to 5 megabytes in size. + + +   + + + Keep it friendly for all audiences + + + Make sure your photo doesn't include graphic violence or sexual content. + + + + + + + + + + + + + +
+ ); + } +} +ChallengeStartAddPhoto.propTypes = { + classes: PropTypes.object, +}; + + +const InnerWrapper = styled('div')` +`; + +export default withStyles(commonMuiStyles)(ChallengeStartAddPhoto); diff --git a/src/js/common/pages/ChallengeStart/ChallengeStartAddTitle.jsx b/src/js/common/pages/ChallengeStart/ChallengeStartAddTitle.jsx new file mode 100644 index 000000000..4a7350041 --- /dev/null +++ b/src/js/common/pages/ChallengeStart/ChallengeStartAddTitle.jsx @@ -0,0 +1,140 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import ChallengeStartActions from '../../actions/ChallengeStartActions'; +import { AdviceBox, AdviceBoxText, AdviceBoxTitle, AdviceBoxWrapper } from '../../components/Style/adviceBoxStyles'; +import commonMuiStyles from '../../components/Style/commonMuiStyles'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import ChallengeTitleInputField from '../../components/ChallengeStart/ChallengeTitleInputField'; +import ChallengeStartSteps from '../../components/Navigation/ChallengeStartSteps'; +import { CampaignProcessStepIntroductionText, CampaignProcessStepTitle } from '../../components/Style/CampaignProcessStyles'; +import { CampaignStartDesktopButtonPanel, CampaignStartDesktopButtonWrapper, CampaignStartMobileButtonPanel, CampaignStartMobileButtonWrapper, CampaignStartSection, CampaignStartSectionWrapper } from '../../components/Style/CampaignStartStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; +import initializejQuery from '../../utils/initializejQuery'; + + +class ChallengeStartAddTitle extends Component { + constructor (props) { + super(props); + this.state = { + }; + } + + componentDidMount () { + // console.log('ChallengeStartAddTitle, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + initializejQuery(() => { + ChallengeStartActions.challengeRetrieveAsOwner(''); + }); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + submitChallengeTitle = () => { + const challengeTitleQueuedToSave = ChallengeStartStore.getChallengeTitleQueuedToSave(); + const challengeTitleQueuedToSaveSet = ChallengeStartStore.getChallengeTitleQueuedToSaveSet(); + console.log('ChallengeStartAddTitle, challengeTitleQueuedToSaveSet:', challengeTitleQueuedToSaveSet); + if (challengeTitleQueuedToSaveSet) { + // console.log('ChallengeStartAddTitle, challengeTitleQueuedToSave:', challengeTitleQueuedToSave); + const challengeWeVoteId = ''; + ChallengeStartActions.challengeTitleSave(challengeWeVoteId, challengeTitleQueuedToSave); + ChallengeStartActions.challengeTitleQueuedToSave(''); + } + historyPush('/start-a-challenge-why-winning-matters'); + } + + render () { + renderLog('ChallengeStartAddTitle'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { chosenWebsiteName } = this.state; + const mobileButtonClasses = classes.buttonDefault; // isWebApp() ? classes.buttonDefault : classes.buttonDefaultCordova; + return ( +
+ + + + + + + Write your Democracy Challenge title + + + This is the first thing people will see about your challenge. Get their attention with a short title that focuses on why we vote. + + + + + + + + + + + + + Keep it short and to the point + + + Example: "Sam Davis for Oakland School Board" + + + Not: "If you want to have your kids be more engaged at school, vote for Sam Davis for Oakland School Board" + + + + + + + + + + + + + +
+ ); + } +} +ChallengeStartAddTitle.propTypes = { + classes: PropTypes.object, +}; + + +const InnerWrapper = styled('div')` +`; + +export default withStyles(commonMuiStyles)(ChallengeStartAddTitle); diff --git a/src/js/common/pages/ChallengeStart/ChallengeStartEditAll.jsx b/src/js/common/pages/ChallengeStart/ChallengeStartEditAll.jsx new file mode 100644 index 000000000..1d6a9c275 --- /dev/null +++ b/src/js/common/pages/ChallengeStart/ChallengeStartEditAll.jsx @@ -0,0 +1,380 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component, Suspense } from 'react'; +import { Helmet } from 'react-helmet-async'; +import ChallengeStartActions from '../../actions/ChallengeStartActions'; +import commonMuiStyles from '../../components/Style/commonMuiStyles'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import OpenExternalWebSite from '../../components/Widgets/OpenExternalWebSite'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +// import AddCandidateInputField from '../../components/ChallengeStart/AddPoliticianInputField'; +import ChallengeDescriptionInputField from '../../components/ChallengeStart/ChallengeDescriptionInputField'; +import ChallengePhotoUpload from '../../components/ChallengeStart/ChallengePhotoUpload'; +import ChallengeTitleInputField from '../../components/ChallengeStart/ChallengeTitleInputField'; +// import EditPoliticianList from '../../components/ChallengeStart/EditPoliticianList'; +import { BlockedReason } from '../../components/Style/CampaignIndicatorStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; +import ChallengeStore from '../../stores/ChallengeStore'; +import { getChallengeValuesFromIdentifiers, retrieveChallengeFromIdentifiersIfNeeded } from '../../utils/challengeUtils'; +import initializejQuery from '../../utils/initializejQuery'; + + +const ChallengeRetrieveController = React.lazy(() => import(/* webpackChunkName: 'ChallengeRetrieveController' */ '../../components/Challenge/ChallengeRetrieveController')); + + +class ChallengeStartEditAll extends Component { + constructor (props) { + super(props); + this.state = { + challengeSEOFriendlyPath: '', + challengeWeVoteId: '', + chosenWebsiteName: '', + isBlockedByWeVote: false, + isBlockedByWeVoteReason: false, + voterIsChallengeOwner: true, // Start by assuming true + }; + } + + componentDidMount () { + // console.log('ChallengeStartEditAll, componentDidMount'); + const { editExistingChallenge } = this.props; + if (this.props.setShowHeaderFooter) { + this.props.setShowHeaderFooter(false); + } + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + this.challengeStoreListener = ChallengeStore.addListener(this.onChallengeStoreChange.bind(this)); + if (editExistingChallenge) { + const { match: { params } } = this.props; + const { + challengeSEOFriendlyPath: challengeSEOFriendlyPathFromParams, + challengeWeVoteId: challengeWeVoteIdFromParams, + } = params; + // console.log('componentDidMount challengeSEOFriendlyPathFromParams: ', challengeSEOFriendlyPathFromParams, ', challengeWeVoteIdFromParams: ', challengeWeVoteIdFromParams); + const { + challengeSEOFriendlyPath, + challengeWeVoteId, + isBlockedByWeVote, + isBlockedByWeVoteReason, + voterIsChallengeOwner, + } = getChallengeValuesFromIdentifiers(challengeSEOFriendlyPathFromParams, challengeWeVoteIdFromParams); + this.setState({ + isBlockedByWeVote, + isBlockedByWeVoteReason, + voterIsChallengeOwner, + }); + if (challengeSEOFriendlyPath) { + this.setState({ + challengeSEOFriendlyPath, + }); + } else if (challengeSEOFriendlyPathFromParams) { + this.setState({ + challengeSEOFriendlyPath: challengeSEOFriendlyPathFromParams, + }); + } + if (challengeWeVoteId) { + this.setState({ + challengeWeVoteId, + }); + } else if (challengeWeVoteIdFromParams) { + this.setState({ + challengeWeVoteId: challengeWeVoteIdFromParams, + }); + } + // Take the "calculated" identifiers and retrieve if missing + retrieveChallengeFromIdentifiersIfNeeded(challengeSEOFriendlyPath, challengeWeVoteId); + } else { + initializejQuery(() => { + ChallengeStartActions.challengeRetrieveAsOwner(''); + ChallengeStartActions.challengeEditAllReset(); + }); + } + window.scrollTo(0, 0); + } + + componentWillUnmount () { + if (this.props.setShowHeaderFooter) { + this.props.setShowHeaderFooter(true); + } + this.appStateSubscription.unsubscribe(); + this.challengeStoreListener.remove(); + if (this.timer) { + clearTimeout(this.timer); + } + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + onChallengeStoreChange () { + const { editExistingChallenge } = this.props; + // console.log('onChallengeStoreChange challengeSEOFriendlyPathFromParams: ', challengeSEOFriendlyPathFromParams, ', challengeWeVoteIdFromParams: ', challengeWeVoteIdFromParams); + if (editExistingChallenge) { + const { match: { params } } = this.props; + const { + challengeSEOFriendlyPath: challengeSEOFriendlyPathFromParams, + challengeWeVoteId: challengeWeVoteIdFromParams, + } = params; + // console.log('componentDidMount challengeSEOFriendlyPathFromParams: ', challengeSEOFriendlyPathFromParams, ', challengeWeVoteIdFromParams: ', challengeWeVoteIdFromParams); + const { + challengeSEOFriendlyPath, + challengeWeVoteId, + isBlockedByWeVote, + isBlockedByWeVoteReason, + voterIsChallengeOwner, + } = getChallengeValuesFromIdentifiers(challengeSEOFriendlyPathFromParams, challengeWeVoteIdFromParams); + this.setState({ + isBlockedByWeVote, + isBlockedByWeVoteReason, + voterIsChallengeOwner, + }); + if (challengeSEOFriendlyPath) { + this.setState({ + challengeSEOFriendlyPath, + }); + } else if (challengeSEOFriendlyPathFromParams) { + this.setState({ + challengeSEOFriendlyPath: challengeSEOFriendlyPathFromParams, + }); + } + if (challengeWeVoteId) { + this.setState({ + challengeWeVoteId, + }); + } else if (challengeWeVoteIdFromParams) { + this.setState({ + challengeWeVoteId: challengeWeVoteIdFromParams, + }); + } + } + } + + cancelEditAll = () => { + const { editExistingChallenge } = this.props; + if (editExistingChallenge) { + ChallengeStartActions.challengeEditAllReset(); + const { challengeWeVoteId, challengeSEOFriendlyPath } = this.state; + if (challengeSEOFriendlyPath) { + historyPush(`/c/${challengeSEOFriendlyPath}`); + } else { + historyPush(`/id/${challengeWeVoteId}`); + } + } else { + historyPush('/start-a-challenge-preview'); + } + } + + submitChallengeEditAll = () => { + const { editExistingChallenge } = this.props; + const { challengeWeVoteId, voterIsChallengeOwner } = this.state; + const challengeDescriptionQueuedToSave = ChallengeStartStore.getChallengeDescriptionQueuedToSave(); + const challengeDescriptionQueuedToSaveSet = ChallengeStartStore.getChallengeDescriptionQueuedToSaveSet(); + const challengePhotoQueuedToDelete = ChallengeStartStore.getChallengePhotoQueuedToDelete(); + const challengePhotoQueuedToDeleteSet = ChallengeStartStore.getChallengePhotoQueuedToDeleteSet(); + const challengePhotoQueuedToSave = ChallengeStartStore.getChallengePhotoQueuedToSave(); + const challengePhotoQueuedToSaveSet = ChallengeStartStore.getChallengePhotoQueuedToSaveSet(); + const challengePoliticianDeleteList = ChallengeStartStore.getChallengePoliticianDeleteList(); + const challengePoliticianStarterListQueuedToSave = ChallengeStartStore.getChallengePoliticianStarterListQueuedToSave(); + const challengePoliticianStarterListQueuedToSaveSet = ChallengeStartStore.getChallengePoliticianStarterListQueuedToSaveSet(); + const challengeTitleQueuedToSave = ChallengeStartStore.getChallengeTitleQueuedToSave(); + const challengeTitleQueuedToSaveSet = ChallengeStartStore.getChallengeTitleQueuedToSaveSet(); + // console.log('ChallengeStartEditAll challengePoliticianStarterListQueuedToSaveSet:', challengePoliticianStarterListQueuedToSaveSet); + if (voterIsChallengeOwner && (challengeDescriptionQueuedToSaveSet || challengePhotoQueuedToDeleteSet || challengePhotoQueuedToSaveSet || challengePoliticianDeleteList || challengePoliticianStarterListQueuedToSaveSet || challengeTitleQueuedToSaveSet)) { + const challengePoliticianDeleteListJson = JSON.stringify(challengePoliticianDeleteList); + const challengePoliticianStarterListQueuedToSaveJson = JSON.stringify(challengePoliticianStarterListQueuedToSave); + // console.log('ChallengeStartEditAll challengePoliticianStarterListQueuedToSaveJson:', challengePoliticianStarterListQueuedToSaveJson); + ChallengeStartActions.challengeEditAllSave( + challengeWeVoteId, + challengeDescriptionQueuedToSave, challengeDescriptionQueuedToSaveSet, + challengePhotoQueuedToDelete, challengePhotoQueuedToDeleteSet, + challengePhotoQueuedToSave, challengePhotoQueuedToSaveSet, + challengePoliticianDeleteListJson, + challengePoliticianStarterListQueuedToSaveJson, challengePoliticianStarterListQueuedToSaveSet, + challengeTitleQueuedToSave, challengeTitleQueuedToSaveSet, + ); + ChallengeStartActions.challengeEditAllReset(); + } + // We want to wait 1 second before redirecting, so the save has a chance to execute + this.timer = setTimeout(() => { + if (editExistingChallenge) { + const { challengeSEOFriendlyPath } = this.state; + if (challengeSEOFriendlyPath) { + historyPush(`/c/${challengeSEOFriendlyPath}`); + } else { + historyPush(`/id/${challengeWeVoteId}`); + } + } else { + historyPush('/start-a-challenge-preview'); + } + }, 750); + } + + render () { + renderLog('ChallengeStartEditAll'); // Set LOG_RENDER_EVENTS to log all renders + const { classes, editExistingChallenge } = this.props; + const { + challengeSEOFriendlyPath, challengeWeVoteId, chosenWebsiteName, + isBlockedByWeVote, isBlockedByWeVoteReason, voterIsChallengeOwner, + } = this.state; + return ( +
+  }> + + + + + + + + {voterIsChallengeOwner && ( + + )} + + + + + + {voterIsChallengeOwner ? ( + + {isBlockedByWeVote && ( + + + + Your challenge has been blocked by moderators from We Vote. Please make any requested modifications so you are in compliance with our terms of service and + {' '} + contact We Vote support for help.} + /> + {isBlockedByWeVoteReason && ( + <> +
+
+ " + {isBlockedByWeVoteReason} + " + + )} +
+
+
+ )} + + + + + We recommend you use a photo that is 1200 x 628 pixels or larger. We can accept one photo up to 5 megabytes in size. + + + + + +
+ ) : ( + + + + + You do not have permission to edit this challenge. + + + + + )} +
+
+
+ ); + } +} +ChallengeStartEditAll.propTypes = { + classes: PropTypes.object, + editExistingChallenge: PropTypes.bool, + match: PropTypes.object, + setShowHeaderFooter: PropTypes.func, +}; + + +const ChallengeStartSection = styled('div')` + margin-bottom: 60px !important; + max-width: 620px; + width: 100%; +`; + +const ChallengeStartSectionWrapper = styled('div')` + display: flex; + justify-content: center; +`; + +const SaveCancelButtonsWrapper = styled('div')` + display: flex; +`; + +const SaveCancelInnerWrapper = styled('div')` + align-items: center; + display: flex; + justify-content: flex-end; + margin: 0 auto; + max-width: 960px; + padding: 8px 0; + @media (max-width: 1005px) { + // Switch to 15px left/right margin when auto is too small + margin: 0 15px; + } +`; + +const SaveCancelOuterWrapper = styled('div')` + background-color: #f6f4f6; + border-bottom: 1px solid #ddd; + margin-top: 0; + position: fixed; + width: 100%; + z-index: 2; +`; + +const InnerWrapper = styled('div')` + margin-top: 75px; + width: 100%; +`; + +const PhotoUploadWrapper = styled('div')` + margin-top: 32px; +`; + +export default withStyles(commonMuiStyles)(ChallengeStartEditAll); diff --git a/src/js/common/pages/ChallengeStart/ChallengeStartIntro.jsx b/src/js/common/pages/ChallengeStart/ChallengeStartIntro.jsx new file mode 100644 index 000000000..6c8898df3 --- /dev/null +++ b/src/js/common/pages/ChallengeStart/ChallengeStartIntro.jsx @@ -0,0 +1,321 @@ +import { Button } from '@mui/material'; +import styled from 'styled-components'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import { PageContentContainer } from '../../../components/Style/pageLayoutStyles'; +import { OuterWrapper, PageWrapper, StepNumberBordered, StepNumberPlaceholder } from '../../components/Style/stepDisplayStyles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import { publicFigureQuotes } from "../../constants/whyVoteQuotes"; +import WhyVoteQuote from "../../../components/Remind/WhyVoteQuote"; + + +class ChallengeStartIntro extends Component { + constructor (props) { + super(props); + this.state = { + chosenDomainTypeIsChallenge: false, + chosenWebsiteName: '', + inPrivateLabelMode: false, + siteConfigurationHasBeenRetrieved: false, + }; + } + + componentDidMount () { + // console.log('ChallengeSupportSteps, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + } + + onAppObservableStoreChange () { + const chosenDomainTypeIsChallenge = AppObservableStore.getChosenDomainTypeIsChallenge(); + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + const inPrivateLabelMode = AppObservableStore.inPrivateLabelMode(); + const siteConfigurationHasBeenRetrieved = AppObservableStore.siteConfigurationHasBeenRetrieved(); + this.setState({ + chosenDomainTypeIsChallenge, + chosenWebsiteName, + inPrivateLabelMode, + siteConfigurationHasBeenRetrieved, + }); + } + + nextStep = () => { + historyPush('/start-a-challenge-add-title'); + } + + render () { + renderLog('ChallengeStartIntro'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { chosenDomainTypeIsChallenge, chosenWebsiteName, inPrivateLabelMode, siteConfigurationHasBeenRetrieved } = this.state; + const mobileButtonClasses = classes.buttonDefault; // isWebApp() ? classes.buttonDefault : classes.buttonDefaultCordova; + return ( +
+ + + + + {siteConfigurationHasBeenRetrieved && ( + + + Help energize elections! + + + + + 1 + Your why? + + +   + + We recognize you have a tremendously busy schedule. As you consider embracing our mission: + Democracy is fundamental to your freedom to express yourself, your creativity, and your opinion. Protecting these rights are important. + Powerful people spend millions to deceive your friends and followers to stay home, or worse, make misinformed decisions against their own interests. + + + + + 2 + You can increase participation + + +   + + Help your friends and followers make choices that align with their hopes, dreams, and values across the entire ballot. + WeVote.US has tools to help engage directly with friends via text and email, more broadly via social media, or with other WeVote.US voters. + + + + + 3 + Person-to-person persuasion is effective + + +   + + You can make a difference by reminding your friends and followers about the upcoming election. The more of your friends who vote, the more impact you will have on the outcome of the election. + + + + {inPrivateLabelMode && ( + <> + + 4 + Our Approval Process + + +   + + Your challenge will appear on + {' '} + {chosenWebsiteName} + {' '} + as soon as it has been reviewed and approved. In the meantime, you will be able to see your challenge on Challenges.WeVote.US. + + + + )} + + + + + + + + + + + {publicFigureQuotes.map((oneQuote) => ( + + ))} + + + + )} + + + + + + + + +
+ ); + } +} +ChallengeStartIntro.propTypes = { + classes: PropTypes.object, +}; + +const styles = (theme) => ({ + buttonDefault: { + boxShadow: 'none !important', + fontSize: '14px', + height: '45px !important', + padding: '0 12px', + textTransform: 'none', + width: '100%', + [theme.breakpoints.up('xs')]: { + fontSize: '15px', + }, + }, + buttonDefaultCordova: { + boxShadow: 'none !important', + fontSize: '14px', + height: '35px !important', + padding: '0 12px', + textTransform: 'none', + width: '100%', + }, + buttonDesktop: { + boxShadow: 'none !important', + fontSize: '18px', + height: '45px !important', + padding: '0 12px', + textTransform: 'none', + width: '100%', + }, + buttonRoot: { + width: 250, + }, +}); + +const ChallengeStartSection = styled('div')` + margin-bottom: 60px !important; + max-width: 450px; +`; + +const ChallengeStartSectionWrapper = styled('div')` + display: flex; + justify-content: center; +`; + +const ContentRow = styled('div')` + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; +`; + +const ContentTitle = styled('h1')(({ theme }) => (` + font-size: 22px; + font-weight: 600; + margin: 20px 0; + ${theme.breakpoints.down('sm')} { + font-size: 20px; + } +`)); + +const DesktopButtonPanel = styled('div')` + background-color: #fff; + padding: 10px 0; +`; + +const DesktopButtonWrapper = styled('div')` + width: 100%; + display: block; + margin: 30px 0; +`; + +const Dot = styled('div')(({ theme }) => (` + align-self: center; + display: block; + padding-top: 2px; + text-align: center; + ${theme.breakpoints.down('md')} { + padding-top: 3px; + } +`)); + +const InnerWrapper = styled('div')` +`; + +const MobileButtonPanel = styled('div')` + background-color: #fff; + border-top: 1px solid #ddd; + margin: 0; + padding: 10px; +`; + +export const MobileButtonWrapper = styled('div', { + shouldForwardProp: (prop) => !['isChallengeSite'].includes(prop), +})(({ isChallengeSite }) => (` + ${isChallengeSite ? 'bottom: 0;' : 'bottom: 57px;'} + display: block; + position: fixed; + width: 100%; + z-index: 9001 !important; +`)); + +const StepText = styled('div')(({ theme }) => (` + color: #555; + font-size: 16px; + padding: 0 8px; + text-align: left; + vertical-align: top; + ${theme.breakpoints.down('sm')} { + font-size: 16px; + padding: 0 12px; + } +`)); + +const StepTitle = styled('div')(({ theme }) => (` + font-size: 20px; + font-weight: 500; + padding: 0 8px; + text-align: left; + ${theme.breakpoints.down('sm')} { + font-size: 17px; + } +`)); + +const TitleRow = styled('div')` + align-content: center; + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; + padding-top: 14px; +`; + +const WhyVoteQuoteBlock = styled('div')` + max-width: 450px; +`; + +const WhyVoteQuoteBlockOuterWrapper = styled('div')` + display: flex; + justify-content: center; + margin-bottom: 68px; + width: 100%; +`; + +export default withStyles(styles)(ChallengeStartIntro); diff --git a/src/js/common/pages/ChallengeStart/ChallengeStartPreview.jsx b/src/js/common/pages/ChallengeStart/ChallengeStartPreview.jsx new file mode 100644 index 000000000..15e3091d7 --- /dev/null +++ b/src/js/common/pages/ChallengeStart/ChallengeStartPreview.jsx @@ -0,0 +1,350 @@ +import { Button } from '@mui/material'; +import withStyles from '@mui/styles/withStyles'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Helmet } from 'react-helmet-async'; +import styled from 'styled-components'; +import ChallengeStartActions from '../../actions/ChallengeStartActions'; +import { OuterWrapper, PageWrapper } from '../../components/Style/stepDisplayStyles'; +import DelayedLoad from '../../components/Widgets/DelayedLoad'; +import historyPush from '../../utils/historyPush'; +import { renderLog } from '../../utils/logging'; +import CompleteYourProfileModalController from '../../components/Settings/CompleteYourProfileModalController'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import ChallengeStartStore from '../../stores/ChallengeStartStore'; +import VoterStore from '../../../stores/VoterStore'; +import initializejQuery from '../../utils/initializejQuery'; + + +class ChallengeStartPreview extends Component { + constructor (props) { + super(props); + this.state = { + challengeDescription: '', + challengePhotoLargeUrl: '', + challengePoliticianList: [], + challengeTitle: '', + readyToPublish: false, + voterFirstName: '', + voterLastName: '', + voterSignedInWithEmail: false, + }; + } + + componentDidMount () { + // console.log('ChallengeStartPreview, componentDidMount'); + this.onAppObservableStoreChange(); + this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + this.onChallengeStartStoreChange(); + this.onVoterStoreChange(); + this.challengeStartStoreListener = ChallengeStartStore.addListener(this.onChallengeStartStoreChange.bind(this)); + this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this)); + initializejQuery(() => { + ChallengeStartActions.challengeRetrieveAsOwner(''); + ChallengeStartActions.challengeEditAllReset(); + }); + window.scrollTo(0, 0); + } + + componentWillUnmount () { + this.appStateSubscription.unsubscribe(); + this.challengeStartStoreListener.remove(); + this.voterStoreListener.remove(); + } + + onAppObservableStoreChange () { + const chosenWebsiteName = AppObservableStore.getChosenWebsiteName(); + this.setState({ + chosenWebsiteName, + }); + } + + onChallengeStartStoreChange () { + const challengeDescription = ChallengeStartStore.getChallengeDescription(); + const challengePhotoLargeUrl = ChallengeStartStore.getChallengePhotoLargeUrl(); + const challengeTitle = ChallengeStartStore.getChallengeTitle(); + const step1Completed = ChallengeStartStore.challengeTitleExists(); + const step2Completed = ChallengeStartStore.challengePoliticianListExists(); + const step3Completed = ChallengeStartStore.challengeDescriptionExists(); + const readyToPublish = step1Completed && step2Completed && step3Completed; + const voterSignedInWithEmail = ChallengeStartStore.getVoterSignedInWithEmail(); + this.setState({ + challengeDescription, + challengePhotoLargeUrl, + challengeTitle, + readyToPublish, + voterSignedInWithEmail, + }); + } + + onVoterStoreChange () { + const voterFirstName = VoterStore.getFirstName(); + const voterLastName = VoterStore.getLastName(); + const voterSignedInWithEmail = VoterStore.getVoterIsSignedInWithEmail(); + this.setState({ + voterFirstName, + voterLastName, + voterSignedInWithEmail, + }); + } + + challengeEditAll = () => { + historyPush('/start-a-challenge-edit-all'); + } + + submitPublishNowDesktop = () => { + const { voterFirstName, voterLastName, voterSignedInWithEmail } = this.state; + if (!voterFirstName || !voterLastName || !voterSignedInWithEmail) { + // Open complete your profile modal + AppObservableStore.setShowCompleteYourProfileModal(true); + } else { + // Mark the challenge as published + const challengeWeVoteId = ''; + ChallengeStartActions.inDraftModeSave(challengeWeVoteId, false); + historyPush('/profile/started'); + } + } + + submitPublishNowMobile = () => { + const { voterFirstName, voterLastName, voterSignedInWithEmail } = this.state; + // console.log('ChallengeStartPreview submitPublishNowMobile'); + if (!voterFirstName || !voterLastName || !voterSignedInWithEmail) { + // Navigate to the mobile complete your profile page + historyPush('/start-a-challenge-complete-your-profile'); + } else { + this.functionToUseWhenProfileComplete(); + } + } + + functionToUseWhenProfileComplete = () => { + // Mark the challenge as published + const challengeWeVoteId = ''; + ChallengeStartActions.inDraftModeSave(challengeWeVoteId, false); + historyPush('/profile/started'); + } + + render () { + renderLog('ChallengeStartPreview'); // Set LOG_RENDER_EVENTS to log all renders + const { classes } = this.props; + const { + challengeDescription, challengePhotoLargeUrl, challengePoliticianList, + challengeTitle, chosenWebsiteName, readyToPublish, + } = this.state; + let challengePoliticianNumber = 0; + let commaOrNot = ''; + return ( +
+ + + + + +
+ +
+
+ +
+
+
+
+ + + + + + + {challengeTitle || Title Required} + + + {challengeTitle || Title Required} + + {challengePhotoLargeUrl ? ( + + ) : ( + + + + <> + Photo Missing + + + + + )} + {challengeDescription ? ( + {challengeDescription} + ) : ( + Description Required + )} + + + + + + +
+ ); + } +} +ChallengeStartPreview.propTypes = { + classes: PropTypes.object, +}; + +const styles = (theme) => ({ + buttonEdit: { + boxShadow: 'none !important', + fontSize: '18px', + height: '45px !important', + padding: '0 30px', + textTransform: 'none', + width: 100, + }, + buttonSave: { + boxShadow: 'none !important', + fontSize: '18px', + height: '45px !important', + marginLeft: 10, + textTransform: 'none', + width: 200, + [theme.breakpoints.down('sm')]: { + width: 150, + }, + }, + buttonRoot: { + width: 250, + }, +}); + +const ChallengeDescription = styled('div')` + font-size: 15px; + margin: 10px 0; + white-space: pre-wrap; +`; + +const ChallengeDescriptionMissing = styled('div')` + color: red; + font-size: 18px; + margin: 10px 0; +`; + +const ChallengeImage = styled('img')` + width: 100%; +`; + +const ChallengeImageMissing = styled('div')` + color: red; + font-size: 18px; + font-weight: 600; +`; + +const ChallengeImageMissingWrapper = styled('div')` + display: flex; + justify-content: flex-start; +`; + +const ChallengePoliticianList = styled('div')` + font-size: 17px; + margin: 10px 0; +`; + +const ChallengePoliticianListMissing = styled('div')` + color: red; + font-size: 18px; + margin: 10px 0; +`; + +const ChallengeStartSection = styled('div')` + margin-bottom: 60px !important; + max-width: 620px; + width: 100%; +`; + +const ChallengeStartSectionWrapper = styled('div')` + display: flex; + justify-content: center; +`; + +const ChallengeTitleDesktop = styled('h1')(({ theme }) => (` + font-size: 28px; + text-align: center; + margin: 30px 20px 40px 20px; + ${theme.breakpoints.down('md')} { + font-size: 24px; + } +`)); + +const ChallengeTitleMissing = styled('div')` + color: red; +`; + +const ChallengeTitleMobile = styled('h1')` + font-size: 18px; + text-align: left; + margin: 0; +`; + +const DesktopDisplayWrapper = styled('div')` +`; + +const InnerWrapper = styled('div')` + width: 100%; +`; + +const MobileDisplayWrapper = styled('div')` +`; + +const SaveCancelButtonsWrapper = styled('div')` + display: flex; +`; + +const SaveCancelInnerWrapper = styled('div')` + align-items: center; + display: flex; + justify-content: flex-end; + margin: 0 auto; + max-width: 960px; + padding: 8px 0; + @media (max-width: 1005px) { + // Switch to 15px left/right margin when auto is too small + margin: 0 15px; + } +`; + +const SaveCancelOuterWrapper = styled('div')` + background-color: #f6f4f6; + border-bottom: 1px solid #ddd; + // margin: 10px 0; + width: 100%; +`; + +export default withStyles(styles)(ChallengeStartPreview); diff --git a/src/js/common/stores/AppObservableStore.js b/src/js/common/stores/AppObservableStore.js index 5c28a0a6f..adf8436f2 100644 --- a/src/js/common/stores/AppObservableStore.js +++ b/src/js/common/stores/AppObservableStore.js @@ -103,6 +103,10 @@ export default { return nonFluxState.chosenDomainTypeIsCampaign; }, + getChosenDomainTypeIsChallenge () { + return false; + }, + getChosenGoogleAnalyticsTrackingID () { return nonFluxState.chosenGoogleAnalyticsTrackingID; }, diff --git a/src/js/common/stores/CampaignStartStore.js b/src/js/common/stores/CampaignStartStore.js new file mode 100644 index 000000000..d00967a8b --- /dev/null +++ b/src/js/common/stores/CampaignStartStore.js @@ -0,0 +1,314 @@ +import { ReduceStore } from 'flux/utils'; +import Dispatcher from '../dispatcher/Dispatcher'; + +class CampaignStartStore extends ReduceStore { + getInitialState () { + return { + campaignDescription: '', + campaignDescriptionQueuedToSave: '', + campaignDescriptionQueuedToSaveSet: false, + campaignPhotoLargeUrl: '', + campaignPhotoQueuedToDelete: false, + campaignPhotoQueuedToDeleteSet: false, + campaignPhotoQueuedToSave: '', + campaignPhotoQueuedToSaveSet: false, + campaignPoliticianDeleteList: [], + campaignPoliticianList: [], + campaignPoliticianListExists: false, + campaignPoliticianStarterList: [], + campaignPoliticianStarterListQueuedToSave: [], + campaignPoliticianStarterListQueuedToSaveSet: false, + campaignTitle: '', + campaignTitleQueuedToSave: '', + campaignTitleQueuedToSaveSet: false, + campaignXOwnerList: [], + campaignXWeVoteId: '', + voterSignedInWithEmail: false, + }; + } + + resetState () { + return this.getInitialState(); + } + + campaignDescriptionExists () { + if (this.getState().campaignDescription) { + return Boolean(this.getState().campaignDescription.length > 0); + } else { + return false; + } + } + + campaignPhotoExists () { + if (this.getState().campaignPhotoLargeUrl) { + return Boolean(this.getState().campaignPhotoLargeUrl.length > 10); + } else { + return false; + } + } + + campaignPoliticianListExists () { + if (this.getState().campaignPoliticianList) { + return Boolean(this.getState().campaignPoliticianList.length > 0); + } else { + return false; + } + } + + campaignPoliticianStarterListExists () { + if (this.getState().campaignPoliticianStarterList) { + return Boolean(this.getState().campaignPoliticianStarterList.length > 0); + } else { + return false; + } + } + + campaignTitleExists () { + if (this.getState().campaignTitle) { + return Boolean(this.getState().campaignTitle.length > 10); + } else { + return false; + } + } + + getCampaignDescription () { + return this.getState().campaignDescription || ''; + } + + getCampaignDescriptionQueuedToSave () { + return this.getState().campaignDescriptionQueuedToSave; + } + + getCampaignDescriptionQueuedToSaveSet () { + return this.getState().campaignDescriptionQueuedToSaveSet; + } + + getCampaignPhotoLargeUrl () { + return this.getState().campaignPhotoLargeUrl || ''; + } + + getCampaignPhotoQueuedToDelete () { + return this.getState().campaignPhotoQueuedToDelete; + } + + getCampaignPhotoQueuedToDeleteSet () { + return this.getState().campaignPhotoQueuedToDeleteSet; + } + + getCampaignPhotoQueuedToSave () { + return this.getState().campaignPhotoQueuedToSave; + } + + getCampaignPhotoQueuedToSaveSet () { + return this.getState().campaignPhotoQueuedToSaveSet; + } + + getCampaignPoliticianList () { + return this.getState().campaignPoliticianList || []; + } + + getCampaignPoliticianDeleteList () { + return this.getState().campaignPoliticianDeleteList || []; + } + + getCampaignPoliticianStarterList () { + return this.getState().campaignPoliticianStarterList || []; + } + + getCampaignPoliticianStarterListQueuedToSave () { + return this.getState().campaignPoliticianStarterListQueuedToSave || []; + } + + getCampaignPoliticianStarterListQueuedToSaveSet () { + return this.getState().campaignPoliticianStarterListQueuedToSaveSet || false; + } + + getCampaignTitle () { + return this.getState().campaignTitle || ''; + } + + getCampaignTitleQueuedToSave () { + return this.getState().campaignTitleQueuedToSave; + } + + getCampaignTitleQueuedToSaveSet () { + return this.getState().campaignTitleQueuedToSaveSet; + } + + getInDraftMode () { + return this.getState().inDraftMode; + } + + getVoterSignedInWithEmail () { + return this.getState().voterSignedInWithEmail || false; + } + + reduce (state, action) { + const { campaignPoliticianDeleteList } = state; + switch (action.type) { + case 'campaignDescriptionQueuedToSave': + // console.log('CampaignStartStore campaignDescriptionQueuedToSave: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + campaignDescriptionQueuedToSave: '', + campaignDescriptionQueuedToSaveSet: false, + }; + } else { + return { + ...state, + campaignDescriptionQueuedToSave: action.payload, + campaignDescriptionQueuedToSaveSet: true, + }; + } + + case 'campaignEditAllReset': + // console.log('campaignEditAllReset'); + return { + ...state, + campaignDescriptionQueuedToSave: '', + campaignDescriptionQueuedToSaveSet: false, + campaignPhotoQueuedToDelete: false, + campaignPhotoQueuedToDeleteSet: false, + campaignPhotoQueuedToSave: '', + campaignPhotoQueuedToSaveSet: false, + campaignPoliticianStarterListQueuedToSave: [], + campaignPoliticianStarterListQueuedToSaveSet: false, + campaignTitleQueuedToSave: '', + campaignTitleQueuedToSaveSet: false, + }; + + case 'campaignPhotoQueuedToDelete': + console.log('CampaignStartStore campaignPhotoQueuedToDelete: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + campaignPhotoQueuedToDelete: false, + campaignPhotoQueuedToDeleteSet: false, + }; + } else { + return { + ...state, + campaignPhotoQueuedToDelete: action.payload, + campaignPhotoQueuedToDeleteSet: true, + }; + } + + case 'campaignPhotoQueuedToSave': + // console.log('CampaignStartStore campaignPhotoQueuedToSave: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + campaignPhotoQueuedToSave: '', + campaignPhotoQueuedToSaveSet: false, + }; + } else { + return { + ...state, + campaignPhotoQueuedToSave: action.payload, + campaignPhotoQueuedToSaveSet: true, + }; + } + + case 'campaignPoliticianDeleteAddQueuedToSave': + // console.log('CampaignStartStore campaignPoliticianDeleteAddQueuedToSave: ', action.payload); + if (campaignPoliticianDeleteList.indexOf(action.payload) === -1) { + campaignPoliticianDeleteList.push(action.payload); + } + // console.log('campaignPoliticianDeleteList:', campaignPoliticianDeleteList); + return { + ...state, + campaignPoliticianDeleteList, + }; + + case 'campaignPoliticianDeleteRemoveQueuedToSave': + // console.log('CampaignStartStore campaignPoliticianDeleteRemoveQueuedToSave: ', action.payload); + if (campaignPoliticianDeleteList.indexOf(action.payload) !== -1) { + campaignPoliticianDeleteList.splice(campaignPoliticianDeleteList.indexOf(action.payload), 1); + } + // console.log('campaignPoliticianDeleteList:', campaignPoliticianDeleteList); + return { + ...state, + campaignPoliticianDeleteList, + }; + + case 'campaignPoliticianStarterListQueuedToSave': + // console.log('CampaignStartStore campaignPoliticianStarterListQueuedToSave: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + campaignPoliticianStarterListQueuedToSave: [], + campaignPoliticianStarterListQueuedToSaveSet: false, + }; + } else { + return { + ...state, + campaignPoliticianStarterListQueuedToSave: action.payload, + campaignPoliticianStarterListQueuedToSaveSet: true, + }; + } + + // case 'campaignRetrieve': + case 'campaignRetrieveAsOwner': + // console.log('CampaignStartStore campaignRetrieveAsOwner, action.res:', action.res); + return { + ...state, + campaignDescription: action.res.campaign_description, + campaignPhotoLargeUrl: action.res.we_vote_hosted_campaign_photo_large_url, + campaignPhotoMediumUrl: action.res.we_vote_hosted_campaign_photo_medium_url, + campaignPhotoSmallUrl: action.res.we_vote_hosted_campaign_photo_small_url, + campaignPoliticianList: action.res.campaignx_politician_list, + campaignPoliticianListExists: action.res.campaignx_politician_list_exists, + campaignPoliticianStarterList: action.res.campaignx_politician_starter_list, + campaignTitle: action.res.campaign_title, + campaignXOwnerList: action.res.campaignx_owner_list, + campaignXWeVoteId: action.res.campaignx_we_vote_id, + inDraftMode: action.res.in_draft_mode, + voterSignedInWithEmail: action.res.voter_signed_in_with_email, + }; + + case 'campaignStartSave': + // console.log('CampaignStartStore campaignStartSave, action.res:', action.res); + return { + ...state, + campaignDescription: action.res.campaign_description, + campaignPhotoLargeUrl: action.res.we_vote_hosted_campaign_photo_large_url, + campaignPhotoMediumUrl: action.res.we_vote_hosted_campaign_photo_medium_url, + campaignPhotoSmallUrl: action.res.we_vote_hosted_campaign_photo_small_url, + campaignPoliticianList: action.res.campaignx_politician_list, + campaignPoliticianListExists: action.res.campaignx_politician_list_exists, + campaignPoliticianStarterList: action.res.campaignx_politician_starter_list, + campaignTitle: action.res.campaign_title, + campaignXOwnerList: action.res.campaignx_owner_list, + campaignXWeVoteId: action.res.campaignx_we_vote_id, + inDraftMode: action.res.in_draft_mode, + voterSignedInWithEmail: action.res.voter_signed_in_with_email, + }; + + case 'campaignTitleQueuedToSave': + // console.log('CampaignStartStore campaignTitleQueuedToSave: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + campaignTitleQueuedToSave: '', + campaignTitleQueuedToSaveSet: false, + }; + } else { + return { + ...state, + campaignTitleQueuedToSave: action.payload, + campaignTitleQueuedToSaveSet: true, + }; + } + + case 'voterSignOut': + // console.log("resetting Campaign"); + return this.resetState(); + + default: + return state; + } + } +} + +export default new CampaignStartStore(Dispatcher); diff --git a/src/js/common/stores/ChallengeStartStore.js b/src/js/common/stores/ChallengeStartStore.js new file mode 100644 index 000000000..d3e52d8bf --- /dev/null +++ b/src/js/common/stores/ChallengeStartStore.js @@ -0,0 +1,314 @@ +import { ReduceStore } from 'flux/utils'; +import Dispatcher from '../dispatcher/Dispatcher'; + +class ChallengeStartStore extends ReduceStore { + getInitialState () { + return { + challengeDescription: '', + challengeDescriptionQueuedToSave: '', + challengeDescriptionQueuedToSaveSet: false, + challengePhotoLargeUrl: '', + challengePhotoQueuedToDelete: false, + challengePhotoQueuedToDeleteSet: false, + challengePhotoQueuedToSave: '', + challengePhotoQueuedToSaveSet: false, + challengePoliticianDeleteList: [], + challengePoliticianList: [], + challengePoliticianListExists: false, + challengePoliticianStarterList: [], + challengePoliticianStarterListQueuedToSave: [], + challengePoliticianStarterListQueuedToSaveSet: false, + challengeTitle: '', + challengeTitleQueuedToSave: '', + challengeTitleQueuedToSaveSet: false, + challengeOwnerList: [], + challengeWeVoteId: '', + voterSignedInWithEmail: false, + }; + } + + resetState () { + return this.getInitialState(); + } + + challengeDescriptionExists () { + if (this.getState().challengeDescription) { + return Boolean(this.getState().challengeDescription.length > 0); + } else { + return false; + } + } + + challengePhotoExists () { + if (this.getState().challengePhotoLargeUrl) { + return Boolean(this.getState().challengePhotoLargeUrl.length > 10); + } else { + return false; + } + } + + challengePoliticianListExists () { + if (this.getState().challengePoliticianList) { + return Boolean(this.getState().challengePoliticianList.length > 0); + } else { + return false; + } + } + + challengePoliticianStarterListExists () { + if (this.getState().challengePoliticianStarterList) { + return Boolean(this.getState().challengePoliticianStarterList.length > 0); + } else { + return false; + } + } + + challengeTitleExists () { + if (this.getState().challengeTitle) { + return Boolean(this.getState().challengeTitle.length > 10); + } else { + return false; + } + } + + getChallengeDescription () { + return this.getState().challengeDescription || ''; + } + + getChallengeDescriptionQueuedToSave () { + return this.getState().challengeDescriptionQueuedToSave; + } + + getChallengeDescriptionQueuedToSaveSet () { + return this.getState().challengeDescriptionQueuedToSaveSet; + } + + getChallengePhotoLargeUrl () { + return this.getState().challengePhotoLargeUrl || ''; + } + + getChallengePhotoQueuedToDelete () { + return this.getState().challengePhotoQueuedToDelete; + } + + getChallengePhotoQueuedToDeleteSet () { + return this.getState().challengePhotoQueuedToDeleteSet; + } + + getChallengePhotoQueuedToSave () { + return this.getState().challengePhotoQueuedToSave; + } + + getChallengePhotoQueuedToSaveSet () { + return this.getState().challengePhotoQueuedToSaveSet; + } + + getChallengePoliticianList () { + return this.getState().challengePoliticianList || []; + } + + getChallengePoliticianDeleteList () { + return this.getState().challengePoliticianDeleteList || []; + } + + getChallengePoliticianStarterList () { + return this.getState().challengePoliticianStarterList || []; + } + + getChallengePoliticianStarterListQueuedToSave () { + return this.getState().challengePoliticianStarterListQueuedToSave || []; + } + + getChallengePoliticianStarterListQueuedToSaveSet () { + return this.getState().challengePoliticianStarterListQueuedToSaveSet || false; + } + + getChallengeTitle () { + return this.getState().challengeTitle || ''; + } + + getChallengeTitleQueuedToSave () { + return this.getState().challengeTitleQueuedToSave; + } + + getChallengeTitleQueuedToSaveSet () { + return this.getState().challengeTitleQueuedToSaveSet; + } + + getInDraftMode () { + return this.getState().inDraftMode; + } + + getVoterSignedInWithEmail () { + return this.getState().voterSignedInWithEmail || false; + } + + reduce (state, action) { + const { challengePoliticianDeleteList } = state; + switch (action.type) { + case 'challengeDescriptionQueuedToSave': + // console.log('ChallengeStartStore challengeDescriptionQueuedToSave: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + challengeDescriptionQueuedToSave: '', + challengeDescriptionQueuedToSaveSet: false, + }; + } else { + return { + ...state, + challengeDescriptionQueuedToSave: action.payload, + challengeDescriptionQueuedToSaveSet: true, + }; + } + + case 'challengeEditAllReset': + // console.log('challengeEditAllReset'); + return { + ...state, + challengeDescriptionQueuedToSave: '', + challengeDescriptionQueuedToSaveSet: false, + challengePhotoQueuedToDelete: false, + challengePhotoQueuedToDeleteSet: false, + challengePhotoQueuedToSave: '', + challengePhotoQueuedToSaveSet: false, + challengePoliticianStarterListQueuedToSave: [], + challengePoliticianStarterListQueuedToSaveSet: false, + challengeTitleQueuedToSave: '', + challengeTitleQueuedToSaveSet: false, + }; + + case 'challengePhotoQueuedToDelete': + console.log('ChallengeStartStore challengePhotoQueuedToDelete: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + challengePhotoQueuedToDelete: false, + challengePhotoQueuedToDeleteSet: false, + }; + } else { + return { + ...state, + challengePhotoQueuedToDelete: action.payload, + challengePhotoQueuedToDeleteSet: true, + }; + } + + case 'challengePhotoQueuedToSave': + // console.log('ChallengeStartStore challengePhotoQueuedToSave: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + challengePhotoQueuedToSave: '', + challengePhotoQueuedToSaveSet: false, + }; + } else { + return { + ...state, + challengePhotoQueuedToSave: action.payload, + challengePhotoQueuedToSaveSet: true, + }; + } + + case 'challengePoliticianDeleteAddQueuedToSave': + // console.log('ChallengeStartStore challengePoliticianDeleteAddQueuedToSave: ', action.payload); + if (challengePoliticianDeleteList.indexOf(action.payload) === -1) { + challengePoliticianDeleteList.push(action.payload); + } + // console.log('challengePoliticianDeleteList:', challengePoliticianDeleteList); + return { + ...state, + challengePoliticianDeleteList, + }; + + case 'challengePoliticianDeleteRemoveQueuedToSave': + // console.log('ChallengeStartStore challengePoliticianDeleteRemoveQueuedToSave: ', action.payload); + if (challengePoliticianDeleteList.indexOf(action.payload) !== -1) { + challengePoliticianDeleteList.splice(challengePoliticianDeleteList.indexOf(action.payload), 1); + } + // console.log('challengePoliticianDeleteList:', challengePoliticianDeleteList); + return { + ...state, + challengePoliticianDeleteList, + }; + + case 'challengePoliticianStarterListQueuedToSave': + // console.log('ChallengeStartStore challengePoliticianStarterListQueuedToSave: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + challengePoliticianStarterListQueuedToSave: [], + challengePoliticianStarterListQueuedToSaveSet: false, + }; + } else { + return { + ...state, + challengePoliticianStarterListQueuedToSave: action.payload, + challengePoliticianStarterListQueuedToSaveSet: true, + }; + } + + // case 'challengeRetrieve': + case 'challengeRetrieveAsOwner': + // console.log('ChallengeStartStore challengeRetrieveAsOwner, action.res:', action.res); + return { + ...state, + challengeDescription: action.res.challenge_description, + challengePhotoLargeUrl: action.res.we_vote_hosted_challenge_photo_large_url, + challengePhotoMediumUrl: action.res.we_vote_hosted_challenge_photo_medium_url, + challengePhotoSmallUrl: action.res.we_vote_hosted_challenge_photo_small_url, + challengePoliticianList: action.res.challengex_politician_list, + challengePoliticianListExists: action.res.challengex_politician_list_exists, + challengePoliticianStarterList: action.res.challengex_politician_starter_list, + challengeTitle: action.res.challenge_title, + challengeOwnerList: action.res.challengex_owner_list, + challengeWeVoteId: action.res.challengex_we_vote_id, + inDraftMode: action.res.in_draft_mode, + voterSignedInWithEmail: action.res.voter_signed_in_with_email, + }; + + case 'challengeStartSave': + // console.log('ChallengeStartStore challengeStartSave, action.res:', action.res); + return { + ...state, + challengeDescription: action.res.challenge_description, + challengePhotoLargeUrl: action.res.we_vote_hosted_challenge_photo_large_url, + challengePhotoMediumUrl: action.res.we_vote_hosted_challenge_photo_medium_url, + challengePhotoSmallUrl: action.res.we_vote_hosted_challenge_photo_small_url, + challengePoliticianList: action.res.challengex_politician_list, + challengePoliticianListExists: action.res.challengex_politician_list_exists, + challengePoliticianStarterList: action.res.challengex_politician_starter_list, + challengeTitle: action.res.challenge_title, + challengeOwnerList: action.res.challengex_owner_list, + challengeWeVoteId: action.res.challengex_we_vote_id, + inDraftMode: action.res.in_draft_mode, + voterSignedInWithEmail: action.res.voter_signed_in_with_email, + }; + + case 'challengeTitleQueuedToSave': + // console.log('ChallengeStartStore challengeTitleQueuedToSave: ', action.payload); + if (action.payload === undefined) { + return { + ...state, + challengeTitleQueuedToSave: '', + challengeTitleQueuedToSaveSet: false, + }; + } else { + return { + ...state, + challengeTitleQueuedToSave: action.payload, + challengeTitleQueuedToSaveSet: true, + }; + } + + case 'voterSignOut': + // console.log("resetting Challenge"); + return this.resetState(); + + default: + return state; + } + } +} + +export default new ChallengeStartStore(Dispatcher); diff --git a/src/js/components/Navigation/Header.jsx b/src/js/components/Navigation/Header.jsx index eb5ec9181..ca5f79a48 100644 --- a/src/js/components/Navigation/Header.jsx +++ b/src/js/components/Navigation/Header.jsx @@ -193,7 +193,9 @@ export default class Header extends Component { path.startsWith('/more/credits') || (path.startsWith('/remind') && !isSEOFriendlyURL(path)) || path.startsWith('/setupaccount') || - (path.startsWith('/start') && !path.startsWith('/start-a-campaign') && !isSEOFriendlyURL(path)) || + // (path.startsWith('/start') && !path.startsWith('/start-a-campaign') && !path.startsWith('/start-a-challenge') && !isSEOFriendlyURL(path)) || + (path.startsWith('/start-a-campaign') && (path !== '/start-a-campaign')) || + (path.startsWith('/start-a-challenge') && (path !== '/start-a-challenge')) || path.startsWith('/twitter_sign_in') || path.startsWith('/unsubscribe') || path.startsWith('/wevoteintro') || diff --git a/src/js/utils/applicationUtils.js b/src/js/utils/applicationUtils.js index ef8947924..e5abef5a7 100644 --- a/src/js/utils/applicationUtils.js +++ b/src/js/utils/applicationUtils.js @@ -202,6 +202,8 @@ export function getApplicationViewBooleans (pathname) { (pathnameLowerCase === '/more/about') || (pathnameLowerCase === '/more/credits') || (pathnameLowerCase === '/more/myballot') || + (pathnameLowerCase.startsWith('/start-a-campaign') && !(pathnameLowerCase === '/start-a-campaign')) || + (pathnameLowerCase.startsWith('/start-a-challenge') && !(pathnameLowerCase === '/start-a-challenge')) || ((pathnameLowerCase === '/start') && !(pathnameLowerCase === '/start-a-campaign')) || (pathnameLowerCase === '/values/list') || (pathnameLowerCase === '/welcomehome') || @@ -247,7 +249,8 @@ export function getApplicationViewBooleans (pathname) { pathnameLowerCase.startsWith('/settings/tools') || pathnameLowerCase.startsWith('/settings/yourdata') || pathnameLowerCase.startsWith('/settings') || - (pathnameLowerCase === '/start-a-campaign')) { + (pathnameLowerCase === '/start-a-campaign') || + (pathnameLowerCase === '/start-a-challenge')) { // We want to SHOW the footer bar on the above path patterns showFooterBar = isMobileScreenSize(); } else { diff --git a/src/js/utils/service.js b/src/js/utils/service.js index fe04346eb..c6f4800c7 100644 --- a/src/js/utils/service.js +++ b/src/js/utils/service.js @@ -47,7 +47,9 @@ function innerAjax (options) { options.success = options.success || defaults.success; options.error = options.error || defaults.error; // console.log('service.js, options.endpoint: ', options.endpoint); - if (options.endpoint === 'organizationPhotosSave' || + if (options.endpoint === 'campaignStartSave' || + options.endpoint === 'challengeStartSave' || + options.endpoint === 'organizationPhotosSave' || options.endpoint === 'reactionLikeStatusRetrieve' || options.endpoint === 'voterContactListSave' || options.endpoint === 'voterUpdate') {