From aad7f06cf919e0fcf6b2c00855c211866f63fee3 Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Sat, 19 Oct 2024 19:41:48 -0700 Subject: [PATCH] Streamlined ChallengeAbout. Dealt with many rough edges. Fixed Invite bug that was cutting off last character of Invitee's name. Added some TruncateMarkup for Challenge names. Directing to /leaderboard page once a person has joined a challenge. --- .../components/Challenge/ChallengeAbout.jsx | 123 +++++----- .../Challenge/JoinedAndDaysLeft.jsx | 16 +- .../Challenge/PointsExplanationModal.jsx | 61 ++--- .../InviteFriendToChallengeInput.jsx | 51 +++-- .../ChallengeInviteeList.jsx | 19 +- .../ChallengeInviteeListRoot.jsx | 21 +- .../ChallengeCardForList.jsx | 13 +- .../ChallengeCardForListBody.jsx | 213 +++++------------- .../ChallengeListRoot/ChallengeCardList.jsx | 4 + .../ChallengeListRoot/ChallengeListRoot.jsx | 17 +- .../ChallengeListRootPlaceholder.jsx | 6 +- .../ChallengeParticipantListItem.jsx | 72 +++--- .../ChallengeParticipantListRoot.jsx | 75 +++--- .../Navigation/ChallengeHeaderSimple.jsx | 31 +-- .../components/Style/ChallengeCardStyles.jsx | 2 +- .../components/Style/ScrollingStyles.jsx | 12 +- src/js/common/components/Widgets/ReadMore.jsx | 2 - .../pages/Challenge/ChallengeHomePage.jsx | 18 +- .../common/pages/Challenge/ChallengesHome.jsx | 5 +- .../ChallengeInviteCustomizeMessage.jsx | 2 +- .../ChallengeInviteFriends.jsx | 12 +- .../ChallengeInviteFriendsJoin.jsx | 6 +- 22 files changed, 375 insertions(+), 406 deletions(-) diff --git a/src/js/common/components/Challenge/ChallengeAbout.jsx b/src/js/common/components/Challenge/ChallengeAbout.jsx index a3cb40656..11409fb90 100644 --- a/src/js/common/components/Challenge/ChallengeAbout.jsx +++ b/src/js/common/components/Challenge/ChallengeAbout.jsx @@ -69,11 +69,9 @@ function ChallengeAbout ({ challengeWeVoteId }) { {' '} ยท {' '} - - {daysLeft} - {' '} - days left - + {daysLeft} + {' '} + days left )} @@ -81,21 +79,18 @@ function ChallengeAbout ({ challengeWeVoteId }) { ); const challengeStarted = ( - Challenge started by - {challengeCreator} - to support - {challengeIsSupporting} + Challenge started by + {' '} + {challengeCreator} ); const remindFriends = 'Remind as many friends as you can about the date of the election, and let them know you will be voting.'; const currentLeader = `Current leader: ${participantNameWithHighestRank}`; const friendsInvited = ( - - {challengeInviteesCount} - {' '} - friends invited - + {challengeInviteesCount} + {' '} + friends invited {' '} by {' '} @@ -105,65 +100,68 @@ function ChallengeAbout ({ challengeWeVoteId }) { ); + const showStartedBy = false; return ( - {challengeDates && ( - - - - - - {challengeDates} - - - )} - - }> - {challengeStarted && ( - - - { - // Fill property applied to the path element, not SVG element. querySelector to grab the path element and set the attribute. - svg.querySelectorAll('path').forEach((path) => { - path.setAttribute('fill', 'none'); - path.setAttribute('stroke', '#606060'); - }); - }} - /> - - {challengeStarted} - - )} - - }> {remindFriends && ( - + {remindFriends} )} + {challengeDates && ( + + + + + + {challengeDates} + + + )} + {showStartedBy && ( + + }> + {challengeStarted && ( + + + { + // Fill property applied to the path element, not SVG element. querySelector to grab the path element and set the attribute. + svg.querySelectorAll('path').forEach((path) => { + path.setAttribute('fill', 'none'); + path.setAttribute('stroke', '#606060'); + }); + }} + /> + + {challengeStarted} + + )} + + + )} }> {friendsInvited && ( - + + {friendsInvited} {!!(participantNameWithHighestRank) && ( {currentLeader} )} - {friendsInvited} )} @@ -185,9 +183,21 @@ const styles = () => ({ }, }); +export const CampaignOutlinedStyled = styled(CampaignOutlined)` + font-size: 30px; +`; + +export const EmojiEventsOutlinedStyled = styled(EmojiEventsOutlined)` + margin-top: 2px; +`; + +export const EventOutlinedStyled = styled(EventOutlined)` + font-size: 25px; +`; + export const CardForListRow = styled('div')` color: ${DesignTokenColors.neutral500}; - font-size: 14px; + font-size: 16px; padding: 3px 0; `; @@ -209,16 +219,21 @@ export const FlexDivLeft = styled('div')` `; export const SvgImageWrapper = styled('div')` - max-width: 25px; - min-width: 25px; - width: 25px; - margin-right: 15px; + align-items: center; + display: flex; + justify-content: center; + max-width: 35px; + min-width: 35px; + width: 35px; + margin-right: 5px; + margin-top: -4px; `; export const ChallengeDatesDiv = styled('div')` `; export const RemindFriendsDiv = styled('div')` + font-weight: 600; `; export const ChallengeLeaderWrapper = styled('div')` diff --git a/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx b/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx index 0800ff9fa..4413f31f8 100644 --- a/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx +++ b/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx @@ -13,16 +13,14 @@ function JoinedAndDaysLeft ({ challengeWeVoteId, borderSwitcher }) { const [daysLeft, setDaysLeft] = React.useState(0); const [voterIsChallengeParticipant, setVoterIsChallengeParticipant] = React.useState(false); - React.useEffect(() => { - // console.log('Fetching participants for:', challengeWeVoteId); - - const onChallengeStoreChange = () => { - const daysToChallengeEnds = ChallengeStore.getDaysUntilChallengeEnds(challengeWeVoteId); - // console.log('Days to challenge ends:', daysToChallengeEnds); - setDaysLeft(daysToChallengeEnds); - setVoterIsChallengeParticipant(ChallengeStore.getVoterIsChallengeParticipant(challengeWeVoteId)); - }; + const onChallengeStoreChange = () => { + const daysToChallengeEnds = ChallengeStore.getDaysUntilChallengeEnds(challengeWeVoteId); + // console.log('Days to challenge ends:', daysToChallengeEnds); + setDaysLeft(daysToChallengeEnds); + setVoterIsChallengeParticipant(ChallengeStore.getVoterIsChallengeParticipant(challengeWeVoteId)); + }; + React.useEffect(() => { const challengeStoreListener = ChallengeStore.addListener(onChallengeStoreChange); onChallengeStoreChange(); diff --git a/src/js/common/components/Challenge/PointsExplanationModal.jsx b/src/js/common/components/Challenge/PointsExplanationModal.jsx index 71c3a7bf7..24bd75efc 100644 --- a/src/js/common/components/Challenge/PointsExplanationModal.jsx +++ b/src/js/common/components/Challenge/PointsExplanationModal.jsx @@ -1,11 +1,11 @@ +import { DialogTitle } from '@mui/material'; import withStyles from '@mui/styles/withStyles'; import withTheme from '@mui/styles/withTheme'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import styled from 'styled-components'; import DesignTokenColors from '../Style/DesignTokenColors'; -import ModalDisplayTemplateA, { templateAStyles, TextFieldWrapper } from '../../../components/Widgets/ModalDisplayTemplateA'; -import { DialogTitle, DialogTitleText } from '@mui/material'; +import ModalDisplayTemplateA, { templateAStyles } from '../../../components/Widgets/ModalDisplayTemplateA'; import { renderLog } from '../../utils/logging'; class PointsExplanationModal extends Component { @@ -17,7 +17,8 @@ class PointsExplanationModal extends Component { } toggleTerms = () => { - this.setState({ showTerms: !this.state.showTerms }); + const { showTerms } = this.state; + this.setState({ showTerms: !showTerms }); }; render() { @@ -102,26 +103,26 @@ class PointsExplanationModal extends Component { -
    -
  • Sponsor: WeVote USA
  • + +
  • Sponsor: We Vote USA
  • Eligibility: Open to residents of the USA who are 18 years or older.
  • Entry Period: see challenge homepage
  • -
  • How to Enter: To enter, simply [Describe entry method].
  • -
  • Price: One lucky winner will receive [Price Description].
  • +
  • How to Enter: To enter, simply click the Join Challenge button.
  • +
  • Prize: No prizes are given by We Vote USA.
  • Odds of Winning: Odds of winning depend on the number of eligible entries received.
  • No Purchase necessary: No purchase is necessary to enter or win.
  • -
  • Alternative Method of Entry: To enter without purchasing, send a handwritten letter to [Address].
  • + {/*
  • Alternative Method of Entry: To enter without purchasing, send a handwritten letter to [Address].
  • */}
  • Taxes: Winner is responsible for all applicable taxes.
  • Winner Notification: Winners will be notified by email or phone.
  • -
  • Rules and Regulations: For a complete set of rules, please visit [Link to Rules].
  • -
+ {/*
  • Rules and Regulations: For a complete set of rules, please visit [Link to Rules].
  • */} + )} -
    + ); - + return ( {dialogTitleText}} @@ -133,20 +134,11 @@ class PointsExplanationModal extends Component { ); } } - PointsExplanationModal.propTypes = { show: PropTypes.bool.isRequired, toggleModal: PropTypes.func.isRequired, }; -const styles = () => ({ - howToVoteRoot: { - color: '#999', - height: 18, - width: 18, - }, -}); - const PointsWrapper = styled('div')` white-space: normal; `; @@ -157,14 +149,14 @@ export const CardRowsWrapper = styled('div')` export const CardForListRow = styled('div')` color: ${DesignTokenColors.neutral900}; - font-size: 12px; + //font-size: 12px; line-height: 1.5; padding-bottom: 8px; &:First-child { border-bottom: 1px solid ${DesignTokenColors.neutral300}; } - + &:nth-child(2) { padding-top: 8px; } @@ -177,21 +169,20 @@ export const FlexDivLeft = styled('div')` `; export const HowWeCalculateDiv = styled('div')` - font-size: 10px; - + //font-size: 10px; `; export const AtTheEndDiv = styled('div')` font-weight: bold; - font-size: 10px; + //font-size: 10px; `; export const HowYouEarnPointsDiv = styled('div')` - font-size: 12px; + //font-size: 12px; `; export const ViewContestTermsDiv = styled('div')` - font-size: 8px; + //font-size: 8px; `; const Table = styled('table')` @@ -202,7 +193,7 @@ const Table = styled('table')` const Th = styled('th')` text-align: left; color: ${DesignTokenColors.neutral900}; - font-size: 8px; + //font-size: 8px; padding-top: 8px; &:nth-child(2) { @@ -211,7 +202,7 @@ const Th = styled('th')` `; const Tr = styled('tr')` - background-color: white; + background-color: white; &:last-child { td { @@ -221,7 +212,7 @@ const Tr = styled('tr')` const Td = styled('td')` color: ${DesignTokenColors.neutral900}; - font-size: 10px; + //font-size: 10px; padding: 2px; border-bottom: 1px solid ${DesignTokenColors.neutral300}; @@ -231,17 +222,15 @@ const Td = styled('td')` `; const ViewContestTermsLink = styled('span')` - color: ${DesignTokenColors.accent500}; + color: ${DesignTokenColors.accent500}; cursor: pointer; - text-decoration: underline; + text-decoration: underline; `; export const ContestTermDiv = styled('div')` - font-size: 12px; `; -const Ul = styled('ul')` - font-size: 10px; +const StyledUnorderedList = styled('ul')` line-height: 1.5; text-align: left; padding-left: 10px; diff --git a/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx b/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx index fee3d57df..b04b83ff1 100755 --- a/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx +++ b/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx @@ -5,6 +5,7 @@ import PropTypes from 'prop-types'; import React, { Suspense } from 'react'; import CopyToClipboard from 'react-copy-to-clipboard'; import { renderLog } from '../../utils/logging'; +import stringContains from '../../utils/stringContains'; import ChallengeInviteeActions from '../../actions/ChallengeInviteeActions'; import ChallengeInviteeStore from '../../stores/ChallengeInviteeStore'; import ChallengeParticipantActions from '../../actions/ChallengeParticipantActions'; @@ -29,10 +30,19 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq // const [urlToSend, setUrlToSend] = React.useState(''); function prepareInviteTextToSend () { - const inviteeFirstName = inviteeName ? inviteeName.split(' ')[0] : ''; - const inviterFirstName = inviterName ? inviterName.split(' ')[0] : ''; - let inviteTextToSendTemp1 = inviteeFirstName ? `Hi ${inviteeFirstName}` : 'Hi'; - inviteTextToSendTemp1 += inviterFirstName ? `, this is ${inviterFirstName}. ` : ', '; + let inviteeFirstName = ''; + if (inviteeName) { + inviteeFirstName = stringContains(' ', inviteeName) ? inviteeName.split(' ')[0] : inviteeName; + } + let inviterFirstName = ''; + if (inviterName) { + inviterFirstName = stringContains(' ', inviterName) ? inviterName.split(' ')[0] : inviterName; + } + // console.log('prepareInviteTextToSend, inviteeName:', inviteeName, ', inviteeFirstName:', inviteeFirstName, ', inviterName:', inviterName, ', inviterFirstName:', inviterFirstName); + const inviteTextGreeting = inviteeFirstName ? `Hi ${inviteeFirstName}` : 'Hi'; + const inviteTextFrom = inviterFirstName ? `, this is ${inviterFirstName}. ` : ', '; + const inviteTextToSendTemp1 = `${inviteTextGreeting}${inviteTextFrom}`; + // console.log('prepareInviteTextToSend, inviteTextToSendTemp1:', inviteTextToSendTemp1); const inviteTextToSendTemp2 = inviteTextForFriends || challengeInviteTextDefault; const inviteeUrlCode = ChallengeInviteeStore.getNextInviteeUrlCode(); const urlToSendTemp = `${ChallengeStore.getSiteUrl(challengeWeVoteId)}/-${inviteeUrlCode}`; @@ -45,9 +55,6 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq function resetForm () { setInviteeName(''); - setTimeout(() => { - prepareInviteTextToSend(); - }, 250); } const handleShare = async () => { @@ -87,7 +94,6 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq function setInviteeNameFromEvent (event) { if (event.target.name === 'inviteeNameTextField') { setInviteeName(event.target.value); - prepareInviteTextToSend(); } } @@ -95,7 +101,6 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq const onChallengeInviteeStoreChange = () => { setInviterName(VoterStore.getFirstName()); const inviteeList = ChallengeInviteeStore.getChallengeInviteeList(challengeWeVoteId); - console.log('Former inviteeListLength:', inviteeListLength, 'New inviteeList.length:', inviteeList.length); if (inviteeListLength < inviteeList.length) { // If inviteeList length changes, make call for refreshed ChallengeParticipant, so we can make sure we have the updated score/rank. ChallengeParticipantActions.challengeParticipantRetrieve(challengeWeVoteId); @@ -139,6 +144,10 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq }; }, [challengeWeVoteId]); + React.useEffect(() => { + prepareInviteTextToSend(); + }, [inviteeName]); + return (
    { e.preventDefault(); }}> @@ -175,20 +184,28 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq Invite copied! ) : ( - - Invite - {' '} - {`${inviteeName ? `${inviteeName.length > 18 ? `${inviteeName.slice(0, 18)}...` : inviteeName}` : 'friend'}`} - {' '} - {inviteeName.length < 12 && 'to challenge'} - + <> + {(inviteeName && inviteeName.length > 1) ? ( + + Invite + {' '} + {`${inviteeName ? `${inviteeName.length > 18 ? `${inviteeName.slice(0, 18)}...` : inviteeName}` : 'friend'}`} + {' '} + {inviteeName.length < 12 && 'to challenge'} + + ) : ( + Copy message & link to challenge + )} + )}  }> - + ); diff --git a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeList.jsx b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeList.jsx index 1b2b218a1..2f1946199 100644 --- a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeList.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeList.jsx @@ -5,6 +5,11 @@ import ChallengeInviteeListItem from './ChallengeInviteeListItem'; const ChallengeInviteeList = ({ inviteeList }) => ( + {inviteeList.length === 0 && ( + + No friends invited yet. + + )} {inviteeList.map((invitee) => ( { )} - - FRIENDS NAME - STATUS - + + Invited Friends + @@ -292,6 +301,8 @@ ChallengeCardForList.propTypes = { challengeWeVoteId: PropTypes.string, voterWeVoteId: PropTypes.string, limitCardWidth: PropTypes.bool, + titleLengthRestricted: PropTypes.bool, + titleLinkOff: PropTypes.bool, useVerticalCard: PropTypes.bool, }; diff --git a/src/js/common/components/ChallengeListRoot/ChallengeCardForListBody.jsx b/src/js/common/components/ChallengeListRoot/ChallengeCardForListBody.jsx index a540516b2..7dd86248a 100644 --- a/src/js/common/components/ChallengeListRoot/ChallengeCardForListBody.jsx +++ b/src/js/common/components/ChallengeListRoot/ChallengeCardForListBody.jsx @@ -1,20 +1,17 @@ import withStyles from '@mui/styles/withStyles'; import PropTypes from 'prop-types'; -import React, { Suspense } from 'react'; +import React from 'react'; import { Link } from 'react-router-dom'; -// import TruncateMarkup from 'react-truncate-markup'; import styled from 'styled-components'; +import TruncateMarkup from 'react-truncate-markup'; import isMobileScreenSize from '../../utils/isMobileScreenSize'; import { renderLog } from '../../utils/logging'; -// import numberWithCommas from '../../utils/numberWithCommas'; -// import ChallengeOwnersList from '../ChallengeInviteeListRoot/ChallengeOwnersList'; import { ChallengeImageDesktop, ChallengeImageDesktopPlaceholder, ChallengeImageMobile, ChallengeImageMobilePlaceholder, ChallengeImagePlaceholderText, - CandidateCardForListWrapper, OneChallengeInnerWrapper, OneChallengeOuterWrapper, OneChallengePhotoDesktopColumn, @@ -33,12 +30,11 @@ import JoinedAndDaysLeft from '../Challenge/JoinedAndDaysLeft'; function ChallengeCardForListBody (props) { renderLog('ChallengeCardForListBody'); // Set LOG_RENDER_EVENTS to log all renders const { - challengeDescription, challengeSupported, challengeTitle, challengeWeVoteId, - hideCardMargins, inDraftMode, joinedAndDaysLeftOff, functionToUseToKeepHelping, functionToUseWhenProfileComplete, - limitCardWidth, onChallengeClick, onChallengeClickLink, onChallengeEditClick, + challengeTitle, challengeWeVoteId, + hideCardMargins, inDraftMode, joinedAndDaysLeftOff, + limitCardWidth, onChallengeClick, onChallengeClickLink, photoLargeUrl, profileImageBackgroundColor, - participantsCount, participantsCountNextGoalWithFloor, tagIdBaseName, useVerticalCard, - voterCanEditThisChallenge, + tagIdBaseName, titleLengthRestricted, titleLinkOff, useVerticalCard, } = props; const politicalPartySvgNameWithPath = '../../img/global/svg-icons/political-party-unspecified.svg'; // console.log('ChallengeCardForListBody functional component photoLargeUrl:', photoLargeUrl); @@ -54,85 +50,50 @@ function ChallengeCardForListBody (props) { - - {challengeTitle} - - - {/* - - - {numberWithCommas(participantsCount)} - {' '} - {participantsCount === 1 ? 'participant.' : 'participants.'} - - {' '} - {challengeSupported ? ( - - Thank you for supporting! - + {titleLinkOff ? ( + <> + {titleLengthRestricted ? ( + + + {challengeTitle} + + + ) : ( + + {challengeTitle} + + )} + ) : ( - - Let's get to - {' '} - {numberWithCommas(participantsCountNextGoalWithFloor)} - ! - + + {titleLengthRestricted ? ( + + + {challengeTitle} + + + ) : ( + + {challengeTitle} + + )} + + )} - - - -
    - {challengeDescription} -
    -
    -
    - */} - {/* - - - - */} +
    - {/* - - {finalElectionDateInPast && ( - - - Election in Past - - - )} - {isBlockedByWeVote && ( - - - Blocked: Changes Needed - - - )} - {!!(!inDraftMode && !isSupportersCountMinimumExceeded && !inPrivateLabelMode) && ( - - - Needs Five Supporters - - - )} - - */} {inDraftMode && ( @@ -141,60 +102,6 @@ function ChallengeCardForListBody (props) { )} - {/* - {!visibleOnThisSite && ( - - - - Not Visible - - - Not Visible On This Site - - - - )} - {isInTeamReviewMode && ( - - - - Team Reviewing - - - Team Still Reviewing - - - - )} - */} - {/* - {voterCanEditThisChallenge && ( - - - - Edit - - - Edit Challenge - - - - )} - */} - {/* - {(challengeSupported && !inDraftMode) && ( - - - - Share - - - Share Challenge - - - - )} - */}
    ({ }, }, }); + const ChallengeImageContainer = styled('div')` position: relative; width: 100%; height: auto; `; + const JoinedDaysLeftOverlayMobile = styled('div')` position: absolute; top: 130px; left: 10px; - `; +`; + const JoinedDaysLeftOverlayDesktop = styled('div')` position: absolute; top: 175px; left: 10px; -// const ChallengeOwnersWrapper = styled('div')` -// `; - -// export const FlexDivLeft = styled('div')` -// align-items: center; -// display: flex; -// justify-content: start; -// `; - -// export const SvgImageWrapper = styled('div')` -// max-width: 25px; -// min-width: 25px; -// width: 25px; -// `; +`; export const SvgWatermarkWrapper = styled('div')` `; diff --git a/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx b/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx index b7ff6f5f6..c29fac91a 100644 --- a/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx +++ b/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx @@ -130,8 +130,11 @@ class ChallengeCardList extends Component { const { in_draft_mode: inDraftMode, } = challenge; + const voterIsChallengeParticipant = ChallengeStore.getVoterIsChallengeParticipant(challengeWeVoteId); if (inDraftMode) { return '/start-a-challenge-preview'; + } else if (voterIsChallengeParticipant) { + return `${this.getChallengeBasePath(challengeWeVoteId)}leaderboard`; } else { return `${this.getChallengeBasePath(challengeWeVoteId)}`; } @@ -181,6 +184,7 @@ class ChallengeCardList extends Component { challengeWeVoteId={oneChallenge.challenge_we_vote_id} joinedAndDaysLeftOff limitCardWidth={useVerticalCard} + titleLengthRestricted useVerticalCard={useVerticalCard} /> {/* JoinedAndDaysLeft component positioned absolutely */} diff --git a/src/js/common/components/ChallengeListRoot/ChallengeListRoot.jsx b/src/js/common/components/ChallengeListRoot/ChallengeListRoot.jsx index 72fafeeaf..b1dc0c800 100644 --- a/src/js/common/components/ChallengeListRoot/ChallengeListRoot.jsx +++ b/src/js/common/components/ChallengeListRoot/ChallengeListRoot.jsx @@ -5,10 +5,15 @@ import PropTypes from 'prop-types'; import React, { Component, createRef } from 'react'; import styled from 'styled-components'; import { - CampaignsHorizontallyScrollingContainer, RightArrowInnerWrapper, - RightArrowOuterWrapper, LeftArrowInnerWrapper, LeftArrowOuterWrapper, - CampaignsScrollingInnerWrapper, CampaignsScrollingOuterWrapper, - TitleAndMobileArrowsOuterWrapper, MobileArrowsInnerWrapper, + CampaignsHorizontallyScrollingContainer, + RightArrowInnerWrapper, + RightArrowOuterWrapper, + LeftArrowInnerWrapper, + LeftArrowOuterWrapper, + CampaignsScrollingInnerWrapper, + ChallengesScrollingOuterWrapper, + TitleAndMobileArrowsOuterWrapper, + MobileArrowsInnerWrapper, } from '../Style/ScrollingStyles'; import { convertStateCodeToStateText } from '../../utils/addressFunctions'; import { handleHorizontalScroll, leftAndRightArrowStateCalculation, checkDivPositionForLoadMore } from '../../utils/leftRightArrowCalculation'; @@ -317,7 +322,7 @@ class ChallengeListRoot extends Component { - + { handleHorizontalScroll(this.scrollElement.current, HORIZONTAL_SCROLL_DISTANCE_ON_LEFT_ARROW_CLICK, this.leftAndRightArrowSetState, RIGHT_MARGIN_SIZE); }}> { this.state.hideLeftArrow ? null : } @@ -346,7 +351,7 @@ class ChallengeListRoot extends Component { { this.state.hideRightArrow ? null : } - + ); } diff --git a/src/js/common/components/ChallengeListRoot/ChallengeListRootPlaceholder.jsx b/src/js/common/components/ChallengeListRoot/ChallengeListRootPlaceholder.jsx index adc2c7cc1..3566a21bd 100644 --- a/src/js/common/components/ChallengeListRoot/ChallengeListRootPlaceholder.jsx +++ b/src/js/common/components/ChallengeListRoot/ChallengeListRootPlaceholder.jsx @@ -7,7 +7,7 @@ import { renderLog } from '../../utils/logging'; import { CampaignsHorizontallyScrollingContainer, CampaignsScrollingInnerWrapper, - CampaignsScrollingOuterWrapper, + ChallengesScrollingOuterWrapper, LeftArrowInnerWrapper, LeftArrowOuterWrapper, MobileArrowsInnerWrapper, RightArrowInnerWrapper, RightArrowOuterWrapper, TitleAndMobileArrowsOuterWrapper, @@ -70,7 +70,7 @@ function ChallengeListRootPlaceholder (props) { - +   @@ -91,7 +91,7 @@ function ChallengeListRootPlaceholder (props) { - + ); } diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx index 414e63583..48c29529e 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx @@ -8,25 +8,26 @@ import speakerDisplayNameToInitials from '../../utils/speakerDisplayNameToInitia const ChallengeParticipantListItem = ({ participant, isCurrentUser }) => { let avatarJsx; if (participant && participant.we_vote_hosted_profile_image_url_medium) { - avatarJsx = ; + avatarJsx = ; } else { const { sx, children } = speakerDisplayNameToInitials(participant.participant_name); - avatarJsx = {children}; + avatarJsx = {children}; } return ( {`#${participant.rank}`} - + {avatarJsx} {participant.participant_name} - + {participant.points} 0}>{participant.invitees_who_joined}
    - {`${participant.invitees_count} invited, `} - {`${participant.invitees_who_viewed} viewed challenge`} + {participant.invitees_count > 0 && `${participant.invitees_count} invited`} + {(participant.invitees_count > 0 && participant.invitees_who_viewed > 0) ? ', ' : ''} + {participant.invitees_who_viewed > 0 && `${participant.invitees_who_viewed} viewed challenge`} {(participant.invitees_who_viewed_plus > 0 && participant.invitees_who_viewed !== participant.invitees_who_viewed_plus) && ( <> {' '} @@ -42,6 +43,26 @@ ChallengeParticipantListItem.propTypes = { participant: PropTypes.object, }; +const AvatarStyled = styled(Avatar)` +`; + +const Details = styled('div')` + color: ${DesignTokenColors.neutral900}; + font-size: 14px; + margin-top: 8px; + text-align: left; +`; + +const FriendsJoined = styled('div', { + shouldForwardProp: (prop) => !['makeBold'].includes(prop), +})(({ makeBold }) => (` + color: ${DesignTokenColors.neutral900}; + font-size: 14px; + ${makeBold ? 'font-weight: bold;' : ''} + text-align: center; + width: 76px; +`)); + const ParticipantItem = styled('div', { shouldForwardProp: (prop) => !['isCurrentUser'].includes(prop), })(({ isCurrentUser }) => (` @@ -50,19 +71,7 @@ const ParticipantItem = styled('div', { border-bottom: 1px solid ${DesignTokenColors.neutral100}; `)); -const ParticipantRow = styled.div` - display: flex; - justify-content: space-between; - align-items: center; -`; - -const Rank = styled.div` - font-weight: bold; - color: ${DesignTokenColors.neutral900}; - width: 35px; /* Adjust width as needed */ -`; - -const Name = styled.div` +const ParticipantName = styled('div')` align-items: center; color: ${DesignTokenColors.neutral900}; display: flex; @@ -72,7 +81,13 @@ const Name = styled.div` margin-left: 10px; `; -const Points = styled.div` +const ParticipantRow = styled('div')` + display: flex; + justify-content: space-between; + align-items: center; +`; + +const Points = styled('div')` color: ${DesignTokenColors.neutral900}; font-size: 14px; font-weight: bold; @@ -80,21 +95,10 @@ const Points = styled.div` width: 80px; `; -const FriendsJoined = styled('div', { - shouldForwardProp: (prop) => !['makeBold'].includes(prop), -})(({ makeBold }) => (` - color: ${DesignTokenColors.neutral900}; - font-size: 14px; - ${makeBold ? 'font-weight: bold;' : ''} - text-align: center; - width: 76px; -`)); - -const Details = styled.div` +const Rank = styled('div')` + font-weight: bold; color: ${DesignTokenColors.neutral900}; - font-size: 14px; - margin-top: 8px; - text-align: left; + width: 35px; /* Adjust width as needed */ `; export default ChallengeParticipantListItem; diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx index 7154a99fd..f027221bf 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx @@ -10,6 +10,7 @@ import AppObservableStore, { messageService } from '../../stores/AppObservableSt import ChallengeParticipantStore from '../../stores/ChallengeParticipantStore'; import FirstChallengeParticipantListController from './FirstChallengeParticipantListController'; import YourRankOutOf from '../Challenge/YourRankOutOf'; +import ChallengeStore from "../../stores/ChallengeStore"; // const FirstChallengeParticipantListController = React.lazy(() => import(/* webpackChunkName: 'FirstChallengeParticipantListController' */ './FirstChallengeParticipantListController')); const participantListDummyData = [ @@ -55,6 +56,7 @@ const ChallengeParticipantListRoot = ({ challengeWeVoteId, classes, uniqueExtern const [participantList, setParticipantList] = React.useState([]); const [participantsCount, setParticipantsCount] = useState(0); const [rankOfVoter, setRankOfVoter] = React.useState(0); + const [voterIsChallengeParticipant, setVoterIsChallengeParticipant] = React.useState(false); const onAppObservableStoreChange = () => { setRankOfVoter(AppObservableStore.getChallengeParticipantRankOfVoterByChallengeWeVoteId(challengeWeVoteId)); @@ -66,53 +68,62 @@ const ChallengeParticipantListRoot = ({ challengeWeVoteId, classes, uniqueExtern setParticipantsCount(sortedParticipantsWithRank.length); }; + const onChallengeStoreChange = () => { + setVoterIsChallengeParticipant(ChallengeStore.getVoterIsChallengeParticipant(challengeWeVoteId)); + }; + React.useEffect(() => { // console.log('Fetching participants for:', challengeWeVoteId); const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); onAppObservableStoreChange(); const challengeParticipantStoreListener = ChallengeParticipantStore.addListener(onChallengeParticipantStoreChange); onChallengeParticipantStoreChange(); + const challengeStoreListener = ChallengeStore.addListener(onChallengeStoreChange); + onChallengeStoreChange(); return () => { appStateSubscription.unsubscribe(); challengeParticipantStoreListener.remove(); + challengeStoreListener.remove(); }; }, [challengeWeVoteId]); return ( - - - - - - - - - + {voterIsChallengeParticipant && ( + + + + + + + + + + )} {!!(rankOfVoter) && ( diff --git a/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx b/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx index f44ae58ab..fe695f874 100644 --- a/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx +++ b/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx @@ -4,27 +4,17 @@ import withTheme from '@mui/styles/withTheme'; import withStyles from '@mui/styles/withStyles'; import styled from 'styled-components'; import PropTypes from 'prop-types'; -import React, { Suspense } from 'react'; -// import { Link } from 'react-router-dom'; +import React from 'react'; +import TruncateMarkup from 'react-truncate-markup'; import { renderLog } from '../../utils/logging'; -import { - Candidate, - CandidateNameAndPartyWrapper, - CandidateNameH4, - CandidateTopRow, -} from '../../../components/Style/BallotStyles'; import { cordovaBallotFilterTopMargin } from '../../../utils/cordovaOffsets'; import standardBoxShadow from '../Style/standardBoxShadow'; -import normalizedImagePath from '../../utils/normalizedImagePath'; import JoinedAndDaysLeft from '../Challenge/JoinedAndDaysLeft'; -const ImageHandler = React.lazy(() => import(/* webpackChunkName: 'ImageHandler' */ '../../../components/ImageHandler')); - // React functional component example function ChallengeHeaderSimple (props) { renderLog('ChallengeHeaderSimple'); // Set LOG_RENDER_EVENTS to log all renders const { challengeTitle, challengeWeVoteId, classes, challengePhotoLargeUrl, goToChallengeHome, hideCloseIcon } = props; - return ( @@ -38,16 +28,20 @@ function ChallengeHeaderSimple (props) { )} {/* Title of the Challenge */} - + - {challengeTitle} + …} tokenize="words"> + + {challengeTitle} + + {/* Joined and Days Left Info */} - + {!hideCloseIcon && ( @@ -148,6 +142,13 @@ const ChallengePhotoAndTitle = styled('div')` flex-grow: 8; `; +const ChallengeTitleAndDaysLeftWrapper = styled('div')` + display: flex; + flex-flow: column nowrap; + align-items: flex-start; + justify-content: flex-start; +`; + const ChallengeTitleRow = styled('div')` display: flex; flex-flow: row nowrap; diff --git a/src/js/common/components/Style/ChallengeCardStyles.jsx b/src/js/common/components/Style/ChallengeCardStyles.jsx index 1e01401e5..a3429c14e 100644 --- a/src/js/common/components/Style/ChallengeCardStyles.jsx +++ b/src/js/common/components/Style/ChallengeCardStyles.jsx @@ -11,7 +11,6 @@ export const ChallengeCardForListWrapper = styled('div', { export const ChallengeDescription = styled('div')` color: ${DesignTokenColors.neutral500}; font-size: 16px; - line-height: 1.1; padding-bottom: 18px; padding-top: 12px; text-align: left; @@ -165,6 +164,7 @@ export const OneChallengeTextColumn = styled('div', { `)); export const OneChallengeTitleLink = styled('h1')(({ theme }) => (` + color: ${DesignTokenColors.neutralUI900}; font-size: 22px; font-weight: 400; margin: 20px 0 4px 0; diff --git a/src/js/common/components/Style/ScrollingStyles.jsx b/src/js/common/components/Style/ScrollingStyles.jsx index 943c930c5..4e750fcdb 100644 --- a/src/js/common/components/Style/ScrollingStyles.jsx +++ b/src/js/common/components/Style/ScrollingStyles.jsx @@ -93,7 +93,17 @@ export const CampaignsScrollingOuterWrapper = styled('div')` min-height: 400px; min-width: 0; width: 100%; - position:relative + position:relative; +`; + +export const ChallengesScrollingOuterWrapper = styled('div')` + display: flex; + justify-content: space-between; + height: 450px; + min-height: 450px; + min-width: 0; + width: 100%; + position:relative; `; export const RightArrowInnerWrapper = styled('div', { diff --git a/src/js/common/components/Widgets/ReadMore.jsx b/src/js/common/components/Widgets/ReadMore.jsx index 5725bd25a..2d00a1f3f 100644 --- a/src/js/common/components/Widgets/ReadMore.jsx +++ b/src/js/common/components/Widgets/ReadMore.jsx @@ -115,7 +115,6 @@ export default class ReadMore extends Component { … {' '} {linkText} - ); diff --git a/src/js/common/pages/Challenge/ChallengeHomePage.jsx b/src/js/common/pages/Challenge/ChallengeHomePage.jsx index 577a0a67c..aea48549c 100644 --- a/src/js/common/pages/Challenge/ChallengeHomePage.jsx +++ b/src/js/common/pages/Challenge/ChallengeHomePage.jsx @@ -559,6 +559,7 @@ class ChallengeHomePage extends Component { @@ -587,9 +588,10 @@ class ChallengeHomePage extends Component { {challengeDescription && ( - }> - - + {challengeDescription} + {/* }> */} + {/* */} + {/* */} )} @@ -624,8 +626,7 @@ class ChallengeHomePage extends Component { @@ -641,9 +642,10 @@ class ChallengeHomePage extends Component { {challengeDescription && ( - }> - - + {challengeDescription} + {/* }> */} + {/* */} + {/* */} )} diff --git a/src/js/common/pages/Challenge/ChallengesHome.jsx b/src/js/common/pages/Challenge/ChallengesHome.jsx index 754cb317a..3b74945ae 100644 --- a/src/js/common/pages/Challenge/ChallengesHome.jsx +++ b/src/js/common/pages/Challenge/ChallengesHome.jsx @@ -331,7 +331,9 @@ class ChallengesHome extends Component { clearSearchFunction={this.clearSearchFunction} searchFunction={this.searchFunction} /> - +  }> { - historyPush(this.getChallengeBasePath()); + historyPush(`${this.getChallengeBasePath()}leaderboard`); } saveInviteTextForFriendsAndGoToNextStep = () => { diff --git a/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriends.jsx b/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriends.jsx index 78a0a98d3..196d68b74 100644 --- a/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriends.jsx +++ b/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriends.jsx @@ -173,7 +173,7 @@ class ChallengeInviteFriends extends Component { } goToChallengeHome = () => { - historyPush(this.getChallengeBasePath()); + historyPush(`${this.getChallengeBasePath()}leaderboard`); } render () { @@ -214,12 +214,10 @@ class ChallengeInviteFriends extends Component { - {inviteeList.length > 0 && ( - - - - - )} + + + +  }> diff --git a/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriendsJoin.jsx b/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriendsJoin.jsx index 73e36cbfc..214cffe73 100644 --- a/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriendsJoin.jsx +++ b/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriendsJoin.jsx @@ -124,6 +124,7 @@ class ChallengeInviteFriendsJoin extends Component { const { challengeSEOFriendlyPath: challengeSEOFriendlyPathFromParams, challengeWeVoteId: challengeWeVoteIdFromParams } = params; // console.log('onChallengeStoreChange challengeSEOFriendlyPathFromParams: ', challengeSEOFriendlyPathFromParams, ', challengeWeVoteIdFromParams: ', challengeWeVoteIdFromParams); const { + challengeInviteTextDefault, challengePhotoLargeUrl, challengeSEOFriendlyPath, challengeTitle, @@ -133,6 +134,7 @@ class ChallengeInviteFriendsJoin extends Component { weVoteHostedProfileImageUrlLarge, } = getChallengeValuesFromIdentifiers(challengeSEOFriendlyPathFromParams, challengeWeVoteIdFromParams); this.setState({ + challengeInviteTextDefault, challengePhotoLargeUrl, challengeTitle, challengePoliticianList, @@ -205,7 +207,7 @@ class ChallengeInviteFriendsJoin extends Component { } joinChallengeNowSubmitPart2 = () => { - const { challengeWeVoteId } = this.state; + const { challengeInviteTextDefault, challengeWeVoteId } = this.state; // console.log('ChallengeInviteFriendsJoin, joinChallengeNowSubmitPart2, challengeWeVoteId:', challengeWeVoteId); if (challengeWeVoteId) { // const participantEndorsementQueuedToSave = ChallengeParticipantStore.getSupporterEndorsementQueuedToSave(); @@ -235,7 +237,7 @@ class ChallengeInviteFriendsJoin extends Component { VoterActions.voterPhotoQueuedToSave(undefined); }); } - ChallengeParticipantActions.challengeParticipantSave(challengeWeVoteId); + ChallengeParticipantActions.challengeParticipantSave(challengeWeVoteId, challengeInviteTextDefault, true); // If all the necessary data has been saved, proceed to the next step // console.log(`ChallengeInviteFriendsJoin, joinChallengeNowSubmitPart2, redirect to ${this.getChallengeBasePath()}customize-message`);