From 457db4f1488a4538930f2cfd3e0f3ac3899e9975 Mon Sep 17 00:00:00 2001 From: lavishaGit Date: Thu, 26 Sep 2024 09:22:47 -0700 Subject: [PATCH 01/54] wdio change in mobile cababilities --- .../config/wdio.config.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/browserstack_automation/config/wdio.config.js b/tests/browserstack_automation/config/wdio.config.js index 45e9efe0d..1396ee790 100644 --- a/tests/browserstack_automation/config/wdio.config.js +++ b/tests/browserstack_automation/config/wdio.config.js @@ -3,17 +3,17 @@ const { readFileSync } = require('fs'); const browserStackConfig = require('./browserstack.config'); const browserCapabilities = require('../capabilities/browser.json'); -let mobileCapabilities = []; +// let mobileCapabilities = []; -try { - const data = readFileSync('./tests/browserstack_automation/capabilities/mobile.json', { encoding: 'utf8' }); - mobileCapabilities = JSON.parse(data); -} catch (error) { - // Run `npm run wdio:setup` -} - -const capabilities = [...browserCapabilities, ...mobileCapabilities]; +// try { +// const data = readFileSync('./tests/browserstack_automation/capabilities/mobile.json', { encoding: 'utf8' }); +// mobileCapabilities = JSON.parse(data); +// } catch (error) { +// // Run `npm run wdio:setup` +// } +// const capabilities = [...browserCapabilities, ...mobileCapabilities]; +const capabilities = [...browserCapabilities]; const date = new Date(); const dateForDisplay = date.toDateString(); From 982341c51143fc401da5e5708f590945297c287b Mon Sep 17 00:00:00 2001 From: erinw Date: Tue, 1 Oct 2024 14:09:41 -0400 Subject: [PATCH 02/54] add ThanksForViewingChallenge file and insert into ChallengeHomePage --- .../Challenge/ThanksForViewingChallenge.jsx | 116 ++++++++++++++++++ .../ThanksForJoiningChallenge.jsx | 2 +- .../pages/Challenge/ChallengeHomePage.jsx | 10 ++ 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/js/common/components/Challenge/ThanksForViewingChallenge.jsx diff --git a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx new file mode 100644 index 000000000..7ad0b9624 --- /dev/null +++ b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx @@ -0,0 +1,116 @@ +import { IconButton } from '@mui/material'; +import { Close } from '@mui/icons-material'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; + +import React, { useState, useEffect } from 'react'; + +const ThanksForViewingChallenge = ({ userName, challengeOwner, onClose }) => { + const [isClosing, setIsClosing] = useState(false); + + useEffect(() => { + if (isClosing) { + const timer = setTimeout(() => { + onClose(); + }, 500); + return () => clearTimeout(timer); + } + }, [isClosing, onClose]); + + return ( + + + + + Thanks for confirming + the link from  + {challengeOwner} + ! + + + setIsClosing(true)} + size="large" + > + + + + + + + + + ); +}; +ThanksForViewingChallenge.propTypes = { + userName: PropTypes.string.isRequired, + challengeOwner: PropTypes.string.isRequired, + onClose: PropTypes.func.isRequired, +}; + +const CloseMessageIconWrapper = styled.div` + background: none; + border: none; + display: flex; + justify-content: flex-end; +`; + +const RankListOuterWrapper = styled.div` + display: flex; + margin-bottom: 10px; +`; + +const RankMessageWrapper = styled.div` + display: flex; + margin-bottom: 10px; +`; + +const ThanksForViewingInnerWrapper = styled.div` + width: 500px; + max-height: ${(props) => (props.isClosing ? '0' : '300px')}; + border-radius: 20px; + filter: drop-shadow(4px 4px 10px rgba(222,222,222,2)); + display: flex; + flex-direction: column; + overflow: hidden; + background-color: white; + padding: ${(props) => (props.isClosing ? '0' : '0px 10px 20px 20px')}; + transition: max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), + padding 0.5s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.5s cubic-bezier(0.4, 0, 0.2, 1), + transform 0.5s cubic-bezier(0.4, 0, 0.2, 1); + opacity: ${(props) => (props.isClosing ? 0 : 1)}; + transform: ${(props) => (props.isClosing ? 'translateY(-20px)' : 'translateY(0)')}; +`; + +const ThanksForViewingOuterWrapper = styled.div` + max-height: ${(props) => (props.isClosing ? '0' : '400px')}; + overflow: hidden; + display: flex; + justify-content: center; + padding: ${(props) => (props.isClosing ? '0' : '30px 0px 30px')}; + transition: max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), + padding 0.5s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.5s cubic-bezier(0.4, 0, 0.2, 1), + margin-bottom 0.5s cubic-bezier(0.4, 0, 0.2, 1); + opacity: ${(props) => (props.isClosing ? 0 : 1)}; + margin-bottom: ${(props) => (props.isClosing ? '0' : '-50px')}; + z-index: 100; + position: relative; +`; + +const ThankYouMessage = styled.p` + font-size: large; + text-align: left; + font-family: Poppins; + font-weight: 500; + text-decoration: none; +`; + +const ThankYouMessageWrapper = styled.div` + display: flex; + justify-content: space-between; + align-items: baseline; +`; +export default ThanksForViewingChallenge; diff --git a/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx b/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx index a10afbc0e..342864472 100644 --- a/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx +++ b/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import React, { useState, useEffect } from 'react'; const ThanksForJoiningChallenge = ({ userName, challengeOwner, onClose }) => { - const [isClosing, setIsClosing] = useState(false); + const [isClosing, setIsClosing] = useState(true); useEffect(() => { if (isClosing) { diff --git a/src/js/common/pages/Challenge/ChallengeHomePage.jsx b/src/js/common/pages/Challenge/ChallengeHomePage.jsx index c7b37fa5d..c2381069d 100644 --- a/src/js/common/pages/Challenge/ChallengeHomePage.jsx +++ b/src/js/common/pages/Challenge/ChallengeHomePage.jsx @@ -43,6 +43,7 @@ import normalizedImagePath from '../../utils/normalizedImagePath'; import ChallengeAbout from '../../components/Challenge/ChallengeAbout'; import ChallengeParticipantListRoot from '../../components/ChallengeParticipantListRoot/ChallengeParticipantListRoot'; import ChallengeInviteeListRoot from '../../components/ChallengeInviteeListRoot/ChallengeInviteeListRoot'; +import ThanksForViewingChallenge from '../../components/Challenge/ThanksForViewingChallenge' const ChallengeCardForList = React.lazy(() => import(/* webpackChunkName: 'ChallengeCardForList' */ '../../components/ChallengeListRoot/ChallengeCardForList')); // const ChallengeCommentsList = React.lazy(() => import(/* webpackChunkName: 'ChallengeCommentsList' */ '../../components/Challenge/ChallengeCommentsList')); @@ -440,6 +441,10 @@ class ChallengeHomePage extends Component { return null; } + handleCloseFunction = () => { + console.log('click') + } + render () { renderLog('ChallengeHomePage'); // Set LOG_RENDER_EVENTS to log all renders @@ -517,6 +522,11 @@ class ChallengeHomePage extends Component { ); return ( +  }> Date: Thu, 3 Oct 2024 10:47:23 -0700 Subject: [PATCH 03/54] Signin page added --- .../page_objects/signin.page.js | 148 +++++ .../specs/SignInPage.js | 585 ++++++++++++++++++ 2 files changed, 733 insertions(+) create mode 100644 tests/browserstack_automation/page_objects/signin.page.js create mode 100644 tests/browserstack_automation/specs/SignInPage.js diff --git a/tests/browserstack_automation/page_objects/signin.page.js b/tests/browserstack_automation/page_objects/signin.page.js new file mode 100644 index 000000000..5f982276b --- /dev/null +++ b/tests/browserstack_automation/page_objects/signin.page.js @@ -0,0 +1,148 @@ +import { cardHeaderClasses } from '@mui/material'; +import {$,$$} from '@wdio/globals'; +import Page from './page'; + +class SignIn extends Page{ + /* constructor(){ + super().title= 'Ready to Vote? - WeVote'; + }*/ + + get signInLinkElement(){ + return $('.StyledButton-sc-1hu720d-1'); + } + get signInElement(){ + return $('.u-f3'); + } + + get signInWithTwitterTextElement(){ + return $('//span[text()="Sign in with Twitter"]'); + } + get signInWithAppleTextElement(){ + return $('//span[text()="Sign in with Apple"]'); // #appleSignInText + } + get twitterBttnElement(){ + return $('#twitterSignIn-splitIconButton'); + } + get appleBttnElement(){ + return $('.AppleSignInButton-sc-1tt5cpk-2'); + } + + + + get phoneNumberLabelElement(){ + return $('#enterVoterPhone-label'); + } + + get phoneNumberFieldElement(){ + return $('#enterVoterPhone'); + } + + get emailLabelElement(){ + return $('#enterVoterEmailAddress-label'); + } + + get emailFieldElement(){ + return $('#enterVoterEmailAddress'); + } +get iconElements(){ + return $$('#SignInOptionsMain-undefined svg'); + } + get cancelPhoneBttnElement(){ + return $('#cancelVoterPhoneSendSMS'); + } + get cancelEmailBttnElement(){ + return $('#cancelEmailButton'); + } + + get sendVerificationPhoneBttnElement(){ + return $('#voterPhoneSendSMS'); + } + get sendVerificationEmailBttnElement(){ + return $('#voterEmailAddressEntrySendCode'); + } + get closeBttnElement(){ + return $('#signInModalSimpleCloseIcon'); + } + get codeVerifyElement(){ + return $('.Title-sc-27qyt7-4'); + } + get backButtonElement(){ + return $('#emailVerificationBackButton'); +} +get sendVeificationAgainElement(){ + return $('//*[text()="Send verification again"]'); +} + async getIcons(){ + const iconList= await this.iconElements; + // for(const icon of iconList){ + // console.log('Icon: ${icon.toString()}'); // If toString() provides meaningful output + // } + const visibilityList = []; + + for(const icon of iconList){ + const isIconVisible =await icon.isDisplayed(); // call isDisplayed + visibilityList.push(isIconVisible); + } + return visibilityList; + } + + + async getText1(element) { + try { + const text = await element.getText(); + console.log(`Element extracted text is: ${text}`); + return text; + } catch (error) { + console.error('Error extracting text:', error); + return ''; + } + } + + randomString(length,withNum=false,withDecimal=false,withUnderscore=false,withDash=false){ + + let chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let result=''; + let genresult='0123456789'; + if (withNum==true) { + chars = chars+'0123456789'; + } + +// if (withDecimal==true) { +// chars =chars+ '.'; +// } + +// if (withUnderscore==true) { +// chars = chars+'_'; +// } +// if(withDash==true){ +// chars=chars+'-' +// } + //console.log('Available characters:', chars); + for(let i=0;i '0123456789'.includes(char ))) { + // const randomIndex = Math.floor(Math.random() * chars.length); // Use parentheses for Math.random + // result = result + chars.charAt(randomIndex); + //for(let i=0;i<2;i++) + //{ + result=result+genresult.charAt(Math.floor(Math.random() * genresult.length)); + //} + }} + + return result; + + + + + } + + + +} +export default new SignIn(); diff --git a/tests/browserstack_automation/specs/SignInPage.js b/tests/browserstack_automation/specs/SignInPage.js new file mode 100644 index 000000000..1a027931c --- /dev/null +++ b/tests/browserstack_automation/specs/SignInPage.js @@ -0,0 +1,585 @@ +import { browser,driver, expect } from '@wdio/globals'; +import{describe, it } from 'mocha' +import { Key } from 'webdriverio'; +import { platform } from 'node:process'; +const os=require ('os'); +import ReadyPage from '../page_objects/ready.page'; +import SignIn from '../page_objects/signin.page'; +const { describe, it } = require('mocha'); + +const waitTime = 5000; + +beforeEach(async()=>{ + await ReadyPage.load(); ; + await driver.pause(waitTime); + await driver.maximizeWindow(); + await (await SignIn.signInLinkElement).click(); ///await driver.pause(waitTime); +}); + + +const testEmails = [ + //`${SignIn.randomString(1)}@w.us`, //cannot test with invalid 5 letters email because @w.us itself counted as 5 letters + `${SignIn.randomString(1)}@w.us`,//generates valid 6 letters email + `${SignIn.randomString(244)}@wevote.us`,//generates valid 254 letters email + `${SignIn.randomString(245)}@wevote.us` //generates invalid 255 letters email + ]; + + +describe('SignIn', () => { +// SignIn_001 + it('verifySignInPage', async () => { + + + await expect ( await SignIn.signInElement).toHaveText('Sign In or Join'); + }); + + // SignIn_002 and SignIn_007 and SignIn_008 + + + it('verifySpellingsOfAllElementsOnSignInPage', async () => { + const TwitterText="Sign in with Twitter"; + const AppleText="Sign in with Apple"; + //const phoneNumberLabelText = await SignIn.phoneNumberLabelElement; + //const elementText = await phoneNumberLabelText .getText(); +// Locate the input field + +// await ReadyPage.load(); +// await driver.pause(waitTime); +// await (await SignIn.signInLinkElement).click(); +// await driver.pause(waitTime); + + await expect(await SignIn.signInWithTwitterTextElement).toHaveText(TwitterText); +await expect(await SignIn.signInWithAppleTextElement).toHaveText(AppleText); +await expect(await SignIn.phoneNumberLabelElement).toHaveText("Mobile Phone Number"); +await expect(await SignIn.emailLabelElement).toHaveText("Email"); + + + /* const phoneNumberField = await SignIn.phoneNumberPlaceholderElement; + + // Get the placeholder attribute value + const phoneNumberplaceholderText = await phoneNumberField.getAttribute('placeholder'); + const emailField = await SignIn.emailPlaceholderElement; + await expect (phoneNumberplaceholderText ).toBe("Type phone number here...");*/ + await expect (await SignIn.phoneNumberFieldElement).toBeDisplayed(); + await expect (await SignIn.phoneNumberFieldElement.getAttribute('placeholder')).toBe("Type phone number here..."); + await expect (await SignIn.emailFieldElement).toBeDisplayed(); + await expect (await SignIn.emailFieldElement.getAttribute('placeholder')).toBe("Type email here..."); + + + }); + + // SignIn_003 + it('verifyAllIconsOnSignInPage', async () => { + + + // await ReadyPage.load(); + // await driver.pause(waitTime); + // await (await SignIn.signInLinkElement).click(); + // await driver.pause(waitTime); + + const iconsVisibility = await SignIn.getIcons(); + for(const iconVisible of iconsVisibility){ + await expect (iconVisible).toBe(true); + } + + + }); + +//SignIn_004 +it('verifyAllButtonsAndFieldsAlignedAndPresent', async () => { + + + // await ReadyPage.load(); + // await driver.pause(waitTime); + // await (await SignIn.signInLinkElement).click(); + // await driver.pause(waitTime); + + await expect (await SignIn.phoneNumberFieldElement).toBePresent(); + console.log("passed"); + await expect (await SignIn.emailFieldElement).toBePresent(); + console.log("passed"); + await expect (await SignIn.twitterBttnElement).toBePresent(); + console.log("passed"); + await expect (await SignIn.appleBttnElement).toBePresent(); + console.log("passed"); + + //const cssProperty = await SignIn.twitterElement.getCSSProperty('text-align'); + //await expect(cssProperty.value).toBe('center'); + await expect(await (await SignIn.twitterBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); + console.log("twitter passed"); + // await expect(await(await SignIn.appleBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); +// Error: expect(received).toBe(expected) // Object.is equality + +// Expected: "inline-flex" +// Received: "inline-block" + // console.log("apple passed"); + + await expect(await (await SignIn.phoneNumberFieldElement.getCSSProperty('display')).value).toBe('block'); + console.log("phoneNumber passed"); + + await expect(await (await SignIn.emailFieldElement.getCSSProperty('display')).value).toBe('block'); + console.log("emailField passed"); + + + + + await (await SignIn.phoneNumberFieldElement).click(); + //await (await SignIn.cancelPhoneBttnElement).waitForDisplayed(); + await expect(await (await SignIn.cancelPhoneBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); + await expect (await SignIn.cancelPhoneBttnElement).toBePresent(); + console.log(" cancel passed"); + + await expect(await (await SignIn.sendVerificationPhoneBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); +await expect(await SignIn.sendVerificationPhoneBttnElement).toBeDisabled();; +console.log("Its Disabled passed"); + + + }); +//SignIn_005 and SignIn_006 + +it('validateSendVerificationBttn',async() => { + // const randomNumber = Math.floor(40000000 + Math.random() * 9000000000); + const randomNumber = `4089${Math.floor(100000 + Math.random() * 900000)}`; + + const randomEmail = `user${Date.now()}@email.com`; +// await ReadyPage.load(); + +// await driver.pause(waitTime); +//await expect (await SignIn.signInLinkElement).toBeDisabled(); + +// await (await SignIn.signInLinkElement).click(); +await SignIn.phoneNumberFieldElement.click(); +console.log(randomNumber); +await SignIn.phoneNumberFieldElement.addValue(randomNumber); +await expect(await SignIn.sendVerificationPhoneBttnElement).toBeEnabled(); +console.log("phone verify passed"); +await SignIn.emailFieldElement.click(); +await SignIn.emailFieldElement.addValue(randomEmail); +await expect(await SignIn.sendVerificationEmailBttnElement).toBeEnabled(); +console.log(" email verify passed"); + +}); + +//SignIn_009 +it('verifyColorForContents', async()=>{ + +//console.log('Background color twitter :', await(await (await SignIn.twitterBttnElement).getCSSProperty('background-color')).value); +//console.log('Background color apple :', await(await (await SignIn.appleBttnElement).getCSSProperty('background-color')).value); + +const twitterbackgroundColor = await (await SignIn.twitterBttnElement).getCSSProperty('background-color'); +const applebackgroundColor= await (await SignIn.appleBttnElement).getCSSProperty('background-color'); +const twitterTextColor= await (await SignIn.signInWithTwitterTextElement).getCSSProperty('color'); +const appleTextColor= await (await SignIn.signInWithAppleTextElement).getCSSProperty('color'); +// Convert 'rgba' to 'rgb' by removing the alpha value if present +await expect(await twitterbackgroundColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(85,172,238)'); + +await expect(await applebackgroundColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(0,0,0)'); + +await expect(await twitterTextColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(255,255,255)'); +await expect(await appleTextColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(255,255,255)'); + +}); + + +//SignIn_010 and +it('verifyTwitterSignInLinkResponsiveness',async()=>{ + + +// await ReadyPage.load(); //await driver.pause(waitTime); + +// await (await SignIn.signInLinkElement).waitForClickable(); +// await (await SignIn.signInLinkElement).click(); + // await driver.pause(waitTime); + await (await SignIn.twitterBttnElement).waitForClickable(); + await SignIn.twitterBttnElement.click(); + await driver.waitUntil(async () => { + return await driver.getTitle()=== 'X / Authorize an application'}, { + timeout: 5000, + }); + + + // await expect (await driver.getTitle()).toBe('Twitter / Authorize an application'); + +}); +//SignIn_013 and SignIn_014 +it('verifyAppleSignInLinkResponsiveness',async()=>{ +await (await SignIn.appleBttnElement).waitForClickable(); + await SignIn.appleBttnElement.click(); + await driver.waitUntil(async () => {return await driver.getTitle()=== 'Sign in to Apple Account'}, { + timeout: 5000, + }); + await driver.back(); + +}); + + +//SignIn_15 and //SignIn_16 +it('verifyVisiblityOfPhoneAndEmailCancelAndSendBttn',async()=>{ + // let element = await SignIn.cancelPhoneBttnElement; + // console.log(element); + await SignIn.phoneNumberFieldElement.click(); + await expect(await SignIn.cancelPhoneBttnElement).toBeDisplayed(); + await expect(await SignIn.sendVerificationPhoneBttnElement).toBeDisplayed(); + await SignIn.emailFieldElement.click(); + await expect(await SignIn.cancelEmailBttnElement).toBeDisplayed(); + await expect(await SignIn.sendVerificationEmailBttnElement).toBeDisplayed(); + + +}); + + +//SignIn_017 and //SignIn_018 and //SignIn_019 and //SignIn_020 and //SignIn_021 and//SignIn_022 + +it('verifyTabKeyFunctionality',async()=>{ + await driver.keys('Tab'); + // await browser.keys('Tab');//first press tab +await expect(await SignIn.closeBttnElement).toBeFocused(); +await driver.keys('Tab','Tab'); +await expect(await SignIn.twitterBttnElement).toBeFocused(); +await driver.keys('Tab','Tab','Tab'); +await expect(await SignIn.appleBttnElement).toBeFocused(); +await driver.keys('Tab','Tab','Tab','Tab'); +await expect(await SignIn.phoneNumberFieldElement).toBeFocused(); +}); + + + +// //SignIn_026 +// it.only('verifyEmailFieldPasteFunctionalityUsingKeyboard',async()=>{ +// const testdata='wevote@wevote.us' +// //await SignIn.emailFieldElement.click(); + +// await SignIn.emailFieldElement.setValue(testdata); +// await driver.pause(5000); +// await driver.keys(['Command','a']) +// await driver.keys(['Command','c']); +// await driver.pause(5000); + +// // await driver.keys([Key.Command,'a']) +// // await driver.keys([Key.Command,'c']) +// await SignIn.emailFieldElement.setValue(''); + +// //await SignIn.emailFieldElement.clearValue(); +// await driver.pause(5000); +// await driver.keys(['Command','v']); +// await driver.pause(5000); +// const value = await SignIn.emailFieldElement.getValue(); +// await expect(value).toBe(testdata); + + + + + +// }); +//SignIn_026 +it('verifyEmailFieldPasteFunctionalityUsingKeyboard',async()=>{ + // console.log(`This platform is ${platform}`); + // console.log(process.env); + const testdata='wevote@wevote.us'; + const valueLength = testdata.length; + + const selector=await SignIn.emailFieldElement; + await (await SignIn.emailFieldElement).setValue(testdata); + await driver.pause(5000); +// if (process.platform === 'darwin') { +// console.log("running in macos");} +// else { +// console.log("running inother os"); +// } + //await SignIn.emailFieldElement.click(); +const platformName = browser.capabilities.platformName; // Gets the platform like 'Windows', 'macOS' +const browserName=browser.capabilities.browserName; +console.log(`Platform: ${platformName}`); +console.log(`Browser: ${browserName}`); +if(platformName==='Windows XP'&& browserName==='chrome'){ + +await browser.keys([Key.Control,'a']); +//await browser.keys('NULL'); // Releases the Ctrl key + +await browser.keys([Key.Control,'c']); +//await browser.keys('NULL'); +//for (let i = 0; i < valueLength; i++) { // Releases the Ctrl key + await browser.keys(Key.Backspace); + await SignIn.emailFieldElement.click(); + await browser.keys([Key.Control,'v']); +} + +if(platformName==='mac'&& browserName==='Safari') + { //For macOS, the correct value for process.platform is "darwin" +await browser.keys([Key.Command,'a']); + await browser.keys([Key.Command,'c']); + + await browser.keys(Key.Backspace); + await driver.keys([Key.Command,'v']); + + } + + const value = await SignIn.emailFieldElement.getValue(); + await expect(value).toBe(testdata); + + +}); +// //SignIn_028 +it('verifyEmailFieldWithValidAddress',async()=>{ + const testData='wevote@wevote.us'; + await SignIn.emailFieldElement.click(); + await (await SignIn.emailFieldElement).addValue(testData); + await (await SignIn.sendVerificationEmailBttnElement).click(); + const textData=await SignIn.codeVerifyElement.getText(); +await expect(textData).toBe('Code Verification'); + + +}); + +//SignIn_029 //SignIn_030 +it('verifyEmailFieldWithInvalidAddress',async()=>{ + const testDataNumber='11111'; + const testDataUrl= 'wevotewevote.us'; + await SignIn.emailFieldElement.click(); + await (await SignIn.emailFieldElement).addValue(testDataNumber); +const isClickableNumber=await(await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isClickableNumber).toBe(false); + await (await SignIn.emailFieldElement).setValue(testDataUrl); + const isClickableURL=await(await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isClickableURL).toBe(false); + + + }); + + + //SignIn_031 //SignIn_033 //SignIn_034 //SignIn_035 //SignIn_036 +it("verifyEmailFieldAcceptsOnlyLatinLetters",async()=>{ + +const withLatinLettersOnly=`${SignIn.randomString(6)}@wevote.us`; +//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)}@wevote.us`; + //const lettersWithDecimalOnly=`${randomString(6,false,true)}@wevote.us`; + +// const lettersWithUnderscoreOnly=`${randomString(6,false,false,true)}@wevote.us`; +// + +// const lettersWithDashOnly=`${randomString(6,false,false,false,true)}@wevote.us`; + +await (await SignIn.emailFieldElement).setValue(withLatinLettersOnly); +const emailValue= await (await SignIn.emailFieldElement).getValue(); +console.log('email value ',emailValue); + +//await expect(emailValue).toBe(emailWithLatinLettersOnly); +await expect(emailValue).toMatch(/^[a-zA-Z]+@wevote\.us$/); +let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); +await expect(isDisplayed).toBe(true); +//await (await SignIn.emailFieldElement).click(); // Focus on the field +// Use JavaScript to select all text in the input field + +//await (await SignIn.emailFieldElement).doubleClick(); // Focus on the field + await (await SignIn.emailFieldElement).setValue(''); // Clear using setValue + await driver.pause(waitTime); // Pause to ensure value is cleared + +// await (await SignIn.emailFieldElement).setValue(lettersWithNumOnly); +// const valueWithNum= await (await SignIn.emailFieldElement).getValue(); +// console.log('email value ',valueWithNum); +// await expect(valueWithNum).toMatch(/^[a-zA-Z0-9]+@wevote\.us$/); + +}); +//SignIn_033 + +it("verifyEmailFieldAcceptsLettersWithNum",async()=>{ +const lettersWithNumOnly=`${SignIn.randomString(6,true)}@wevote.us`;//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} +// or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; + await (await SignIn.emailFieldElement).setValue(lettersWithNumOnly); + const valueWithNum= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueWithNum); + await expect(valueWithNum).toMatch(/^[a-zA-Z0-9]+@wevote\.us$/); + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isDisplayed).toBe(true); +//*************************setvalue/cleae value not working ********************/ + +// await (await SignIn.emailFieldElement).clearValue();; +// await driver.pause(10000); +// await (await SignIn.emailFieldElement).setValue(''); +// await driver.pause(10000); +//******************************************************************************** + +}); +//SignIn_034 +it("verifyEmailFieldAcceptsLettersWithDecimal",async()=>{ + const lettersWithDecimalOnly=`${SignIn.randomString(2)}.${SignIn.randomString(2)}@wevote.us`; +//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} + // or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; + await (await SignIn.emailFieldElement).setValue(lettersWithDecimalOnly); + const valueWithDec= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueWithDec); + await expect(valueWithDec).toMatch(/^[a-zA-Z.]*\.[a-zA-Z.]*@wevote\.us$/); + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isDisplayed).toBe(true); + }); + //SignIn_035 +it("verifyEmailFieldAcceptsLettersWithUnderscore",async()=>{ + const lettersWithUnderscore=`${SignIn.randomString(2)}_${SignIn.randomString(2)}@wevote.us`; +//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} + // or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; + await (await SignIn.emailFieldElement).setValue(lettersWithUnderscore); + const valueWithUnderscore= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueWithUnderscore); + await expect(valueWithUnderscore).toMatch(/^[a-zA-Z]*\_[a-zA-Z]*@wevote\.us$/); + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isDisplayed).toBe(true); +}); +// //SignIn_036 +it("verifyEmailFieldAcceptsLettersWithDash",async()=>{ + const lettersWithDash=`${SignIn.randomString(3)}-${SignIn.randomString(3)}@wevote.us`; +//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} + // or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; + await (await SignIn.emailFieldElement).setValue(lettersWithDash); + const valueWithDash= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueWithDash); + await expect(valueWithDash).toMatch(/^[a-zA-Z]*\-[a-zA-Z]*@wevote\.us$/); + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isDisplayed).toBe(true); + }); + // //SignIn_037 +it("verifyEmailFieldDoesntAcceptStartWithDot",async()=>{ + const lettersStartWithDot=`.${SignIn.randomString(4)}@wevote.us`; + + await (await SignIn.emailFieldElement).setValue(lettersStartWithDot); + const valueStarWithDot= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueStarWithDot); + await expect(valueStarWithDot).toMatch(/^\.[a-zA-Z]*@wevote\.us$/); + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(false); +}); +// //SignIn_040 +it("verifyEmailFieldDoesntAcceptStartWithDomain",async()=>{ + const lettersStartWithDomain=`@wevote.us`; + + await (await SignIn.emailFieldElement).setValue(lettersStartWithDomain); + const valueStarWithDomain= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueStarWithDomain); + await expect(valueStarWithDomain).toMatch(/^@wevote\.us$/); + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(false); + +}); + + //SignIn_042 +it("verifyEmailFieldDoesntAcceptSpaces",async()=>{ + //*******************************Running in Safari only******************************************* */ + // const randomletters = `${SignIn.randomString(4)}`; + // const withSpace = ' '; + + // const randomletters1 = `${SignIn.randomString(2)}@wevote.us`; + // const lettersWithSpace = randomletters+withSpace+randomletters1 ; + // const lettersWithSpace=`${SignIn.randomString(2)} ${SignIn.randomString(1)}@wevote.us`; + if (os.platform() === 'win32') { + console.log('Running on Windows'); +} else if (os.platform() === 'darwin') { + console.log('Running on macOS'); +} else { + console.log(`Running on ${os.platform()}`); +} const platformName = browser.capabilities.platformName; // Gets the platform like 'Windows', 'macOS' + + const browserName = browser.capabilities.browserName; + console.log(`Platform: ${platformName}`); + console.log(`Browser: ${browserName}`); + + //space in chrome-windows not counted + // const lettersWithSpace=`${SignIn.randomString(2)} ${SignIn.randomString(2)}@wevote.us`; + + //const lettersWithSpace='We Vote@wevote.us'; + await (await SignIn.emailFieldElement).click(); + + + + + + await (await SignIn.emailFieldElement).addValue(`${SignIn.randomString(2)}`); + await (await SignIn.emailFieldElement).addValue(' '); + await (await SignIn.emailFieldElement).addValue(`${SignIn.randomString(2)}@wevote.us`); + const valueWithSpace= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueWithSpace); + await expect(valueWithSpace).toMatch(/^[a-zA-Z]* [a-zA-Z]*@wevote\.us$/); + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(false); + +}); +//SignIn_045 +it("verifyEmailFieldWithBlank",async()=>{ + + await (await SignIn.emailFieldElement).setValue(' '); + const valueWithBlank= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueWithBlank); + await expect(valueWithBlank).toMatch(/^$/); // Validating that the value is empty + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(false); + +}); + // //SignIn_046 +it("verifyEmailFieldAcceptsLettersWithTwoDots",async()=>{ + const lettersWithDoubleDots=`${SignIn.randomString(2)}.${SignIn.randomString(1)}.${SignIn.randomString(2)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersWithDoubleDots); + const valueWithTwoDots= await (await SignIn.emailFieldElement).getValue(); + console.log('email value ',valueWithTwoDots); + await expect(valueWithTwoDots).toMatch(/^[a-zA-Z]*\.[a-zA-Z]*\.[a-zA-Z]*@wevote\.us$/); + let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(true); +}); + +//SignIn_047 +for(let email of testEmails){ +it('verifyEmailFieldAcceptsCharactersBetween6to254',async()=>{ + + + console.log(`Testing email: ${email}`); + console.log('email length:',email.length); + + await (await SignIn.emailFieldElement).setValue(email); + const emailValue= await (await SignIn.emailFieldElement).getValue(); +//console.log('email value ',emailValue); +const len=emailValue.length; +if(len>=6 && len<=254){ + await expect(await SignIn.cancelEmailBttnElement).toBeDisplayed(); + +await expect(await SignIn.sendVerificationEmailBttnElement).toBeEnabled(); +}else{ + + await expect(await SignIn.cancelEmailBttnElement).toBeDisplayed(); + +await expect(await SignIn.sendVerificationEmailBttnElement).not.toBeEnabled(); + + } + +}); +} + // //SignIn_052 + it('verifyBackButtonOnVerificationPage',async()=>{ + const lettersWithDoubleDots=`${SignIn.randomString(2)}.${SignIn.randomString(5)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersWithDoubleDots); + + await (await SignIn.sendVerificationEmailBttnElement).click(); + await driver.waitUntil(async () => { + return await (await SignIn.codeVerifyElement).getText()=== 'Code Verification'}, { + timeout: 5000, + }); + await (await SignIn.backButtonElement).click(); + await expect (await SignIn.sendVeificationAgainElement).toBeDisplayed(); + +}); + +// //SignIn_054 +it('verifyCancelButtonClearEmailField',async()=>{ + const email=`${SignIn.randomString(5)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(email); + + await (await SignIn.cancelEmailBttnElement).click(); + const fieldvalue = await (await SignIn.emailFieldElement).getValue(); + await expect(fieldvalue).toBe(''); + await expect(await SignIn.cancelEmailBttnElement).not.toBeDisplayed(); + await expect(await SignIn.sendVerificationEmailBttnElement).not.toBeDisplayed(); + + //***********Both assertion works same way************************* + //await expect(fieldvalue).toHaveLength(0); + //await expect(fieldvalue).toEqual(''); +//*********************************************************** */ + + +}); +}); \ No newline at end of file From f9c23efe1fbb8f53683508d94c800b194245b748 Mon Sep 17 00:00:00 2001 From: lavishaGit <97263933+lavishaGit@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:59:59 -0700 Subject: [PATCH 04/54] Update wdio.config.js --- .../config/wdio.config.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/browserstack_automation/config/wdio.config.js b/tests/browserstack_automation/config/wdio.config.js index 1396ee790..45e9efe0d 100644 --- a/tests/browserstack_automation/config/wdio.config.js +++ b/tests/browserstack_automation/config/wdio.config.js @@ -3,17 +3,17 @@ const { readFileSync } = require('fs'); const browserStackConfig = require('./browserstack.config'); const browserCapabilities = require('../capabilities/browser.json'); -// let mobileCapabilities = []; +let mobileCapabilities = []; -// try { -// const data = readFileSync('./tests/browserstack_automation/capabilities/mobile.json', { encoding: 'utf8' }); -// mobileCapabilities = JSON.parse(data); -// } catch (error) { -// // Run `npm run wdio:setup` -// } +try { + const data = readFileSync('./tests/browserstack_automation/capabilities/mobile.json', { encoding: 'utf8' }); + mobileCapabilities = JSON.parse(data); +} catch (error) { + // Run `npm run wdio:setup` +} + +const capabilities = [...browserCapabilities, ...mobileCapabilities]; -// const capabilities = [...browserCapabilities, ...mobileCapabilities]; -const capabilities = [...browserCapabilities]; const date = new Date(); const dateForDisplay = date.toDateString(); From e5c19173473068317a6e392bae951c41e0b4da59 Mon Sep 17 00:00:00 2001 From: JedwardMook Date: Thu, 3 Oct 2024 16:11:48 -0500 Subject: [PATCH 05/54] Creates ThumbsUpDownToggle/Icon updates PositionForBallotItem --- .../Position/PositionForBallotItem.jsx | 36 +--------- .../ThumbsUpDownToggle/ThumbsUpDownToggle.jsx | 32 +++++++++ .../ThumbsUpDownToggleIcon.jsx | 65 +++++++++++++++++++ 3 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx create mode 100644 src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggleIcon.jsx diff --git a/src/js/common/components/Position/PositionForBallotItem.jsx b/src/js/common/components/Position/PositionForBallotItem.jsx index e78788548..b671f4be8 100644 --- a/src/js/common/components/Position/PositionForBallotItem.jsx +++ b/src/js/common/components/Position/PositionForBallotItem.jsx @@ -3,12 +3,12 @@ import React, { useState } from 'react'; import styled, { withTheme } from 'styled-components'; import CheckOutlinedIcon from '@mui/icons-material/CheckOutlined'; import BlockOutlinedIcon from '@mui/icons-material/BlockOutlined'; -import ThumbDownOffAltRoundedIcon from '@mui/icons-material/ThumbDownOffAltRounded'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; import Popover from '@mui/material/Popover'; import { Typography } from '@mui/material'; import { withStyles } from '@mui/styles'; import HeartFavoriteToggleBase from '../Widgets/HeartFavoriteToggle/HeartFavoriteToggleBase'; +import ThumbsUpDownToggle from '../Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle'; function PositionForBallotItem ({ classes }) { const [anchorEl, setAnchorEL] = useState(null); @@ -63,15 +63,8 @@ function PositionForBallotItem ({ classes }) { - - - -

7

-   - - View source of opinion @@ -186,7 +168,6 @@ const VoterLikesSourceWrapper = styled('div')` display: flex; align-items: center; justify-content: center; - margin-top: -15px; `; const VoterLikes = styled('div')` @@ -198,17 +179,6 @@ const OpinionSource = styled('button')` border:none; `; -const VoterLikesThumbsUpContainer = styled('button')` - background: transparent; - border: none; -`; - -const LikeDislikeSeperator = styled('div')` - margin-left: 8px; - line-height: 16px; - border-right: 1px solid rgba(197, 197, 197, 1); -`; - const styles = () => ({ popoverRoot: { borderRadius: 2, diff --git a/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx new file mode 100644 index 000000000..606a5463a --- /dev/null +++ b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { styled } from '@mui/material'; +import DesignTokenColors from '../../Style/DesignTokenColors'; +import ThumbsUpDownToggleIcon from './ThumbsUpDownToggleIcon'; +import numberWithCommas from '../../../utils/numberWithCommas'; + +function ThumbsUpDownToggle () { + return ( + + + {numberWithCommas(0)} +   + + {numberWithCommas(0)} + + ); +} + +const ThumbsUpThumbsDownContainer = styled('div')` + display: flex; +`; + +const Amount = styled('span')` + margin-right: 10px; +`; + +const ThumbsUpDownSeperator = styled('div')` + max-width: 1px; + border-right: 1px solid ${DesignTokenColors.neutralUI100}; +`; + +export default ThumbsUpDownToggle; diff --git a/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggleIcon.jsx b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggleIcon.jsx new file mode 100644 index 000000000..55ddbe6a4 --- /dev/null +++ b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggleIcon.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; +import { ThumbDownAltRounded, ThumbDownOffAltRounded } from '@mui/icons-material'; +import DesignTokenColors from '../../Style/DesignTokenColors'; + +const ThumbsUpDownToggleIcon = ({ isFavorite, isDislike, supports, rejects }) => ( + <> + {isFavorite && ( + + {supports ? : } + + )} + {isDislike && ( + + {rejects ? : } + + )} + +); + +const Icon = styled('div')` + flex: display; + padding: 0 5px 0 5px; + +`; + +const ThumbsUpOutlineStyled = styled(ThumbDownOffAltRounded)` + color: ${DesignTokenColors.neutral400}; + cursor: pointer; + transform: rotate(180deg); + transition: path 0.3 ease; + + &:hover { + path { + fill: ${DesignTokenColors.neutral400}; + } + } +`; + +const ThumbsUpPressedStyled = styled(ThumbDownAltRounded)` + color: ${DesignTokenColors.neutral400}; + cursor: pointer; + transform: rotate(180deg); +`; + +const ThumbsDownOutlineStyled = styled(ThumbDownOffAltRounded)` + color: ${DesignTokenColors.neutral400}; + cursor: pointer; + transition: color 0.3 ease; +`; + +const ThumbsDownPressedStyled = styled(ThumbDownAltRounded)` + color: ${DesignTokenColors.neutral400}; + cursor: pointer; +`; + +export default ThumbsUpDownToggleIcon; + +ThumbsUpDownToggleIcon.propTypes = { + isFavorite: PropTypes.bool, + isDislike: PropTypes.bool, + supports: PropTypes.bool, + rejects: PropTypes.bool, +}; From 86a7ca0421ef1ae7acc693498311492ceeb91135 Mon Sep 17 00:00:00 2001 From: Tejas Aditya Date: Sun, 6 Oct 2024 13:26:29 -0700 Subject: [PATCH 06/54] use Link component as the root element to remove unnecessary hierarchy --- src/js/components/Navigation/TabWithPushHistory.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/js/components/Navigation/TabWithPushHistory.jsx b/src/js/components/Navigation/TabWithPushHistory.jsx index f0b367205..5535f3275 100644 --- a/src/js/components/Navigation/TabWithPushHistory.jsx +++ b/src/js/components/Navigation/TabWithPushHistory.jsx @@ -22,9 +22,7 @@ export default function TabWithPushHistory (props) { // console.log(`TabWithPushHistory label:${label}`); return ( - - handleClick(to)} /> - + handleClick(to)} /> ); } TabWithPushHistory.propTypes = { From b7a346755593513a924fe597fbc195eae0f2f297 Mon Sep 17 00:00:00 2001 From: erinw Date: Mon, 7 Oct 2024 12:08:19 -0400 Subject: [PATCH 07/54] add spacing around ThanksForViewingOuterWrapper --- .../common/components/Challenge/ThanksForViewingChallenge.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx index 7ad0b9624..1f4dc8d04 100644 --- a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx +++ b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx @@ -89,13 +89,13 @@ const ThanksForViewingOuterWrapper = styled.div` overflow: hidden; display: flex; justify-content: center; - padding: ${(props) => (props.isClosing ? '0' : '30px 0px 30px')}; + padding: ${(props) => (props.isClosing ? '0' : '0px 0px 30px')}; transition: max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), padding 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.5s cubic-bezier(0.4, 0, 0.2, 1), margin-bottom 0.5s cubic-bezier(0.4, 0, 0.2, 1); opacity: ${(props) => (props.isClosing ? 0 : 1)}; - margin-bottom: ${(props) => (props.isClosing ? '0' : '-50px')}; + margin-bottom: ${(props) => (props.isClosing ? '0' : '5px')}; z-index: 100; position: relative; `; From 8acf3216736587249d4d8f848df87346de51aa2d Mon Sep 17 00:00:00 2001 From: erinw Date: Mon, 7 Oct 2024 13:23:16 -0400 Subject: [PATCH 08/54] add react-confetti to thank you message --- .../Challenge/ThanksForViewingChallenge.jsx | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx index 1f4dc8d04..1135b0f11 100644 --- a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx +++ b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx @@ -2,26 +2,37 @@ import { IconButton } from '@mui/material'; import { Close } from '@mui/icons-material'; import styled from 'styled-components'; import PropTypes from 'prop-types'; - +import Confetti from 'react-confetti'; import React, { useState, useEffect } from 'react'; -const ThanksForViewingChallenge = ({ userName, challengeOwner, onClose }) => { +const ThanksForViewingChallenge = ({ challengeOwner }) => { const [isClosing, setIsClosing] = useState(false); + const [showConfetti, setShowConfetti] = useState(false) useEffect(() => { if (isClosing) { const timer = setTimeout(() => { - onClose(); }, 500); return () => clearTimeout(timer); } - }, [isClosing, onClose]); + }, [isClosing]); + + useEffect(() => { + // Show confetti when the component mounts + setShowConfetti(true); + // Hide confetti after a short duration + const timer = setTimeout(() => { + setShowConfetti(false); + }, 3000); // Adjust the duration as needed + return () => clearTimeout(timer); + }, []); return ( + {showConfetti && } Thanks for confirming the link from  {challengeOwner} @@ -75,7 +86,7 @@ const ThanksForViewingInnerWrapper = styled.div` flex-direction: column; overflow: hidden; background-color: white; - padding: ${(props) => (props.isClosing ? '0' : '0px 10px 20px 20px')}; + padding: ${(props) => (props.isClosing ? '0' : '0px 10px 10px')}; transition: max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), padding 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.5s cubic-bezier(0.4, 0, 0.2, 1), @@ -114,3 +125,6 @@ const ThankYouMessageWrapper = styled.div` align-items: baseline; `; export default ThanksForViewingChallenge; + + + From 1f34b286a181cc298a0467103272f7b2e681a97f Mon Sep 17 00:00:00 2001 From: erinw Date: Mon, 7 Oct 2024 13:27:47 -0400 Subject: [PATCH 09/54] remove handleClose from ChallengeHomePage --- src/js/common/pages/Challenge/ChallengeHomePage.jsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/js/common/pages/Challenge/ChallengeHomePage.jsx b/src/js/common/pages/Challenge/ChallengeHomePage.jsx index c2381069d..45f83e6c9 100644 --- a/src/js/common/pages/Challenge/ChallengeHomePage.jsx +++ b/src/js/common/pages/Challenge/ChallengeHomePage.jsx @@ -441,10 +441,6 @@ class ChallengeHomePage extends Component { return null; } - handleCloseFunction = () => { - console.log('click') - } - render () { renderLog('ChallengeHomePage'); // Set LOG_RENDER_EVENTS to log all renders @@ -525,7 +521,6 @@ class ChallengeHomePage extends Component {  }> Date: Mon, 7 Oct 2024 13:47:29 -0400 Subject: [PATCH 10/54] cleanup --- .../common/components/Challenge/ThanksForViewingChallenge.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx index 1135b0f11..ff917cb59 100644 --- a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx +++ b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx @@ -23,7 +23,7 @@ const ThanksForViewingChallenge = ({ challengeOwner }) => { // Hide confetti after a short duration const timer = setTimeout(() => { setShowConfetti(false); - }, 3000); // Adjust the duration as needed + }, 3000); return () => clearTimeout(timer); }, []); From cf245b237e2c313a81c349203d329c3706fe9868 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Mon, 7 Oct 2024 17:07:36 -0700 Subject: [PATCH 11/54] add some space after eslint run --- src/js/common/components/Navigation/ChallengeHeaderSimple.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx b/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx index 3a98be6ea..a895d3533 100644 --- a/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx +++ b/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx @@ -21,7 +21,7 @@ import JoinedAndDaysLeft from '../Challenge/JoinedAndDaysLeft'; const ImageHandler = React.lazy(() => import(/* webpackChunkName: 'ImageHandler' */ '../../../components/ImageHandler')); // React functional component example -function ChallengeHeaderSimple(props) { +function ChallengeHeaderSimple (props) { renderLog('ChallengeHeaderSimple'); // Set LOG_RENDER_EVENTS to log all renders const { challengeTitle, challengeWeVoteId, classes, challengePhotoLargeUrl, goToChallengeHome } = props; From 941d370d40e31c2b1a73ae204e0d522f07f1d259 Mon Sep 17 00:00:00 2001 From: Steven Gutierrez Date: Mon, 7 Oct 2024 19:34:27 -0700 Subject: [PATCH 12/54] WV-599 --- .../common/components/Challenge/YourRank.jsx | 13 +++- .../components/Challenge/YourRankModal.jsx | 62 +++++++++++++++++++ .../ChallengeParticipantList.jsx | 1 + .../ChallengeParticipantListRoot.jsx | 5 +- src/js/common/stories/YourRank.stories.js | 10 +++ 5 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 src/js/common/components/Challenge/YourRankModal.jsx create mode 100644 src/js/common/stories/YourRank.stories.js diff --git a/src/js/common/components/Challenge/YourRank.jsx b/src/js/common/components/Challenge/YourRank.jsx index 9f057855a..1d519e86b 100644 --- a/src/js/common/components/Challenge/YourRank.jsx +++ b/src/js/common/components/Challenge/YourRank.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, Suspense } from 'react'; import styled from 'styled-components'; import withStyles from '@mui/styles/withStyles'; import DesignTokenColors from '../../components/Style/DesignTokenColors'; @@ -7,6 +7,7 @@ import { CampaignSupportDesktopButtonPanel, CampaignSupportDesktopButtonWrapper, import { SupportButtonFooterWrapper, SupportButtonPanel} from '../../components/Style/CampaignDetailsStyles'; import arrow from '../../../../img/global/icons/ph_arrow-up-bold.png'; import arrow1 from '../../../../img/global/icons/ph_arrow-up-bold_1.png'; +import YourRankModal from './YourRankModal'; const URL = '/:challengeSEOFriendlyPath/+/customize-message'; const YourRank =({classes})=>{ @@ -15,6 +16,8 @@ const YourRank =({classes})=>{ const [note, setNote] = useState(""); const [arrowImage, setArrowImage] = useState(arrow) + const [openYourRankModal, setOpenYourRankModal] = useState(false) + const calculateRank = (points) => 5336 + points * 5; const handleClick = () => { @@ -29,6 +32,7 @@ const YourRank =({classes})=>{ }, 3000); return newPoints; }); + setOpenYourRankModal(!openYourRankModal) }; return ( @@ -62,6 +66,13 @@ const YourRank =({classes})=>{ arrow + }> + setOpenYourRankModal(!openYourRankModal)} + /> + ); diff --git a/src/js/common/components/Challenge/YourRankModal.jsx b/src/js/common/components/Challenge/YourRankModal.jsx new file mode 100644 index 000000000..e59c5e424 --- /dev/null +++ b/src/js/common/components/Challenge/YourRankModal.jsx @@ -0,0 +1,62 @@ +import { Close } from '@mui/icons-material' +import { Dialog, DialogContent, DialogTitle, IconButton } from '@mui/material' +import { withStyles } from '@mui/styles' +import React from 'react' +import styled from 'styled-components' +import ChallengeParticipantListRoot from '../ChallengeParticipantListRoot/ChallengeParticipantListRoot' + + +const YourRankModal = ({ classes, userRank, show, toggleModal }) => { + const challengeName = `Mr. Beast's "Get Out the Vote"` + return ( + toggleModal()} + open={show} + > + + + + Ranking -  + {challengeName}  + Challenge + + toggleModal()} + size='large' + > + + + + + + + + + ); +}; +const styles = (theme) => ({ + dialogPaper: { + borderRadius: '16px', + }, + dialogTitle: { + padding: '0px 0px 0px 10px', + } +}) +const DialogTitleWrapper = styled.div` + display: flex; + min-height: 30px; +` + +const Title = styled.h2` + font-size: 16px; + font-weight: bold; + margin: 0; + margin-top: 10px; + text-align: left; + padding-left: 0px; +` +export default withStyles(styles)(YourRankModal); \ No newline at end of file diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantList.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantList.jsx index 7bfc8299b..88f29af4e 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantList.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantList.jsx @@ -44,6 +44,7 @@ const LeaderboardListContainer = styled.div` flex-direction: column; overflow-y: scroll; height: calc(100vh - 270px); + padding: 10px; `; export default ChallengeParticipantList; diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx index 1f8747831..3c56c06bb 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx @@ -37,12 +37,12 @@ const participantListDummyData = [ { rank: 5342, participant_name: 'Anusha G.', points: 118, friends_who_joined: 1, friends_invited: 5, friends_who_viewed: 2, friends_who_viewed_plus: 15, voter_we_vote_id: 'wv02voter12325' }, ]; -function clearSearchFunction () { +function clearSearchFunction() { // This is just a stub return true; } -function searchFunction () { +function searchFunction() { // This is just a stub return true; } @@ -166,6 +166,7 @@ const TopSection = styled.div` z-index: 1; position: sticky; top: 0; + padding: 10px; `; const ButtonAndSearchWrapper = styled.div` diff --git a/src/js/common/stories/YourRank.stories.js b/src/js/common/stories/YourRank.stories.js new file mode 100644 index 000000000..6bafa9ee9 --- /dev/null +++ b/src/js/common/stories/YourRank.stories.js @@ -0,0 +1,10 @@ +import React from 'react'; +import YourRank from '../components/Challenge/YourRank'; + +export default { + title: 'Ranking', + component: YourRank, +}; + + +export const Default = () => ; From d627a44a295f4ffeb40c79e9a9c40248bba2ef23 Mon Sep 17 00:00:00 2001 From: Steven Gutierrez Date: Mon, 7 Oct 2024 20:32:34 -0700 Subject: [PATCH 13/54] Fixed minor lint issues --- .../common/components/Challenge/YourRank.jsx | 13 +++--- .../components/Challenge/YourRankModal.jsx | 41 +++++++++++-------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/js/common/components/Challenge/YourRank.jsx b/src/js/common/components/Challenge/YourRank.jsx index 57190dc66..9d92a86e5 100644 --- a/src/js/common/components/Challenge/YourRank.jsx +++ b/src/js/common/components/Challenge/YourRank.jsx @@ -16,9 +16,8 @@ const YourRank = ({ classes, challengeWeVoteId }) => { const [participantsCount, setParticipantsCount] = useState(0); const [points, setPoints] = useState(0); // const [note, setNote] = useState(""); - const [arrowImage, setArrowImage] = useState(arrow) - - const [openYourRankModal, setOpenYourRankModal] = useState(false) + const [arrowImage, setArrowImage] = useState(arrow); + const [openYourRankModal, setOpenYourRankModal] = useState(false); const onAppObservableStoreChange = () => { setRankOfVoter(AppObservableStore.getChallengeParticipantRankOfVoterByChallengeWeVoteId(challengeWeVoteId)); @@ -41,7 +40,7 @@ const YourRank = ({ classes, challengeWeVoteId }) => { }, 3000); return newPoints; }); - setOpenYourRankModal(!openYourRankModal) + setOpenYourRankModal(!openYourRankModal); }; React.useEffect(() => { @@ -72,7 +71,7 @@ const YourRank = ({ classes, challengeWeVoteId }) => { fontWeight: '400', lineHeight: '19.5px', textAlign: 'left', - color: 'var(--Neutral-700, #484848)' + color: 'var(--Neutral-700, #484848)', }} >

Your rank in the challenge:

@@ -92,7 +91,6 @@ const YourRank = ({ classes, challengeWeVoteId }) => { }> setOpenYourRankModal(!openYourRankModal)} /> @@ -111,7 +109,6 @@ const styles = (theme) => ({ borderRadius: '20px 20px 20px 20px', transition: 'color 0.3s ease', textTransform: 'none', - width: '100%', }, desktopSimpleLink: { border: '2px solid #AC5204', @@ -155,7 +152,7 @@ const YourRankWrapper = styled('div')` justify-content: center; `; const CompleteYourProfileButtonWrapper = styled('div')` - background-color: ${(props) => (props.clicked ? "#AC5204" : "#FFFFFF")}; + background-color: ${(props) => (props.clicked ? '#AC5204' : '#FFFFFF')}; width: 105px; height: 34px; top: 443px; diff --git a/src/js/common/components/Challenge/YourRankModal.jsx b/src/js/common/components/Challenge/YourRankModal.jsx index e59c5e424..36fcdd250 100644 --- a/src/js/common/components/Challenge/YourRankModal.jsx +++ b/src/js/common/components/Challenge/YourRankModal.jsx @@ -1,13 +1,12 @@ -import { Close } from '@mui/icons-material' -import { Dialog, DialogContent, DialogTitle, IconButton } from '@mui/material' -import { withStyles } from '@mui/styles' -import React from 'react' -import styled from 'styled-components' -import ChallengeParticipantListRoot from '../ChallengeParticipantListRoot/ChallengeParticipantListRoot' +import { Close } from '@mui/icons-material'; +import { Dialog, DialogContent, DialogTitle, IconButton } from '@mui/material'; +import { withStyles } from '@mui/styles'; +import React from 'react'; +import styled from 'styled-components'; +import ChallengeParticipantListRoot from '../ChallengeParticipantListRoot/ChallengeParticipantListRoot'; - -const YourRankModal = ({ classes, userRank, show, toggleModal }) => { - const challengeName = `Mr. Beast's "Get Out the Vote"` +const YourRankModal = ({ classes, show, toggleModal }) => { + const challengeName = `Mr. Beast's "Get Out the Vote"`; return ( { Ranking -  - {challengeName}  + {challengeName} +   Challenge toggleModal()} - size='large' + size="large" > @@ -38,18 +38,24 @@ const YourRankModal = ({ classes, userRank, show, toggleModal }) => { ); }; +YourRankModal.propTypes = { + classes: PropTypes.object.isRequired, + show: PropTypes.bool.isRequired, + toggleModal: PropTypes.func.isRequired, +}; + const styles = (theme) => ({ dialogPaper: { borderRadius: '16px', }, dialogTitle: { padding: '0px 0px 0px 10px', - } -}) + }, +}); const DialogTitleWrapper = styled.div` display: flex; min-height: 30px; -` +`; const Title = styled.h2` font-size: 16px; @@ -58,5 +64,6 @@ const Title = styled.h2` margin-top: 10px; text-align: left; padding-left: 0px; -` -export default withStyles(styles)(YourRankModal); \ No newline at end of file +`; + +export default withStyles(styles)(YourRankModal); From a723863578c921f584f979d4a7e98493429a849d Mon Sep 17 00:00:00 2001 From: Steven Gutierrez <115047871+Succorro@users.noreply.github.com> Date: Mon, 7 Oct 2024 20:38:36 -0700 Subject: [PATCH 14/54] Minor lint fixes --- .../ChallengeParticipantListRoot.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx index 0f57ebc01..69f40e1a2 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx @@ -38,12 +38,12 @@ const participantListDummyData = [ { rank: 5342, participant_name: 'Anusha G.', points: 118, invitees_who_joined: 1, invitees_count: 5, invitees_who_viewed: 2, invitees_who_viewed_plus: 15, voter_we_vote_id: 'wv02voter12325' }, ]; -function clearSearchFunction() { +function clearSearchFunction () { // This is just a stub return true; } -function searchFunction() { +function searchFunction () { // This is just a stub return true; } From bc2894024b0c0327cb169aa71bd9918452e85938 Mon Sep 17 00:00:00 2001 From: erinw Date: Tue, 8 Oct 2024 11:06:09 -0400 Subject: [PATCH 15/54] resolve npm lint issues --- package.json | 1 + .../Challenge/ThanksForViewingChallenge.jsx | 30 ++++++------------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 1de4db75e..e964f5145 100644 --- a/package.json +++ b/package.json @@ -140,6 +140,7 @@ "puppeteer": "^22.10.0", "react": "~17.0.2", "react-bootstrap": "^1.6.4", + "react-confetti": "^6.1.0", "react-copy-to-clipboard": "^5.0.3", "react-dom": "~17.0.2", "react-fullstory": "^1.4.0", diff --git a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx index ff917cb59..441345393 100644 --- a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx +++ b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx @@ -7,7 +7,7 @@ import React, { useState, useEffect } from 'react'; const ThanksForViewingChallenge = ({ challengeOwner }) => { const [isClosing, setIsClosing] = useState(false); - const [showConfetti, setShowConfetti] = useState(false) + const [showConfetti, setShowConfetti] = useState(false); useEffect(() => { if (isClosing) { @@ -18,14 +18,14 @@ const ThanksForViewingChallenge = ({ challengeOwner }) => { }, [isClosing]); useEffect(() => { - // Show confetti when the component mounts - setShowConfetti(true); - // Hide confetti after a short duration - const timer = setTimeout(() => { - setShowConfetti(false); - }, 3000); - return () => clearTimeout(timer); - }, []); + // Show confetti when the component mounts + setShowConfetti(true); + // Hide confetti after a short duration + const timer = setTimeout(() => { + setShowConfetti(false); + }, 3000); + return () => clearTimeout(timer); + }, []); return ( @@ -55,9 +55,7 @@ const ThanksForViewingChallenge = ({ challengeOwner }) => { ); }; ThanksForViewingChallenge.propTypes = { - userName: PropTypes.string.isRequired, challengeOwner: PropTypes.string.isRequired, - onClose: PropTypes.func.isRequired, }; const CloseMessageIconWrapper = styled.div` @@ -67,16 +65,6 @@ const CloseMessageIconWrapper = styled.div` justify-content: flex-end; `; -const RankListOuterWrapper = styled.div` - display: flex; - margin-bottom: 10px; -`; - -const RankMessageWrapper = styled.div` - display: flex; - margin-bottom: 10px; -`; - const ThanksForViewingInnerWrapper = styled.div` width: 500px; max-height: ${(props) => (props.isClosing ? '0' : '300px')}; From 2c4f96b8b24a0766b6d7b1a1fac3ef8c968d91c2 Mon Sep 17 00:00:00 2001 From: erinw Date: Tue, 8 Oct 2024 11:07:26 -0400 Subject: [PATCH 16/54] resolve merge conflict --- .../ChallengeInviteFriends/ThanksForJoiningChallenge.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx b/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx index 342864472..a10afbc0e 100644 --- a/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx +++ b/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import React, { useState, useEffect } from 'react'; const ThanksForJoiningChallenge = ({ userName, challengeOwner, onClose }) => { - const [isClosing, setIsClosing] = useState(true); + const [isClosing, setIsClosing] = useState(false); useEffect(() => { if (isClosing) { From 48a93fbe8fde255bb0f3e5445c025e50ea08360c Mon Sep 17 00:00:00 2001 From: erinw Date: Tue, 8 Oct 2024 11:18:42 -0400 Subject: [PATCH 17/54] update package-lock.json --- package-lock.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/package-lock.json b/package-lock.json index 6813458e2..50cc77066 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "puppeteer": "^22.10.0", "react": "~17.0.2", "react-bootstrap": "^1.6.4", + "react-confetti": "^6.1.0", "react-copy-to-clipboard": "^5.0.3", "react-dom": "~17.0.2", "react-fullstory": "^1.4.0", @@ -23468,6 +23469,20 @@ "react-dom": ">=16.8.0" } }, + "node_modules/react-confetti": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", + "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0" + } + }, "node_modules/react-copy-to-clipboard": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", @@ -26815,6 +26830,11 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", From 595f57f42d010b06169e81c5283b5c2a516ac452 Mon Sep 17 00:00:00 2001 From: Anna Fedorova Date: Tue, 8 Oct 2024 09:34:40 -0700 Subject: [PATCH 18/54] [Issue #WV-615] Reimplemented test 007: verifyTabKeySelectEnterVoterEmailAddressTextBox, created method tabToSelectElement(driver, targetElementId),created and updated variable email --- .../page_objects/discuss.page.js | 22 ++++++++++++++- .../specs/DiscussPage.js | 28 +++++++++---------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/tests/browserstack_automation/page_objects/discuss.page.js b/tests/browserstack_automation/page_objects/discuss.page.js index 5507b8883..488b3482e 100644 --- a/tests/browserstack_automation/page_objects/discuss.page.js +++ b/tests/browserstack_automation/page_objects/discuss.page.js @@ -36,6 +36,26 @@ class DiscussPage extends Page { async toggleEmailVerificationButton () { await this.voterEmailAddressVerificationButton.findAndClick(); } -} + async tabToSelectElement(driver, targetElementId) { + // Max number of iterations to find target element. + // Prevents waiting for a timeout when the element is missing or unreachable. + const maxCount = 100; + let count = 0; + + let activeElement; + let activeElementId; + + do { + await driver.keys(['Tab']); + activeElement = await driver.getActiveElement(); + activeElementId = await (await $(activeElement)).getProperty('id'); + if (targetElementId === activeElementId) { + return $(activeElement); + } + ++count; + } while (activeElementId !== targetElementId && count <= maxCount); + return null; + } +} export default new DiscussPage(); diff --git a/tests/browserstack_automation/specs/DiscussPage.js b/tests/browserstack_automation/specs/DiscussPage.js index 2116945b2..04b706e0b 100644 --- a/tests/browserstack_automation/specs/DiscussPage.js +++ b/tests/browserstack_automation/specs/DiscussPage.js @@ -4,6 +4,7 @@ import DiscussPage from '../page_objects/discuss.page'; const { describe, it } = require('mocha'); const waitTime = 5000; +const email = 'wevote@wevote.us'; describe('Discuss Page', () => { @@ -35,7 +36,7 @@ describe('Discuss Page', () => { await expect(DiscussPage.voterEmailAddressVerificationButton).not.toBeClickable(); const element = await DiscussPage.enterVoterEmailAddressTextBox; // Locate the text box element using a selector await driver.pause(waitTime); - element.setValue('wevote@gmail.com'); + element.setValue(email); await driver.pause(waitTime); await driver.waitUntil(async () => ((DiscussPage.toggleEmailVerificationButton))); }); @@ -73,23 +74,22 @@ describe('Discuss Page', () => { }); // Discuss_007 - it('verifyTabKeySelectenterVoterEmailAddressTextBox', async () => { + it('verifyTabKeySelectEnterVoterEmailAddressTextBox', async () => { await DiscussPage.load(); await driver.switchWindow('https://quality.wevote.us/news'); - const element = await DiscussPage.enterVoterEmailAddressTextBox; // Locate the text box element using a selector - element.setValue('wevote@wevote.us'); - // Press the tab key 11 times - for (let i = 0; i < 12; i++) { - driver.keys(['Tab']); + const element = await DiscussPage.enterVoterEmailAddressTextBox; + const elementId = await element.getAttribute('id'); + + const voterEmailAddressTextBox = await DiscussPage.tabToSelectElement(driver, elementId); + if (voterEmailAddressTextBox) { + await voterEmailAddressTextBox.setValue(email); + } else { + throw new Error('Element with ID ' + elementId + ' not found or not reachable while selectig with Tab.'); } - await driver.pause(waitTime); - // Check if the active element is the email text box after pressing the tab key 11 times - const activeElement = await driver.getActiveElement(); - const activeElementWdio = await (await $(activeElement)).getProperty('id'); - await driver.pause(waitTime); - console.log(activeElementWdio); - await expect(activeElement).toBe(element); + + await expect(DiscussPage.voterEmailAddressVerificationButton).toBeClickable(); + await expect(await element.getAttribute('value')).toBe(email); }); // Test Case Doesn't work From 949132c441d25cdd44ec4cb19990bf48eceb868d Mon Sep 17 00:00:00 2001 From: erinw Date: Tue, 8 Oct 2024 14:56:16 -0400 Subject: [PATCH 19/54] add cursor to candidateContainer --- src/js/components/Ballot/BallotScrollingContainer.jsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/js/components/Ballot/BallotScrollingContainer.jsx b/src/js/components/Ballot/BallotScrollingContainer.jsx index 34e654e10..2f96bf06b 100644 --- a/src/js/components/Ballot/BallotScrollingContainer.jsx +++ b/src/js/components/Ballot/BallotScrollingContainer.jsx @@ -100,12 +100,16 @@ class BallotScrollingContainer extends Component { }; handleContainerClick = (e, weVoteId, externalUniqueId) => { - + console.log(e.target, externalUniqueId) const candidateContainer = document.getElementById(`candidateContainer-${weVoteId}-${externalUniqueId}`) const positionRowListOuterWrapper = document.getElementById(`positionRowListOuterWrapper-${weVoteId}-${externalUniqueId}`) const candidateImageAndName = document.getElementById(`officeItemCompressedCandidateImageAndName-${weVoteId}-${externalUniqueId}`); const candidateNameAndPartyWrapper = document.getElementById(`candidateNameAndPartyWrapper-${weVoteId}-${externalUniqueId}`) const candidateNameH4 = document.getElementById(`candidateNameH4-${weVoteId}-${externalUniqueId}`) + //change to ! any of the ones below instead + //get rid of these ones in IssuesByBallotItemDisplayList and PositionRowListCompressed + const listWrapper = document.getElementById(`IssueListWrapper-${weVoteId}`) + const candidateEndorsementText = document.getElementById(`CandidateEndorsementText-${weVoteId}`) if (e.target === candidateImageAndName || e.target === candidateContainer || e.target === positionRowListOuterWrapper @@ -148,6 +152,8 @@ class BallotScrollingContainer extends Component { > @@ -203,6 +209,7 @@ class BallotScrollingContainer extends Component { ballotItemDisplayName={oneCandidate.ballot_item_display_name} ballotItemWeVoteId={oneCandidate.we_vote_id} externalUniqueId={`officeItemCompressed-${oneCandidate.we_vote_id}-${externalUniqueId}`} + handleContainerClick={this.handleContainerClick} /> )} From 321efdf45ca30764dba36eae2248c87f61d003dd Mon Sep 17 00:00:00 2001 From: Joseph Szpigiel Date: Tue, 8 Oct 2024 15:11:34 -0400 Subject: [PATCH 20/54] Set open state on Unfollow --- src/js/components/Values/IssueFollowToggleButton.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/js/components/Values/IssueFollowToggleButton.jsx b/src/js/components/Values/IssueFollowToggleButton.jsx index c5dde9c4a..ed4f68cc7 100644 --- a/src/js/components/Values/IssueFollowToggleButton.jsx +++ b/src/js/components/Values/IssueFollowToggleButton.jsx @@ -141,6 +141,8 @@ class IssueFollowToggleButton extends Component { this.setState({ isFollowing: false, isFollowingLocalValue: false, + open: false, + anchorEl: null }); } From 5fe1989c9db23ef6ea29402c262cf06459eb1acf Mon Sep 17 00:00:00 2001 From: lavishaGit Date: Tue, 8 Oct 2024 12:51:25 -0700 Subject: [PATCH 21/54] SignIn Page TestScripts --- .../page_objects/signin.page.js | 6 +- .../specs/SignInPage.js | 805 +++++++----------- 2 files changed, 328 insertions(+), 483 deletions(-) diff --git a/tests/browserstack_automation/page_objects/signin.page.js b/tests/browserstack_automation/page_objects/signin.page.js index 5f982276b..354374000 100644 --- a/tests/browserstack_automation/page_objects/signin.page.js +++ b/tests/browserstack_automation/page_objects/signin.page.js @@ -74,13 +74,9 @@ get sendVeificationAgainElement(){ } async getIcons(){ const iconList= await this.iconElements; - // for(const icon of iconList){ - // console.log('Icon: ${icon.toString()}'); // If toString() provides meaningful output - // } const visibilityList = []; - for(const icon of iconList){ - const isIconVisible =await icon.isDisplayed(); // call isDisplayed + const isIconVisible =await icon.isDisplayed()// call isDisplayed visibilityList.push(isIconVisible); } return visibilityList; diff --git a/tests/browserstack_automation/specs/SignInPage.js b/tests/browserstack_automation/specs/SignInPage.js index 1a027931c..fb8eed4a9 100644 --- a/tests/browserstack_automation/specs/SignInPage.js +++ b/tests/browserstack_automation/specs/SignInPage.js @@ -1,585 +1,434 @@ -import { browser,driver, expect } from '@wdio/globals'; -import{describe, it } from 'mocha' +import { browser, driver, expect } from '@wdio/globals'; import { Key } from 'webdriverio'; -import { platform } from 'node:process'; -const os=require ('os'); +import { isWebTarget } from 'webpack-dev-server'; +const os = require('os'); import ReadyPage from '../page_objects/ready.page'; import SignIn from '../page_objects/signin.page'; const { describe, it } = require('mocha'); const waitTime = 5000; -beforeEach(async()=>{ - await ReadyPage.load(); ; - await driver.pause(waitTime); +beforeEach(async () => { + await ReadyPage.load();; + //await driver.pause(waitTime); await driver.maximizeWindow(); - await (await SignIn.signInLinkElement).click(); ///await driver.pause(waitTime); + await (await SignIn.signInLinkElement).click(); }); const testEmails = [ //`${SignIn.randomString(1)}@w.us`, //cannot test with invalid 5 letters email because @w.us itself counted as 5 letters `${SignIn.randomString(1)}@w.us`,//generates valid 6 letters email - `${SignIn.randomString(244)}@wevote.us`,//generates valid 254 letters email - `${SignIn.randomString(245)}@wevote.us` //generates invalid 255 letters email - ]; + `${SignIn.randomString(244)}@wevote.us`,//generates valid 254 letters email + `${SignIn.randomString(245)}@wevote.us` //generates invalid 255 letters email +]; describe('SignIn', () => { -// SignIn_001 - it('verifySignInPage', async () => { - - await expect ( await SignIn.signInElement).toHaveText('Sign In or Join'); - }); - - // SignIn_002 and SignIn_007 and SignIn_008 - - - it('verifySpellingsOfAllElementsOnSignInPage', async () => { - const TwitterText="Sign in with Twitter"; - const AppleText="Sign in with Apple"; - //const phoneNumberLabelText = await SignIn.phoneNumberLabelElement; - //const elementText = await phoneNumberLabelText .getText(); -// Locate the input field - -// await ReadyPage.load(); -// await driver.pause(waitTime); -// await (await SignIn.signInLinkElement).click(); -// await driver.pause(waitTime); - - await expect(await SignIn.signInWithTwitterTextElement).toHaveText(TwitterText); -await expect(await SignIn.signInWithAppleTextElement).toHaveText(AppleText); -await expect(await SignIn.phoneNumberLabelElement).toHaveText("Mobile Phone Number"); -await expect(await SignIn.emailLabelElement).toHaveText("Email"); - - - /* const phoneNumberField = await SignIn.phoneNumberPlaceholderElement; - - // Get the placeholder attribute value - const phoneNumberplaceholderText = await phoneNumberField.getAttribute('placeholder'); - const emailField = await SignIn.emailPlaceholderElement; - await expect (phoneNumberplaceholderText ).toBe("Type phone number here...");*/ - await expect (await SignIn.phoneNumberFieldElement).toBeDisplayed(); - await expect (await SignIn.phoneNumberFieldElement.getAttribute('placeholder')).toBe("Type phone number here..."); - await expect (await SignIn.emailFieldElement).toBeDisplayed(); - await expect (await SignIn.emailFieldElement.getAttribute('placeholder')).toBe("Type email here..."); - - - }); - - // SignIn_003 - it('verifyAllIconsOnSignInPage', async () => { - - - // await ReadyPage.load(); - // await driver.pause(waitTime); - // await (await SignIn.signInLinkElement).click(); - // await driver.pause(waitTime); - - const iconsVisibility = await SignIn.getIcons(); - for(const iconVisible of iconsVisibility){ - await expect (iconVisible).toBe(true); - } - - - }); - -//SignIn_004 -it('verifyAllButtonsAndFieldsAlignedAndPresent', async () => { - - - // await ReadyPage.load(); - // await driver.pause(waitTime); - // await (await SignIn.signInLinkElement).click(); - // await driver.pause(waitTime); - - await expect (await SignIn.phoneNumberFieldElement).toBePresent(); - console.log("passed"); - await expect (await SignIn.emailFieldElement).toBePresent(); - console.log("passed"); - await expect (await SignIn.twitterBttnElement).toBePresent(); - console.log("passed"); - await expect (await SignIn.appleBttnElement).toBePresent(); - console.log("passed"); - - //const cssProperty = await SignIn.twitterElement.getCSSProperty('text-align'); - //await expect(cssProperty.value).toBe('center'); - await expect(await (await SignIn.twitterBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); - console.log("twitter passed"); - // await expect(await(await SignIn.appleBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); -// Error: expect(received).toBe(expected) // Object.is equality + // SignIn_001 + it('verifySignInPage', async () => { + await expect(await SignIn.signInElement).toHaveText('Sign In or Join'); + }); -// Expected: "inline-flex" -// Received: "inline-block" - // console.log("apple passed"); - await expect(await (await SignIn.phoneNumberFieldElement.getCSSProperty('display')).value).toBe('block'); - console.log("phoneNumber passed"); + // SignIn_002 and SignIn_007 and SignIn_008 + it('verifySpellingsOfAllElementsOnSignInPage', async () => { + const TwitterText = "Sign in with Twitter"; + const AppleText = "Sign in with Apple"; + await expect(SignIn.signInWithTwitterTextElement).toHaveText(TwitterText); + await expect(SignIn.signInWithAppleTextElement).toHaveText(AppleText); + await expect(SignIn.phoneNumberLabelElement).toHaveText("Mobile Phone Number"); + await expect(SignIn.emailLabelElement).toHaveText("Email"); + await expect(await SignIn.phoneNumberFieldElement).toBeDisplayed(); + await expect(await SignIn.phoneNumberFieldElement.getAttribute('placeholder')).toBe("Type phone number here..."); + await expect(await SignIn.emailFieldElement).toBeDisplayed(); + await expect(await SignIn.emailFieldElement.getAttribute('placeholder')).toBe("Type email here..."); - await expect(await (await SignIn.emailFieldElement.getCSSProperty('display')).value).toBe('block'); - console.log("emailField passed"); + }); - + // SignIn_003 + it('verifyAllIconsOnSignInPage', async () => { - await (await SignIn.phoneNumberFieldElement).click(); - //await (await SignIn.cancelPhoneBttnElement).waitForDisplayed(); - await expect(await (await SignIn.cancelPhoneBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); - await expect (await SignIn.cancelPhoneBttnElement).toBePresent(); - console.log(" cancel passed"); + const iconsVisibility = await SignIn.getIcons(); + for (const iconVisible of iconsVisibility) { + await expect(iconVisible).toBe(true); + } - await expect(await (await SignIn.sendVerificationPhoneBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); -await expect(await SignIn.sendVerificationPhoneBttnElement).toBeDisabled();; -console.log("Its Disabled passed"); + }); - }); -//SignIn_005 and SignIn_006 + //SignIn_004 + it('verifyAllButtonsAndFieldsAlignedAndPresent', async () => { -it('validateSendVerificationBttn',async() => { - // const randomNumber = Math.floor(40000000 + Math.random() * 9000000000); - const randomNumber = `4089${Math.floor(100000 + Math.random() * 900000)}`; + await expect(SignIn.phoneNumberFieldElement).toBePresent(); + await expect(SignIn.emailFieldElement).toBePresent(); - const randomEmail = `user${Date.now()}@email.com`; -// await ReadyPage.load(); + await expect(SignIn.twitterBttnElement).toBePresent(); -// await driver.pause(waitTime); -//await expect (await SignIn.signInLinkElement).toBeDisabled(); + await expect(SignIn.appleBttnElement).toBePresent(); -// await (await SignIn.signInLinkElement).click(); -await SignIn.phoneNumberFieldElement.click(); -console.log(randomNumber); -await SignIn.phoneNumberFieldElement.addValue(randomNumber); -await expect(await SignIn.sendVerificationPhoneBttnElement).toBeEnabled(); -console.log("phone verify passed"); -await SignIn.emailFieldElement.click(); -await SignIn.emailFieldElement.addValue(randomEmail); -await expect(await SignIn.sendVerificationEmailBttnElement).toBeEnabled(); -console.log(" email verify passed"); -}); + await expect(await (await SignIn.twitterBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); -//SignIn_009 -it('verifyColorForContents', async()=>{ + await expect(await (await SignIn.phoneNumberFieldElement.getCSSProperty('display')).value).toBe('block'); -//console.log('Background color twitter :', await(await (await SignIn.twitterBttnElement).getCSSProperty('background-color')).value); -//console.log('Background color apple :', await(await (await SignIn.appleBttnElement).getCSSProperty('background-color')).value); + await expect(await (await SignIn.emailFieldElement.getCSSProperty('display')).value).toBe('block'); -const twitterbackgroundColor = await (await SignIn.twitterBttnElement).getCSSProperty('background-color'); -const applebackgroundColor= await (await SignIn.appleBttnElement).getCSSProperty('background-color'); -const twitterTextColor= await (await SignIn.signInWithTwitterTextElement).getCSSProperty('color'); -const appleTextColor= await (await SignIn.signInWithAppleTextElement).getCSSProperty('color'); -// Convert 'rgba' to 'rgb' by removing the alpha value if present -await expect(await twitterbackgroundColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(85,172,238)'); + await (await SignIn.phoneNumberFieldElement).click(); + await expect(await (await SignIn.cancelPhoneBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); + await expect(await SignIn.cancelPhoneBttnElement).toBePresent(); -await expect(await applebackgroundColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(0,0,0)'); + await expect(await (await SignIn.sendVerificationPhoneBttnElement.getCSSProperty('display')).value).toBe('inline-flex'); + await expect(SignIn.sendVerificationPhoneBttnElement).toBeDisabled();; -await expect(await twitterTextColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(255,255,255)'); -await expect(await appleTextColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(255,255,255)'); - -}); + }); + //SignIn_005 and SignIn_006 -//SignIn_010 and -it('verifyTwitterSignInLinkResponsiveness',async()=>{ + it('validateSendVerificationBttn', async () => { + const randomNumber = `4089${Math.floor(100000 + Math.random() * 900000)}`; + const randomEmail = `user${Date.now()}@email.com`; + + await SignIn.phoneNumberFieldElement.click(); + await expect(SignIn.sendVerificationPhoneBttnElement).not.toBeEnabled(); -// await ReadyPage.load(); //await driver.pause(waitTime); + await SignIn.phoneNumberFieldElement.addValue(randomNumber); + await expect(SignIn.sendVerificationPhoneBttnElement).toBeEnabled(); + await SignIn.emailFieldElement.click(); + await expect (SignIn.sendVerificationEmailBttnElement).not.toBeEnabled(); -// await (await SignIn.signInLinkElement).waitForClickable(); -// await (await SignIn.signInLinkElement).click(); - // await driver.pause(waitTime); - await (await SignIn.twitterBttnElement).waitForClickable(); - await SignIn.twitterBttnElement.click(); - await driver.waitUntil(async () => { - return await driver.getTitle()=== 'X / Authorize an application'}, { - timeout: 5000, - }); - + await SignIn.emailFieldElement.addValue(randomEmail); + await expect(SignIn.sendVerificationEmailBttnElement).toBeEnabled(); - // await expect (await driver.getTitle()).toBe('Twitter / Authorize an application'); - -}); -//SignIn_013 and SignIn_014 -it('verifyAppleSignInLinkResponsiveness',async()=>{ -await (await SignIn.appleBttnElement).waitForClickable(); - await SignIn.appleBttnElement.click(); - await driver.waitUntil(async () => {return await driver.getTitle()=== 'Sign in to Apple Account'}, { - timeout: 5000, }); - await driver.back(); -}); + //SignIn_009 + it('verifyColorForContents', async () => { + const twitterbackgroundColor = await (SignIn.twitterBttnElement).getCSSProperty('background-color'); + const applebackgroundColor = await (SignIn.appleBttnElement).getCSSProperty('background-color'); + const twitterTextColor = await (SignIn.signInWithTwitterTextElement).getCSSProperty('color'); + const appleTextColor = await (SignIn.signInWithAppleTextElement).getCSSProperty('color'); + // Convert 'rgba' to 'rgb' by removing the alpha value if present + await expect(await twitterbackgroundColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(85,172,238)'); -//SignIn_15 and //SignIn_16 -it('verifyVisiblityOfPhoneAndEmailCancelAndSendBttn',async()=>{ - // let element = await SignIn.cancelPhoneBttnElement; - // console.log(element); - await SignIn.phoneNumberFieldElement.click(); - await expect(await SignIn.cancelPhoneBttnElement).toBeDisplayed(); - await expect(await SignIn.sendVerificationPhoneBttnElement).toBeDisplayed(); - await SignIn.emailFieldElement.click(); - await expect(await SignIn.cancelEmailBttnElement).toBeDisplayed(); - await expect(await SignIn.sendVerificationEmailBttnElement).toBeDisplayed(); + await expect(await applebackgroundColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(0,0,0)'); + await expect(await twitterTextColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(255,255,255)'); + await expect(await appleTextColor.value.replace('rgba', 'rgb').replace(/,\s*1\)$/, ')')).toBe('rgb(255,255,255)'); -}); + }); -//SignIn_017 and //SignIn_018 and //SignIn_019 and //SignIn_020 and //SignIn_021 and//SignIn_022 + //SignIn_010 + it('verifyTwitterSignInLinkResponsiveness', async () => { -it('verifyTabKeyFunctionality',async()=>{ - await driver.keys('Tab'); - // await browser.keys('Tab');//first press tab -await expect(await SignIn.closeBttnElement).toBeFocused(); -await driver.keys('Tab','Tab'); -await expect(await SignIn.twitterBttnElement).toBeFocused(); -await driver.keys('Tab','Tab','Tab'); -await expect(await SignIn.appleBttnElement).toBeFocused(); -await driver.keys('Tab','Tab','Tab','Tab'); -await expect(await SignIn.phoneNumberFieldElement).toBeFocused(); -}); + await SignIn.twitterBttnElement.waitForClickable(); + await SignIn.twitterBttnElement.click(); + await driver.waitUntil(async () => { + return await driver.getTitle() === 'X / Authorize an application' + }, { + timeout: 5000, + }); -// //SignIn_026 -// it.only('verifyEmailFieldPasteFunctionalityUsingKeyboard',async()=>{ -// const testdata='wevote@wevote.us' -// //await SignIn.emailFieldElement.click(); -// await SignIn.emailFieldElement.setValue(testdata); -// await driver.pause(5000); -// await driver.keys(['Command','a']) -// await driver.keys(['Command','c']); -// await driver.pause(5000); + }); + //SignIn_013 and SignIn_014 + it('verifyAppleSignInLinkResponsiveness', async () => { + await SignIn.appleBttnElement.waitForClickable(); + await SignIn.appleBttnElement.click(); + await driver.waitUntil(async () => { return await driver.getTitle() === 'Sign in to Apple Account' }, { + timeout: 5000, + }); + await driver.back(); + await expect(await SignIn.signInElement).toHaveText('Sign In or Join'); -// // await driver.keys([Key.Command,'a']) -// // await driver.keys([Key.Command,'c']) -// await SignIn.emailFieldElement.setValue(''); + }); -// //await SignIn.emailFieldElement.clearValue(); -// await driver.pause(5000); -// await driver.keys(['Command','v']); -// await driver.pause(5000); -// const value = await SignIn.emailFieldElement.getValue(); -// await expect(value).toBe(testdata); + //SignIn_15 and //SignIn_16 + it('verifyVisiblityOfPhoneAndEmailCancelAndSendBttn', async () => { + + await SignIn.phoneNumberFieldElement.click(); + await expect(SignIn.cancelPhoneBttnElement).toBeDisplayed(); + await expect(SignIn.sendVerificationPhoneBttnElement).toBeDisplayed(); + await SignIn.emailFieldElement.click(); + await expect(SignIn.cancelEmailBttnElement).toBeDisplayed(); + await expect(SignIn.sendVerificationEmailBttnElement).toBeDisplayed(); + }); -// }); -//SignIn_026 -it('verifyEmailFieldPasteFunctionalityUsingKeyboard',async()=>{ - // console.log(`This platform is ${platform}`); - // console.log(process.env); - const testdata='wevote@wevote.us'; - const valueLength = testdata.length; + //SignIn_017 and //SignIn_018 and //SignIn_019 and //SignIn_020 and //SignIn_021 and//SignIn_022 - const selector=await SignIn.emailFieldElement; - await (await SignIn.emailFieldElement).setValue(testdata); - await driver.pause(5000); -// if (process.platform === 'darwin') { -// console.log("running in macos");} -// else { -// console.log("running inother os"); -// } - //await SignIn.emailFieldElement.click(); -const platformName = browser.capabilities.platformName; // Gets the platform like 'Windows', 'macOS' -const browserName=browser.capabilities.browserName; -console.log(`Platform: ${platformName}`); -console.log(`Browser: ${browserName}`); -if(platformName==='Windows XP'&& browserName==='chrome'){ + it('verifyTabKeyFunctionality', async () => { + await driver.keys('Tab'); + // await browser.keys('Tab');//first press tab + await expect(await SignIn.closeBttnElement).toBeFocused(); + await driver.keys('Tab', 'Tab'); + await expect(await SignIn.twitterBttnElement).toBeFocused(); + await driver.keys('Tab', 'Tab', 'Tab'); + await expect(await SignIn.appleBttnElement).toBeFocused(); + await driver.keys('Tab', 'Tab', 'Tab', 'Tab'); + await expect(await SignIn.phoneNumberFieldElement).toBeFocused(); + }); -await browser.keys([Key.Control,'a']); -//await browser.keys('NULL'); // Releases the Ctrl key -await browser.keys([Key.Control,'c']); -//await browser.keys('NULL'); -//for (let i = 0; i < valueLength; i++) { // Releases the Ctrl key - await browser.keys(Key.Backspace); - await SignIn.emailFieldElement.click(); - await browser.keys([Key.Control,'v']); -} + //SignIn_026 + it('verifyEmailFieldPasteFunctionalityUsingKeyboard', async () => { + + const testdata = 'wevote@wevote.us'; + const valueLength = testdata.length; -if(platformName==='mac'&& browserName==='Safari') - { //For macOS, the correct value for process.platform is "darwin" -await browser.keys([Key.Command,'a']); - await browser.keys([Key.Command,'c']); + const selector = await SignIn.emailFieldElement; + await SignIn.emailFieldElement.setValue(testdata); + await driver.pause(5000); + + const platformName = browser.capabilities.platformName; // Gets the platform like 'Windows', 'macOS' + const browserName = browser.capabilities.browserName; + console.log(`Platform: ${platformName}`); + console.log(`Browser: ${browserName}`); + if (platformName === 'Windows XP' && browserName === 'chrome') { - await browser.keys(Key.Backspace); - await driver.keys([Key.Command,'v']); + await browser.keys([Key.Control, 'a']); + //await browser.keys('NULL'); // Releases the Ctrl key + await browser.keys([Key.Control, 'c']); + //await browser.keys('NULL'); + //for (let i = 0; i < valueLength; i++) { // Releases the Ctrl key + await browser.keys(Key.Backspace); + await SignIn.emailFieldElement.click(); + await browser.keys([Key.Control, 'v']); + } - } + if (platformName === 'mac' && browserName === 'Safari') { //For macOS, the correct value for process.platform is "darwin" + await browser.keys([Key.Command, 'a']); + await browser.keys([Key.Command, 'c']); - const value = await SignIn.emailFieldElement.getValue(); - await expect(value).toBe(testdata); - + await browser.keys(Key.Backspace); + await driver.keys([Key.Command, 'v']); -}); -// //SignIn_028 -it('verifyEmailFieldWithValidAddress',async()=>{ - const testData='wevote@wevote.us'; - await SignIn.emailFieldElement.click(); - await (await SignIn.emailFieldElement).addValue(testData); - await (await SignIn.sendVerificationEmailBttnElement).click(); - const textData=await SignIn.codeVerifyElement.getText(); -await expect(textData).toBe('Code Verification'); + } + const value = await SignIn.emailFieldElement.getValue(); + await expect(value).toBe(testdata); -}); -//SignIn_029 //SignIn_030 -it('verifyEmailFieldWithInvalidAddress',async()=>{ - const testDataNumber='11111'; - const testDataUrl= 'wevotewevote.us'; - await SignIn.emailFieldElement.click(); - await (await SignIn.emailFieldElement).addValue(testDataNumber); -const isClickableNumber=await(await SignIn.sendVerificationEmailBttnElement).isClickable(); - await expect(isClickableNumber).toBe(false); - await (await SignIn.emailFieldElement).setValue(testDataUrl); - const isClickableURL=await(await SignIn.sendVerificationEmailBttnElement).isClickable(); - await expect(isClickableURL).toBe(false); + }); + // //SignIn_028 + it('verifyEmailFieldWithValidAddress', async () => { + const testData = 'wevote@wevote.us'; + await SignIn.emailFieldElement.click(); + await SignIn.emailFieldElement.addValue(testData); + await SignIn.sendVerificationEmailBttnElement.click(); + const textData = await SignIn.codeVerifyElement.getText(); + await expect(textData).toBe('Code Verification'); }); + //SignIn_029 //SignIn_030 + it('verifyEmailFieldWithInvalidAddress', async () => { + const testDataNumber = '11111'; + const testDataUrl = 'wevotewevote.us'; + await SignIn.emailFieldElement.click(); + await SignIn.emailFieldElement.addValue(testDataNumber); + const isClickableNumber = await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isClickableNumber).toBe(false); + await SignIn.emailFieldElement.setValue(testDataUrl); + const isClickableURL = await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isClickableURL).toBe(false); - //SignIn_031 //SignIn_033 //SignIn_034 //SignIn_035 //SignIn_036 -it("verifyEmailFieldAcceptsOnlyLatinLetters",async()=>{ - -const withLatinLettersOnly=`${SignIn.randomString(6)}@wevote.us`; -//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)}@wevote.us`; - //const lettersWithDecimalOnly=`${randomString(6,false,true)}@wevote.us`; -// const lettersWithUnderscoreOnly=`${randomString(6,false,false,true)}@wevote.us`; -// + }); -// const lettersWithDashOnly=`${randomString(6,false,false,false,true)}@wevote.us`; -await (await SignIn.emailFieldElement).setValue(withLatinLettersOnly); -const emailValue= await (await SignIn.emailFieldElement).getValue(); -console.log('email value ',emailValue); + //SignIn_031 + it("verifyEmailFieldAcceptsOnlyLatinLetters", async () => { -//await expect(emailValue).toBe(emailWithLatinLettersOnly); -await expect(emailValue).toMatch(/^[a-zA-Z]+@wevote\.us$/); -let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); -await expect(isDisplayed).toBe(true); -//await (await SignIn.emailFieldElement).click(); // Focus on the field -// Use JavaScript to select all text in the input field + const withLatinLettersOnly = `${SignIn.randomString(6)}@wevote.us`; + await SignIn.emailFieldElement.setValue(withLatinLettersOnly); + const emailValue = await SignIn.emailFieldElement.getValue(); + console.log('email value ', emailValue); + await expect(emailValue).toMatch(/^[a-zA-Z]+@wevote\.us$/); + let isDisplayed = await SignIn.sendVerificationEmailBttnElement.isClickable(); + await expect(isDisplayed).toBe(true); -//await (await SignIn.emailFieldElement).doubleClick(); // Focus on the field - await (await SignIn.emailFieldElement).setValue(''); // Clear using setValue - await driver.pause(waitTime); // Pause to ensure value is cleared + //await SignIn.emailFieldElement.setValue(''); // Clear using setValue + // await driver.pause(waitTime); // Pause to ensure value is cleared -// await (await SignIn.emailFieldElement).setValue(lettersWithNumOnly); -// const valueWithNum= await (await SignIn.emailFieldElement).getValue(); -// console.log('email value ',valueWithNum); -// await expect(valueWithNum).toMatch(/^[a-zA-Z0-9]+@wevote\.us$/); -}); -//SignIn_033 - -it("verifyEmailFieldAcceptsLettersWithNum",async()=>{ -const lettersWithNumOnly=`${SignIn.randomString(6,true)}@wevote.us`;//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} -// or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; - await (await SignIn.emailFieldElement).setValue(lettersWithNumOnly); - const valueWithNum= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueWithNum); - await expect(valueWithNum).toMatch(/^[a-zA-Z0-9]+@wevote\.us$/); - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); - await expect(isDisplayed).toBe(true); -//*************************setvalue/cleae value not working ********************/ - -// await (await SignIn.emailFieldElement).clearValue();; -// await driver.pause(10000); -// await (await SignIn.emailFieldElement).setValue(''); -// await driver.pause(10000); -//******************************************************************************** + }); + //SignIn_033 + + it("verifyEmailFieldAcceptsLettersWithNum", async () => { + const lettersWithNumOnly = `${SignIn.randomString(6, true)}@wevote.us`;//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} + // or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; + await (await SignIn.emailFieldElement).setValue(lettersWithNumOnly); + const valueWithNum = await (await SignIn.emailFieldElement).getValue(); + console.log('email value ', valueWithNum); + await expect(valueWithNum).toMatch(/^[a-zA-Z0-9]+@wevote\.us$/); + let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isDisplayed).toBe(true); + + }); + //SignIn_034 + it("verifyEmailFieldAcceptsLettersWithDecimal", async () => { + const lettersWithDecimalOnly = `${SignIn.randomString(2)}.${SignIn.randomString(2)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersWithDecimalOnly); + const valueWithDec = await (await SignIn.emailFieldElement).getValue(); + console.log('email value ', valueWithDec); + await expect(valueWithDec).toMatch(/^[a-zA-Z.]*\.[a-zA-Z.]*@wevote\.us$/); + let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + + await expect(isDisplayed).toBe(true); + }); + //SignIn_035 + it("verifyEmailFieldAcceptsLettersWithUnderscore", async () => { + const lettersWithUnderscore = `${SignIn.randomString(2)}_${SignIn.randomString(2)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersWithUnderscore); + const valueWithUnderscore = await (await SignIn.emailFieldElement).getValue(); + console.log('email value ', valueWithUnderscore); + await expect(valueWithUnderscore).toMatch(/^[a-zA-Z]*\_[a-zA-Z]*@wevote\.us$/); + let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isDisplayed).toBe(true); + }); + // //SignIn_036 + it("verifyEmailFieldAcceptsLettersWithDash", async () => { + const lettersWithDash = `${SignIn.randomString(3)}-${SignIn.randomString(3)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersWithDash); + const valueWithDash = await (await SignIn.emailFieldElement).getValue(); + console.log('email value ', valueWithDash); + await expect(valueWithDash).toMatch(/^[a-zA-Z]*\-[a-zA-Z]*@wevote\.us$/); + let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isClickable(); + await expect(isDisplayed).toBe(true); + }); + // //SignIn_037 + it("verifyEmailFieldDoesntAcceptStartWithDot", async () => { + const lettersStartWithDot = `.${SignIn.randomString(4)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersStartWithDot); + const valueStarWithDot = await (await SignIn.emailFieldElement).getValue(); + console.log('email value ', valueStarWithDot); + await expect(valueStarWithDot).toMatch(/^\.[a-zA-Z]*@wevote\.us$/); + let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(false); + }); + // //SignIn_040 + it("verifyEmailFieldDoesntAcceptStartWithDomain", async () => { + const lettersStartWithDomain = `@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersStartWithDomain); + const valueStarWithDomain = await (await SignIn.emailFieldElement).getValue(); + console.log('email value ', valueStarWithDomain); + await expect(valueStarWithDomain).toMatch(/^@wevote\.us$/); + let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(false); -}); -//SignIn_034 -it("verifyEmailFieldAcceptsLettersWithDecimal",async()=>{ - const lettersWithDecimalOnly=`${SignIn.randomString(2)}.${SignIn.randomString(2)}@wevote.us`; -//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} - // or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; - await (await SignIn.emailFieldElement).setValue(lettersWithDecimalOnly); - const valueWithDec= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueWithDec); - await expect(valueWithDec).toMatch(/^[a-zA-Z.]*\.[a-zA-Z.]*@wevote\.us$/); - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); - await expect(isDisplayed).toBe(true); }); - //SignIn_035 -it("verifyEmailFieldAcceptsLettersWithUnderscore",async()=>{ - const lettersWithUnderscore=`${SignIn.randomString(2)}_${SignIn.randomString(2)}@wevote.us`; -//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} - // or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; - await (await SignIn.emailFieldElement).setValue(lettersWithUnderscore); - const valueWithUnderscore= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueWithUnderscore); - await expect(valueWithUnderscore).toMatch(/^[a-zA-Z]*\_[a-zA-Z]*@wevote\.us$/); - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); - await expect(isDisplayed).toBe(true); -}); -// //SignIn_036 -it("verifyEmailFieldAcceptsLettersWithDash",async()=>{ - const lettersWithDash=`${SignIn.randomString(3)}-${SignIn.randomString(3)}@wevote.us`; -//const lettersWithNumOnly=`${SignIn.randomString(6,true,false,false,false)} - // or only need to use the parameters that are relevant for the string you want to generate. If you want a random string that includes numbers but excludes decimals, underscores, and dashes, you can simply call: const lettersWithNumOnly=`${SignIn.randomString(6,true)}`; - await (await SignIn.emailFieldElement).setValue(lettersWithDash); - const valueWithDash= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueWithDash); - await expect(valueWithDash).toMatch(/^[a-zA-Z]*\-[a-zA-Z]*@wevote\.us$/); - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isClickable(); - await expect(isDisplayed).toBe(true); - }); - // //SignIn_037 -it("verifyEmailFieldDoesntAcceptStartWithDot",async()=>{ - const lettersStartWithDot=`.${SignIn.randomString(4)}@wevote.us`; - - await (await SignIn.emailFieldElement).setValue(lettersStartWithDot); - const valueStarWithDot= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueStarWithDot); - await expect(valueStarWithDot).toMatch(/^\.[a-zA-Z]*@wevote\.us$/); - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); - await expect(isDisplayed).toBe(false); -}); -// //SignIn_040 -it("verifyEmailFieldDoesntAcceptStartWithDomain",async()=>{ - const lettersStartWithDomain=`@wevote.us`; - await (await SignIn.emailFieldElement).setValue(lettersStartWithDomain); - const valueStarWithDomain= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueStarWithDomain); - await expect(valueStarWithDomain).toMatch(/^@wevote\.us$/); - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); - await expect(isDisplayed).toBe(false); + //SignIn_042 //This code works only in Running in Safari only so commented out + // it("verifyEmailFieldDoesntAcceptSpaces", async () => { + + + // const browserName = browser.capabilities.browserName; + // console.log(`Platform: ${platformName}`); + // console.log(`Browser: ${browserName}`); + + // await (await SignIn.emailFieldElement).click(); + // await (await SignIn.emailFieldElement).addValue(`${SignIn.randomString(2)}`); + // await (await SignIn.emailFieldElement).addValue(' '); + // await (await SignIn.emailFieldElement).addValue(`${SignIn.randomString(2)}@wevote.us`); + // const valueWithSpace = await (await SignIn.emailFieldElement).getValue(); + // console.log('email value ', valueWithSpace); + // await expect(valueWithSpace).toMatch(/^[a-zA-Z]* [a-zA-Z]*@wevote\.us$/); + // let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + // await expect(isDisplayed).toBe(false); + + // }); + //SignIn_045 + it("verifyEmailFieldWithBlank", async () => { + + await (await SignIn.emailFieldElement).setValue(' '); + const valueWithBlank = await (await SignIn.emailFieldElement).getValue(); + console.log('email value ', valueWithBlank); + await expect(valueWithBlank).toMatch(/^$/); // Validating that the value is empty + let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(false); -}); - - //SignIn_042 -it("verifyEmailFieldDoesntAcceptSpaces",async()=>{ - //*******************************Running in Safari only******************************************* */ - // const randomletters = `${SignIn.randomString(4)}`; - // const withSpace = ' '; - - // const randomletters1 = `${SignIn.randomString(2)}@wevote.us`; - // const lettersWithSpace = randomletters+withSpace+randomletters1 ; - // const lettersWithSpace=`${SignIn.randomString(2)} ${SignIn.randomString(1)}@wevote.us`; - if (os.platform() === 'win32') { - console.log('Running on Windows'); -} else if (os.platform() === 'darwin') { - console.log('Running on macOS'); -} else { - console.log(`Running on ${os.platform()}`); -} const platformName = browser.capabilities.platformName; // Gets the platform like 'Windows', 'macOS' - - const browserName = browser.capabilities.browserName; - console.log(`Platform: ${platformName}`); - console.log(`Browser: ${browserName}`); - - //space in chrome-windows not counted - // const lettersWithSpace=`${SignIn.randomString(2)} ${SignIn.randomString(2)}@wevote.us`; - - //const lettersWithSpace='We Vote@wevote.us'; - await (await SignIn.emailFieldElement).click(); - - - - - - await (await SignIn.emailFieldElement).addValue(`${SignIn.randomString(2)}`); - await (await SignIn.emailFieldElement).addValue(' '); - await (await SignIn.emailFieldElement).addValue(`${SignIn.randomString(2)}@wevote.us`); - const valueWithSpace= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueWithSpace); - await expect(valueWithSpace).toMatch(/^[a-zA-Z]* [a-zA-Z]*@wevote\.us$/); - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); - await expect(isDisplayed).toBe(false); + }); + // //SignIn_046 + it("verifyEmailFieldAcceptsLettersWithTwoDots", async () => { + const lettersWithDoubleDots = `${SignIn.randomString(2)}.${SignIn.randomString(1)}.${SignIn.randomString(2)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersWithDoubleDots); + const valueWithTwoDots = await (await SignIn.emailFieldElement).getValue(); + console.log('email value ', valueWithTwoDots); + await expect(valueWithTwoDots).toMatch(/^[a-zA-Z]*\.[a-zA-Z]*\.[a-zA-Z]*@wevote\.us$/); + let isDisplayed = await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); + await expect(isDisplayed).toBe(true); + }); -}); -//SignIn_045 -it("verifyEmailFieldWithBlank",async()=>{ + //SignIn_047 + for (let email of testEmails) { + it('verifyEmailFieldAcceptsCharactersBetween6to254', async () => { - await (await SignIn.emailFieldElement).setValue(' '); - const valueWithBlank= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueWithBlank); - await expect(valueWithBlank).toMatch(/^$/); // Validating that the value is empty - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); - await expect(isDisplayed).toBe(false); -}); - // //SignIn_046 -it("verifyEmailFieldAcceptsLettersWithTwoDots",async()=>{ - const lettersWithDoubleDots=`${SignIn.randomString(2)}.${SignIn.randomString(1)}.${SignIn.randomString(2)}@wevote.us`; - await (await SignIn.emailFieldElement).setValue(lettersWithDoubleDots); - const valueWithTwoDots= await (await SignIn.emailFieldElement).getValue(); - console.log('email value ',valueWithTwoDots); - await expect(valueWithTwoDots).toMatch(/^[a-zA-Z]*\.[a-zA-Z]*\.[a-zA-Z]*@wevote\.us$/); - let isDisplayed= await (await SignIn.sendVerificationEmailBttnElement).isEnabled(); - await expect(isDisplayed).toBe(true); -}); + console.log(`Testing email: ${email}`); + console.log('email length:', email.length); -//SignIn_047 -for(let email of testEmails){ -it('verifyEmailFieldAcceptsCharactersBetween6to254',async()=>{ - - - console.log(`Testing email: ${email}`); - console.log('email length:',email.length); + await (await SignIn.emailFieldElement).setValue(email); + const emailValue = await (await SignIn.emailFieldElement).getValue(); + //console.log('email value ',emailValue); + const len = emailValue.length; + if (len >= 6 && len <= 254) { + await expect(await SignIn.cancelEmailBttnElement).toBeDisplayed(); - await (await SignIn.emailFieldElement).setValue(email); - const emailValue= await (await SignIn.emailFieldElement).getValue(); -//console.log('email value ',emailValue); -const len=emailValue.length; -if(len>=6 && len<=254){ - await expect(await SignIn.cancelEmailBttnElement).toBeDisplayed(); + await expect(await SignIn.sendVerificationEmailBttnElement).toBeEnabled(); + } else { -await expect(await SignIn.sendVerificationEmailBttnElement).toBeEnabled(); -}else{ + await expect(await SignIn.cancelEmailBttnElement).toBeDisplayed(); - await expect(await SignIn.cancelEmailBttnElement).toBeDisplayed(); + await expect(await SignIn.sendVerificationEmailBttnElement).not.toBeEnabled(); -await expect(await SignIn.sendVerificationEmailBttnElement).not.toBeEnabled(); + } + }); } + // //SignIn_052 + it('verifyBackButtonOnVerificationPage', async () => { + const lettersWithDoubleDots = `${SignIn.randomString(2)}.${SignIn.randomString(5)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(lettersWithDoubleDots); + + await (await SignIn.sendVerificationEmailBttnElement).click(); + await driver.waitUntil(async () => { + return await (await SignIn.codeVerifyElement).getText() === 'Code Verification' + }, { + timeout: 5000, + }); + await (await SignIn.backButtonElement).click(); + await expect(await SignIn.sendVeificationAgainElement).toBeDisplayed(); -}); -} - // //SignIn_052 - it('verifyBackButtonOnVerificationPage',async()=>{ - const lettersWithDoubleDots=`${SignIn.randomString(2)}.${SignIn.randomString(5)}@wevote.us`; - await (await SignIn.emailFieldElement).setValue(lettersWithDoubleDots); - - await (await SignIn.sendVerificationEmailBttnElement).click(); - await driver.waitUntil(async () => { - return await (await SignIn.codeVerifyElement).getText()=== 'Code Verification'}, { - timeout: 5000, - }); - await (await SignIn.backButtonElement).click(); - await expect (await SignIn.sendVeificationAgainElement).toBeDisplayed(); + }); -}); + // //SignIn_054 + it('verifyCancelButtonClearEmailField', async () => { + const email = `${SignIn.randomString(5)}@wevote.us`; + await (await SignIn.emailFieldElement).setValue(email); -// //SignIn_054 -it('verifyCancelButtonClearEmailField',async()=>{ - const email=`${SignIn.randomString(5)}@wevote.us`; - await (await SignIn.emailFieldElement).setValue(email); - - await (await SignIn.cancelEmailBttnElement).click(); - const fieldvalue = await (await SignIn.emailFieldElement).getValue(); - await expect(fieldvalue).toBe(''); - await expect(await SignIn.cancelEmailBttnElement).not.toBeDisplayed(); - await expect(await SignIn.sendVerificationEmailBttnElement).not.toBeDisplayed(); + await (await SignIn.cancelEmailBttnElement).click(); + const fieldvalue = await (await SignIn.emailFieldElement).getValue(); + await expect(fieldvalue).toBe(''); + await expect(await SignIn.cancelEmailBttnElement).not.toBeDisplayed(); + await expect(await SignIn.sendVerificationEmailBttnElement).not.toBeDisplayed(); - //***********Both assertion works same way************************* - //await expect(fieldvalue).toHaveLength(0); - //await expect(fieldvalue).toEqual(''); -//*********************************************************** */ + //***********Both assertion works same way************************* + //await expect(fieldvalue).toHaveLength(0); + //await expect(fieldvalue).toEqual(''); + //*********************************************************** */ -}); + }); }); \ No newline at end of file From 1f92203a1d14646c77bf71125e2f9718da49bd28 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Mon, 7 Oct 2024 11:36:14 -0700 Subject: [PATCH 22/54] [WV-581]Modal for learn more created BoostLearnMoreModal.jsx and added here src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx --- .../BoostLearnMoreModal.jsx | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx new file mode 100644 index 000000000..009be4fc5 --- /dev/null +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -0,0 +1,211 @@ +import withStyles from '@mui/styles/withStyles'; +import withTheme from '@mui/styles/withTheme'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import ModalDisplayTemplateA, { templateAStyles, TextFieldWrapper } from '../../../components/Widgets/ModalDisplayTemplateA'; +import { renderLog } from '../../utils/logging'; +import stringContains from '../../utils/stringContains'; +import CandidateStore from '../../../stores/CandidateStore'; +import MeasureStore from '../../../stores/MeasureStore'; +import SupportStore from '../../../stores/SupportStore'; +import PayToPromoteProcess from '../CampaignSupport/PayToPromoteProcess'; + +// const PayToPromoteProcess = React.lazy(() => import(/* webpackChunkName: 'PayToPromoteProcess' */ './PayToPromoteProcess')); // eslint-disable-line import/no-cycle + +class BoostLearnMoreModal extends Component { + constructor (props) { + super(props); + this.state = { + }; + } + + componentDidMount () { + this.supportStoreListener = SupportStore.addListener(this.onSupportStoreChange.bind(this)); + // this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this)); + this.candidateStoreListener = CandidateStore.addListener(this.onCandidateStoreChange.bind(this)); + this.measureStoreListener = MeasureStore.addListener(this.onMeasureStoreChange.bind(this)); + const { ballotItemWeVoteId } = this.props; + const ballotItemStatSheet = SupportStore.getBallotItemStatSheet(ballotItemWeVoteId); + if (ballotItemStatSheet) { + const { voterOpposesBallotItem, voterSupportsBallotItem } = ballotItemStatSheet; + this.setState({ + voterOpposesBallotItem, + voterSupportsBallotItem, + }); + } + + // const voter = VoterStore.getVoter(); + // const voterIsSignedIn = VoterStore.getVoterIsSignedIn(); + // const { voter_photo_url_medium: voterPhotoUrlMedium } = voter; + + let ballotItemDisplayName = ''; + // let ballotItemType; + let campaignXWeVoteId; + let isCandidate = false; + let isMeasure = false; + if (stringContains('cand', this.props.ballotItemWeVoteId)) { + const candidate = CandidateStore.getCandidateByWeVoteId(this.props.ballotItemWeVoteId); + ballotItemDisplayName = candidate.ballot_item_display_name || ''; + // ballotItemType = 'CANDIDATE'; + campaignXWeVoteId = candidate.linked_campaignx_we_vote_id || ''; + isCandidate = true; + } else if (stringContains('meas', this.props.ballotItemWeVoteId)) { + const measure = MeasureStore.getMeasure(this.props.ballotItemWeVoteId); + ballotItemDisplayName = measure.ballot_item_display_name || ''; + // ballotItemType = 'MEASURE'; + isMeasure = true; + } + this.setState({ + ballotItemDisplayName, + // ballotItemType, + campaignXWeVoteId, + isCandidate, + isMeasure, + // voterIsSignedIn, + // voterPhotoUrlMedium, + }); + } + + componentDidUpdate () { + const { initialFocusSet } = this.state; + if (this.positionInput) { + // Set the initial focus at the end of any existing text + if (!initialFocusSet) { + const { positionInput } = this; + const { length } = positionInput.value; + positionInput.focus(); + positionInput.setSelectionRange(length, length); + this.setState({ + initialFocusSet: true, + }); + } + } + } + + componentWillUnmount () { + this.candidateStoreListener.remove(); + this.measureStoreListener.remove(); + this.supportStoreListener.remove(); + // this.voterStoreListener.remove(); + } + + onCandidateStoreChange () { + if (this.state.isCandidate) { + const { ballotItemWeVoteId } = this.props; + const candidate = CandidateStore.getCandidateByWeVoteId(ballotItemWeVoteId); + const ballotItemDisplayName = candidate.ballot_item_display_name || ''; + const campaignXWeVoteId = candidate.linked_campaignx_we_vote_id || ''; + this.setState({ + ballotItemDisplayName, + campaignXWeVoteId, + }); + } + } + + onMeasureStoreChange () { + if (this.state.isMeasure) { + const { ballotItemWeVoteId } = this.props; + const measure = MeasureStore.getMeasure(ballotItemWeVoteId); + const ballotItemDisplayName = measure.ballot_item_display_name || ''; + this.setState({ + ballotItemDisplayName, + }); + } + } + + onSupportStoreChange () { + const { ballotItemWeVoteId } = this.props; + const ballotItemStatSheet = SupportStore.getBallotItemStatSheet(ballotItemWeVoteId); + let voterOpposesBallotItem = ''; + let voterSupportsBallotItem = ''; + // let voterTextStatement = ''; + // let voterPositionIsPublic = ''; + if (ballotItemStatSheet) { + ({ voterOpposesBallotItem, voterSupportsBallotItem } = ballotItemStatSheet); + } + this.setState({ + voterOpposesBallotItem, + voterSupportsBallotItem, + }); + + // if (ballotItemStatSheet) { + // ({ voterPositionIsPublic, voterTextStatement } = ballotItemStatSheet); + // } + // this.setState({ + // voterTextStatement, + // voterPositionIsPublic, + // }); + } + + // onVoterStoreChange () { + // const voter = VoterStore.getVoter(); + // const voterIsSignedIn = VoterStore.getVoterIsSignedIn(); + // const { voter_photo_url_medium: voterPhotoUrlMedium } = voter; + // this.setState({ + // voterIsSignedIn, + // voterPhotoUrlMedium, + // }); + // } + + render () { + renderLog('BoostLearnMoreModal'); // Set LOG_RENDER_EVENTS to log all renders + // const { ballotItemWeVoteId } = this.props; + const { show } = this.props; + // console.log('BoostLearnMoreModal render, ballotItemWeVoteId: ', ballotItemWeVoteId, ', show: ', show); + const { + // ballotItemDisplayName, + campaignXWeVoteId, + // voterOpposesBallotItem, voterSupportsBallotItem, + } = this.state; + + // const horizontalEllipsis = '\u2026'; + let dialogTitleText = ''; + + // if (voterSupportsBallotItem) { + // if (ballotItemDisplayName) { + // dialogTitleText = `Why you chose ${ballotItemDisplayName}${horizontalEllipsis}`; + // } else { + // dialogTitleText = `Why you support${horizontalEllipsis}`; + // } + // } else if (voterOpposesBallotItem) { + // if (ballotItemDisplayName) { + // dialogTitleText = `Why you oppose ${ballotItemDisplayName}${horizontalEllipsis}`; + // } else { + // dialogTitleText = `Why you oppose${horizontalEllipsis}`; + // } + // } else if (ballotItemDisplayName) { + // dialogTitleText = `Your thoughts about ${ballotItemDisplayName}${horizontalEllipsis}`; + // } else { + // dialogTitleText = `Your thoughts${horizontalEllipsis}`; + // } + dialogTitleText = ''; // Overwrite until we can adjust + + // console.log('BoostLearnMoreModal render, voter_address_object: ', voter_address_object); + const textFieldJSX = ( + + + + ); + + return ( + {dialogTitleText}} + show={show} + tallMode + textFieldJSX={textFieldJSX} + toggleModal={this.props.toggleModal} + /> + ); + } +} +BoostLearnMoreModal.propTypes = { + ballotItemWeVoteId: PropTypes.string.isRequired, + show: PropTypes.bool, + toggleModal: PropTypes.func.isRequired, +}; + +export default withTheme(withStyles(templateAStyles)(BoostLearnMoreModal)); From 47d91c3c9fbaffa600fd3fdd3ce8b0217028010d Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Mon, 7 Oct 2024 12:51:13 -0700 Subject: [PATCH 23/54] Refactor BoostLearnMoreModal and ChallengeInviteSteps components for improved functionality --- .../BoostLearnMoreModal.jsx | 8 +++--- .../Navigation/ChallengeInviteSteps.jsx | 25 +++++++++++++++++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx index 009be4fc5..36c835339 100644 --- a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -193,10 +193,12 @@ class BoostLearnMoreModal extends Component { return ( {dialogTitleText}} + // dialogTitleJSX={<>{dialogTitleText}} commented because it is not working but can restore if needed show={show} - tallMode - textFieldJSX={textFieldJSX} + dialogTitleJSX={
Learn More
} + textFieldJSX={
Your content here
} + // tallMode commented because it is not working but can restore if needed + // textFieldJSX={textFieldJSX} commented because it is not working but can restore if needed toggleModal={this.props.toggleModal} /> ); diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index aba53bd79..f421bffb6 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Suspense } from 'react'; import { Link, withRouter } from 'react-router-dom'; import PropTypes from 'prop-types'; import { withStyles } from '@mui/styles'; @@ -13,6 +13,8 @@ import StepOneActiveIcon from '../../../../img/global/svg-icons/issues/material- import StepTwoIcon from '../../../../img/global/svg-icons/issues/material-symbols-counter-2.svg'; import StepTwoActiveIcon from '../../../../img/global/svg-icons/issues/material-symbols-counter-2-active.svg'; +const BoostLearnMoreModal = React.lazy(() => import(/* webpackChunkName: 'BoostLearnMoreModal' */ '../ChallengeInviteFriends/BoostLearnMoreModal')); + // Color and font variables const commonTextStyle = { fontSize: '13px', @@ -29,8 +31,10 @@ class ChallengeInviteSteps extends React.Component { super(props); this.state = { activeStep: this.getActiveStepFromPath(), + showBoostLearnMoreModal: false, }; } + // Get the current step based on the URL to determine which step is active by default when the page loads getActiveStepFromPath = () => { const { location } = this.props; @@ -65,6 +69,13 @@ class ChallengeInviteSteps extends React.Component { this.setState({ activeStep: stepNumber }); }; + // Function to toggle modal visibility + toggleBoostLearnMoreModal = () => { + this.setState((prevState) => ({ + showBoostLearnMoreModal: !prevState.showBoostLearnMoreModal, + })); + }; + render() { return ( @@ -80,7 +91,7 @@ class ChallengeInviteSteps extends React.Component { - @@ -128,6 +139,16 @@ class ChallengeInviteSteps extends React.Component { + {/* Render BoostLearnMoreModal */} + }> + {this.state.showBoostLearnMoreModal && ( + + )} + ); } From ef850308483789cc4aa6e03c13ea3cb1f14c5ff8 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Mon, 7 Oct 2024 13:15:35 -0700 Subject: [PATCH 24/54] Refactor BoostLearnMoreModal and ChallengeInviteSteps components for improved functionality --- .../components/ChallengeInviteFriends/BoostLearnMoreModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx index 36c835339..6006aa963 100644 --- a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -196,7 +196,7 @@ class BoostLearnMoreModal extends Component { // dialogTitleJSX={<>{dialogTitleText}} commented because it is not working but can restore if needed show={show} dialogTitleJSX={
Learn More
} - textFieldJSX={
Your content here
} + textFieldJSX={
Learn more content here
} // tallMode commented because it is not working but can restore if needed // textFieldJSX={textFieldJSX} commented because it is not working but can restore if needed toggleModal={this.props.toggleModal} From 055aed8f4a2b2253870956d00c26c85d48d512f7 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Tue, 8 Oct 2024 14:38:31 -0700 Subject: [PATCH 25/54] delete unnecesary div --- .../ChallengeInviteFriends/BoostLearnMoreModal.jsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx index 6006aa963..833f353f9 100644 --- a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -8,7 +8,6 @@ import stringContains from '../../utils/stringContains'; import CandidateStore from '../../../stores/CandidateStore'; import MeasureStore from '../../../stores/MeasureStore'; import SupportStore from '../../../stores/SupportStore'; -import PayToPromoteProcess from '../CampaignSupport/PayToPromoteProcess'; // const PayToPromoteProcess = React.lazy(() => import(/* webpackChunkName: 'PayToPromoteProcess' */ './PayToPromoteProcess')); // eslint-disable-line import/no-cycle @@ -183,11 +182,8 @@ class BoostLearnMoreModal extends Component { // console.log('BoostLearnMoreModal render, voter_address_object: ', voter_address_object); const textFieldJSX = ( - + +
Learn more content here
); @@ -196,9 +192,9 @@ class BoostLearnMoreModal extends Component { // dialogTitleJSX={<>{dialogTitleText}} commented because it is not working but can restore if needed show={show} dialogTitleJSX={
Learn More
} - textFieldJSX={
Learn more content here
} + //textFieldJSX={
Learn more content here
} // tallMode commented because it is not working but can restore if needed - // textFieldJSX={textFieldJSX} commented because it is not working but can restore if needed + textFieldJSX={textFieldJSX} toggleModal={this.props.toggleModal} /> ); From 5b88ce367dbc194a38b335cc7600f2913a85f8d6 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Tue, 8 Oct 2024 16:08:39 -0700 Subject: [PATCH 26/54] delete unnecesary div --- .../components/ChallengeInviteFriends/BoostLearnMoreModal.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx index 833f353f9..643e6fc07 100644 --- a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -8,6 +8,7 @@ import stringContains from '../../utils/stringContains'; import CandidateStore from '../../../stores/CandidateStore'; import MeasureStore from '../../../stores/MeasureStore'; import SupportStore from '../../../stores/SupportStore'; +import PayToPromoteProcess from '../CampaignSupport/PayToPromoteProcess'; // const PayToPromoteProcess = React.lazy(() => import(/* webpackChunkName: 'PayToPromoteProcess' */ './PayToPromoteProcess')); // eslint-disable-line import/no-cycle From 6fe93236a013a69f304b4dba3969b9fae48a75f2 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Sat, 5 Oct 2024 13:42:13 -0700 Subject: [PATCH 27/54] rename to change h2 and button to custom style name component remove css for img becouse we use svgimage now --- .../Navigation/ChallengeInviteSteps.jsx | 61 ++++++++----------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index aba53bd79..85a734862 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -5,13 +5,7 @@ import { withStyles } from '@mui/styles'; import styled from 'styled-components'; import commonMuiStyles from '../Style/commonMuiStyles'; import DesignTokenColors from '../Style/DesignTokenColors'; - -// Import icons -import RocketIcon from '../../../../img/global/svg-icons/issues/rocket-ship.svg'; -import StepOneIcon from '../../../../img/global/svg-icons/issues/material-symbols-counter-1.svg'; -import StepOneActiveIcon from '../../../../img/global/svg-icons/issues/material-symbols-counter-1-active.svg'; -import StepTwoIcon from '../../../../img/global/svg-icons/issues/material-symbols-counter-2.svg'; -import StepTwoActiveIcon from '../../../../img/global/svg-icons/issues/material-symbols-counter-2-active.svg'; +import SvgImage from '../Widgets/SvgImage'; // Color and font variables const commonTextStyle = { @@ -31,6 +25,7 @@ class ChallengeInviteSteps extends React.Component { activeStep: this.getActiveStepFromPath(), }; } + // Get the current step based on the URL to determine which step is active by default when the page loads getActiveStepFromPath = () => { const { location } = this.props; @@ -70,19 +65,20 @@ class ChallengeInviteSteps extends React.Component { {/* Rocket, Invite more friends, and Learn More */} - Rocket Icon -

+ To boost your ranking, invite your friends to join. -

+ - +
@@ -93,8 +89,8 @@ class ChallengeInviteSteps extends React.Component { isActive={this.isStepActive(1)} onClick={() => this.handleStepClick(1)} > - Step 1 Icon this.handleStepClick(2)} > - Step 2 Icon (isActive ? StepOneActiveIcon : StepOneIcon)}); - } - a { font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; @@ -238,10 +230,6 @@ const StepTwoIconAndText = styled('div')` text-align: center; width: 109px; - img { - content: url(${({ isActive }) => (isActive ? StepTwoActiveIcon : StepTwoIcon)}); - } - a { font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; @@ -251,7 +239,6 @@ const StepTwoIconAndText = styled('div')` font-weight: 600; } } - &:hover { // border-bottom: 2px solid ${DesignTokenColors.primary500}; } From af964cdc548465571edf1d2e937c6095f65c7dd3 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Mon, 7 Oct 2024 16:55:59 -0700 Subject: [PATCH 28/54] add some space after eslint run --- src/js/common/components/Navigation/ChallengeInviteSteps.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index 85a734862..c54b89f9a 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -19,7 +19,7 @@ const commonTextStyle = { }; // ChallengeInviteSteps component to display the steps class ChallengeInviteSteps extends React.Component { - constructor(props) { + constructor (props) { super(props); this.state = { activeStep: this.getActiveStepFromPath(), @@ -60,7 +60,7 @@ class ChallengeInviteSteps extends React.Component { this.setState({ activeStep: stepNumber }); }; - render() { + render () { return ( {/* Rocket, Invite more friends, and Learn More */} From f0738829fd394f434a4b134b79c12161c413698b Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Tue, 8 Oct 2024 16:18:57 -0700 Subject: [PATCH 29/54] [WV-514] Use StyledLink instead of link and move code for tag to styled link component --- .../Navigation/ChallengeInviteSteps.jsx | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index c54b89f9a..1e4ace61a 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -114,14 +114,14 @@ class ChallengeInviteSteps extends React.Component { imageName={this.isStepActive(2) ? 'material-symbols-counter-2-active' : 'material-symbols-counter-2'} alt="Step 2 Icon" /> - this.handleStepClick(2)} > Copy message & link - + @@ -229,18 +229,16 @@ const StepTwoIconAndText = styled('div')` margin-left: 25px; text-align: center; width: 109px; +`; +const StyledLink = styled(Link)` + font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; + color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; + text-decoration: none; - a { - font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; - color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; - - &:hover { - color: ${DesignTokenColors.primary500}; - font-weight: 600; - } - } &:hover { - // border-bottom: 2px solid ${DesignTokenColors.primary500}; + color: ${DesignTokenColors.primary500}; + font-weight: 600; + text-decoration: underline; } `; From eb7a3275bcbc3e5c754ba12405e9d424e519cfbd Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Tue, 8 Oct 2024 16:25:31 -0700 Subject: [PATCH 30/54] [WV-514] Remove unused code ufter running Eslint --- src/js/common/components/Navigation/ChallengeInviteSteps.jsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index 1e4ace61a..9e6279e28 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -37,9 +37,6 @@ class ChallengeInviteSteps extends React.Component { return 1; }; - // Check if a step is active based on the current step number - isStepActive = (stepNumber) => this.props.currentStep === stepNumber; - // Get the path for the challenge getChallengeBasePath = () => { const { challengeSEOFriendlyPath, challengeWeVoteId } = this.props; @@ -130,7 +127,6 @@ class ChallengeInviteSteps extends React.Component { } ChallengeInviteSteps.propTypes = { - currentStep: PropTypes.number.isRequired, challengeSEOFriendlyPath: PropTypes.string, challengeWeVoteId: PropTypes.string, location: PropTypes.object.isRequired, From a2eeaebff4a6047423511e268ee86d124f5f2e36 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Tue, 8 Oct 2024 16:28:45 -0700 Subject: [PATCH 31/54] [WV-514] Remove unused code ufter running Eslint --- src/js/common/components/Navigation/ChallengeInviteSteps.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index 9e6279e28..3afc37e7b 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -15,7 +15,6 @@ const commonTextStyle = { textAlign: 'center', colors: DesignTokenColors.neutral900, textDecoration: 'none', - // width: '272px', }; // ChallengeInviteSteps component to display the steps class ChallengeInviteSteps extends React.Component { @@ -90,14 +89,14 @@ class ChallengeInviteSteps extends React.Component { imageName={this.isStepActive(1) ? 'material-symbols-counter-1-active' : 'material-symbols-counter-1'} alt="Step 1 Icon" /> - this.handleStepClick(1)} > Customize the message to your friends - + {/* Horizontal Line Between Steps */} From 8e21b6ab3832adb3913fff9d4c1b3961d7f33b7a Mon Sep 17 00:00:00 2001 From: erinw Date: Wed, 9 Oct 2024 10:55:33 -0400 Subject: [PATCH 32/54] add more elements to handleContainerClick and fix npm lint issues --- .../Ballot/BallotScrollingContainer.jsx | 64 +++++++++++-------- .../Ballot/PositionRowListCompressed.jsx | 5 +- src/js/components/ImageHandler.jsx | 5 +- .../Values/IssuesByBallotItemDisplayList.jsx | 3 +- .../Values/ValueNameWithPopoverDisplay.jsx | 1 - 5 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/js/components/Ballot/BallotScrollingContainer.jsx b/src/js/components/Ballot/BallotScrollingContainer.jsx index 2f96bf06b..9abf4cd76 100644 --- a/src/js/components/Ballot/BallotScrollingContainer.jsx +++ b/src/js/components/Ballot/BallotScrollingContainer.jsx @@ -100,24 +100,38 @@ class BallotScrollingContainer extends Component { }; handleContainerClick = (e, weVoteId, externalUniqueId) => { - console.log(e.target, externalUniqueId) - const candidateContainer = document.getElementById(`candidateContainer-${weVoteId}-${externalUniqueId}`) - const positionRowListOuterWrapper = document.getElementById(`positionRowListOuterWrapper-${weVoteId}-${externalUniqueId}`) - const candidateImageAndName = document.getElementById(`officeItemCompressedCandidateImageAndName-${weVoteId}-${externalUniqueId}`); - const candidateNameAndPartyWrapper = document.getElementById(`candidateNameAndPartyWrapper-${weVoteId}-${externalUniqueId}`) - const candidateNameH4 = document.getElementById(`candidateNameH4-${weVoteId}-${externalUniqueId}`) - //change to ! any of the ones below instead - //get rid of these ones in IssuesByBallotItemDisplayList and PositionRowListCompressed - const listWrapper = document.getElementById(`IssueListWrapper-${weVoteId}`) - const candidateEndorsementText = document.getElementById(`CandidateEndorsementText-${weVoteId}`) - if (e.target === candidateImageAndName - || e.target === candidateContainer - || e.target === positionRowListOuterWrapper - || e.target === candidateNameAndPartyWrapper - ||e.target ===candidateNameH4) { - this.onClickShowOrganizationModalWithBallotItemInfoAndPositions(weVoteId) - } + console.log(e.target, externalUniqueId); + const candidateContainer = document.getElementById(`candidateContainer-${weVoteId}-${externalUniqueId}`); + const positionRowListOuterWrapper = document.getElementById(`positionRowListOuterWrapper-${weVoteId}-${externalUniqueId}`); + const candidateDiv = document.getElementById(`candidateDiv-${weVoteId}`); + const candidateNameAndPartyWrapper = document.getElementById(`candidateNameAndPartyWrapper-${weVoteId}-${externalUniqueId}`); + const candidateImageAndMatchWrapper = document.getElementById(`candidateImageAndMatchWrapper-${weVoteId}`); + const imageHandlerDiv = document.getElementById(`imageHandlerDiv-${weVoteId}`); + const candidateNameH4 = document.getElementById(`candidateNameH4-${weVoteId}-${externalUniqueId}`); + const candidateEndorsementsContainer = document.getElementById(`CandidateEndorsementsContainer-${weVoteId}`); + const candidateBottomRow = document.getElementById(`candidateBottomRow-${weVoteId}`); + const issuesListWrapper = document.getElementById(`IssueListWrapper-${weVoteId}`); + const candidateInfo = document.getElementById(`candidateInfo-${weVoteId}`); + const itemActionBarOutsideWrapper = document.getElementById(`itemActionBarOutsideWrapper-${weVoteId}`); + // EAW VERIFY - might not need this one + const candidateParty = document.getElementById(`candidateParty-${weVoteId}`); + console.log(itemActionBarOutsideWrapper); + if (e.target === candidateDiv || + e.target === candidateContainer || + e.target === positionRowListOuterWrapper || + e.target === candidateNameAndPartyWrapper || + e.target === candidateNameH4 || + e.target === candidateEndorsementsContainer || + e.target === candidateBottomRow || + e.target === issuesListWrapper || + e.target === candidateInfo || + e.target === candidateImageAndMatchWrapper || + e.target === imageHandlerDiv || + e.target === candidateParty || + e.target === itemActionBarOutsideWrapper) + this.onClickShowOrganizationModalWithBallotItemInfoAndPositions(weVoteId); } + } render () { const { oneCandidate, externalUniqueId, isFirstBallotItem, candidateCount, limitNumberOfCandidatesShownToThisNumber } = this.props; @@ -152,20 +166,20 @@ class BallotScrollingContainer extends Component { > + > - + {/* Candidate Image */} - + }> {oneCandidate.ballot_item_display_name} - + {candidatePartyText} - + {!hideCandidateDetails && ( }> )} {!hideItemActionBar && ( - + }> - + this.onClickShowOrganizationModalWithPositions()}> {filteredPositionList.map((onePosition) => { // console.log('numberOfPositionItemsDisplayed:', numberOfPositionItemsDisplayed, ', numberOfImagesToDisplay:', numberOfImagesToDisplay); diff --git a/src/js/components/ImageHandler.jsx b/src/js/components/ImageHandler.jsx index 23e8db8c2..ff757ae5b 100644 --- a/src/js/components/ImageHandler.jsx +++ b/src/js/components/ImageHandler.jsx @@ -31,7 +31,7 @@ export default class ImageHandler extends Component { const { kind_of_ballot_item: kindOfBallotItem } = this.props; const kindOfImage = this.props.kind_of_image ? this.props.kind_of_image : kindOfBallotItem; const imagePlaceholderIcon = null; - + const { ballotItemWeVoteId } = this.props; // handles setting the placeholder image by "kind_of_image" or "ballot item" type. switch (kindOfImage) { case 'CANDIDATE': @@ -62,6 +62,7 @@ export default class ImageHandler extends Component { {alt} @@ -69,6 +70,7 @@ export default class ImageHandler extends Component { {alt} {issuesChips} {totalLengthOfIssuesToRenderList && ( diff --git a/src/js/components/Values/ValueNameWithPopoverDisplay.jsx b/src/js/components/Values/ValueNameWithPopoverDisplay.jsx index d6e9c6786..7f5533b42 100644 --- a/src/js/components/Values/ValueNameWithPopoverDisplay.jsx +++ b/src/js/components/Values/ValueNameWithPopoverDisplay.jsx @@ -170,7 +170,6 @@ class ValueNameWithPopoverDisplay extends Component { color="valueChip" id={`${externalUniqueId}-valueIconAndText-${oneIssue.issue_we_vote_id}`} key={`${externalUniqueId}-valueIconAndTextKey-${oneIssue.issue_we_vote_id}`} - className="u-cursor--pointer" style={{ margin: '5px', borderRadius: '4px', From 7d0c7e00453f304e79e1534eaadb92fb835e2f96 Mon Sep 17 00:00:00 2001 From: erinw Date: Wed, 9 Oct 2024 11:20:57 -0400 Subject: [PATCH 33/54] removed uniqueId from id because not needed and made StyledButton cursor default --- .../Ballot/BallotScrollingContainer.jsx | 30 ++++++++++--------- .../BallotItem/BallotMatchIndicator2024.jsx | 1 + .../Values/IssuesByBallotItemDisplayList.jsx | 2 +- .../Widgets/ItemActionBar/ItemActionBar.jsx | 5 +++- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/js/components/Ballot/BallotScrollingContainer.jsx b/src/js/components/Ballot/BallotScrollingContainer.jsx index 9abf4cd76..4deffbfe9 100644 --- a/src/js/components/Ballot/BallotScrollingContainer.jsx +++ b/src/js/components/Ballot/BallotScrollingContainer.jsx @@ -99,23 +99,24 @@ class BallotScrollingContainer extends Component { } }; - handleContainerClick = (e, weVoteId, externalUniqueId) => { - console.log(e.target, externalUniqueId); - const candidateContainer = document.getElementById(`candidateContainer-${weVoteId}-${externalUniqueId}`); - const positionRowListOuterWrapper = document.getElementById(`positionRowListOuterWrapper-${weVoteId}-${externalUniqueId}`); + handleContainerClick = (e, weVoteId) => { + console.log(e.target); + const candidateContainer = document.getElementById(`candidateContainer-${weVoteId}`); + const positionRowListOuterWrapper = document.getElementById(`positionRowListOuterWrapper-${weVoteId}`); const candidateDiv = document.getElementById(`candidateDiv-${weVoteId}`); - const candidateNameAndPartyWrapper = document.getElementById(`candidateNameAndPartyWrapper-${weVoteId}-${externalUniqueId}`); + const candidateNameAndPartyWrapper = document.getElementById(`candidateNameAndPartyWrapper-${weVoteId}`); const candidateImageAndMatchWrapper = document.getElementById(`candidateImageAndMatchWrapper-${weVoteId}`); const imageHandlerDiv = document.getElementById(`imageHandlerDiv-${weVoteId}`); - const candidateNameH4 = document.getElementById(`candidateNameH4-${weVoteId}-${externalUniqueId}`); + const candidateNameH4 = document.getElementById(`candidateNameH4-${weVoteId}`); const candidateEndorsementsContainer = document.getElementById(`CandidateEndorsementsContainer-${weVoteId}`); const candidateBottomRow = document.getElementById(`candidateBottomRow-${weVoteId}`); const issuesListWrapper = document.getElementById(`IssueListWrapper-${weVoteId}`); const candidateInfo = document.getElementById(`candidateInfo-${weVoteId}`); const itemActionBarOutsideWrapper = document.getElementById(`itemActionBarOutsideWrapper-${weVoteId}`); + const buttonWrapper = document.getElementById(`buttonWrapper-${weVoteId}`); // EAW VERIFY - might not need this one const candidateParty = document.getElementById(`candidateParty-${weVoteId}`); - console.log(itemActionBarOutsideWrapper); + console.log(buttonWrapper); if (e.target === candidateDiv || e.target === candidateContainer || e.target === positionRowListOuterWrapper || @@ -128,8 +129,9 @@ class BallotScrollingContainer extends Component { e.target === candidateImageAndMatchWrapper || e.target === imageHandlerDiv || e.target === candidateParty || - e.target === itemActionBarOutsideWrapper) - this.onClickShowOrganizationModalWithBallotItemInfoAndPositions(weVoteId); + e.target === itemActionBarOutsideWrapper || + e.target === buttonWrapper) { + this.onClickShowOrganizationModalWithBallotItemInfoAndPositions(weVoteId); } } @@ -165,7 +167,7 @@ class BallotScrollingContainer extends Component { onClick={(e) => this.handleContainerClick(e, oneCandidate.we_vote_id, externalUniqueId)} > @@ -195,12 +197,12 @@ class BallotScrollingContainer extends Component { {/* Candidate Name */} - {oneCandidate.ballot_item_display_name} + {oneCandidate.ballot_item_display_name} {candidatePartyText} @@ -247,7 +249,7 @@ class BallotScrollingContainer extends Component { {!!(oneCandidate.linked_campaignx_we_vote_id) && ( diff --git a/src/js/components/BallotItem/BallotMatchIndicator2024.jsx b/src/js/components/BallotItem/BallotMatchIndicator2024.jsx index bb5fed54e..e486c582c 100644 --- a/src/js/components/BallotItem/BallotMatchIndicator2024.jsx +++ b/src/js/components/BallotItem/BallotMatchIndicator2024.jsx @@ -136,6 +136,7 @@ const StyledButton = styled("div")` justify-content: center; // Centers text horizontally align-items: center; // Centers text vertically min-width: 72px; + cursor: default; `; const BoldText = styled.span` diff --git a/src/js/components/Values/IssuesByBallotItemDisplayList.jsx b/src/js/components/Values/IssuesByBallotItemDisplayList.jsx index 140b3b69e..faf50101d 100644 --- a/src/js/components/Values/IssuesByBallotItemDisplayList.jsx +++ b/src/js/components/Values/IssuesByBallotItemDisplayList.jsx @@ -186,7 +186,7 @@ class IssuesByBallotItemDisplayList extends Component { if (!oneIssue) { return null; } - //console.log('oneIssue.issue_name: ', oneIssue.issue_name); + // console.log('oneIssue.issue_name: ', oneIssue.issue_name); localCounter++; if (localCounter <= currentNumberOfIssuesToDisplay) { issueFollowedByVoter = IssueStore.isVoterFollowingThisIssue(oneIssue.issue_we_vote_id); diff --git a/src/js/components/Widgets/ItemActionBar/ItemActionBar.jsx b/src/js/components/Widgets/ItemActionBar/ItemActionBar.jsx index af832e85a..e99ce529a 100644 --- a/src/js/components/Widgets/ItemActionBar/ItemActionBar.jsx +++ b/src/js/components/Widgets/ItemActionBar/ItemActionBar.jsx @@ -853,7 +853,10 @@ class ItemActionBar extends PureComponent { {(ballotItemType === 'MEASURE') && this.measureYesButtonNoText(`desktopVersion-${ballotItemWeVoteId}`)} ) : ( - + Date: Wed, 9 Oct 2024 10:47:10 -0500 Subject: [PATCH 34/54] defines logic for thumbsUpDownToggle, adds toolTip and styling, minor changes to colors on PositionForBallot --- .../Position/PositionForBallotItem.jsx | 60 ++++-- .../ThumbsUpDownToggle/ThumbsUpDownToggle.jsx | 181 +++++++++++++++++- .../ThumbsUpDownToggleIcon.jsx | 16 +- 3 files changed, 223 insertions(+), 34 deletions(-) diff --git a/src/js/common/components/Position/PositionForBallotItem.jsx b/src/js/common/components/Position/PositionForBallotItem.jsx index b671f4be8..55f88e22b 100644 --- a/src/js/common/components/Position/PositionForBallotItem.jsx +++ b/src/js/common/components/Position/PositionForBallotItem.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React, { useState } from 'react'; -import styled, { withTheme } from 'styled-components'; +import styled from 'styled-components'; import CheckOutlinedIcon from '@mui/icons-material/CheckOutlined'; import BlockOutlinedIcon from '@mui/icons-material/BlockOutlined'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; @@ -9,6 +9,7 @@ import { Typography } from '@mui/material'; import { withStyles } from '@mui/styles'; import HeartFavoriteToggleBase from '../Widgets/HeartFavoriteToggle/HeartFavoriteToggleBase'; import ThumbsUpDownToggle from '../Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle'; +import DesignTokenColors from '../Style/DesignTokenColors'; function PositionForBallotItem ({ classes }) { const [anchorEl, setAnchorEL] = useState(null); @@ -19,7 +20,7 @@ function PositionForBallotItem ({ classes }) { bio: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', }; - const voterEndorsed = true; + const positionEndorsed = false; const onDotButtonClick = (e) => { setAnchorEL(e.currentTarget); @@ -49,14 +50,14 @@ function PositionForBallotItem ({ classes }) { - {voterEndorsed ? ( + {positionEndorsed ? ( - + Endorsed a month ago ) : ( - + Opposed a month ago )} @@ -64,9 +65,9 @@ function PositionForBallotItem ({ classes }) { - + + + ({ popoverRoot: { borderRadius: 2, - border: '1px solid rgba(210, 210, 210, 1)', + border: `1px solid ${DesignTokenColors.neutral100}`, marginTop: '3px', }, }); -export default withTheme(withStyles(styles)(PositionForBallotItem)); +export default withStyles(styles)(PositionForBallotItem); diff --git a/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx index 606a5463a..61d69833d 100644 --- a/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx +++ b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx @@ -1,27 +1,179 @@ -import React from 'react'; -import { styled } from '@mui/material'; +import PropTypes from 'prop-types'; +import React, { useState } from 'react'; +import { styled, Tooltip } from '@mui/material'; +import { withStyles } from '@mui/styles'; import DesignTokenColors from '../../Style/DesignTokenColors'; import ThumbsUpDownToggleIcon from './ThumbsUpDownToggleIcon'; import numberWithCommas from '../../../utils/numberWithCommas'; -function ThumbsUpDownToggle () { +function ThumbsUpDownToggle ({ classes }) { + const [thumbsUpAmountLocal, setThumbsUpAmountLocal] = useState(1237653); + const [thumbsDownAmountLocal, setThumbsDownAmountLocal] = useState(1237653); + const [supports, setSupports] = useState(false); + const [opposes, setOpposes] = useState(false); + + const handleThumbsUpClick = () => { + if (!supports) { + if (!opposes) { + setSupports(true); + setThumbsUpAmountLocal((prevAmountLocal) => prevAmountLocal + 1); + } else { + setSupports(true); + setOpposes(false); + setThumbsUpAmountLocal((prevAmountLocal) => prevAmountLocal + 1); + setThumbsDownAmountLocal((prevAmountLocal) => prevAmountLocal - 1); + } + } + if (supports) { + setSupports(false); + setThumbsUpAmountLocal((prevAmountLocal) => prevAmountLocal - 1); + } + }; + + const handleThumbsDownClick = () => { + if (!opposes) { + if (!supports) { + setOpposes(true); + setThumbsDownAmountLocal((prevAmountLocal) => prevAmountLocal + 1); + } else { + setOpposes(true); + setSupports(false); + setThumbsUpAmountLocal((prevAmountLocal) => prevAmountLocal - 1); + setThumbsDownAmountLocal((prevAmountLocal) => prevAmountLocal + 1); + } + } + if (opposes) { + setOpposes(false); + setThumbsDownAmountLocal((prevAmountLocal) => prevAmountLocal - 1); + } + }; + + const handleThumbsUpToolTipMessage = () => { + if (opposes) { + return ( + <> +

+ Favorited by + {' '} + {thumbsUpAmountLocal} + {' '} + people +

+

Favoriting helps us show you what other candidates match your values

+ + ); + } if (supports) { + return 'Remove Favorite'; + } else { + return 'Favoriting helps us show you what other candidates match your values.'; + } + }; + + const handleThumbsDownToolTipMessage = () => { + if (opposes) { + return 'Remove Dislike'; + } else { + return ( + <> +

+ Disliked by + {' '} + {thumbsDownAmountLocal} + {' '} + people +

+

Disliking helps us show you what other candidates match your values

+ + ); + } + }; + + const displayAmountConversion = (amount) => { + if (amount >= 1000000) { + return `${(amount / 100000).toFixed(1).replace(/\.0$/, '')}M`; + } + if (amount >= 1000) { + return `${(amount / 1000).toFixed(1).replace(/\.0$/, '')}K`; + } + return numberWithCommas(amount); + }; + return ( - - {numberWithCommas(0)} + + + + + + + {displayAmountConversion(thumbsUpAmountLocal)} +   - - {numberWithCommas(0)} + + + + + + + {displayAmountConversion(thumbsDownAmountLocal)} + ); } +ThumbsUpDownToggle.propTypes = { + classes: PropTypes.object, +}; + const ThumbsUpThumbsDownContainer = styled('div')` display: flex; + max-width: 100px; + justify-content: space-evenly; +`; + +const ThumbsContainer = styled('div')` + display: flex; + justify-content: space-between; + align-items: center; +`; + +const ThumbsUpClickableContainer = styled('button')` + background: transparent; + border: none; + cursor: pointer; + padding: 0; + margin: 0; +`; + +const ThumbsDownClickableContainer = styled('button')` + background: transparent; + border: none; + cursor: pointer; + padding: 0; + margin: 0; `; const Amount = styled('span')` - margin-right: 10px; + color: ${DesignTokenColors.neutral900}; + margin: 0 5px 0 5px; + overflow: hidden; + max-width: 200px; + transition: max-width .3s ease-in-out, opacity 1s ease-in-out; + + &.hidden { + max-width: 0px; + opacity: 0; + } `; const ThumbsUpDownSeperator = styled('div')` @@ -29,4 +181,15 @@ const ThumbsUpDownSeperator = styled('div')` border-right: 1px solid ${DesignTokenColors.neutralUI100}; `; -export default ThumbsUpDownToggle; +const styles = () => ({ + toolTip: { + backgroundColor: `${DesignTokenColors.neutral900}`, + fontSize: '12px', + }, + arrow: { + color: `${DesignTokenColors.neutral900}`, + }, +}); + + +export default withStyles(styles)(ThumbsUpDownToggle); diff --git a/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggleIcon.jsx b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggleIcon.jsx index 55ddbe6a4..2c90f65fd 100644 --- a/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggleIcon.jsx +++ b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggleIcon.jsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { ThumbDownAltRounded, ThumbDownOffAltRounded } from '@mui/icons-material'; import DesignTokenColors from '../../Style/DesignTokenColors'; -const ThumbsUpDownToggleIcon = ({ isFavorite, isDislike, supports, rejects }) => ( +const ThumbsUpDownToggleIcon = ({ isFavorite, isDislike, supports, opposes }) => ( <> {isFavorite && ( @@ -13,7 +13,7 @@ const ThumbsUpDownToggleIcon = ({ isFavorite, isDislike, supports, rejects }) => )} {isDislike && ( - {rejects ? : } + {opposes ? : } )} @@ -21,7 +21,7 @@ const ThumbsUpDownToggleIcon = ({ isFavorite, isDislike, supports, rejects }) => const Icon = styled('div')` flex: display; - padding: 0 5px 0 5px; + padding-left: 5px; `; @@ -32,9 +32,7 @@ const ThumbsUpOutlineStyled = styled(ThumbDownOffAltRounded)` transition: path 0.3 ease; &:hover { - path { - fill: ${DesignTokenColors.neutral400}; - } + color: ${DesignTokenColors.neutral600} } `; @@ -48,6 +46,10 @@ const ThumbsDownOutlineStyled = styled(ThumbDownOffAltRounded)` color: ${DesignTokenColors.neutral400}; cursor: pointer; transition: color 0.3 ease; + + &:hover { + color: ${DesignTokenColors.neutral600} + } `; const ThumbsDownPressedStyled = styled(ThumbDownAltRounded)` @@ -61,5 +63,5 @@ ThumbsUpDownToggleIcon.propTypes = { isFavorite: PropTypes.bool, isDislike: PropTypes.bool, supports: PropTypes.bool, - rejects: PropTypes.bool, + opposes: PropTypes.bool, }; From 155fc0c086a087ab56144955a083e87d07be9a59 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Wed, 9 Oct 2024 11:58:46 -0700 Subject: [PATCH 35/54] Remove PayToPromoteProcess import, uncomment modal section, and apply changes based on meeting discussion - Following the meeting, made changes to the modal section as discussed. - Removed the unused PayToPromoteProcess import. - Uncommented the modal-related code to restore functionality. --- .../ChallengeInviteFriends/BoostLearnMoreModal.jsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx index 643e6fc07..6f4a3bdcc 100644 --- a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -8,7 +8,6 @@ import stringContains from '../../utils/stringContains'; import CandidateStore from '../../../stores/CandidateStore'; import MeasureStore from '../../../stores/MeasureStore'; import SupportStore from '../../../stores/SupportStore'; -import PayToPromoteProcess from '../CampaignSupport/PayToPromoteProcess'; // const PayToPromoteProcess = React.lazy(() => import(/* webpackChunkName: 'PayToPromoteProcess' */ './PayToPromoteProcess')); // eslint-disable-line import/no-cycle @@ -190,10 +189,8 @@ class BoostLearnMoreModal extends Component { return ( {dialogTitleText}} commented because it is not working but can restore if needed + dialogTitleJSX={<>{dialogTitleText}} show={show} - dialogTitleJSX={
Learn More
} - //textFieldJSX={
Learn more content here
} // tallMode commented because it is not working but can restore if needed textFieldJSX={textFieldJSX} toggleModal={this.props.toggleModal} From 2adc2bb43a0bfbdc578502c465bdc88bdfd0d318 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Wed, 9 Oct 2024 12:04:50 -0700 Subject: [PATCH 36/54] delete Lazyload for PayToPromote --- .../components/ChallengeInviteFriends/BoostLearnMoreModal.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx index 6f4a3bdcc..4ad82cb43 100644 --- a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -9,8 +9,6 @@ import CandidateStore from '../../../stores/CandidateStore'; import MeasureStore from '../../../stores/MeasureStore'; import SupportStore from '../../../stores/SupportStore'; -// const PayToPromoteProcess = React.lazy(() => import(/* webpackChunkName: 'PayToPromoteProcess' */ './PayToPromoteProcess')); // eslint-disable-line import/no-cycle - class BoostLearnMoreModal extends Component { constructor (props) { super(props); From 3b9bf69a02d9171b6b649320c9b32e53879ea2c0 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Wed, 9 Oct 2024 12:07:56 -0700 Subject: [PATCH 37/54] remove extra space after esLint --- .../components/ChallengeInviteFriends/BoostLearnMoreModal.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx index 4ad82cb43..409003bfd 100644 --- a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -180,7 +180,6 @@ class BoostLearnMoreModal extends Component { // console.log('BoostLearnMoreModal render, voter_address_object: ', voter_address_object); const textFieldJSX = ( -
Learn more content here
); From 064a8dc8dbaf532ff36affd6881f02ba2d718cc0 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Wed, 9 Oct 2024 12:51:54 -0700 Subject: [PATCH 38/54] remove unnesesary
tag in styles --- .../Navigation/ChallengeInviteSteps.jsx | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index 3afc37e7b..8ad31787b 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -198,21 +198,6 @@ const StepOneIconAndText = styled('div')` margin-right: 25px; text-align: center; width: 169px; - - a { - font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; - color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; - - &:hover { - color: ${DesignTokenColors.primary500}; - font-weight: 600; - text-decoration: underline; - } - } - - &:hover { - border-bottom: 2px solid ${DesignTokenColors.primary500}; - } `; const StepTwoIconAndText = styled('div')` @@ -225,7 +210,7 @@ const StepTwoIconAndText = styled('div')` text-align: center; width: 109px; `; -const StyledLink = styled(Link)` +const StyledLink = styled('a')` font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; text-decoration: none; From 5df8e7fbef3d8815a27919dd8c9a27e393de311f Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Wed, 9 Oct 2024 12:58:27 -0700 Subject: [PATCH 39/54] roll back changes, steps not working with new code --- .../components/Navigation/ChallengeInviteSteps.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index 8ad31787b..fb44c98f5 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -209,6 +209,16 @@ const StepTwoIconAndText = styled('div')` margin-left: 25px; text-align: center; width: 109px; + a { + font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; + color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; + + &:hover { + color: ${DesignTokenColors.primary500}; + font-weight: 600; + text-decoration: underline; + } + } `; const StyledLink = styled('a')` font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; From c98b73d683a29e8aa268d1dbad489d450a766164 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Wed, 9 Oct 2024 13:00:13 -0700 Subject: [PATCH 40/54] roll back changes, steps not working with new code --- .../components/Navigation/ChallengeInviteSteps.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index fb44c98f5..bd3389587 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -198,6 +198,16 @@ const StepOneIconAndText = styled('div')` margin-right: 25px; text-align: center; width: 169px; + a { + font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; + color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; + + &:hover { + color: ${DesignTokenColors.primary500}; + font-weight: 600; + text-decoration: underline; + } + } `; const StepTwoIconAndText = styled('div')` From fe67f2750f95d1ecad35945eae82a614d2243e53 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Wed, 9 Oct 2024 13:01:40 -0700 Subject: [PATCH 41/54] roll back changes, steps not working with new code --- .../Navigation/ChallengeInviteSteps.jsx | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index bd3389587..8b332d6b0 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -89,14 +89,14 @@ class ChallengeInviteSteps extends React.Component { imageName={this.isStepActive(1) ? 'material-symbols-counter-1-active' : 'material-symbols-counter-1'} alt="Step 1 Icon" /> - this.handleStepClick(1)} > Customize the message to your friends - + {/* Horizontal Line Between Steps */} @@ -110,14 +110,14 @@ class ChallengeInviteSteps extends React.Component { imageName={this.isStepActive(2) ? 'material-symbols-counter-2-active' : 'material-symbols-counter-2'} alt="Step 2 Icon" /> - this.handleStepClick(2)} > Copy message & link - +
@@ -230,17 +230,6 @@ const StepTwoIconAndText = styled('div')` } } `; -const StyledLink = styled('a')` - font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; - color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; - text-decoration: none; - - &:hover { - color: ${DesignTokenColors.primary500}; - font-weight: 600; - text-decoration: underline; - } -`; const HorizontalLine = styled('div')` border-top: 1px solid ${DesignTokenColors.neutral100}; From e5c1edbef7031a3894466b0691b423a4d8942543 Mon Sep 17 00:00:00 2001 From: charanya-QA Date: Wed, 9 Oct 2024 16:58:59 -0700 Subject: [PATCH 42/54] Changes with respect to WV-421 First Pass of How it works Page Automation Test Cases: Web --- .../capabilities/testData.js | 8 + .../config/wdio.config.js | 1 + .../page_objects/howitworks.js | 140 +++++++++- .../specs/HowItWorks.js | 250 +++++++++++++----- 4 files changed, 334 insertions(+), 65 deletions(-) create mode 100644 tests/browserstack_automation/capabilities/testData.js diff --git a/tests/browserstack_automation/capabilities/testData.js b/tests/browserstack_automation/capabilities/testData.js new file mode 100644 index 000000000..58a01c04f --- /dev/null +++ b/tests/browserstack_automation/capabilities/testData.js @@ -0,0 +1,8 @@ +module.exports = { + MOBILE_NUMBER: '808-935-8555', + MOBILE_VERIFICATION: '123456', + EMAIL_NEGATIVE_SCENARIO: 'wevote@wevote.us', + INVALID_MOBILE_NUMBER: '808-935-855', + INVALID_EMAIL_ADDRESS: 'wevote@wevote', + UNVERIFIED_PHONE_NUMBER: '808-935-8554' +}; diff --git a/tests/browserstack_automation/config/wdio.config.js b/tests/browserstack_automation/config/wdio.config.js index 45e9efe0d..1d7f059ee 100644 --- a/tests/browserstack_automation/config/wdio.config.js +++ b/tests/browserstack_automation/config/wdio.config.js @@ -42,6 +42,7 @@ module.exports.config = { '../specs/ReadyPage.js', '../specs/TermsPage.js', '../specs/TopNavigation.js', + '../specs/HowItWorks.js', ], capabilities, commonCapabilities: { diff --git a/tests/browserstack_automation/page_objects/howitworks.js b/tests/browserstack_automation/page_objects/howitworks.js index 1ca5075ff..0a264e789 100644 --- a/tests/browserstack_automation/page_objects/howitworks.js +++ b/tests/browserstack_automation/page_objects/howitworks.js @@ -1,15 +1,145 @@ import { $ } from '@wdio/globals'; import Page from './page'; +class HowItWorks extends Page { + get howItWorksTitle () { + return $('div>h3[class~="gNNNpX"]'); + } -class HowItWorks extends Page { - get FirstModalbutton () { - return $('(//div[@p = "How WeVote works"])'); + get findNextButtonHowItWorksWindow () { + return $('.kMeOcV'); + } + + get findBackButtonHowItWorksWindow () { + return $('//button[text() = "Back"]'); + } + + get getTitleSignUpPopUp () { + return $('.u-f3'); + } + + get getStartedButton () { + return $('.cqTvJR>button'); + } + + get enterVoterEmailAddressTextBox () { + return $('#enterVoterEmailAddress'); + } + + get cancelEmailButton () { + return $('#cancelEmailButton'); + } + + get cancelMobilePhoneNumberButton(){ + return $('#cancelVoterPhoneSendSMS') + } + + get enterMobilePhoneNumber() { + return $('#enterVoterPhone'); + } + + get enterSignInWithApple() { + return $('#appleLogo'); + } + + get enterSignInWithTwitter () { + return $('.csbvaL'); + } + + get cancelTwitterSignin(){ + return $('#cancel') + } + + get gotoWeVoteBallotGuide() { + return $('*=homepage') + } + + get enterSendVerificationCode() { + return $('#desktopSmsSendCode') + } + + get enterSendEmailVerificationCode() { + return $('#voterEmailAddressEntrySendCode') + } + + get enterVerifyButton(){ + return $('#emailVerifyButton') + } + + get enterProfileAvatar(){ + return $('#profileAvatarHeaderBar') + } + + get phoneNumberHelperText(){ + return $('#enterVoterPhone-helper-text') + } + + get emailAddressHelperText() { + return $('#enterVoterEmailAddress-helper-text') + } + + get backArrow() { + return $('#emailVerificationBackButton') + } + + get deleteIcon() { + return $('svg[data-testid="DeleteIcon"]') + } + + get alertMessage() { + return $('.MuiAlert-message') + } + + async enterDigit(num){ + if (num === 0) { + return $('#digit1') + }else if (num === 1) { + return $('#digit2') + } else if (num === 2) { + return $('#digit3') + } else if (num === 3) { + return $('#digit4') + } else if (num == 4) { + return $('#digit5') + } else{ + return $('#digit6') + } + + } + + async clickButton(element){ + await element.findAndClick() + } + + async scrollToView(element) { + await element.scrollIntoView() + } + + async clickNextButtonFourTimes () { + for (let i = 1; i <= 4; i++) { + await this.findNextButtonHowItWorksWindow.click(); + } + } + + async clickBackButtonFourTimes () { + for (let i = 1; i <= 4; i++) { + await this.findBackButtonHowItWorksWindow.click(); + } } - get modalTitle () { - return $('.3Title-sc-1rpx53i-1 iavXrP'); + async checkTitleOfHowItWorksWindow (num) { + if (num === 1) { + return '1. Choose your interests'; + }else if (num === 2) { + return '2. Follow organizations and people you trust'; + } else if (num === 3) { + return '3. See who endorsed each choice on your ballot'; + } else if (num === 4) { + return '4. Complete your ballot with confidence'; + } else { + return '5. Share with friends who could use a guide'; + } } } diff --git a/tests/browserstack_automation/specs/HowItWorks.js b/tests/browserstack_automation/specs/HowItWorks.js index 6de88d1b4..c17f4bc85 100644 --- a/tests/browserstack_automation/specs/HowItWorks.js +++ b/tests/browserstack_automation/specs/HowItWorks.js @@ -1,73 +1,203 @@ import { driver, expect } from '@wdio/globals'; import ReadyPage from '../page_objects/ready.page'; import TopNavigation from '../page_objects/topnavigation'; - import HowItWorks from '../page_objects/howitworks'; - -const { describe, it } = require('mocha'); - +const testData = require('../capabilities/testData.js'); const waitTime = 5000; - - describe('HowItWorks', () => { // HowItWorks_001 - it('verifyHowItWorksModalWindowOpen', async () => { + it('verifyNextButton', async () => { await ReadyPage.load(); await driver.pause(waitTime); - await TopNavigation.getBallotLinkLocator.click(); - await driver.waitUntil(async () => { - // Add condition to check for the expected URL - const currentUrl = await driver.getUrl(); - console.log(currentUrl); - return currentUrl.includes('ballot'); - }, { - timeout: 10000, - timeoutMsg: 'Expected URL to contain "ballot" not found, timeout after 10000ms', - }); - await HowItWorks.FirstModalbutton.click(); - await expect(HowItWorks.modalTitle).toBeDisplayed(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + for (let i = 1; i < 6; i++) { + const expectedResult = await HowItWorks.checkTitleOfHowItWorksWindow(i); + await expect(HowItWorks.howItWorksTitle).toHaveText(expectedResult); + if (i!= 5) { + const nextButton = await HowItWorks.findNextButtonHowItWorksWindow; + await HowItWorks.clickButton(nextButton) + } + } + console.log("Next Button and titles of the page verified successfully") }); - // it('verifyHowItWorksModalWindowClosed', async () => { - // await ReadyPage.load(); - // await driver.pause(waitTime); - // await ReadyPage.clickHowItWorksLink(); - // await driver.pause(waitTime); - // await ReadyPage.howItWorksTitle.isDisplayed(); - // await ReadyPage.closeHowItWorksModalWindow(); - // await driver.pause(waitTime); - // await expect(ReadyPage.elementHowItWorksWindow).not.toBeDisplayed(); - // }); - - // // Ready_012 - // it('verifyHowItWorksModalWindowNextButton', async () => { - // await ReadyPage.load(); - // await driver.pause(waitTime); - // await ReadyPage.clickHowItWorksLink(); - // await driver.pause(waitTime); - // const expectedResult = await ReadyPage.checkTitleOfHowItWorksWindow(); - // await expect(ReadyPage.howItWorksTitle).toHaveText(expectedResult); - // }); - - // // Ready_013 - // it('verifyHowItWorksModalWindowNextGetStartedButton', async () => { - // await ReadyPage.load(); - // await ReadyPage.clickHowItWorksLink(); - // await driver.pause(waitTime); - // await ReadyPage.clickNextButtonFourTimes(); - // await driver.pause(waitTime); - // await ReadyPage.clickGetStartedButton(); - // await driver.pause(waitTime); - // await expect(ReadyPage.getTitleSignUpPopUp).toHaveText('Sign In or Join'); - // }); + // HowItWorks_002 + it('verifyBackButton', async () => { + await ReadyPage.load(); + await driver.pause(waitTime); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + await HowItWorks.clickBackButtonFourTimes() + const expectedResult = await HowItWorks.checkTitleOfHowItWorksWindow(1); + await expect(HowItWorks.howItWorksTitle).toHaveText(expectedResult); + console.log("Back button clicked successfully and user is on first page") + }); + // HowItWorks_003 + it('verifyGetStartedButton', async () => { + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + await driver.pause(waitTime); + await expect(HowItWorks.getTitleSignUpPopUp).toHaveText('Sign In or Join'); + console.log("GetStarted Button Clicked Successfully, user on the signIn page") + }); + // HowItWorks_004 + it('verifyCancelSigninwithEmail', async () => { + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const emailTextBox = await HowItWorks.enterVoterEmailAddressTextBox; + await emailTextBox.addValue(testData.EMAIL_NEGATIVE_SCENARIO); + const cancelButton = await HowItWorks.cancelEmailButton; + await HowItWorks.clickButton(cancelButton) + console.log("Email SignIn was Cancelled") + await expect(HowItWorks.getTitleSignUpPopUp).toHaveText('Sign In or Join'); + }); + // HowItWorks_005 + it('verifyCancelSigninWithMobile', async () => { + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const mobilePhoneNumber = await HowItWorks.enterMobilePhoneNumber; + await mobilePhoneNumber.addValue(testData.MOBILE_NUMBER); + const cancelButton = await HowItWorks.cancelMobilePhoneNumberButton; + await HowItWorks.clickButton(cancelButton) + await expect(HowItWorks.getTitleSignUpPopUp).toHaveText('Sign In or Join'); + console.log("Mobile SignIn was Cancelled") + }); + // HowItWorks_006 + it('verifyCancelSigninWithApple', async () => { + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const signinWithAppleID = await HowItWorks.enterSignInWithApple; + await HowItWorks.clickButton(signinWithAppleID) + await driver.back() //This line won't work in Safari. Needs to be addressed after WV-557 issue is fixed + await expect(HowItWorks.getTitleSignUpPopUp).toHaveText('Sign In or Join'); + console.log("AppleID SignIn was Cancelled") + }); + // HowItWorks_007 + it('verifyCancelSigninWithTwitter', async () => { + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const signinWithTwitter = await HowItWorks.enterSignInWithTwitter; + await HowItWorks.clickButton(signinWithTwitter) + const cancelButton = await HowItWorks.cancelTwitterSignin; + await HowItWorks.clickButton(cancelButton) + const gotoHomePage = await HowItWorks.gotoWeVoteBallotGuide; + await HowItWorks.clickButton(gotoHomePage) + await driver.pause(waitTime); + await expect(driver).toHaveUrl(expect.stringContaining('quality')); + console.log("Twitter SignIn was Cancelled") + }); + // HowItWorks_008 + it('verifySigninUsingMobile', async () => { + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const mobilePhoneNumber = await HowItWorks.enterMobilePhoneNumber; + await mobilePhoneNumber.addValue(testData.MOBILE_NUMBER); + const sendCode = await HowItWorks.enterSendVerificationCode; + await HowItWorks.clickButton(sendCode) + for (let i = 0; i < 6; i++) { + const digitValue = await HowItWorks.enterDigit(i); + await digitValue.addValue(testData.MOBILE_VERIFICATION[i]); + } + const verifyButton = await HowItWorks.enterVerifyButton; + await HowItWorks.clickButton(verifyButton) + const profileAvatar = await HowItWorks.enterProfileAvatar; + await HowItWorks.clickButton(profileAvatar) + console.log("User was able to successfully signIn using mobile") + }); + //HowItWorks_013 + it('verifyInvalidMobileNumber' , async () =>{ + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const mobilePhoneNumber = await HowItWorks.enterMobilePhoneNumber; + await mobilePhoneNumber.addValue(testData.INVALID_MOBILE_NUMBER); + await driver.pause(waitTime); + await expect(HowItWorks.phoneNumberHelperText).toHaveText('Enter a valid phone number'); + console.log("Invalid Mobile number error message verified") + }); + //HowItWorks_014 + it('VerifyInvalidEmailAddress' , async () =>{ + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const emailTextBox = await HowItWorks.enterVoterEmailAddressTextBox; + await emailTextBox.addValue(testData.INVALID_EMAIL_ADDRESS); + await driver.pause(waitTime); + await expect(HowItWorks.emailAddressHelperText).toHaveText('Enter valid email 6 to 254 characters long'); + console.log("Invalid Email Address error message verified") + }); + // HowItWorks_015 + it('verifyDeleteUnverifiedPhoneNumbers', async () => { + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const mobilePhoneNumber = await HowItWorks.enterMobilePhoneNumber; + await mobilePhoneNumber.addValue(testData.UNVERIFIED_PHONE_NUMBER); + const sendCode = await HowItWorks.enterSendVerificationCode; + await HowItWorks.clickButton(sendCode) + const backButton = await HowItWorks.backArrow; + await HowItWorks.clickButton(backButton) + const deleteButton = await HowItWorks.deleteIcon; + await driver.pause(waitTime); + await HowItWorks.clickButton(deleteButton); + await expect(HowItWorks.alertMessage).toHaveText('Your Phone number was deleted.'); + console.log("Deleted unverified phone numbers") + }); + // HowItWorks_016 + it('verifyDeleteUnverifiedEmailAddress', async () => { + await ReadyPage.load(); + await ReadyPage.clickHowItWorksLink(); + await driver.pause(waitTime); + await HowItWorks.clickNextButtonFourTimes(); + const getStarted = await HowItWorks.getStartedButton; + await HowItWorks.clickButton(getStarted) + const mobilePhoneNumber = await HowItWorks.enterMobilePhoneNumber; + const emailTextBox = await HowItWorks.enterVoterEmailAddressTextBox; + await emailTextBox.addValue(testData.EMAIL_NEGATIVE_SCENARIO); + const sendCode = await HowItWorks.enterSendEmailVerificationCode; + await HowItWorks.clickButton(sendCode) + const backButton = await HowItWorks.backArrow; + await HowItWorks.clickButton(backButton) + const deleteButton = await HowItWorks.deleteIcon; + await driver.pause(waitTime); + await HowItWorks.clickButton(deleteButton); + await expect(HowItWorks.alertMessage).toHaveText('Your email address was deleted.'); + console.log("Deleted unverified Email address") + }); - // // Ready_014 - // it('verifyHowItWorksModalWindowBackButton', async () => { - // await ReadyPage.load(); - // await driver.pause(waitTime); - // await ReadyPage.clickHowItWorksLink(); - // await driver.pause(waitTime); - // const expectedResult = await ReadyPage.getTitleOfHowItWorksWindowAfterBackButton(); - // await expect(ReadyPage.howItWorksTitle).toHaveText(expectedResult); - // }); }); From 48d4cca5ccee6d103b2a5de53e564ea637d00018 Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Thu, 10 Oct 2024 12:35:28 -0700 Subject: [PATCH 43/54] Inviting friend to Challenge now creates functioning SharedItem on back end. Consolidating font-color to main.css. Bulk update of "all of the" to "all the". --- src/App.jsx | 15 +-- src/css/main.css | 4 +- .../svg-icons/{issues => }/rocket-ship.svg | 0 src/js/actions/ReadyActions.js | 2 +- .../common/actions/ChallengeInviteeActions.js | 4 +- src/js/common/actions/ShareActions.js | 2 +- .../Challenge/ThanksForViewingChallenge.jsx | 20 ++-- .../InviteFriendToChallengeInput.jsx | 29 +++++- .../ChallengeInviteeListRoot.jsx | 2 +- .../InviteAgainButton.jsx | 2 +- .../Navigation/ChallengeInviteSteps.jsx | 10 +- src/js/common/components/PrivacyBody.jsx | 2 +- .../Settings/CompleteYourProfile.jsx | 2 +- .../pages/Challenge/ChallengeHomePage.jsx | 40 +++++--- .../ChallengeInviteCustomizeMessage.jsx | 11 ++- .../ChallengeInviteFriends.jsx | 31 +++++- .../stores/ChallengeParticipantStore.js | 6 +- src/js/common/stores/ChallengeStore.js | 11 ++- src/js/common/stores/ShareStore.js | 3 + .../Ballot/BallotScrollingContainer.jsx | 4 +- src/js/components/Ballot/PositionDrawer.jsx | 2 +- src/js/components/Ballot/PositionItem.jsx | 4 +- .../components/Ballot/PositionItemSquare.jsx | 4 +- src/js/components/Ballot/PositionRowItem.jsx | 2 +- src/js/components/Ready/ReadyTaskBallot.jsx | 4 +- src/js/components/Ready/VoterPlanModal.jsx | 2 +- .../Values/IssuesByBallotItemDisplayList.jsx | 2 +- .../IssuesByOrganizationDisplayList.jsx | 2 +- src/js/pages/SharedItemLanding.jsx | 95 +++++++++++-------- src/js/stores/FriendStore.js | 2 +- src/js/stores/IssueStore.js | 4 +- 31 files changed, 218 insertions(+), 105 deletions(-) rename src/img/global/svg-icons/{issues => }/rocket-ship.svg (100%) diff --git a/src/App.jsx b/src/App.jsx index 8b90704d2..1e5e9d2a5 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -411,6 +411,7 @@ class App extends Component { } /> } /> + } /> } /> } /> } /> @@ -737,14 +738,14 @@ class App extends Component { } const WeVoteBody = styled('div')` - background-color: #fff; // rgb(235, 236, 238); // #fafafa; - color: #000; + // We rely on many of these from the body from main.css, including: + //background-color: #fff; // rgb(235, 236, 238); // #fafafa; + //color: #000; + //font-family: "Poppins", "Helvetica Neue Light", "Helvetica Neue", "Helvetica", "Arial", sans-serif; + //line-height: 1.4; + // margin: 0 auto; + display: block; - font-family: "Poppins", "Helvetica Neue Light", "Helvetica Neue", "Helvetica", "Arial", sans-serif; - line-height: 1.4; - margin: 0 auto; - // max-width: 960px; - //height: 100vw; position: relative; z-index: 0; // this debug technique works! ${() => console.log('-----------------------------')} diff --git a/src/css/main.css b/src/css/main.css index 24af97cba..df8233bf4 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -59,8 +59,8 @@ body { font-style:normal; font-weight:normal; letter-spacing:.15px; - line-height:24px; - margin:0; + line-height: 1.4; + margin:0 auto; text-align:left } diff --git a/src/img/global/svg-icons/issues/rocket-ship.svg b/src/img/global/svg-icons/rocket-ship.svg similarity index 100% rename from src/img/global/svg-icons/issues/rocket-ship.svg rename to src/img/global/svg-icons/rocket-ship.svg diff --git a/src/js/actions/ReadyActions.js b/src/js/actions/ReadyActions.js index 6f68edb45..b5b77a2e3 100644 --- a/src/js/actions/ReadyActions.js +++ b/src/js/actions/ReadyActions.js @@ -2,7 +2,7 @@ import Dispatcher from '../common/dispatcher/Dispatcher'; export default { voterPlansForVoterRetrieve (year = 0, month = 0, googleCivicElectionId = 0, stateCode = '') { - // Retrieve the click statistics for all of the items you have shared + // Retrieve the click statistics for all the items you have shared return Dispatcher.loadEndpoint('voterPlansForVoterRetrieve', { google_civic_election_id: googleCivicElectionId, month, diff --git a/src/js/common/actions/ChallengeInviteeActions.js b/src/js/common/actions/ChallengeInviteeActions.js index 0f768833c..faccac9ce 100644 --- a/src/js/common/actions/ChallengeInviteeActions.js +++ b/src/js/common/actions/ChallengeInviteeActions.js @@ -16,11 +16,13 @@ export default { }); }, - challengeInviteeSave (challengeWeVoteId, inviteeId = 0, inviteeName = '', inviteeNameChanged = false, inviteTextFromInviter = '', inviteTextFromInviterChanged = false, inviteeUrlCode = '', inviteeUrlCodeChanged = false) { + challengeInviteeSave (challengeWeVoteId, destinationFullURL = '', googleCivicElectionId = 0, inviteeId = 0, inviteeName = '', inviteeNameChanged = false, inviteTextFromInviter = '', inviteTextFromInviterChanged = false, inviteeUrlCode = '', inviteeUrlCodeChanged = false) { // console.log('challengeInviteeSave called with challengeWeVoteId: ', challengeWeVoteId, ' and inviteeName: ', inviteeName); Dispatcher.loadEndpoint('challengeInviteeSave', { challenge_we_vote_id: challengeWeVoteId, + destination_full_url: destinationFullURL, + google_civic_election_id: googleCivicElectionId, invitee_id: inviteeId, invitee_name: inviteeName, invitee_name_changed: inviteeNameChanged, diff --git a/src/js/common/actions/ShareActions.js b/src/js/common/actions/ShareActions.js index c8a1d72d1..19bd11c18 100644 --- a/src/js/common/actions/ShareActions.js +++ b/src/js/common/actions/ShareActions.js @@ -28,7 +28,7 @@ export default { }, sharedItemListRetrieve (year = 0, month = 0, googleCivicElectionId = 0, stateCode = '') { - // Retrieve the click statistics for all of the items you have shared + // Retrieve the click statistics for all the items you have shared return Dispatcher.loadEndpoint('sharedItemListRetrieve', { google_civic_election_id: googleCivicElectionId, month, diff --git a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx index 441345393..73f866b2a 100644 --- a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx +++ b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import Confetti from 'react-confetti'; import React, { useState, useEffect } from 'react'; -const ThanksForViewingChallenge = ({ challengeOwner }) => { +const ThanksForViewingChallenge = ({ sharedByDisplayName }) => { const [isClosing, setIsClosing] = useState(false); const [showConfetti, setShowConfetti] = useState(false); @@ -33,10 +33,18 @@ const ThanksForViewingChallenge = ({ challengeOwner }) => { {showConfetti && } - Thanks for confirming - the link from  - {challengeOwner} - ! + Thanks for checking out this challenge + {sharedByDisplayName && ( + <> + {' '} + your friend + {' '} + {sharedByDisplayName} + {' '} + has shared with you + + )} + ! Join the challenge below. { ); }; ThanksForViewingChallenge.propTypes = { - challengeOwner: PropTypes.string.isRequired, + sharedByDisplayName: PropTypes.string, }; const CloseMessageIconWrapper = styled.div` diff --git a/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx b/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx index 83330ac0c..7f31894e8 100755 --- a/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx +++ b/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx @@ -17,6 +17,8 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq renderLog('InviteFriendToChallengeInputBox'); // Set LOG_RENDER_EVENTS to log all renders const [challengeInviteTextDefault, setChallengeInviteTextDefault] = React.useState(''); const [challengeTitle, setChallengeTitle] = React.useState(''); + const [destinationFullURL, setDestinationFullURL] = React.useState(''); + const [googleCivicElectionId, setGoogleCivicElectionId] = React.useState(0); const [inviteCopiedMessageOn, setInviteCopiedMessageOn] = React.useState(false); const [inviteeName, setInviteeName] = React.useState(''); const [inviterName, setInviterName] = React.useState(''); @@ -31,9 +33,11 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq inviteTextToSendTemp1 += inviterFirstName ? `, this is ${inviterFirstName}. ` : ', '; const inviteTextToSendTemp2 = inviteTextForFriends || challengeInviteTextDefault; const inviteeUrlCode = ChallengeInviteeStore.getNextInviteeUrlCode(); - const urlToSendTemp = `${ChallengeStore.getSiteUrl(challengeWeVoteId)}/++/${inviteeUrlCode}`; + const urlToSendTemp = `${ChallengeStore.getSiteUrl(challengeWeVoteId)}/-${inviteeUrlCode}`; const inviteTextToSendTemp3 = `${inviteTextToSendTemp1}${inviteTextToSendTemp2} ${urlToSendTemp}`; setInviteTextToSend(inviteTextToSendTemp3); + const SEOFriendlyPath = ChallengeStore.getChallengeSEOFriendlyPathByWeVoteId(challengeWeVoteId); + setDestinationFullURL(`${ChallengeStore.getSiteUrl(challengeWeVoteId)}/${SEOFriendlyPath}/+/`); // setUrlToSend(urlToSendTemp); } @@ -46,13 +50,21 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq const handleShare = async () => { const inviteeUrlCode = ChallengeInviteeStore.getNextInviteeUrlCode(); - ChallengeInviteeActions.challengeInviteeSave(challengeWeVoteId, 0, inviteeName, true, inviteTextToSend, true, inviteeUrlCode, true); + ChallengeInviteeActions.challengeInviteeSave( + challengeWeVoteId, + destinationFullURL, + googleCivicElectionId, + 0, + inviteeName, true, + inviteTextToSend, true, + inviteeUrlCode, true, + ); setInviteCopiedMessageOn(true); setTimeout(() => { console.log('handleShare setTimeout fired'); setInviteCopiedMessageOn(false); resetForm(); - }, 1000); + }, 2000); if (navigator.share) { try { await navigator.share({ @@ -84,18 +96,22 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq }; const onChallengeParticipantStoreChange = () => { - setInviterName(VoterStore.getFirstName()); setInviteTextForFriends(ChallengeParticipantStore.getInviteTextForFriends(challengeWeVoteId)); prepareInviteTextToSend(); }; const onChallengeStoreChange = () => { - setInviterName(VoterStore.getFirstName()); setChallengeInviteTextDefault(ChallengeStore.getChallengeInviteTextDefaultByWeVoteId(challengeWeVoteId)); setChallengeTitle(ChallengeStore.getChallengeTitleByWeVoteId(challengeWeVoteId)); prepareInviteTextToSend(); }; + const onVoterStoreChange = () => { + setGoogleCivicElectionId(VoterStore.electionId()); + setInviterName(VoterStore.getFirstName()); + prepareInviteTextToSend(); + }; + // console.log('Fetching participants for:', challengeWeVoteId); const challengeInviteeStoreListener = ChallengeInviteeStore.addListener(onChallengeInviteeStoreChange); onChallengeParticipantStoreChange(); @@ -103,11 +119,14 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq onChallengeParticipantStoreChange(); const challengeStoreListener = ChallengeStore.addListener(onChallengeStoreChange); onChallengeStoreChange(); + const voterStoreListener = VoterStore.addListener(onVoterStoreChange); + onVoterStoreChange(); return () => { challengeInviteeStoreListener.remove(); challengeParticipantStoreListener.remove(); challengeStoreListener.remove(); + voterStoreListener.remove(); }; }, [challengeWeVoteId]); diff --git a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListRoot.jsx b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListRoot.jsx index 233e93187..e300d155d 100644 --- a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListRoot.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListRoot.jsx @@ -7,7 +7,7 @@ import FirstChallengeInviteeListController from './FirstChallengeInviteeListCont import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; import ChallengeInviteeStore from '../../stores/ChallengeInviteeStore'; import DesignTokenColors from '../Style/DesignTokenColors'; -import ChallengeParticipantStore from "../../stores/ChallengeParticipantStore"; +import ChallengeParticipantStore from '../../stores/ChallengeParticipantStore'; const ChallengeParticipantFirstRetrieveController = React.lazy(() => import(/* webpackChunkName: 'ChallengeParticipantFirstRetrieveController' */ '../ChallengeParticipant/ChallengeParticipantFirstRetrieveController')); diff --git a/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx b/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx index 0651e46b2..6fbcf626e 100755 --- a/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx @@ -107,7 +107,7 @@ const InviteAgainButton = ({ classes, challengeWeVoteId, challengeInviteeId }) = } // console.log('challengeInviteTextDefault: ', challengeInviteTextDefault); const inviteeUrlCode = ChallengeInviteeStore.getNextInviteeUrlCode(); - const urlToSendTemp = `${ChallengeStore.getSiteUrl(challengeWeVoteId)}/++/${inviteeUrlCode}`; + const urlToSendTemp = `${ChallengeStore.getSiteUrl(challengeWeVoteId)}/-${inviteeUrlCode}`; const inviteTextToSendTemp3 = `${inviteTextToSendTemp1}${inviteTextToSendTemp2} ${urlToSendTemp}`; setInviteTextToSend(inviteTextToSendTemp3); // setUrlToSend(urlToSendTemp); diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index e1e20dd65..812de0fc2 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -39,6 +39,12 @@ class ChallengeInviteSteps extends React.Component { return 1; }; + // Check if a step is active based on the current step number + // isStepActive = (stepNumber) => this.props.currentStep === stepNumber; + + // Set a step as active when clicked + isStepActive = (stepNumber) => this.state.activeStep === stepNumber; + // Get the path for the challenge getChallengeBasePath = () => { const { challengeSEOFriendlyPath, challengeWeVoteId } = this.props; @@ -51,9 +57,6 @@ class ChallengeInviteSteps extends React.Component { return challengeBasePath; }; - // Set a step as active when clicked - isStepActive = (stepNumber) => this.state.activeStep === stepNumber; - // Update the active step when the link is clicked handleStepClick = (stepNumber) => { this.setState({ activeStep: stepNumber }); @@ -146,6 +149,7 @@ class ChallengeInviteSteps extends React.Component { } ChallengeInviteSteps.propTypes = { + currentStep: PropTypes.number.isRequired, challengeSEOFriendlyPath: PropTypes.string, challengeWeVoteId: PropTypes.string, location: PropTypes.object.isRequired, diff --git a/src/js/common/components/PrivacyBody.jsx b/src/js/common/components/PrivacyBody.jsx index 568fc9e33..f410439ad 100755 --- a/src/js/common/components/PrivacyBody.jsx +++ b/src/js/common/components/PrivacyBody.jsx @@ -171,7 +171,7 @@ export default class PrivacyBody extends Component { Who you Follow on Twitter - When you sign in with Twitter, all of the Twitter accounts you follow on Twitter which have endorsements stored in WeVote, are displayed on your profile + When you sign in with Twitter, all the Twitter accounts you follow on Twitter which have endorsements stored in WeVote, are displayed on your profile Yes No diff --git a/src/js/common/components/Settings/CompleteYourProfile.jsx b/src/js/common/components/Settings/CompleteYourProfile.jsx index fc8f0dc0d..672ca865c 100644 --- a/src/js/common/components/Settings/CompleteYourProfile.jsx +++ b/src/js/common/components/Settings/CompleteYourProfile.jsx @@ -296,7 +296,7 @@ class CompleteYourProfile extends Component { } else { buttonText = 'Help them win'; } - introductionText = Leading up to election day, WeVote.US will remind you to vote for all of the candidates you support. We keep your email secure and confidential.; + introductionText = Leading up to election day, WeVote.US will remind you to vote for all the candidates you support. We keep your email secure and confidential.; } else if (supportCampaignOnCampaignHome) { if (voterCanVoteForPoliticianInCampaign) { buttonText = 'Support with my vote'; diff --git a/src/js/common/pages/Challenge/ChallengeHomePage.jsx b/src/js/common/pages/Challenge/ChallengeHomePage.jsx index 9c68e960b..e4cc94581 100644 --- a/src/js/common/pages/Challenge/ChallengeHomePage.jsx +++ b/src/js/common/pages/Challenge/ChallengeHomePage.jsx @@ -44,6 +44,7 @@ import ChallengeAbout from '../../components/Challenge/ChallengeAbout'; import ChallengeParticipantListRoot from '../../components/ChallengeParticipantListRoot/ChallengeParticipantListRoot'; import ChallengeInviteeListRoot from '../../components/ChallengeInviteeListRoot/ChallengeInviteeListRoot'; import ThanksForViewingChallenge from '../../components/Challenge/ThanksForViewingChallenge' +import ShareStore from '../../stores/ShareStore'; const ChallengeCardForList = React.lazy(() => import(/* webpackChunkName: 'ChallengeCardForList' */ '../../components/ChallengeListRoot/ChallengeCardForList')); // const ChallengeCommentsList = React.lazy(() => import(/* webpackChunkName: 'ChallengeCommentsList' */ '../../components/Challenge/ChallengeCommentsList')); @@ -108,6 +109,7 @@ class ChallengeHomePage extends Component { challengeWeVoteIdForDisplay: '', // Value for challenge already received sharingStepCompleted: false, step2Completed: false, + thanksForViewingChallengeOn: false, voterCanEditThisChallenge: false, }; // this.onScroll = this.onScroll.bind(this); @@ -116,7 +118,11 @@ class ChallengeHomePage extends Component { componentDidMount () { // console.log('ChallengeHomePage componentDidMount'); const { match: { params } } = this.props; - const { challengeSEOFriendlyPath: challengeSEOFriendlyPathFromUrl, challengeWeVoteId } = params; + const { + challengeSEOFriendlyPath: challengeSEOFriendlyPathFromUrl, + challengeWeVoteId, + shared_item_code: sharedItemCodeIncoming, + } = params; // console.log('ChallengeHomePage componentDidMount tabSelected: ', tabSelected); // console.log('componentDidMount challengeSEOFriendlyPathFromUrl: ', challengeSEOFriendlyPathFromUrl, ', challengeWeVoteId: ', challengeWeVoteId); this.onAppObservableStoreChange(); @@ -162,6 +168,20 @@ class ChallengeHomePage extends Component { } }, 5000); // April 19, 2021: Tuned to keep performance above 83. LCP at 597ms + // If we came in through a sharedItem link and then redirected to this page, fetch the shared item details + const sharedItem = ShareStore.getSharedItemByCode(sharedItemCodeIncoming); + // console.log('sharedItem:', sharedItem); + if (sharedItem && sharedItem.shared_by_display_name) { + const { + shared_by_display_name: sharedByDisplayName, + // shared_by_first_name: sharedByFirstName, + } = sharedItem; + this.setState({ + sharedByDisplayName, + thanksForViewingChallengeOn: true, + }); + } + // console.log('componentDidMount triggerSEOPathRedirect: ', triggerSEOPathRedirect, ', challengeSEOFriendlyPathFromObject: ', challengeSEOFriendlyPathFromObject); if (triggerSEOPathRedirect && challengeSEOFriendlyPathFromObject) { historyPush(`/${challengeSEOFriendlyPathFromObject}/+/`, true); @@ -453,12 +473,9 @@ class ChallengeHomePage extends Component { challengeDataFound, challengeDataNotFound, challengeDescription, challengeDescriptionLimited, challengeImageUrlLarge, challengeSEOFriendlyPath, challengeSEOFriendlyPathForDisplay, - challengeTitle, - challengeWeVoteIdForDisplay, - scrolledDown, - voterCanEditThisChallenge, - voterIsChallengeParticipant, - voterWeVoteId, + challengeTitle, challengeWeVoteIdForDisplay, + scrolledDown, sharedByDisplayName, thanksForViewingChallengeOn, + voterCanEditThisChallenge, voterIsChallengeParticipant, voterWeVoteId, } = this.state; // console.log('ChallengeHomePage render challengeSEOFriendlyPath: ', challengeSEOFriendlyPath, ', challengeSEOFriendlyPathForDisplay: ', challengeSEOFriendlyPathForDisplay); const challengeAdminEditUrl = `${webAppConfig.WE_VOTE_SERVER_ROOT_URL}challenge/${challengeWeVoteId}/summary`; @@ -520,10 +537,11 @@ class ChallengeHomePage extends Component { ); return ( - + {thanksForViewingChallengeOn && ( + + )}  }> @@ -200,7 +201,15 @@ class ChallengeInviteCustomizeMessage extends Component { - Hi [your friend's name], it's David. + Hi [your friend's name] + {voterFirstName && ( + <> + , it's + {' '} + {voterFirstName} + + )} + . diff --git a/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriends.jsx b/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriends.jsx index 987bc91b6..be43f6f00 100644 --- a/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriends.jsx +++ b/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriends.jsx @@ -18,10 +18,12 @@ import { renderLog } from '../../utils/logging'; import DesignTokenColors from '../../components/Style/DesignTokenColors'; import ChallengeInviteSteps from '../../components/Navigation/ChallengeInviteSteps'; import ChallengeInviteeListRoot from '../../components/ChallengeInviteeListRoot/ChallengeInviteeListRoot'; +import ChallengeInviteeStore from '../../stores/ChallengeInviteeStore'; import InviteFriendToChallengeInput from '../../components/ChallengeInviteFriends/InviteFriendToChallengeInput'; import YourRank from '../../components/Challenge/YourRank'; const ChallengeRetrieveController = React.lazy(() => import(/* webpackChunkName: 'ChallengeRetrieveController' */ '../../components/Challenge/ChallengeRetrieveController')); +const FirstChallengeInviteeListController = React.lazy(() => import(/* webpackChunkName: 'ChallengeRetrieveController' */ '../../components/ChallengeInviteeListRoot/FirstChallengeInviteeListController')); const VoterFirstRetrieveController = loadable(() => import(/* webpackChunkName: 'VoterFirstRetrieveController' */ '../../components/Settings/VoterFirstRetrieveController')); @@ -34,6 +36,7 @@ class ChallengeInviteFriends extends Component { challengeTitle: '', challengeWeVoteId: '', chosenWebsiteName: '', + inviteeList: [], }; } @@ -42,6 +45,8 @@ class ChallengeInviteFriends extends Component { this.props.setShowHeaderFooter(false); this.onAppObservableStoreChange(); this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange()); + this.onChallengeInviteeStoreChange(); + this.challengeInviteeStoreListener = ChallengeInviteeStore.addListener(this.onChallengeInviteeStoreChange.bind(this)); this.onChallengeStoreChange(); this.challengeStoreListener = ChallengeStore.addListener(this.onChallengeStoreChange.bind(this)); const { match: { params } } = this.props; @@ -85,6 +90,7 @@ class ChallengeInviteFriends extends Component { componentWillUnmount () { this.props.setShowHeaderFooter(true); this.appStateSubscription.unsubscribe(); + this.challengeInviteeStoreListener.remove(); this.challengeStoreListener.remove(); } @@ -96,6 +102,16 @@ class ChallengeInviteFriends extends Component { }); } + onChallengeInviteeStoreChange () { + const { challengeWeVoteId } = this.state; + if (challengeWeVoteId) { + const inviteeList = ChallengeInviteeStore.getChallengeInviteeList(challengeWeVoteId); + this.setState({ + inviteeList, + }); + } + } + onChallengeStoreChange () { const { match: { params } } = this.props; const { challengeSEOFriendlyPath: challengeSEOFriendlyPathFromParams, challengeWeVoteId: challengeWeVoteIdFromParams } = params; @@ -153,7 +169,7 @@ class ChallengeInviteFriends extends Component { renderLog('ChallengeInviteFriends'); // Set LOG_RENDER_EVENTS to log all renders const { challengePhotoLargeUrl, challengeSEOFriendlyPath, challengeTitle, - challengeWeVoteId, chosenWebsiteName, + challengeWeVoteId, chosenWebsiteName, inviteeList, } = this.state; const htmlTitle = `Invite your friends - ${chosenWebsiteName}`; return ( @@ -197,16 +213,21 @@ class ChallengeInviteFriends extends Component { - - - - + {inviteeList.length > 0 && ( + + + + + )}  }>  }> + }> + + ); } diff --git a/src/js/common/stores/ChallengeParticipantStore.js b/src/js/common/stores/ChallengeParticipantStore.js index 5673ca1cf..9871bec13 100644 --- a/src/js/common/stores/ChallengeParticipantStore.js +++ b/src/js/common/stores/ChallengeParticipantStore.js @@ -6,7 +6,7 @@ import AppObservableStore from './AppObservableStore'; const orderByDateJoined = (firstEntry, secondEntry) => new Date(secondEntry.date_joined) - new Date(firstEntry.date_joined); -const orderByParticipantsCount = (firstEntry, secondEntry) => secondEntry.points - firstEntry.points; +const orderByPoints = (firstEntry, secondEntry) => secondEntry.points - firstEntry.points; class ChallengeParticipantStore extends ReduceStore { getInitialState () { @@ -196,7 +196,7 @@ class ChallengeParticipantStore extends ReduceStore { if (!action.res || !action.res.success) return state; revisedState = state; challengeParticipantList = action.res.challenge_participant_list || []; - // A little filtering to keep data clean and avoid duplicates + // A little filtering to keep data clean and avoid duplicate participant entries tied to the same voter challengeParticipantList.forEach((oneParticipant) => { if (!(oneParticipant.voter_we_vote_id in voterWeVoteIdList) && oneParticipant.challenge_we_vote_id === action.res.challenge_we_vote_id) { challengeParticipantListModified.push(oneParticipant); @@ -204,7 +204,7 @@ class ChallengeParticipantStore extends ReduceStore { voterWeVoteIdList.push(oneParticipant.voter_we_vote_id); }); challengeParticipantListModified = challengeParticipantListModified.sort(orderByDateJoined); - challengeParticipantListModified = challengeParticipantListModified.sort(orderByParticipantsCount); + challengeParticipantListModified = challengeParticipantListModified.sort(orderByPoints); challengeParticipantListModified = challengeParticipantListModified.map((participant, index) => ({ ...participant, rank: index + 1 })); challengeParticipantListModified.forEach((participant, index) => { if (index === 0) { diff --git a/src/js/common/stores/ChallengeStore.js b/src/js/common/stores/ChallengeStore.js index 0d2162bfe..8a522c32c 100644 --- a/src/js/common/stores/ChallengeStore.js +++ b/src/js/common/stores/ChallengeStore.js @@ -2,6 +2,7 @@ import { ReduceStore } from 'flux/utils'; import { avatarGeneric } from '../../utils/applicationUtils'; import Dispatcher from '../dispatcher/Dispatcher'; import arrayContains from '../utils/arrayContains'; +import AppObservableStore from './AppObservableStore'; import VoterStore from '../../stores/VoterStore'; import daysUntil from '../utils/daysUntil'; // eslint-disable-line import/no-cycle @@ -249,6 +250,14 @@ class ChallengeStore extends ReduceStore { return SUPPORTERS_COUNT_NEXT_GOAL_DEFAULT; } + getChallengeSEOFriendlyPathByWeVoteId (challengeWeVoteId) { + const challenge = this.getState().allCachedChallengeDicts[challengeWeVoteId]; + if (challenge === undefined || challenge.seo_friendly_path === undefined) { + return ''; + } + return challenge.seo_friendly_path; + } + getChallengeTitleByWeVoteId (challengeWeVoteId) { const challenge = this.getState().allCachedChallengeDicts[challengeWeVoteId]; if (challenge === undefined || challenge.challenge_title === undefined) { @@ -340,7 +349,7 @@ class ChallengeStore extends ReduceStore { if (challenge && challenge.site_url) { return challenge.site_url; } else { - return 'https://wevote.us'; + return AppObservableStore.getWeVoteRootURL(); } } diff --git a/src/js/common/stores/ShareStore.js b/src/js/common/stores/ShareStore.js index 824442cba..109ac635e 100644 --- a/src/js/common/stores/ShareStore.js +++ b/src/js/common/stores/ShareStore.js @@ -226,6 +226,9 @@ class ShareStore extends ReduceStore { if (action.res.shared_item_code_all_opinions) { allCachedSharedItemsBySharedItemCode[action.res.shared_item_code_all_opinions] = sharedItem; } + if (action.res.shared_item_code_challenge) { + allCachedSharedItemsBySharedItemCode[action.res.shared_item_code_challenge] = sharedItem; + } if (action.res.shared_item_code_ready) { allCachedSharedItemsBySharedItemCode[action.res.shared_item_code_ready] = sharedItem; } diff --git a/src/js/components/Ballot/BallotScrollingContainer.jsx b/src/js/components/Ballot/BallotScrollingContainer.jsx index 4deffbfe9..05a77ae22 100644 --- a/src/js/components/Ballot/BallotScrollingContainer.jsx +++ b/src/js/components/Ballot/BallotScrollingContainer.jsx @@ -100,7 +100,7 @@ class BallotScrollingContainer extends Component { }; handleContainerClick = (e, weVoteId) => { - console.log(e.target); + // console.log(e.target); const candidateContainer = document.getElementById(`candidateContainer-${weVoteId}`); const positionRowListOuterWrapper = document.getElementById(`positionRowListOuterWrapper-${weVoteId}`); const candidateDiv = document.getElementById(`candidateDiv-${weVoteId}`); @@ -116,7 +116,7 @@ class BallotScrollingContainer extends Component { const buttonWrapper = document.getElementById(`buttonWrapper-${weVoteId}`); // EAW VERIFY - might not need this one const candidateParty = document.getElementById(`candidateParty-${weVoteId}`); - console.log(buttonWrapper); + // console.log(buttonWrapper); if (e.target === candidateDiv || e.target === candidateContainer || e.target === positionRowListOuterWrapper || diff --git a/src/js/components/Ballot/PositionDrawer.jsx b/src/js/components/Ballot/PositionDrawer.jsx index ffd660604..a5c8b9222 100644 --- a/src/js/components/Ballot/PositionDrawer.jsx +++ b/src/js/components/Ballot/PositionDrawer.jsx @@ -120,7 +120,7 @@ class PositionDrawer extends Component { } // 2022-04-28 This slows down rendering too much - // // We want to make sure we have all of the position information so that comments show up + // // We want to make sure we have all the position information so that comments show up // const voterGuidesForThisBallotItem = VoterGuideStore.getVoterGuidesToFollowForBallotItemId(ballotItemWeVoteId); // // if (voterGuidesForThisBallotItem) { diff --git a/src/js/components/Ballot/PositionItem.jsx b/src/js/components/Ballot/PositionItem.jsx index ff05e0fe4..db5ec88cb 100644 --- a/src/js/components/Ballot/PositionItem.jsx +++ b/src/js/components/Ballot/PositionItem.jsx @@ -47,7 +47,7 @@ class PositionItem extends Component { this.voterGuideStoreListener = VoterGuideStore.addListener(this.onVoterGuideStoreChange.bind(this)); // This creates too much load on the browser - // // We want to make sure we have all of the position information so that comments show up + // // We want to make sure we have all the position information so that comments show up // if (ballotItemWeVoteId) { // const voterGuidesForThisBallotItem = VoterGuideStore.getVoterGuidesToFollowForBallotItemId(ballotItemWeVoteId); // @@ -105,7 +105,7 @@ class PositionItem extends Component { // const { ballot_item_we_vote_id: ballotItemWeVoteId, speaker_we_vote_id: organizationWeVoteId } = position; // This puts too much strain on the browser since PositionItems are in a list - // // We want to make sure we have all of the position information so that comments show up + // // We want to make sure we have all the position information so that comments show up // if (ballotItemWeVoteId) { // const voterGuidesForThisBallotItem = VoterGuideStore.getVoterGuidesToFollowForBallotItemId(ballotItemWeVoteId); // diff --git a/src/js/components/Ballot/PositionItemSquare.jsx b/src/js/components/Ballot/PositionItemSquare.jsx index b9f068e9e..a0c567812 100644 --- a/src/js/components/Ballot/PositionItemSquare.jsx +++ b/src/js/components/Ballot/PositionItemSquare.jsx @@ -31,7 +31,7 @@ class PositionItemSquare extends Component { this.voterGuideStoreListener = VoterGuideStore.addListener(this.onVoterGuideStoreChange.bind(this)); // Creates too much load on the browser - // // We want to make sure we have all of the position information so that comments show up + // // We want to make sure we have all the position information so that comments show up // if (ballotItemWeVoteId) { // const voterGuidesForThisBallotItem = VoterGuideStore.getVoterGuidesToFollowForBallotItemId(ballotItemWeVoteId); // @@ -89,7 +89,7 @@ class PositionItemSquare extends Component { // const { position } = this.props; // const { ballot_item_we_vote_id: ballotItemWeVoteId, speaker_we_vote_id: organizationWeVoteId } = position; // - // // We want to make sure we have all of the position information so that comments show up + // // We want to make sure we have all the position information so that comments show up // if (ballotItemWeVoteId) { // const voterGuidesForThisBallotItem = VoterGuideStore.getVoterGuidesToFollowForBallotItemId(ballotItemWeVoteId); // diff --git a/src/js/components/Ballot/PositionRowItem.jsx b/src/js/components/Ballot/PositionRowItem.jsx index 2d7ba7033..513d8f34c 100644 --- a/src/js/components/Ballot/PositionRowItem.jsx +++ b/src/js/components/Ballot/PositionRowItem.jsx @@ -66,7 +66,7 @@ class PositionRowItem extends Component { const { position } = this.props; const { ballot_item_we_vote_id: ballotItemWeVoteId, speaker_we_vote_id: organizationWeVoteId } = position; - // We want to make sure we have all of the position information so that comments show up + // We want to make sure we have all the position information so that comments show up if (ballotItemWeVoteId) { const voterGuidesForThisBallotItem = VoterGuideStore.getVoterGuidesToFollowForBallotItemId(ballotItemWeVoteId); diff --git a/src/js/components/Ready/ReadyTaskBallot.jsx b/src/js/components/Ready/ReadyTaskBallot.jsx index 85852c13c..13d674e47 100644 --- a/src/js/components/Ready/ReadyTaskBallot.jsx +++ b/src/js/components/Ready/ReadyTaskBallot.jsx @@ -32,7 +32,7 @@ class ReadyTaskBallot extends React.Component { allCandidatesButtonNeeded: false, // Are there candidates on this ballot? allCandidatesAllCompleted: false, allCandidatesNumberCompleted: 0, - allCandidatesShowButton: false, // Given all of the buttons we need to show, should this one be "unfurled"? + allCandidatesShowButton: false, // Given all the buttons we need to show, should this one be "unfurled"? allCandidatesTotalNumber: 0, federalButtonNeeded: false, // Are there Federal candidates on this ballot? federalAllCompleted: false, @@ -256,7 +256,7 @@ class ReadyTaskBallot extends React.Component { // If there are measures, measureShowButton is always true measureShowButton = (measureButtonNeeded); // console.log('measureButtonNeeded:', measureButtonNeeded, ', measureShowButton:', measureShowButton); - // If all of the possible decisions have been made + // If all the possible decisions have been made allDecisionsMadeCount += federalAllCompleted ? 1 : 0; allDecisionsMadeCount += localAllCompleted ? 1 : 0; allDecisionsMadeCount += measureAllCompleted ? 1 : 0; diff --git a/src/js/components/Ready/VoterPlanModal.jsx b/src/js/components/Ready/VoterPlanModal.jsx index 78a91c667..431203e31 100644 --- a/src/js/components/Ready/VoterPlanModal.jsx +++ b/src/js/components/Ready/VoterPlanModal.jsx @@ -70,7 +70,7 @@ class VoterPlanModal extends Component { } componentDidUpdate (prevProps, prevState) { - // Update the Json that we save with all of the settings + // Update the Json that we save with all the settings const { approximateTime, electionDateMonthYear, locationToDeliverBallot, modeOfTransport, showToPublic, voterPlanDataSerializedCalculatedFirstTime, diff --git a/src/js/components/Values/IssuesByBallotItemDisplayList.jsx b/src/js/components/Values/IssuesByBallotItemDisplayList.jsx index faf50101d..991d4eac8 100644 --- a/src/js/components/Values/IssuesByBallotItemDisplayList.jsx +++ b/src/js/components/Values/IssuesByBallotItemDisplayList.jsx @@ -7,7 +7,7 @@ import VoterGuideStore from '../../stores/VoterGuideStore'; import signInModalGlobalState from '../../common/components/Widgets/signInModalGlobalState'; import ValueNameWithPopoverDisplay from './ValueNameWithPopoverDisplay'; -// Show a voter a horizontal list of all of the issues they are following that relate to this ballot item +// Show a voter a horizontal list of all the issues they are following that relate to this ballot item class IssuesByBallotItemDisplayList extends Component { static closePopover () { document.body.click(); diff --git a/src/js/components/Values/IssuesByOrganizationDisplayList.jsx b/src/js/components/Values/IssuesByOrganizationDisplayList.jsx index 4943d7315..f7d873532 100644 --- a/src/js/components/Values/IssuesByOrganizationDisplayList.jsx +++ b/src/js/components/Values/IssuesByOrganizationDisplayList.jsx @@ -14,7 +14,7 @@ import IssueFollowToggleButton from './IssueFollowToggleButton'; const ReadMore = React.lazy(() => import(/* webpackChunkName: 'ReadMore' */ '../../common/components/Widgets/ReadMore')); -// Show a voter a horizontal list of all of the issues they are following that relate to this ballot item +// Show a voter a horizontal list of all the issues they are following that relate to this ballot item class IssuesByOrganizationDisplayList extends Component { static closePopover () { document.body.click(); diff --git a/src/js/pages/SharedItemLanding.jsx b/src/js/pages/SharedItemLanding.jsx index 5b1aa3098..dfd8e2802 100644 --- a/src/js/pages/SharedItemLanding.jsx +++ b/src/js/pages/SharedItemLanding.jsx @@ -18,6 +18,8 @@ export default class SharedItemLanding extends Component { customLinkString: '', destinationFullUrl: '', destinationFullUrlOverride: '', + isBallotShare: false, + isChallengeShare: false, sharedItemCodeIncoming: '', sharedItemCodeRetrieved: false, waitForVoterDeviceId: false, @@ -59,41 +61,48 @@ export default class SharedItemLanding extends Component { // destinationFullUrl, // }); } + // console.log('sharedItemCodeIncoming:', sharedItemCodeIncoming); if (sharedItemCodeIncoming) { const sharedItem = ShareStore.getSharedItemByCode(sharedItemCodeIncoming); // console.log('sharedItem:', sharedItem); - const { - destination_full_url: destinationFullUrl, - destination_full_url_override: destinationFullUrlOverride, - email_secret_key: emailSecretKey, - is_ballot_share: isBallotShare, - shared_item_code_all_opinions: sharedItemCodeAllOpinions, - other_voter_display_name: voterDisplayName, - other_voter_first_name: voterFirstName, - other_voter_last_name: voterLastName, - } = sharedItem; - // console.log('SharedItemLanding emailSecretKey:', emailSecretKey); - let waitForVoterDeviceId = false; - if (emailSecretKey) { - if (VoterStore.voterDeviceId()) { - // We trigger this here (instead of on the API server with ShareActions.sharedItemRetrieveByCode) - // to reduce delay around first page display - // If the email hasn't been previously verified, this verifies it and attaches it to this account - // console.log('SharedItemLanding firstName:', voterFirstName, ', lastName:', voterLastName, ', fullName:', voterDisplayName); - VoterActions.voterEmailAddressVerify(emailSecretKey, voterFirstName, voterLastName, voterDisplayName); - // VoterActions.voterFullNameSoftSave(voterFirstName, voterLastName, voterDisplayName); - } else { - waitForVoterDeviceId = true; + if (sharedItem && sharedItem.destination_full_url) { + const { + destination_full_url: destinationFullUrl, + destination_full_url_override: destinationFullUrlOverride, + email_secret_key: emailSecretKey, + is_ballot_share: isBallotShare, + is_challenge_share: isChallengeShare, + shared_item_code_all_opinions: sharedItemCodeAllOpinions, + other_voter_display_name: voterDisplayName, + other_voter_first_name: voterFirstName, + other_voter_last_name: voterLastName, + } = sharedItem; + // console.log('SharedItemLanding emailSecretKey:', emailSecretKey); + let waitForVoterDeviceId = false; + if (emailSecretKey) { + if (VoterStore.voterDeviceId()) { + // We trigger this here (instead of on the API server with ShareActions.sharedItemRetrieveByCode) + // to reduce delay around first page display + // If the email hasn't been previously verified, this verifies it and attaches it to this account + // console.log('SharedItemLanding firstName:', voterFirstName, ', lastName:', voterLastName, ', fullName:', voterDisplayName); + VoterActions.voterEmailAddressVerify(emailSecretKey, voterFirstName, voterLastName, voterDisplayName); + // VoterActions.voterFullNameSoftSave(voterFirstName, voterLastName, voterDisplayName); + } else { + waitForVoterDeviceId = true; + } } + this.setState({ + destinationFullUrl, + destinationFullUrlOverride, + isBallotShare, + isChallengeShare, + sharedItemCodeAllOpinions, + sharedItemCodeRetrieved: true, + waitForVoterDeviceId, + }); + } else { + console.log('SharedItemLanding destination_full_url not found'); } - this.setState({ - destinationFullUrl, - destinationFullUrlOverride, - isBallotShare, - sharedItemCodeAllOpinions, - sharedItemCodeRetrieved: true, - waitForVoterDeviceId, - }); } } @@ -110,7 +119,11 @@ export default class SharedItemLanding extends Component { render () { renderLog('SharedItemLanding'); // Set LOG_RENDER_EVENTS to log all renders - const { componentDidMount, isBallotShare, destinationFullUrlOverride, sharedItemCodeAllOpinions, sharedItemCodeIncoming, sharedItemCodeRetrieved } = this.state; + const { + componentDidMount, destinationFullUrlOverride, + isBallotShare, isChallengeShare, + sharedItemCodeAllOpinions, sharedItemCodeIncoming, sharedItemCodeRetrieved, + } = this.state; let { destinationFullUrl } = this.state; // console.log('sharedItemCodeIncoming:', sharedItemCodeIncoming, 'sharedItemCodeAllOpinions:', sharedItemCodeAllOpinions); // console.log('destinationFullUrl:', destinationFullUrl, 'destinationFullUrlOverride:', destinationFullUrlOverride); @@ -124,7 +137,7 @@ export default class SharedItemLanding extends Component { // console.log('SharedItemLanding sharedItemCodeRetrieved not retrieved'); return LoadingWheel; } else if (sharedItemCodeRetrieved && (destinationFullUrl === undefined || destinationFullUrl === '')) { - // console.log('SharedItemLanding destinationFullUrl undefined'); + // console.log('SharedItemLanding destinationFullUrl undefined, directing to /ready'); this.localHistoryPush('/ready'); return LoadingWheel; } else { @@ -138,14 +151,20 @@ export default class SharedItemLanding extends Component { // console.log('Ballot Share AllOpinions'); return ; } else if (destinationFullUrl && destinationFullUrl.startsWith(hrefHostname)) { - let destinationLocalUrl = destinationFullUrl.replace(hrefHostname, ''); - destinationLocalUrl = destinationLocalUrl.replace(':3000', ''); // For local development machines - this.localHistoryPush(destinationLocalUrl); - // const destinationLocalUrlWithModal = `${destinationLocalUrl}/modal/sic/${sharedItemCodeIncoming}`; - // // console.log('*** WILL Direct to LOCAL destinationLocalUrlWithModal:', destinationLocalUrlWithModal); - // historyPush(destinationLocalUrlWithModal); + let destinationPath = destinationFullUrl.replace(hrefHostname, ''); + destinationPath = destinationPath.replace(':3000', ''); // For local development machines + if (isChallengeShare) { + // Add the sharedItemCode to the end of the URL so we have access to the sharedItem data on the next page + destinationPath += `-${sharedItemCodeIncoming}`; + } + // console.log('SharedItemLanding destinationPath:', destinationPath); + this.localHistoryPush(destinationPath); + // const destinationPathWithModal = `${destinationPath}/modal/sic/${sharedItemCodeIncoming}`; + // // console.log('*** WILL Direct to LOCAL destinationPathWithModal:', destinationPathWithModal); + // historyPush(destinationPathWithModal); return LoadingWheel; } else { + // console.log('SharedItemLanding destinationFullUrl:', destinationFullUrl); this.localHistoryPush(destinationFullUrl); // const destinationFullUrlWithModal = `${destinationFullUrl}/modal/sic/${sharedItemCodeIncoming}`; // // console.log('*** WILL Direct to EXTERNAL destinationFullUrlWithModal:', destinationFullUrlWithModal); diff --git a/src/js/stores/FriendStore.js b/src/js/stores/FriendStore.js index 685a55db1..5ba54e882 100644 --- a/src/js/stores/FriendStore.js +++ b/src/js/stores/FriendStore.js @@ -459,7 +459,7 @@ class FriendStore extends ReduceStore { if (!action.res.success) { return state; } else { - // Firing all of these "just in case" api queries is slow, and firing queries from Stores should bed avoidd + // Firing all these "just in case" api queries is slow, and firing queries from Stores should bed avoidd // console.log('resetting FriendStore from voterSignOut'); if (apiCalming('friendListsAll', 1500)) { FriendActions.friendListsAll(); diff --git a/src/js/stores/IssueStore.js b/src/js/stores/IssueStore.js index d92b81d7e..95cea01ff 100644 --- a/src/js/stores/IssueStore.js +++ b/src/js/stores/IssueStore.js @@ -237,7 +237,7 @@ class IssueStore extends ReduceStore { // if (!ballotItemWeVoteId) { // return 0; // } - // // These are scores based on all of the organizations under all of the issues a voter follows + // // These are scores based on all the organizations under all the issues a voter follows // const issueScore = this.getState().issueScoreForEachBallotItem[ballotItemWeVoteId]; // if (issueScore === undefined) { // return 0; @@ -876,7 +876,7 @@ class IssueStore extends ReduceStore { }; case 'voterGuidesUpcomingRetrieve': // List of all public voter guides from CDN - // Collect all of the issues an organization is tagged with + // Collect all the issues an organization is tagged with // console.log('IssueStore, case voterGuidesToFollowRetrieve'); voterGuides = action.res.voter_guides; if (!voterGuides || voterGuides.length === 0) { From 6bfbf1c6af69ea13fccb3baa80c15449c16eb70f Mon Sep 17 00:00:00 2001 From: JedwardMook Date: Fri, 11 Oct 2024 18:37:14 -0500 Subject: [PATCH 44/54] changes abbreviateNumber to numberAbbreviate and updates usage, uses instead of numberWithCommas in ThumbsUpDownToggle --- .../PoliticianEndorsementForList.jsx | 4 ++-- .../ThumbsUpDownToggle/ThumbsUpDownToggle.jsx | 20 +++++-------------- ...bbreviateNumber.js => numberAbbreviate.js} | 4 ++-- .../Ballot/CandidateItemEndorsement.jsx | 4 ++-- src/js/components/Ballot/PositionItem.jsx | 4 ++-- src/js/components/Friends/FriendDetails.jsx | 4 ++-- .../CandidateItemForOpinions.jsx | 4 ++-- .../Organization/OrganizationPopoverCard.jsx | 4 ++-- .../components/Twitter/TwitterAccountCard.jsx | 4 ++-- src/js/components/Values/IssueCard.jsx | 8 ++++---- .../OrganizationVoterGuideCandidateItem.jsx | 4 ++-- .../VoterGuide/OrganizationVoterGuideTabs.jsx | 4 ++-- .../Widgets/TwitterAccountStats.jsx | 4 ++-- 13 files changed, 31 insertions(+), 41 deletions(-) rename src/js/common/utils/{abbreviateNumber.js => numberAbbreviate.js} (89%) diff --git a/src/js/common/components/Politician/PoliticianEndorsementForList.jsx b/src/js/common/components/Politician/PoliticianEndorsementForList.jsx index 738eb1dca..fb93c17f1 100644 --- a/src/js/common/components/Politician/PoliticianEndorsementForList.jsx +++ b/src/js/common/components/Politician/PoliticianEndorsementForList.jsx @@ -13,7 +13,7 @@ import { CommentVoterPhotoWrapper, CommentWrapper, OneCampaignInnerWrapper, OneCampaignOuterWrapper, ReadMoreSpan, } from '../Style/CampaignDetailsStyles'; -import abbreviateNumber from '../../utils/abbreviateNumber'; +import numberAbbreviate from '../../utils/numberAbbreviate'; import { getDateFromUltimateElectionDate, getTodayAsInteger, timeFromDate } from '../../utils/dateFormat'; import { isCordova } from '../../utils/isCordovaOrWebApp'; import { renderLog } from '../../utils/logging'; @@ -188,7 +188,7 @@ class PoliticianEndorsementForList extends Component { {!!(twitterFollowersCount) && ( - { abbreviateNumber(twitterFollowersCount) } + { numberAbbreviate(twitterFollowersCount) } {' '} Twitter Followers diff --git a/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx index 61d69833d..730414b01 100644 --- a/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx +++ b/src/js/common/components/Widgets/ThumbsUpDownToggle/ThumbsUpDownToggle.jsx @@ -4,11 +4,11 @@ import { styled, Tooltip } from '@mui/material'; import { withStyles } from '@mui/styles'; import DesignTokenColors from '../../Style/DesignTokenColors'; import ThumbsUpDownToggleIcon from './ThumbsUpDownToggleIcon'; -import numberWithCommas from '../../../utils/numberWithCommas'; +import numberAbbreviate from '../../../utils/numberAbbreviate'; function ThumbsUpDownToggle ({ classes }) { - const [thumbsUpAmountLocal, setThumbsUpAmountLocal] = useState(1237653); - const [thumbsDownAmountLocal, setThumbsDownAmountLocal] = useState(1237653); + const [thumbsUpAmountLocal, setThumbsUpAmountLocal] = useState(9000); + const [thumbsDownAmountLocal, setThumbsDownAmountLocal] = useState(9990); const [supports, setSupports] = useState(false); const [opposes, setOpposes] = useState(false); @@ -88,16 +88,6 @@ function ThumbsUpDownToggle ({ classes }) { } }; - const displayAmountConversion = (amount) => { - if (amount >= 1000000) { - return `${(amount / 100000).toFixed(1).replace(/\.0$/, '')}M`; - } - if (amount >= 1000) { - return `${(amount / 1000).toFixed(1).replace(/\.0$/, '')}K`; - } - return numberWithCommas(amount); - }; - return ( @@ -111,7 +101,7 @@ function ThumbsUpDownToggle ({ classes }) { - {displayAmountConversion(thumbsUpAmountLocal)} + {numberAbbreviate(thumbsUpAmountLocal)}   @@ -125,7 +115,7 @@ function ThumbsUpDownToggle ({ classes }) { - {displayAmountConversion(thumbsDownAmountLocal)} + {numberAbbreviate(thumbsDownAmountLocal)} ); diff --git a/src/js/common/utils/abbreviateNumber.js b/src/js/common/utils/numberAbbreviate.js similarity index 89% rename from src/js/common/utils/abbreviateNumber.js rename to src/js/common/utils/numberAbbreviate.js index 14f22f2a0..ba63e5250 100644 --- a/src/js/common/utils/abbreviateNumber.js +++ b/src/js/common/utils/numberAbbreviate.js @@ -1,6 +1,6 @@ -// abbreviateNumber.js +// numberAbbreviate.js -export default function abbreviateNumber (num) { +export default function numberAbbreviate (num) { // =< 1,000,000 - round to hundred-thousand (1.4M) if (num >= 1000000) { return `${(num / 1000000).toFixed(1).replace(/\.0$/, '')}M`; diff --git a/src/js/components/Ballot/CandidateItemEndorsement.jsx b/src/js/components/Ballot/CandidateItemEndorsement.jsx index 7f6fe02a8..fe113103c 100644 --- a/src/js/components/Ballot/CandidateItemEndorsement.jsx +++ b/src/js/components/Ballot/CandidateItemEndorsement.jsx @@ -5,7 +5,7 @@ import withStyles from '@mui/styles/withStyles'; import PropTypes from 'prop-types'; import React, { Component, Suspense } from 'react'; import VoterGuidePossibilityActions from '../../actions/VoterGuidePossibilityActions'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import historyPush from '../../common/utils/historyPush'; import { displayNoneIfSmallerThanDesktop } from '../../common/utils/isMobileScreenSize'; import { renderLog } from '../../common/utils/logging'; @@ -391,7 +391,7 @@ class CandidateItemEndorsement extends Component { className="twitter-followers__badge" > - {abbreviateNumber(twitterFollowersCount)} + {numberAbbreviate(twitterFollowersCount)} )} {(!hideCandidateUrl && candidateUrl) && ( diff --git a/src/js/components/Ballot/PositionItem.jsx b/src/js/components/Ballot/PositionItem.jsx index ff05e0fe4..78e871587 100644 --- a/src/js/components/Ballot/PositionItem.jsx +++ b/src/js/components/Ballot/PositionItem.jsx @@ -7,7 +7,7 @@ import React, { Component, Suspense } from 'react'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; import SvgImage from '../../common/components/Widgets/SvgImage'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import { renderLog } from '../../common/utils/logging'; import normalizedImagePath from '../../common/utils/normalizedImagePath'; import AppObservableStore from '../../common/stores/AppObservableStore'; @@ -362,7 +362,7 @@ class PositionItem extends Component { {position.speaker_twitter_handle} - {abbreviateNumber(position.twitter_followers_count)} + {numberAbbreviate(position.twitter_followers_count)} )} diff --git a/src/js/components/Friends/FriendDetails.jsx b/src/js/components/Friends/FriendDetails.jsx index d52216a02..55f2ba3fb 100644 --- a/src/js/components/Friends/FriendDetails.jsx +++ b/src/js/components/Friends/FriendDetails.jsx @@ -6,7 +6,7 @@ import Tooltip from 'react-bootstrap/Tooltip'; import styled from 'styled-components'; import isMobileScreenSize from '../../common/utils/isMobileScreenSize'; import { FriendDetailsLine, FriendDetailsWrapper, FriendName, InviteToWeVoteLine } from '../Style/friendStyles'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import { renderLog } from '../../common/utils/logging'; const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite')); @@ -165,7 +165,7 @@ class FriendDetails extends Component { )} - {abbreviateNumber(mutualFriendCount)} + {numberAbbreviate(mutualFriendCount)} {' '} diff --git a/src/js/components/OpinionsAndBallotItems/CandidateItemForOpinions.jsx b/src/js/components/OpinionsAndBallotItems/CandidateItemForOpinions.jsx index b227ff8ac..1f9b0c8e7 100644 --- a/src/js/components/OpinionsAndBallotItems/CandidateItemForOpinions.jsx +++ b/src/js/components/OpinionsAndBallotItems/CandidateItemForOpinions.jsx @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import React, { Component, Suspense } from 'react'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import historyPush from '../../common/utils/historyPush'; import { displayNoneIfSmallerThanDesktop } from '../../common/utils/isMobileScreenSize'; import { renderLog } from '../../common/utils/logging'; @@ -240,7 +240,7 @@ class CandidateItemForOpinions extends Component { onClick={() => this.goToCandidateLink} > - {abbreviateNumber(oneCandidate.twitter_followers_count)} + {numberAbbreviate(oneCandidate.twitter_followers_count)} )} diff --git a/src/js/components/Organization/OrganizationPopoverCard.jsx b/src/js/components/Organization/OrganizationPopoverCard.jsx index 4cca42cc3..05dbaa9dd 100755 --- a/src/js/components/Organization/OrganizationPopoverCard.jsx +++ b/src/js/components/Organization/OrganizationPopoverCard.jsx @@ -8,7 +8,7 @@ import Button from 'react-bootstrap/Button'; import { Link } from 'react-router-dom'; import OrganizationActions from '../../actions/OrganizationActions'; import LoadingWheel from '../../common/components/Widgets/LoadingWheel'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import historyPush from '../../common/utils/historyPush'; import { renderLog } from '../../common/utils/logging'; import numberWithCommas from '../../common/utils/numberWithCommas'; @@ -189,7 +189,7 @@ class OrganizationPopoverCard extends Component { @ {organizationTwitterHandle} - {abbreviateNumber(twitterFollowersCount)} + {numberAbbreviate(twitterFollowersCount)} )} {twitterDescriptionMinusName && ( diff --git a/src/js/components/Twitter/TwitterAccountCard.jsx b/src/js/components/Twitter/TwitterAccountCard.jsx index ddd82ed70..b155631ff 100644 --- a/src/js/components/Twitter/TwitterAccountCard.jsx +++ b/src/js/components/Twitter/TwitterAccountCard.jsx @@ -2,7 +2,7 @@ import { Launch, Twitter } from '@mui/icons-material'; import PropTypes from 'prop-types'; import React, { Component, Suspense } from 'react'; import styled from 'styled-components'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import { renderLog } from '../../common/utils/logging'; import numberWithCommas from '../../common/utils/numberWithCommas'; import removeTwitterNameFromDescription from '../../common/utils/removeTwitterNameFromDescription'; @@ -56,7 +56,7 @@ export default class TwitterAccountCard extends Component { {twitterFollowersCount ? ( - {abbreviateNumber(twitterFollowersCount)} + {numberAbbreviate(twitterFollowersCount)} ) : null} {twitterUserWebsite ? ( diff --git a/src/js/components/Values/IssueCard.jsx b/src/js/components/Values/IssueCard.jsx index ef03484ef..810a68980 100755 --- a/src/js/components/Values/IssueCard.jsx +++ b/src/js/components/Values/IssueCard.jsx @@ -5,7 +5,7 @@ import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Tooltip from 'react-bootstrap/Tooltip'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import { isCordova } from '../../common/utils/isCordovaOrWebApp'; import isMobileScreenSize from '../../common/utils/isMobileScreenSize'; import Cookies from '../../common/utils/js-cookie/Cookies'; @@ -255,7 +255,7 @@ class IssueCard extends Component { const followersTooltip = isMobileScreenSize() ? () : (
- {abbreviateNumber(issueFollowersCount)} + {numberAbbreviate(issueFollowersCount)} {' '} people have followed {' '} @@ -306,7 +306,7 @@ class IssueCard extends Component { )} {!!(linkedOrganizationCount) && ( - {abbreviateNumber(linkedOrganizationCount)} + {numberAbbreviate(linkedOrganizationCount)} @@ -419,7 +419,7 @@ class IssueCard extends Component { {!!(issueFollowersCount) && ( <> - {abbreviateNumber(issueFollowersCount)} + {numberAbbreviate(issueFollowersCount)} {' '} followers diff --git a/src/js/components/VoterGuide/OrganizationVoterGuideCandidateItem.jsx b/src/js/components/VoterGuide/OrganizationVoterGuideCandidateItem.jsx index 35263b000..2539adf32 100644 --- a/src/js/components/VoterGuide/OrganizationVoterGuideCandidateItem.jsx +++ b/src/js/components/VoterGuide/OrganizationVoterGuideCandidateItem.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import React, { Component, Suspense } from 'react'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import historyPush from '../../common/utils/historyPush'; import { renderLog } from '../../common/utils/logging'; import numberWithCommas from '../../common/utils/numberWithCommas'; @@ -144,7 +144,7 @@ export default class OrganizationVoterGuideCandidateItem extends Component { onClick={linkToBallotItemPage ? this.goToCandidateLink : null} > - {abbreviateNumber(twitterFollowersCount)} + {numberAbbreviate(twitterFollowersCount)} ) : null} diff --git a/src/js/components/VoterGuide/OrganizationVoterGuideTabs.jsx b/src/js/components/VoterGuide/OrganizationVoterGuideTabs.jsx index 88d5c649c..94618ab37 100644 --- a/src/js/components/VoterGuide/OrganizationVoterGuideTabs.jsx +++ b/src/js/components/VoterGuide/OrganizationVoterGuideTabs.jsx @@ -7,7 +7,7 @@ import AppObservableStore, { messageService } from '../../common/stores/AppObser import OrganizationStore from '../../stores/OrganizationStore'; import VoterGuideStore from '../../stores/VoterGuideStore'; import VoterStore from '../../stores/VoterStore'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; import apiCalming from '../../common/utils/apiCalming'; import { renderLog } from '../../common/utils/logging'; import LoadingWheel from '../../common/components/Widgets/LoadingWheel'; @@ -334,7 +334,7 @@ export default class OrganizationVoterGuideTabs extends Component { > {(allOrganizationPositionsLength > 0) && ( <> - {abbreviateNumber(allOrganizationPositionsLength)} + {numberAbbreviate(allOrganizationPositionsLength)}   )} diff --git a/src/js/components/Widgets/TwitterAccountStats.jsx b/src/js/components/Widgets/TwitterAccountStats.jsx index 09bbf6f09..5bd741da3 100644 --- a/src/js/components/Widgets/TwitterAccountStats.jsx +++ b/src/js/components/Widgets/TwitterAccountStats.jsx @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import React, { Suspense } from 'react'; import { renderLog } from '../../common/utils/logging'; import numberWithCommas from '../../common/utils/numberWithCommas'; -import abbreviateNumber from '../../common/utils/abbreviateNumber'; +import numberAbbreviate from '../../common/utils/numberAbbreviate'; const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite')); @@ -24,7 +24,7 @@ function TwitterAccountStats (props) { {twitterHandle} )} - {abbreviateNumber(twitterFollowersCount)} + {numberAbbreviate(twitterFollowersCount)} ); return ( From 80f9dcb2d24cbd1601810e81ec430628385c9c60 Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Fri, 11 Oct 2024 19:28:51 -0700 Subject: [PATCH 45/54] Moved icons out of "issues" folder into the root "svg-icons" folder. Significant changes to YourRank. Layout changes based on user testing. Added multiple tips. Highlight Candidates and Challenges top header when on any politician landing page or challenge. If a SharedItem link is sent out without a code, at least display the Ready page. --- src/App.jsx | 1 + .../{issues => }/joined-green-circle.svg | 0 .../material-symbols-counter-1-active.svg | 0 .../material-symbols-counter-1.svg | 0 .../material-symbols-counter-2-active.svg | 0 .../material-symbols-counter-2.svg | 0 .../material-symbols-info-outline.svg | 0 src/js/actions/AnalyticsActions.js | 1 + .../common/actions/ChallengeInviteeActions.js | 4 +- .../components/Challenge/ChallengeAbout.jsx | 2 +- .../Challenge/JoinedAndDaysLeft.jsx | 4 +- .../Challenge/ThanksForViewingChallenge.jsx | 4 +- .../common/components/Challenge/YourRank.jsx | 480 +++--------------- .../components/Challenge/YourRankModal.jsx | 9 +- .../InviteFriendsTips.jsx | 158 ++++++ .../ThanksForJoiningChallenge.jsx | 17 +- .../ChallengeInviteeListItem.jsx | 61 ++- .../ChallengeInviteeListRoot.jsx | 5 +- .../InviteAgainButton.jsx | 43 +- .../Navigation/ChallengeInviteSteps.jsx | 39 +- .../components/Style/ChallengeCardStyles.jsx | 10 + .../pages/Challenge/ChallengeHomePage.jsx | 38 +- .../ChallengeInviteFriends.jsx | 37 +- .../ChallengeInviteFriendsJoin.jsx | 2 +- .../stores/ChallengeParticipantStore.js | 2 +- src/js/common/utils/hrefUtils.js | 4 + 26 files changed, 400 insertions(+), 521 deletions(-) rename src/img/global/svg-icons/{issues => }/joined-green-circle.svg (100%) rename src/img/global/svg-icons/{issues => }/material-symbols-counter-1-active.svg (100%) rename src/img/global/svg-icons/{issues => }/material-symbols-counter-1.svg (100%) rename src/img/global/svg-icons/{issues => }/material-symbols-counter-2-active.svg (100%) rename src/img/global/svg-icons/{issues => }/material-symbols-counter-2.svg (100%) rename src/img/global/svg-icons/{issues => }/material-symbols-info-outline.svg (100%) create mode 100644 src/js/common/components/ChallengeInviteFriends/InviteFriendsTips.jsx diff --git a/src/App.jsx b/src/App.jsx index 1e5e9d2a5..fc5907aa6 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -409,6 +409,7 @@ class App extends Component { + } /> } /> } /> diff --git a/src/img/global/svg-icons/issues/joined-green-circle.svg b/src/img/global/svg-icons/joined-green-circle.svg similarity index 100% rename from src/img/global/svg-icons/issues/joined-green-circle.svg rename to src/img/global/svg-icons/joined-green-circle.svg diff --git a/src/img/global/svg-icons/issues/material-symbols-counter-1-active.svg b/src/img/global/svg-icons/material-symbols-counter-1-active.svg similarity index 100% rename from src/img/global/svg-icons/issues/material-symbols-counter-1-active.svg rename to src/img/global/svg-icons/material-symbols-counter-1-active.svg diff --git a/src/img/global/svg-icons/issues/material-symbols-counter-1.svg b/src/img/global/svg-icons/material-symbols-counter-1.svg similarity index 100% rename from src/img/global/svg-icons/issues/material-symbols-counter-1.svg rename to src/img/global/svg-icons/material-symbols-counter-1.svg diff --git a/src/img/global/svg-icons/issues/material-symbols-counter-2-active.svg b/src/img/global/svg-icons/material-symbols-counter-2-active.svg similarity index 100% rename from src/img/global/svg-icons/issues/material-symbols-counter-2-active.svg rename to src/img/global/svg-icons/material-symbols-counter-2-active.svg diff --git a/src/img/global/svg-icons/issues/material-symbols-counter-2.svg b/src/img/global/svg-icons/material-symbols-counter-2.svg similarity index 100% rename from src/img/global/svg-icons/issues/material-symbols-counter-2.svg rename to src/img/global/svg-icons/material-symbols-counter-2.svg diff --git a/src/img/global/svg-icons/issues/material-symbols-info-outline.svg b/src/img/global/svg-icons/material-symbols-info-outline.svg similarity index 100% rename from src/img/global/svg-icons/issues/material-symbols-info-outline.svg rename to src/img/global/svg-icons/material-symbols-info-outline.svg diff --git a/src/js/actions/AnalyticsActions.js b/src/js/actions/AnalyticsActions.js index 2f6d8191d..8b5defbde 100644 --- a/src/js/actions/AnalyticsActions.js +++ b/src/js/actions/AnalyticsActions.js @@ -82,6 +82,7 @@ import AppObservableStore from '../common/stores/AppObservableStore'; // ACTION_ORGANIZATION_FOLLOW_DISLIKE = 79 // ACTION_ORGANIZATION_STOP_DISLIKING = 80 // ACTION_POLITICIAN_PAGE_VISIT = 81 +// ACTION_VIEW_SHARED_CHALLENGE = 82 export default { diff --git a/src/js/common/actions/ChallengeInviteeActions.js b/src/js/common/actions/ChallengeInviteeActions.js index faccac9ce..330682182 100644 --- a/src/js/common/actions/ChallengeInviteeActions.js +++ b/src/js/common/actions/ChallengeInviteeActions.js @@ -26,8 +26,8 @@ export default { invitee_id: inviteeId, invitee_name: inviteeName, invitee_name_changed: inviteeNameChanged, - invitee_text_from_inviter: inviteTextFromInviter, - invitee_text_from_inviter_changed: inviteTextFromInviterChanged, + invite_text_from_inviter: inviteTextFromInviter, + invite_text_from_inviter_changed: inviteTextFromInviterChanged, invitee_url_code: inviteeUrlCode, invitee_url_code_changed: inviteeUrlCodeChanged, }); diff --git a/src/js/common/components/Challenge/ChallengeAbout.jsx b/src/js/common/components/Challenge/ChallengeAbout.jsx index 8db1c353c..85abf6677 100644 --- a/src/js/common/components/Challenge/ChallengeAbout.jsx +++ b/src/js/common/components/Challenge/ChallengeAbout.jsx @@ -143,7 +143,7 @@ const styles = () => ({ export const CardForListRow = styled('div')` color: ${DesignTokenColors.neutral500}; - font-size: 12px; + font-size: 14px; padding: 3px 0; `; diff --git a/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx b/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx index 2b8253233..edc27ee7e 100644 --- a/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx +++ b/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx @@ -1,8 +1,8 @@ import React, { Suspense } from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; -import JoinedGreenCircle from '../../../../img/global/svg-icons/issues/joined-green-circle.svg'; -import InfoOutlineIcon from '../../../../img/global/svg-icons/issues/material-symbols-info-outline.svg'; +import JoinedGreenCircle from '../../../../img/global/svg-icons/joined-green-circle.svg'; +import InfoOutlineIcon from '../../../../img/global/svg-icons/material-symbols-info-outline.svg'; import ChallengeStore from '../../stores/ChallengeStore'; import DesignTokenColors from '../Style/DesignTokenColors'; diff --git a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx index 73f866b2a..5f948ca72 100644 --- a/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx +++ b/src/js/common/components/Challenge/ThanksForViewingChallenge.jsx @@ -37,11 +37,9 @@ const ThanksForViewingChallenge = ({ sharedByDisplayName }) => { {sharedByDisplayName && ( <> {' '} - your friend + shared with you by {' '} {sharedByDisplayName} - {' '} - has shared with you )} ! Join the challenge below. diff --git a/src/js/common/components/Challenge/YourRank.jsx b/src/js/common/components/Challenge/YourRank.jsx index 9d92a86e5..f93e31ed4 100644 --- a/src/js/common/components/Challenge/YourRank.jsx +++ b/src/js/common/components/Challenge/YourRank.jsx @@ -1,15 +1,15 @@ import { Button } from '@mui/material'; -import React, { useState, Suspense } from 'react'; -import styled from 'styled-components'; import withStyles from '@mui/styles/withStyles'; +import React, { Suspense, useEffect, useState } from 'react'; +import Confetti from 'react-confetti'; +import styled from 'styled-components'; import DesignTokenColors from '../Style/DesignTokenColors'; -// import { CampaignSupportDesktopButtonPanel, CampaignSupportDesktopButtonWrapper, CampaignSupportSection, CampaignSupportSectionWrapper } from '../../components/Style/CampaignSupportStyles'; -// import { SupportButtonFooterWrapper, SupportButtonPanel} from '../../components/Style/CampaignDetailsStyles'; import arrow from '../../../../img/global/icons/ph_arrow-up-bold.png'; import arrow1 from '../../../../img/global/icons/ph_arrow-up-bold_1.png'; import YourRankModal from './YourRankModal'; import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; import ChallengeParticipantStore from '../../stores/ChallengeParticipantStore'; +import FirstChallengeParticipantListController from '../ChallengeParticipantListRoot/FirstChallengeParticipantListController'; const YourRank = ({ classes, challengeWeVoteId }) => { const [clicked, setClicked] = useState(false); @@ -18,6 +18,8 @@ const YourRank = ({ classes, challengeWeVoteId }) => { // const [note, setNote] = useState(""); const [arrowImage, setArrowImage] = useState(arrow); const [openYourRankModal, setOpenYourRankModal] = useState(false); + const [rankOfVoter, setRankOfVoter] = React.useState(0); + const [showConfetti, setShowConfetti] = useState(false); const onAppObservableStoreChange = () => { setRankOfVoter(AppObservableStore.getChallengeParticipantRankOfVoterByChallengeWeVoteId(challengeWeVoteId)); @@ -55,60 +57,62 @@ const YourRank = ({ classes, challengeWeVoteId }) => { challengeParticipantStoreListener.remove(); }; }, [challengeWeVoteId]); + + useEffect(() => { + // Show confetti when the component mounts + setShowConfetti(true); + // Hide confetti after a short duration + const timer = setTimeout(() => { + setShowConfetti(false); + }, 5000); + return () => clearTimeout(timer); + }, []); + return ( - -
-

Your rank in the challenge:

-
- - - }> - setOpenYourRankModal(!openYourRankModal)} - /> - - -
+ + + + {showConfetti && } + Your rank in the challenge: + + + + + + }> + + + }> + setOpenYourRankModal(!openYourRankModal)} + /> + + ); }; const styles = (theme) => ({ buttonDesktop: { boxShadow: 'none !important', color: '#AC5204', - width: '105px', height: '34px', border: '1px solid #AC5204', borderRadius: '20px 20px 20px 20px', transition: 'color 0.3s ease', textTransform: 'none', + width: '105px', }, desktopSimpleLink: { border: '2px solid #AC5204', @@ -141,364 +145,36 @@ const styles = (theme) => ({ angle: '-90 deg', }, }); -const ChallengeTabsWrapper = styled('div')` - background-color: ${DesignTokenColors.neutralUI50}; - display: flex; - justify-content: center; - `; -const YourRankWrapper = styled('div')` - background-color: ${DesignTokenColors.neutralUI50}; - display: flex; - justify-content: center; - `; -const CompleteYourProfileButtonWrapper = styled('div')` - background-color: ${(props) => (props.clicked ? '#AC5204' : '#FFFFFF')}; - width: 105px; - height: 34px; - top: 443px; - left: 234px; - gap: 0px; - border-radius: 20px; - border: 1px solid #AC5204, - display: flex; - align-items: center; - justify-content: center; - transition: background-color 0.3s ease, color 0.3s ease; - `; -export default withStyles(styles)(YourRank); +const YourRankInnerWrapper = styled('div')` + align-items: center; + display: flex; + height: 70px; + justify-content: center; +`; +const YourRankOuterWrapper = styled('div')` + background-color: ${DesignTokenColors.neutralUI50}; + z-index: 100; +`; +const YourRankButtonWrapper = styled('div')` + background-color: ${(props)=>(props.clicked ? "#AC5204" : "#FFFFFF")}; + width: 105px; + height: 34px; + //top: 443px; + //left: 234px; + gap: 0px; + border-radius: 20px; + border: 1px solid #AC5204; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.3s ease, color 0.3s ease; +`; -// import { Button } from '@mui/material'; -// import { CampaignSupportDesktopButtonPanel, CampaignSupportDesktopButtonWrapper, CampaignSupportSection, CampaignSupportSectionWrapper } from '../../components/Style/CampaignSupportStyles'; -// import { SupportButtonFooterWrapper, SupportButtonPanel} from '../../components/Style/CampaignDetailsStyles'; -// // Import pngs -// import vector from '../../../../img/global/icons/Vector.png'; -// import vector1 from '../../../../img/global/icons/Vector1.png'; -// import vector8 from '../../../../img/global/icons/Vector 8.png'; -// import vector9 from '../../../../img/global/icons/Vector 9.png'; -// import vector11 from '../../../../img/global/icons/Vector 11.png'; -// import vector12 from '../../../../img/global/icons/Vector 12.png'; -// import vector13 from '../../../../img/global/icons/Vector 13.png'; -// import yellow_star from '../../../../img/global/icons/material-symbols_star.png'; -// import orange_star from '../../../../img/global/icons/material-symbols_star1.png'; -// import ellipse273 from '../../../../img/global/icons/Ellipse 273.png'; -// import ellipse274 from '../../../../img/global/icons/Ellipse 274.png'; -// import ellipse275 from '../../../../img/global/icons/Ellipse 275.png'; -// import ellipse276 from '../../../../img/global/icons/Ellipse 276.png'; -// import arrow from '../../../../img/global/icons/ph_arrow-up-bold.png'; -// import arrow1 from '../../../../img/global/icons/ph_arrow-up-bold_1.png'; -// // import Button from "@mui/material"; -// const URL = '/:challengeSEOFriendlyPath/+/customize-message'; -// -// const YourRank =({classes})=>{ -// // console.log(classes) -// const [clicked, setClicked] = useState(false); -// const [points, setPoints] = useState(0); -// const [note, setNote] = useState(""); -// const [arrowImage, setArrowImage] = useState(arrow) -// -// const calculateRank = (points) => 5336 + points * 5; -// -// const handleClick = () => { -// setPoints((prevPoints) => { -// const newPoints = prevPoints + 1; -// setClicked(true); -// setArrowImage(arrow1) -// setNote("1 point earned. You move up by 5 ranks!"); -// -// setTimeout(() => { -// setClicked(false); -// setNote(""); -// setArrowImage(arrow) -// }, 3000); -// return newPoints; -// }); -// }; -// return ( -// -//
-//

Your rank in the challenge:

-//
-// {/* */} -// {/* ellipse273 */} -// {/* star */} -// {/* vector8 */} -// {/* ellipse274 */} -// {/* vector_13 */} -// {/* vector11 */} -// {/* vector9 */} -// {/* ellipse276 */} -// {/* blue_star */} -// {/* vector12 */} -// {/* ellipse275 */} -// {/* red_star */} -// {/*
*/} -// {/* */} -// {/* */} -// {/* */} -// {/*
*/} -// {/* {note &&

{note}

} */} -// {/* */} -// -// -// -// -// ); -// }; -// -// const styles = () => ({ -// -// buttonDesktop: { -// boxShadow: 'none !important', -// fontSize: '18px', -// height: '45px !important', -// padding: '0 12px', -// textTransform: 'none', -// width: '100%', -// }, -// desktopSimpleLink: { -// boxShadow: 'none !important', -// color: '#999', -// marginTop: 10, -// padding: '0 20px', -// textTransform: 'none', -// width: 250, -// '&:hover': { -// color: '#4371cc', -// textDecoration: 'underline', -// }, -// }, -// mobileSimpleLink: { -// boxShadow: 'none !important', -// color: '#999', -// marginTop: 10, -// padding: '0 20px', -// textTransform: 'none', -// width: '100%', -// '&:hover': { -// color: '#4371cc', -// textDecoration: 'underline', -// }, -// }, -// arrow: { -// width: '10.5px', -// height: '12.5px', -// top: '2.75px', -// left: '14.25px', -// gap: '0px', -// opacity: '0px', -// angle: '-90 deg' -// }, -// ellipse273: { -// width: '3px', -// height: '3px', -// top: '448px', -// left: '228px', -// opacity: '0px' -// }, -// ellipse274: { -// width: '3px', -// height: '3px', -// top: '434px', -// left: '259px', -// opacity: '0px' -// }, -// ellipse275:{ -// width: '3px', -// height: '3px', -// top: '437px', -// left: '331px', -// gap: '0px', -// opacity: '0px', -// }, -// ellipse276:{ -// width: '3px', -// height: '3px', -// top: '423px', -// left: '302px', -// gap: '0px', -// opacity: '0px' -// }, -// orange_star: { -// width: '11px', -// height: '11px', -// top: '432px', -// left: '338.11px', -// padding: '0.92px 0.92px 1.37px 0.92px', -// gap: '0px', -// opacity: '0px', -// angle: '-16.42 deg' -// }, -// vector1: { -// width: '11px', -// height: '11px', -// top: '427px', -// left: '302.11px', -// padding: '0.92px 0.92px 1.37px 0.92px', -// gap: '0px', -// opacity: '0px', -// angle: '-16.42 deg' -// }, -// vector8: { -// width: '0px', -// height: '9.37px', -// top: '428px', -// left: '243px', -// border: '2px 0px 0px 0px', -// opacity: '0px' -// }, -// vector9:{ -// height: '9.37px', -// top: '429px', -// left: '291.96px', -// border: '2px 0px 0px 0px' -// }, -// vector11: { -// width: '0px', -// height: '7.12px', -// top: '431px', -// left: '274px', -// border: '2px 0px 0px 0px', -// opacity: '0px' -// }, -// vector12: { -// width: '0px', -// height: '9.37px', -// top: '427px', -// left: '324.43px', -// gap: '0px', -// border: '2px 0px 0px 0px', -// opacity: '0px', -// angle: '-15 deg' -// }, -// vector13: { -// height: '7.07px', -// top: '423.02px', -// left: '256.29px', -// border: '2px 0px 0px 0px' -// }, -// yellow_star: { -// width: '11px', -// height: '11px', -// top: '435.81px', -// left: '222px', -// padding: '0.92px 0.92px 1.37px 0.92px', -// opacity: '0px' -// } -// }); -// const ChallengeTabsWrapper = styled('div')` -// background-color: ${DesignTokenColors.neutralUI50}; -// display: flex; -// justify-content: center; -// `; -// const YourRankWrapper = styled('div')` -// background-color: ${DesignTokenColors.neutralUI50}; -// display: flex; -// justify-content: center; -// `; -// const ConfettiWrapper = styled('div')` -// background-color: ${DesignTokenColors.neutralUI50}; -// display: flex; -// justify-content: center; -// `; -// const ChallengeTabsWrapperButton = styled(Button)` -// background-color: ${(props)=>(props.clicked ? "#AC5204" : "#FFFFFF")}; -// color: ${(props)=> (props.clicked ? "white" : "#AC5204")}; -// width: 105px; -// height: 34px; -// top: 443px; -// left: 234px; -// gap: 0px; -// border-radius: 20px 20px 20px 20px; -// border: '1px solid var(--Accent-500, #AC5204)', -// `; -// export default withStyles(styles)(YourRank); - +const YourRankText = styled('div')` + margin-right: 10px; +`; +export default withStyles(styles)(YourRank); diff --git a/src/js/common/components/Challenge/YourRankModal.jsx b/src/js/common/components/Challenge/YourRankModal.jsx index 36fcdd250..4e0e13ad9 100644 --- a/src/js/common/components/Challenge/YourRankModal.jsx +++ b/src/js/common/components/Challenge/YourRankModal.jsx @@ -1,11 +1,12 @@ import { Close } from '@mui/icons-material'; import { Dialog, DialogContent, DialogTitle, IconButton } from '@mui/material'; import { withStyles } from '@mui/styles'; +import PropTypes from 'prop-types'; import React from 'react'; import styled from 'styled-components'; import ChallengeParticipantListRoot from '../ChallengeParticipantListRoot/ChallengeParticipantListRoot'; -const YourRankModal = ({ classes, show, toggleModal }) => { +const YourRankModal = ({ challengeWeVoteId, classes, show, toggleModal }) => { const challengeName = `Mr. Beast's "Get Out the Vote"`; return ( { - + ); }; YourRankModal.propTypes = { + challengeWeVoteId: PropTypes.string.isRequired, classes: PropTypes.object.isRequired, show: PropTypes.bool.isRequired, toggleModal: PropTypes.func.isRequired, @@ -52,6 +56,7 @@ const styles = (theme) => ({ padding: '0px 0px 0px 10px', }, }); + const DialogTitleWrapper = styled.div` display: flex; min-height: 30px; diff --git a/src/js/common/components/ChallengeInviteFriends/InviteFriendsTips.jsx b/src/js/common/components/ChallengeInviteFriends/InviteFriendsTips.jsx new file mode 100644 index 000000000..2c4921bdb --- /dev/null +++ b/src/js/common/components/ChallengeInviteFriends/InviteFriendsTips.jsx @@ -0,0 +1,158 @@ +import withStyles from '@mui/styles/withStyles'; +import Chip from '@mui/material/Chip'; +import PropTypes from 'prop-types'; +import React from 'react'; +import styled from 'styled-components'; +import DesignTokenColors from '../Style/DesignTokenColors'; +import { renderLog } from '../../utils/logging'; +import { CampaignProcessStepIntroductionText } from '../Style/CampaignProcessStyles'; +import ChallengeParticipantStore from '../../stores/ChallengeParticipantStore'; +import ChallengeStore from '../../stores/ChallengeStore'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; + +function InviteFriendsTips ({ challengeWeVoteId, startingTipName }) { + renderLog('InviteFriendsTips'); + const [challengeInviteesCount, setChallengeInviteesCount] = React.useState(0); + const [challengeParticipantCount, setChallengeParticipantCount] = React.useState(0); + const [participantNameWithHighestRank, setParticipantNameWithHighestRank] = React.useState(''); + const [tipToShow, setTipToShow] = React.useState(''); + + const goToNextTip = async () => { + if (tipToShow === 'nameEachFriend') { + setTipToShow('sendMessage'); + } else if (tipToShow === 'sendMessage') { + setTipToShow('youWillGetPoints'); + } else if (tipToShow === 'youWillGetPoints') { + setTipToShow('nameEachFriend'); + } + }; + + const onAppObservableStoreChange = () => { + setParticipantNameWithHighestRank(AppObservableStore.getChallengeParticipantNameWithHighestRankByChallengeWeVoteId(challengeWeVoteId)); + }; + + const onChallengeStoreChange = () => { + if (challengeInviteesCount < ChallengeStore.getNumberOfInviteesInChallenge(challengeWeVoteId)) { + setChallengeInviteesCount(ChallengeStore.getNumberOfInviteesInChallenge(challengeWeVoteId)); + } + if (challengeParticipantCount < ChallengeStore.getNumberOfParticipantsInChallenge(challengeWeVoteId)) { + setChallengeParticipantCount(ChallengeStore.getNumberOfParticipantsInChallenge(challengeWeVoteId)); + } + }; + + const onChallengeParticipantStoreChange = () => { + if (challengeParticipantCount < ChallengeParticipantStore.getNumberOfParticipantsInChallenge(challengeWeVoteId)) { + setChallengeParticipantCount(ChallengeParticipantStore.getNumberOfParticipantsInChallenge(challengeWeVoteId)); + } + }; + + React.useEffect(() => { + 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]); + + React.useEffect(() => { + setTipToShow(startingTipName); + }, [startingTipName]); + + let tipJsx = <>; + if (tipToShow === 'nameEachFriend') { + tipJsx = ( + + +   + + Name each friend + + {' '} + and invite them + {' '} + + separately + + , so we can give you the most boost points. +    + next > + + ); + } else if (tipToShow === 'sendMessage') { + tipJsx = ( + + +   + Send the copied message + {' '} + + from your own phone or email + + {' '} + to your friend, and then click the "Confirm you sent invite" button below. +    + next > + + ); + } else if (tipToShow === 'youWillGetPoints') { + tipJsx = ( + + +   + When your friend views or joins this challenge + {' '} + + you will get points + + {' '} + that boost your rank. +    + next > + + ); + } + return ( + + {tipJsx} + + ); +} +InviteFriendsTips.propTypes = { + challengeWeVoteId: PropTypes.string, + startingTipName: PropTypes.string, +}; + +const styles = () => ({ + howToVoteRoot: { + color: '#999', + height: 18, + width: 18, + }, +}); + +const InviteFriendsTipsWrapper = styled('div')` +`; + +const NextSpan = styled('span')` + color: ${DesignTokenColors.primary500}; + float: right; + margin-right: 10px; + text-decoration:underline; +`; + +const StyledChip = styled(Chip)` + background-color: ${DesignTokenColors.confirmation700}; + color: ${DesignTokenColors.whiteUI}; + height: 20px; + padding-top: 2px; + padding-bottom: 2px; +`; + +export default withStyles(styles)(InviteFriendsTips); diff --git a/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx b/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx index 29558394a..f6ec63d2d 100644 --- a/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx +++ b/src/js/common/components/ChallengeInviteFriends/ThanksForJoiningChallenge.jsx @@ -1,12 +1,14 @@ import { IconButton } from '@mui/material'; import { Close } from '@mui/icons-material'; -import styled from 'styled-components'; import PropTypes from 'prop-types'; - +import Confetti from 'react-confetti'; import React, { useState, useEffect } from 'react'; +import styled from 'styled-components'; + const ThanksForJoiningChallenge = ({ voterFirstName, challengeTitle, onClose }) => { const [isClosing, setIsClosing] = useState(false); + const [showConfetti, setShowConfetti] = useState(false); useEffect(() => { if (isClosing) { @@ -17,11 +19,22 @@ const ThanksForJoiningChallenge = ({ voterFirstName, challengeTitle, onClose }) } }, [isClosing, onClose]); + useEffect(() => { + // Show confetti when the component mounts + setShowConfetti(true); + // Hide confetti after a short duration + const timer = setTimeout(() => { + setShowConfetti(false); + }, 3000); + return () => clearTimeout(timer); + }, []); + return ( + {showConfetti && } Thanks for joining  {challengeTitle} diff --git a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListItem.jsx b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListItem.jsx index 6a8ae5d6f..a51ac1a1b 100644 --- a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListItem.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListItem.jsx @@ -13,7 +13,7 @@ const ChallengeInviteeListItem = ({ invitee, classes }) => { // console.log('ChallengeInviteeListItem:', invitee); const { sx, children } = speakerDisplayNameToInitials(invitee.invitee_name); let challengeStatusIconJsx = <>; - let challengeStatusMessage = '' + let challengeStatusMessage = ''; if (invitee.challenge_joined) { challengeStatusIconJsx = ; challengeStatusMessage = 'Challenge joined'; @@ -24,6 +24,27 @@ const ChallengeInviteeListItem = ({ invitee, classes }) => { challengeStatusIconJsx = ; challengeStatusMessage = 'Invite sent'; } + + let underNameJsx = <>; + if (invitee.challenge_joined || invitee.invite_viewed || invitee.invite_sent === true) { + underNameJsx = ( + + + {challengeStatusIconJsx} + + + {challengeStatusMessage} + + + ); + } else if (invitee.invite_sent === false) { + underNameJsx = ( + + ); + } return ( @@ -39,19 +60,7 @@ const ChallengeInviteeListItem = ({ invitee, classes }) => {
- {invitee.invite_sent === false ? ( - - ) : ( - - - {challengeStatusIconJsx} - - {challengeStatusMessage} - - )} + {underNameJsx}
{invitee.messageStatus !== 'Challenge Joined' && ( ({ }); -const InvitedFriendDetails = styled.div` +const InvitedFriendDetails = styled('div')` display: flex; flex-direction: column; justify-content: space-between; @@ -85,13 +94,13 @@ const InvitedFriendDetails = styled.div` border-bottom: 1px solid ${DesignTokenColors.neutral100}; `; -const PrimaryDetails = styled.div` +const PrimaryDetails = styled('div')` display: flex; justify-content: space-between; align-items: center; `; -const FriendName = styled.div` +const FriendName = styled('div')` display: flex; align-items: center; gap: 10px; @@ -104,23 +113,29 @@ const AvatarDetails = styled(Avatar)` font-size: 1rem; `; -const Name = styled.div` +const Name = styled('div')` font-weight: bold; color: ${DesignTokenColors.neutral900}; `; -const MessageContainer = styled.div` +const MessageContainer = styled('div')` + align-items: center; display: flex; + margin-left: 45px; `; -const MessageStatus = styled.div` +const MessageStatus = styled('div')` text-align: center; font-size: 14px; color: ${DesignTokenColors.confirmation800}; margin-right: 10px; `; -const VerticalLine = styled.div` +const MessageText = styled('div')` + margin-top: 3px; +`; + +const VerticalLine = styled('div')` border-left: 1px solid ${DesignTokenColors.neutral200}; height: 30px; margin: 0 10px; @@ -135,14 +150,14 @@ const ActivityCommentEditWrapper = styled('div')` } `; -const Options = styled.div` +const Options = styled('div')` display: flex; flex-direction: row; justify-content: space-between; font-size: 14px; `; -const Invite = styled.a` +const Invite = styled('a')` padding: 5px; color: #4371cc; `; diff --git a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListRoot.jsx b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListRoot.jsx index e300d155d..025b12082 100644 --- a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListRoot.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListRoot.jsx @@ -29,7 +29,7 @@ const inviteeListDummyData = [ { invitee_id: 15, invitee_name: 'Melina H.', invite_sent: true, invite_viewed: false, challenge_joined: false, messageStatus: 'Message Sent' }, ]; -const ChallengeInviteeListRoot = ({ challengeWeVoteId }) => { +const ChallengeInviteeListRoot = ({ challengeWeVoteId, hideRank }) => { // eslint-disable-next-line no-unused-vars const [inviteeList, setInviteeList] = React.useState([]); const [participantsCount, setParticipantsCount] = useState(0); @@ -70,7 +70,7 @@ const ChallengeInviteeListRoot = ({ challengeWeVoteId }) => { return ( - {!!(rankOfVoter) && ( + {!!(rankOfVoter && !hideRank) && ( You're {' '} @@ -109,6 +109,7 @@ const ChallengeInviteeListRoot = ({ challengeWeVoteId }) => { ChallengeInviteeListRoot.propTypes = { classes: PropTypes.object, challengeWeVoteId: PropTypes.string, + hideRank: PropTypes.bool, }; const styles = () => ({ diff --git a/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx b/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx index 6fbcf626e..40d6f1fcd 100755 --- a/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx @@ -61,16 +61,16 @@ const InviteAgainButton = ({ classes, challengeWeVoteId, challengeInviteeId }) = const onChallengeParticipantStoreChange = () => { const varsChangedNew = inviteTextVarsChangedCount + 1; setInviterName(VoterStore.getFirstName()); - setInviteTextForFriends(ChallengeParticipantStore.getInviteTextForFriends(challengeWeVoteId)); // console.log('InviteAgainButton onChallengeParticipantStoreChange Participant TextForFriends:', ChallengeParticipantStore.getInviteTextForFriends(challengeWeVoteId)); + setInviteTextForFriends(ChallengeParticipantStore.getInviteTextForFriends(challengeWeVoteId)); setInviteTextVarsChangedCount(varsChangedNew); }; const onChallengeStoreChange = () => { const varsChangedNew = inviteTextVarsChangedCount + 1; setInviterName(VoterStore.getFirstName()); - setChallengeInviteTextDefault(ChallengeStore.getChallengeInviteTextDefaultByWeVoteId(challengeWeVoteId)); // console.log('InviteAgainButton onChallengeStoreChange InviteTextDefault:', ChallengeStore.getChallengeInviteTextDefaultByWeVoteId(challengeWeVoteId)); + setChallengeInviteTextDefault(ChallengeStore.getChallengeInviteTextDefaultByWeVoteId(challengeWeVoteId)); setChallengeTitle(ChallengeStore.getChallengeTitleByWeVoteId(challengeWeVoteId)); setInviteTextVarsChangedCount(varsChangedNew); }; @@ -93,24 +93,27 @@ const InviteAgainButton = ({ classes, challengeWeVoteId, challengeInviteeId }) = }, []); React.useEffect(() => { - const inviteeFirstName = inviteeName ? inviteeName.split(' ')[0] : ''; - const inviterFirstName = inviterName ? inviterName.split(' ')[0] : ''; - // console.log('inviteeName: ', inviteeName, ', inviterName: ', inviterName); - let inviteTextToSendTemp1 = inviteeFirstName ? `Hi ${inviteeFirstName}` : 'Hi'; - inviteTextToSendTemp1 += inviterFirstName ? `, this is ${inviterFirstName}. ` : ', '; - let inviteTextToSendTemp2 = challengeInviteTextDefault; - if (inviteTextForFriends && inviteTextForFriends.trim() !== '') { - inviteTextToSendTemp2 = inviteTextForFriends; - } - if (inviteTextForFriends && inviteTextFromInviter.trim() !== '') { - inviteTextToSendTemp2 = inviteTextFromInviter; + let inviteTextToSendAgain = inviteTextFromInviter; + if (!inviteTextToSendAgain || inviteTextToSendAgain.trim() === '') { + const inviteeFirstName = inviteeName ? inviteeName.split(' ')[0] : ''; + const inviterFirstName = inviterName ? inviterName.split(' ')[0] : ''; + // console.log('inviteeName: ', inviteeName, ', inviterName: ', inviterName); + let inviteTextToSendTemp1 = inviteeFirstName ? `Hi ${inviteeFirstName}` : 'Hi'; + inviteTextToSendTemp1 += inviterFirstName ? `, this is ${inviterFirstName}. ` : ', '; + let inviteTextToSendTemp2 = challengeInviteTextDefault; + if (inviteTextForFriends && inviteTextForFriends.trim() !== '') { + inviteTextToSendTemp2 = inviteTextForFriends; + } + if (inviteTextForFriends && inviteTextFromInviter.trim() !== '') { + inviteTextToSendTemp2 = inviteTextFromInviter; + } + // console.log('challengeInviteTextDefault: ', challengeInviteTextDefault); + const invitee = ChallengeInviteeStore.getChallengeInviteeById(challengeInviteeId); + const inviteeUrlCode = invitee.invitee_url_code || ''; + const urlToSendTemp = `${ChallengeStore.getSiteUrl(challengeWeVoteId)}/-${inviteeUrlCode}`; + inviteTextToSendAgain = `${inviteTextToSendTemp1}${inviteTextToSendTemp2} ${urlToSendTemp}`; } - // console.log('challengeInviteTextDefault: ', challengeInviteTextDefault); - const inviteeUrlCode = ChallengeInviteeStore.getNextInviteeUrlCode(); - const urlToSendTemp = `${ChallengeStore.getSiteUrl(challengeWeVoteId)}/-${inviteeUrlCode}`; - const inviteTextToSendTemp3 = `${inviteTextToSendTemp1}${inviteTextToSendTemp2} ${urlToSendTemp}`; - setInviteTextToSend(inviteTextToSendTemp3); - // setUrlToSend(urlToSendTemp); + setInviteTextToSend(inviteTextToSendAgain); }, [inviteTextVarsChangedCount]); React.useEffect(() => { @@ -127,7 +130,7 @@ const InviteAgainButton = ({ classes, challengeWeVoteId, challengeInviteeId }) = onClick={() => handleShare()} variant="outlined" > - {inviteCopiedMessageOn ? 'Invite copied!' : 'Invite again'} + {inviteCopiedMessageOn ? 'Invite copied!' : 'Copy invite again'} diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index 812de0fc2..e32b74802 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -6,6 +6,11 @@ import styled from 'styled-components'; import commonMuiStyles from '../Style/commonMuiStyles'; import DesignTokenColors from '../Style/DesignTokenColors'; import SvgImage from '../Widgets/SvgImage'; +import RocketIcon from '../../../../img/global/svg-icons/rocket-ship.svg'; +import StepOneIcon from '../../../../img/global/svg-icons/material-symbols-counter-1.svg'; +import StepOneActiveIcon from '../../../../img/global/svg-icons/material-symbols-counter-1-active.svg'; +import StepTwoIcon from '../../../../img/global/svg-icons/material-symbols-counter-2.svg'; +import StepTwoActiveIcon from '../../../../img/global/svg-icons/material-symbols-counter-2-active.svg'; const BoostLearnMoreModal = React.lazy(() => import(/* webpackChunkName: 'BoostLearnMoreModal' */ '../ChallengeInviteFriends/BoostLearnMoreModal')); @@ -75,10 +80,10 @@ class ChallengeInviteSteps extends React.Component { {/* Rocket, Invite more friends, and Learn More */} To boost your ranking, invite your friends to join. @@ -96,12 +101,17 @@ class ChallengeInviteSteps extends React.Component { {/* Step 1 Icon and Text */} this.handleStepClick(1)} > - + this.handleStepClick(1)} + > + + this.handleStepClick(2)} > - + this.handleStepClick(2)} + > + + (` color: #555; // font-size: 18px; diff --git a/src/js/common/pages/Challenge/ChallengeHomePage.jsx b/src/js/common/pages/Challenge/ChallengeHomePage.jsx index e4cc94581..735299675 100644 --- a/src/js/common/pages/Challenge/ChallengeHomePage.jsx +++ b/src/js/common/pages/Challenge/ChallengeHomePage.jsx @@ -18,10 +18,11 @@ import VoterStore from '../../../stores/VoterStore'; import CompleteYourProfileModalController from '../../components/Settings/CompleteYourProfileModalController'; import { Candidate, CandidateNameH4, CandidateNameAndPartyWrapper, CandidateTopRow } from '../../../components/Style/BallotStyles'; import { - CampaignDescription, CampaignDescriptionDesktop, CampaignDescriptionDesktopWrapper, CampaignDescriptionWrapper, + CampaignDescriptionDesktop, CampaignDescriptionDesktopWrapper, CampaignDescriptionWrapper, CampaignSubSectionSeeAll, CampaignSubSectionTitle, CampaignSubSectionTitleWrapper, CommentsListWrapper, DetailsSectionDesktopTablet, DetailsSectionMobile, SupportButtonFooterWrapperAboveFooterButtons, SupportButtonPanel, } from '../../components/Style/CampaignDetailsStyles'; +import { ChallengeDescription } from '../../components/Style/ChallengeCardStyles'; import { EditIndicator, IndicatorButtonWrapper, IndicatorRow } from '../../components/Style/CampaignIndicatorStyles'; import { PageWrapper } from '../../components/Style/stepDisplayStyles'; import DelayedLoad from '../../components/Widgets/DelayedLoad'; @@ -43,7 +44,7 @@ import normalizedImagePath from '../../utils/normalizedImagePath'; import ChallengeAbout from '../../components/Challenge/ChallengeAbout'; import ChallengeParticipantListRoot from '../../components/ChallengeParticipantListRoot/ChallengeParticipantListRoot'; import ChallengeInviteeListRoot from '../../components/ChallengeInviteeListRoot/ChallengeInviteeListRoot'; -import ThanksForViewingChallenge from '../../components/Challenge/ThanksForViewingChallenge' +import ThanksForViewingChallenge from '../../components/Challenge/ThanksForViewingChallenge'; import ShareStore from '../../stores/ShareStore'; const ChallengeCardForList = React.lazy(() => import(/* webpackChunkName: 'ChallengeCardForList' */ '../../components/ChallengeListRoot/ChallengeCardForList')); @@ -516,25 +517,6 @@ class ChallengeHomePage extends Component { if (tabSelected === 'friends' || tabSelected === 'leaderboard') { tabSelectedChosen = tabSelected; } - - const challengeDescriptionJsx = ( - - -
-  }> - - -
-
- {challengeDescription ? ( -  }> - - - ) : ( - No description has been provided for this candidate. - )} -
- ); return ( {thanksForViewingChallengeOn && ( @@ -619,12 +601,16 @@ class ChallengeHomePage extends Component { ) : ( + {challengeDescription && ( - {challengeDescriptionJsx} + + }> + + + )} - {!!(voterCanEditThisChallenge || voterIsChallengeParticipant) && ( {voterCanEditThisChallenge && ( @@ -661,16 +647,16 @@ class ChallengeHomePage extends Component { useVerticalCard voterWeVoteId={voterWeVoteId} /> + {challengeDescription && ( - + }> - + )} - }> - - -   - So we can correctly calculate your boost points, - {' '} - - name each friend and invite them separately - - {' '} - (a unique link is generated for each friend). - + @@ -216,7 +217,7 @@ class ChallengeInviteFriends extends Component { {inviteeList.length > 0 && ( - + )}  }> @@ -251,12 +252,4 @@ const InvitedFriendsWrapper = styled('div')` flex-direction: column; `; -const StyledChip = styled(Chip)` - background-color: ${DesignTokenColors.confirmation700}; - color: ${DesignTokenColors.whiteUI}; - height: 20px; - padding-top: 2px; - padding-bottom: 2px; -`; - export default withStyles(commonMuiStyles)(ChallengeInviteFriends); diff --git a/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriendsJoin.jsx b/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriendsJoin.jsx index eaa91690f..73e36cbfc 100644 --- a/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriendsJoin.jsx +++ b/src/js/common/pages/ChallengeInviteFriends/ChallengeInviteFriendsJoin.jsx @@ -269,7 +269,7 @@ class ChallengeInviteFriendsJoin extends Component { /> - To join this challenge, share how you will vote — then ask your friends to join. + To join this challenge, share when you will cast your vote — then ask your friends to join. diff --git a/src/js/common/stores/ChallengeParticipantStore.js b/src/js/common/stores/ChallengeParticipantStore.js index 9871bec13..f3152959c 100644 --- a/src/js/common/stores/ChallengeParticipantStore.js +++ b/src/js/common/stores/ChallengeParticipantStore.js @@ -4,7 +4,7 @@ import VoterStore from '../../stores/VoterStore'; import AppObservableStore from './AppObservableStore'; -const orderByDateJoined = (firstEntry, secondEntry) => new Date(secondEntry.date_joined) - new Date(firstEntry.date_joined); +const orderByDateJoined = (firstEntry, secondEntry) => new Date(firstEntry.date_joined) - new Date(secondEntry.date_joined); const orderByPoints = (firstEntry, secondEntry) => secondEntry.points - firstEntry.points; diff --git a/src/js/common/utils/hrefUtils.js b/src/js/common/utils/hrefUtils.js index af29f1125..2899bcc76 100644 --- a/src/js/common/utils/hrefUtils.js +++ b/src/js/common/utils/hrefUtils.js @@ -15,6 +15,10 @@ export function normalizedHrefPage () { return 'candidatelist'; } else if (second && second === 'cs') { // Does the pathname end with '/cs/', i.e., candidates for state? return 'candidatelist'; + } else if (second && second === '-') { // Does the pathname end with '/-/', i.e., on a candidate landing page? + return 'candidatelist'; + } else if (second && second === '+') { // Does the pathname end with '/-/', i.e., on a candidate landing page? + return 'challenges'; } return page; } From b36c94b97d2339382d1bfa1197445f84244ab9dd Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Sat, 12 Oct 2024 13:42:07 -0700 Subject: [PATCH 46/54] add jointDaysLeft styles as separate component --- .../ChallengeListRoot/ChallengeCardList.jsx | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx b/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx index 5eecd0fa4..8f2b5f699 100644 --- a/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx +++ b/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx @@ -12,6 +12,7 @@ import ChallengeAbout from '../Challenge/ChallengeAbout'; import { isWebApp } from '../../utils/isCordovaOrWebApp'; import ChallengeStore from '../../stores/ChallengeStore'; import JoinChallengeAndLearnMoreButtons from '../Challenge/JoinChallengeAndLearnMoreButtons'; +import JoinedAndDaysLeft from '../Challenge/JoinedAndDaysLeft'; const DelayedLoad = React.lazy(() => import(/* webpackChunkName: 'DelayedLoad' */ '../Widgets/DelayedLoad')); @@ -175,12 +176,18 @@ class ChallengeCardList extends Component { numberDisplayed += 1; return ( - + + + {/* JoinedAndDaysLeft component positioned absolutely */} + + + + ({ }, }); +const CardContainer = styled('div')` + position: relative; +`; + const ChallengeCardForListVerticalWrapper = styled('div')` display: flex; flex-direction: column; @@ -290,5 +301,16 @@ const ChallengeCardForListVerticalWrapper = styled('div')` const Wrapper = styled('div')` min-height: 30px; `; +const StyledJoinedAndDaysLeft = styled('div')` +align-items: center; +border-radius: 20px; +color: #000; +display: flex; +font-size: 12px; +left: 10px; +padding: 5px 10px; +position: absolute; +top: 125px; +`; export default withStyles(styles)(ChallengeCardList); From d970987460ceb4803ab6f8d601977a5db8ac24fd Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Sat, 12 Oct 2024 14:21:55 -0700 Subject: [PATCH 47/54] Created a custom-styled component in for better isolation of challenge-specific styling. --- .../ChallengeListRoot/ChallengeCardList.jsx | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx b/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx index 8f2b5f699..582f299f9 100644 --- a/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx +++ b/src/js/common/components/ChallengeListRoot/ChallengeCardList.jsx @@ -13,6 +13,7 @@ import { isWebApp } from '../../utils/isCordovaOrWebApp'; import ChallengeStore from '../../stores/ChallengeStore'; import JoinChallengeAndLearnMoreButtons from '../Challenge/JoinChallengeAndLearnMoreButtons'; import JoinedAndDaysLeft from '../Challenge/JoinedAndDaysLeft'; +import DesignTokenColors from '../Style/DesignTokenColors'; const DelayedLoad = React.lazy(() => import(/* webpackChunkName: 'DelayedLoad' */ '../Widgets/DelayedLoad')); @@ -184,9 +185,9 @@ class ChallengeCardList extends Component { useVerticalCard={useVerticalCard} /> {/* JoinedAndDaysLeft component positioned absolutely */} - + - + 1 && - numberToDisplay < challengeList.length) && - ( - - - - )} + challengeList.length > 1 && + numberToDisplay < challengeList.length) && + ( + + + + )} }> @@ -293,7 +294,7 @@ const CardContainer = styled('div')` const ChallengeCardForListVerticalWrapper = styled('div')` display: flex; flex-direction: column; - // height: ${isWebApp() ? '100%' : 'unset'}; + // height: ${isWebApp() ? '100%' : 'unset'}; width: 80%; max-width: 300px; `; @@ -301,10 +302,11 @@ const ChallengeCardForListVerticalWrapper = styled('div')` const Wrapper = styled('div')` min-height: 30px; `; -const StyledJoinedAndDaysLeft = styled('div')` + +const JoinedAndDaysForChallengePage = styled('div')` align-items: center; border-radius: 20px; -color: #000; +color: ${DesignTokenColors.gray900}; display: flex; font-size: 12px; left: 10px; From d3e074bff694b0afcb550332bded6aaa933cd3e1 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Thu, 10 Oct 2024 12:38:14 -0700 Subject: [PATCH 48/54] Replace Link with NavLink and style for active state in ChallengeInviteSteps component. Added StyledNavLink component using styled-components to ensure consistent styling and handle active class. --- .../Navigation/ChallengeInviteSteps.jsx | 56 ++++++++----------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx index e32b74802..be3f9b055 100644 --- a/src/js/common/components/Navigation/ChallengeInviteSteps.jsx +++ b/src/js/common/components/Navigation/ChallengeInviteSteps.jsx @@ -1,5 +1,5 @@ import React, { Suspense } from 'react'; -import { Link, withRouter } from 'react-router-dom'; +import { NavLink, withRouter } from 'react-router-dom'; import PropTypes from 'prop-types'; import { withStyles } from '@mui/styles'; import styled from 'styled-components'; @@ -44,9 +44,6 @@ class ChallengeInviteSteps extends React.Component { return 1; }; - // Check if a step is active based on the current step number - // isStepActive = (stepNumber) => this.props.currentStep === stepNumber; - // Set a step as active when clicked isStepActive = (stepNumber) => this.state.activeStep === stepNumber; @@ -74,7 +71,7 @@ class ChallengeInviteSteps extends React.Component { })); }; - render() { + render () { return ( {/* Rocket, Invite more friends, and Learn More */} @@ -102,7 +99,7 @@ class ChallengeInviteSteps extends React.Component { - this.handleStepClick(1)} @@ -111,15 +108,15 @@ class ChallengeInviteSteps extends React.Component { alt="Step 1 Icon" imageName={this.isStepActive(1) ? StepOneActiveIcon : StepOneIcon} /> - - + this.handleStepClick(1)} > Customize the message to your friends - + {/* Horizontal Line Between Steps */} @@ -128,7 +125,7 @@ class ChallengeInviteSteps extends React.Component { - this.handleStepClick(2)} @@ -137,15 +134,15 @@ class ChallengeInviteSteps extends React.Component { alt="Step 2 Icon" imageName={this.isStepActive(2) ? StepTwoActiveIcon : StepTwoIcon} /> - - + this.handleStepClick(2)} > Copy message & link - + {/* Render BoostLearnMoreModal */} @@ -190,7 +187,7 @@ const HeaderContainer = styled('div')` `; const LearnMoreButton = styled('button')`{ -background: none; + background: none; border: none; color: ${DesignTokenColors.primary500}; font-size: 13px; @@ -237,16 +234,6 @@ const StepOneIconAndText = styled('div')` margin-right: 25px; text-align: center; width: 169px; - a { - font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; - color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; - - &:hover { - color: ${DesignTokenColors.primary500}; - font-weight: 600; - text-decoration: underline; - } - } `; const StepTwoIconAndText = styled('div')` @@ -258,15 +245,20 @@ const StepTwoIconAndText = styled('div')` margin-left: 25px; text-align: center; width: 109px; - a { - font-weight: ${({ isActive }) => (isActive ? '600' : 'normal')}; - color: ${({ isActive }) => (isActive ? DesignTokenColors.primary500 : 'inherit')}; +`; - &:hover { - color: ${DesignTokenColors.primary500}; - font-weight: 600; - text-decoration: underline; - } +const StyledNavLink = styled(NavLink)` + font-weight: normal; + color: inherit; + text-decoration: none; + &.active { + font-weight: 600; + color: ${DesignTokenColors.primary500}; + } + &:hover { + color: ${DesignTokenColors.primary500}; + font-weight: 600; + text-decoration: underline; } `; From 52cffa0a2e293beca5bb8ffdfef1f6e8b28abd29 Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Sun, 13 Oct 2024 10:11:35 -0700 Subject: [PATCH 49/54] Better score updating as you add Invitees. Updated Invitee display. --- .../Challenge/JoinChallengeButton.jsx | 9 +++- .../InviteFriendToChallengeInput.jsx | 13 +++++- .../ChallengeInviteeListItem.jsx | 20 +++++---- .../FirstChallengeInviteeListController.jsx | 3 +- .../InviteAgainButton.jsx | 3 +- .../FirstChallengeListController.jsx | 3 +- ...engeParticipantFirstRetrieveController.jsx | 3 +- .../ChallengeParticipantListItem.jsx | 41 +++++++++++-------- .../ChallengeParticipantListRoot.jsx | 2 +- ...irstChallengeParticipantListController.jsx | 3 +- 10 files changed, 64 insertions(+), 36 deletions(-) diff --git a/src/js/common/components/Challenge/JoinChallengeButton.jsx b/src/js/common/components/Challenge/JoinChallengeButton.jsx index 3da3c3c8e..1bd6f3ad3 100644 --- a/src/js/common/components/Challenge/JoinChallengeButton.jsx +++ b/src/js/common/components/Challenge/JoinChallengeButton.jsx @@ -19,6 +19,7 @@ class JoinChallengeButton extends React.Component { challengeSEOFriendlyPath: '', challengeWeVoteId: '', goToNextStepAfterSignIn: false, + challengeInviteTextDefault: '', voterFirstName: '', voterIsSignedIn: false, voterPhotoUrlLarge: '', @@ -43,10 +44,14 @@ class JoinChallengeButton extends React.Component { const { challengeSEOFriendlyPath: challengeSEOFriendlyPathFromProps, challengeWeVoteId: challengeWeVoteIdFromProps } = this.props; // console.log('onChallengeStoreChange challengeSEOFriendlyPathFromProps: ', challengeSEOFriendlyPathFromProps, ', challengeWeVoteIdFromProps: ', challengeWeVoteIdFromProps); const { + challengeInviteTextDefault, challengeSEOFriendlyPath, challengeWeVoteId, } = getChallengeValuesFromIdentifiers(challengeSEOFriendlyPathFromProps, challengeWeVoteIdFromProps); // console.log('onChallengeStoreChange AFTER getChallengeValuesFromIdentifiers challengeWeVoteId: ', challengeWeVoteId); + this.setState({ + challengeInviteTextDefault, + }); if (challengeSEOFriendlyPath) { this.setState({ challengeSEOFriendlyPath, @@ -115,7 +120,7 @@ class JoinChallengeButton extends React.Component { goToJoinChallenge = () => { const challengeBasePath = this.getChallengeBasePath(); // console.log('goToJoinChallenge challengeBasePath: ', challengeBasePath); - const { challengeWeVoteId, voterFirstName, voterPhotoUrlLarge } = this.state; + const { challengeWeVoteId, challengeInviteTextDefault, voterFirstName, voterPhotoUrlLarge } = this.state; const upcomingGoogleCivicElectionId = VoterStore.electionId(); const voterPlanCreatedForThisElection = ReadyStore.getVoterPlanTextForVoterByElectionId(upcomingGoogleCivicElectionId); // console.log('upcomingGoogleCivicElectionId: ', upcomingGoogleCivicElectionId, 'voterPlanCreatedForThisElection: ', voterPlanCreatedForThisElection); @@ -133,7 +138,7 @@ class JoinChallengeButton extends React.Component { if (itemsAreMissing) { historyPush(joinChallengeNextStepPath); } else { - ChallengeParticipantActions.challengeParticipantSave(challengeWeVoteId); + ChallengeParticipantActions.challengeParticipantSave(challengeWeVoteId, challengeInviteTextDefault, true); AppObservableStore.setShowChallengeThanksForJoining(true); // Delay the redirect, so we have time to fire the above API call first this.timer = setTimeout(() => { diff --git a/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx b/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx index 7f31894e8..fee3d57df 100755 --- a/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx +++ b/src/js/common/components/ChallengeInviteFriends/InviteFriendToChallengeInput.jsx @@ -7,6 +7,7 @@ import CopyToClipboard from 'react-copy-to-clipboard'; import { renderLog } from '../../utils/logging'; import ChallengeInviteeActions from '../../actions/ChallengeInviteeActions'; import ChallengeInviteeStore from '../../stores/ChallengeInviteeStore'; +import ChallengeParticipantActions from '../../actions/ChallengeParticipantActions'; import ChallengeParticipantStore from '../../stores/ChallengeParticipantStore'; import ChallengeStore from '../../stores/ChallengeStore'; import VoterStore from '../../../stores/VoterStore'; @@ -20,6 +21,7 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq const [destinationFullURL, setDestinationFullURL] = React.useState(''); const [googleCivicElectionId, setGoogleCivicElectionId] = React.useState(0); const [inviteCopiedMessageOn, setInviteCopiedMessageOn] = React.useState(false); + const [inviteeListLength, setInviteeListLength] = React.useState(0); const [inviteeName, setInviteeName] = React.useState(''); const [inviterName, setInviterName] = React.useState(''); const [inviteTextForFriends, setInviteTextForFriends] = React.useState(''); @@ -92,6 +94,13 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq React.useEffect(() => { 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); + } + setInviteeListLength(inviteeList.length); prepareInviteTextToSend(); }; @@ -143,7 +152,7 @@ const InviteFriendToChallengeInput = ({ classes, challengeWeVoteId, externalUniq margin="dense" value={inviteeName} variant="outlined" - placeholder="Your friend's name" + placeholder="Your friend's name (or a friend group name)" onChange={setInviteeNameFromEvent} // eslint-disable-line react/jsx-no-bind /> @@ -196,7 +205,7 @@ const styles = () => ({ boxShadow: '0 4px 6px rgb(50 50 93 / 11%)', fontSize: '18px', height: '45px !important', - minWidth: '300px', + minWidth: '350px', padding: '0 12px', textTransform: 'none', width: '100%', diff --git a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListItem.jsx b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListItem.jsx index a51ac1a1b..720385c70 100644 --- a/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListItem.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/ChallengeInviteeListItem.jsx @@ -11,7 +11,6 @@ import speakerDisplayNameToInitials from '../../utils/speakerDisplayNameToInitia const ChallengeInviteeListItem = ({ invitee, classes }) => { // console.log('ChallengeInviteeListItem:', invitee); - const { sx, children } = speakerDisplayNameToInitials(invitee.invitee_name); let challengeStatusIconJsx = <>; let challengeStatusMessage = ''; if (invitee.challenge_joined) { @@ -45,13 +44,19 @@ const ChallengeInviteeListItem = ({ invitee, classes }) => { /> ); } + const inviteeName = invitee.invitee_voter_name || invitee.invitee_name; + const { sx, children } = speakerDisplayNameToInitials(inviteeName); return ( - {children} + {invitee.we_vote_hosted_profile_image_url_medium !== '' ? ( + + ) : ( + {children} + )} {' '} - {invitee.invitee_name} + {inviteeName} @@ -62,11 +67,13 @@ const ChallengeInviteeListItem = ({ invitee, classes }) => {
{underNameJsx}
- {invitee.messageStatus !== 'Challenge Joined' && ( + {!(invitee.challenge_joined) ? ( + ) : ( +
 
)}
@@ -157,9 +164,4 @@ const Options = styled('div')` font-size: 14px; `; -const Invite = styled('a')` - padding: 5px; - color: #4371cc; -`; - export default withStyles(styles)(ChallengeInviteeListItem); diff --git a/src/js/common/components/ChallengeInviteeListRoot/FirstChallengeInviteeListController.jsx b/src/js/common/components/ChallengeInviteeListRoot/FirstChallengeInviteeListController.jsx index a890bc971..c9ce17a5f 100644 --- a/src/js/common/components/ChallengeInviteeListRoot/FirstChallengeInviteeListController.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/FirstChallengeInviteeListController.jsx @@ -6,6 +6,7 @@ import initializejQuery from '../../utils/initializejQuery'; import { renderLog } from '../../utils/logging'; import VoterStore from '../../../stores/VoterStore'; +const UPDATE_NO_MORE_OFTEN_THAN = 30000; // 30 seconds class FirstChallengeInviteeListController extends Component { constructor (props) { @@ -47,7 +48,7 @@ class FirstChallengeInviteeListController extends Component { const voterFirstRetrieveCompleted = VoterStore.voterFirstRetrieveCompleted(); // console.log('FirstChallengeInviteeListController challengeInviteeListFirstRetrieveInitiated, voterFirstRetrieveCompleted: ', voterFirstRetrieveCompleted); if (voterFirstRetrieveCompleted && challengeWeVoteId) { - if (apiCalming(`challengeInviteeListFirstRetrieve-${challengeWeVoteId}`, 30000)) { + if (apiCalming(`challengeInviteeListFirstRetrieve-${challengeWeVoteId}`, UPDATE_NO_MORE_OFTEN_THAN)) { ChallengeInviteeActions.challengeInviteeListRetrieve(challengeWeVoteId); } } diff --git a/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx b/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx index 40d6f1fcd..1eaa95eb5 100755 --- a/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx @@ -53,7 +53,8 @@ const InviteAgainButton = ({ classes, challengeWeVoteId, challengeInviteeId }) = setInviterName(VoterStore.getFirstName()); const invitee = ChallengeInviteeStore.getChallengeInviteeById(challengeInviteeId); // console.log('InviteAgainButton onChallengeInviteeStoreChange invitee:', invitee); - setInviteeName(invitee.invitee_name); + const inviteeNameTemp = invitee.invitee_voter_name || invitee.invitee_name; + setInviteeName(inviteeNameTemp); setInviteTextFromInviter(invitee.invite_text_from_inviter); setInviteTextVarsChangedCount(varsChangedNew); }; diff --git a/src/js/common/components/ChallengeListRoot/FirstChallengeListController.jsx b/src/js/common/components/ChallengeListRoot/FirstChallengeListController.jsx index f73061d13..d04a0054f 100644 --- a/src/js/common/components/ChallengeListRoot/FirstChallengeListController.jsx +++ b/src/js/common/components/ChallengeListRoot/FirstChallengeListController.jsx @@ -6,6 +6,7 @@ import initializejQuery from '../../utils/initializejQuery'; import { renderLog } from '../../utils/logging'; import VoterStore from '../../../stores/VoterStore'; +const UPDATE_NO_MORE_OFTEN_THAN = 30000; // 30 seconds class FirstChallengeListController extends Component { constructor (props) { @@ -53,7 +54,7 @@ class FirstChallengeListController extends Component { const voterFirstRetrieveCompleted = VoterStore.voterFirstRetrieveCompleted(); // console.log('FirstChallengeListController challengeListFirstRetrieveInitiated: ', challengeListFirstRetrieveInitiated, ', voterFirstRetrieveCompleted: ', voterFirstRetrieveCompleted); if (voterFirstRetrieveCompleted) { - if (apiCalming('challengeListFirstRetrieve', 60000)) { + if (apiCalming('challengeListFirstRetrieve', UPDATE_NO_MORE_OFTEN_THAN)) { ChallengeActions.challengeListRetrieve(); } } diff --git a/src/js/common/components/ChallengeParticipant/ChallengeParticipantFirstRetrieveController.jsx b/src/js/common/components/ChallengeParticipant/ChallengeParticipantFirstRetrieveController.jsx index 2ad487ec3..9a9785e57 100644 --- a/src/js/common/components/ChallengeParticipant/ChallengeParticipantFirstRetrieveController.jsx +++ b/src/js/common/components/ChallengeParticipant/ChallengeParticipantFirstRetrieveController.jsx @@ -6,6 +6,7 @@ import initializejQuery from '../../utils/initializejQuery'; import { renderLog } from '../../utils/logging'; import VoterStore from '../../../stores/VoterStore'; +const UPDATE_NO_MORE_OFTEN_THAN = 30000; // 30 seconds class ChallengeParticipantFirstRetrieveController extends Component { constructor (props) { @@ -34,7 +35,7 @@ class ChallengeParticipantFirstRetrieveController extends Component { const voterFirstRetrieveCompleted = VoterStore.voterFirstRetrieveCompleted(); // console.log('ChallengeParticipantFirstRetrieveController challengeParticipantFirstRetrieveInitiated: ', challengeParticipantFirstRetrieveInitiated, ', voterFirstRetrieveCompleted: ', voterFirstRetrieveCompleted); if (voterFirstRetrieveCompleted) { - if (apiCalming(`challengeParticipantFirstRetrieve-${challengeWeVoteId}`, 60000)) { + if (apiCalming(`challengeParticipantFirstRetrieve-${challengeWeVoteId}`, UPDATE_NO_MORE_OFTEN_THAN)) { ChallengeParticipantActions.challengeParticipantRetrieve(challengeWeVoteId); } } diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx index 96dcdc624..f1f60e20f 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx @@ -22,7 +22,7 @@ const ChallengeParticipantListItem = ({ participant, isCurrentUser }) => { {participant.participant_name} {participant.points} - {participant.invitees_who_joined} + 0}>{participant.invitees_who_joined}
{`${participant.invitees_count} invited, `} @@ -40,11 +40,13 @@ ChallengeParticipantListItem.propTypes = { participant: PropTypes.object, }; -const ParticipantItem = styled.div` - background-color: ${(props) => (props.isCurrentUser ? '#f9e79f' : '#fff')}; +const ParticipantItem = styled('div', { + shouldForwardProp: (prop) => !['isCurrentUser'].includes(prop), +})(({ isCurrentUser }) => (` + background-color: ${isCurrentUser ? '#f9e79f' : '#fff'}; padding: 15px 0 15px 7px; border-bottom: 1px solid ${DesignTokenColors.neutral100}; -`; +`)); const ParticipantRow = styled.div` display: flex; @@ -55,37 +57,42 @@ const ParticipantRow = styled.div` const Rank = styled.div` font-weight: bold; color: ${DesignTokenColors.neutral900}; - width: 60px; /* Adjust width as needed */ + width: 35px; /* Adjust width as needed */ `; const Name = styled.div` - flex: 1; - display: flex; align-items: center; - margin-left: 10px; - gap: 10px; color: ${DesignTokenColors.neutral900}; + display: flex; + flex: 1; + font-weight: bold; + gap: 10px; + margin-left: 10px; `; const Points = styled.div` - text-align: center; + color: ${DesignTokenColors.neutral900}; font-size: 14px; font-weight: bold; - color: ${DesignTokenColors.neutral900}; + text-align: center; width: 80px; `; -const FriendsJoined = styled.div` - text-align: center; - font-size: 14px; +const FriendsJoined = styled('div', { + shouldForwardProp: (prop) => !['makeBold'].includes(prop), +})(({ makeBold }) => (` color: ${DesignTokenColors.neutral900}; - width: 100px; -`; + font-size: 14px; + ${makeBold ? 'font-weight: bold;' : ''} + text-align: center; + width: 76px; +`)); const Details = styled.div` - text-align: left; + color: ${DesignTokenColors.neutral900}; font-size: 14px; margin-top: 8px; + text-align: left; `; export default ChallengeParticipantListItem; diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx index 69f40e1a2..e7c9714c2 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx @@ -136,7 +136,7 @@ const ChallengeParticipantListRoot = ({ challengeWeVoteId, classes, uniqueExtern RANK NAME - + POINTS FRIENDS JOINED diff --git a/src/js/common/components/ChallengeParticipantListRoot/FirstChallengeParticipantListController.jsx b/src/js/common/components/ChallengeParticipantListRoot/FirstChallengeParticipantListController.jsx index d09853a2a..006e4e758 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/FirstChallengeParticipantListController.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/FirstChallengeParticipantListController.jsx @@ -6,6 +6,7 @@ import initializejQuery from '../../utils/initializejQuery'; import { renderLog } from '../../utils/logging'; import VoterStore from '../../../stores/VoterStore'; +const UPDATE_NO_MORE_OFTEN_THAN = 30000; // 30 seconds class FirstChallengeParticipantListController extends Component { constructor (props) { @@ -47,7 +48,7 @@ class FirstChallengeParticipantListController extends Component { const voterFirstRetrieveCompleted = VoterStore.voterFirstRetrieveCompleted(); // console.log('FirstChallengeParticipantListController challengeParticipantListFirstRetrieveInitiated, voterFirstRetrieveCompleted: ', voterFirstRetrieveCompleted, ', challengeWeVoteId: ', challengeWeVoteId); if (voterFirstRetrieveCompleted && challengeWeVoteId) { - if (apiCalming(`challengeParticipantListFirstRetrieve-${challengeWeVoteId}`, 30000)) { + if (apiCalming(`challengeParticipantListFirstRetrieve-${challengeWeVoteId}`, UPDATE_NO_MORE_OFTEN_THAN)) { ChallengeParticipantActions.challengeParticipantListRetrieve(challengeWeVoteId); } } From 19da753b0c1364e9dfb838d3f30561016b156288 Mon Sep 17 00:00:00 2001 From: Kateryna Stetsenko Date: Sat, 12 Oct 2024 19:33:22 -0700 Subject: [PATCH 50/54] [WV-522]fixed DesignTokensColors in file JoinedAndDaysLeft.jsxas previously were undefined, chanhed to correct ones and created switcher for border joined and days left Fixed DesignTokensColors in src/js/common/components/Challenge/JoinedAndDaysLeft.jsx as previously were undefined, changed to correct ones and created switcher for border joined and days left Renamed style prop to borderSwitcher in JoinedAndDaysLeft and ChallengeHeaderSimple components Applied borderswitcher for ChallengeHeaderSimple.jsx and change border:none to none as this is more correct and don't cause an error --- .../Challenge/JoinedAndDaysLeft.jsx | 24 +++++++++++-------- .../Navigation/ChallengeHeaderSimple.jsx | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx b/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx index edc27ee7e..0800ff9fa 100644 --- a/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx +++ b/src/js/common/components/Challenge/JoinedAndDaysLeft.jsx @@ -8,7 +8,7 @@ import DesignTokenColors from '../Style/DesignTokenColors'; const ChallengeParticipantFirstRetrieveController = React.lazy(() => import(/* webpackChunkName: 'ChallengeParticipantFirstRetrieveController' */ '../ChallengeParticipant/ChallengeParticipantFirstRetrieveController')); -function JoinedAndDaysLeft ({ challengeWeVoteId, style }) { +function JoinedAndDaysLeft ({ challengeWeVoteId, borderSwitcher }) { // eslint-disable-next-line no-unused-vars const [daysLeft, setDaysLeft] = React.useState(0); const [voterIsChallengeParticipant, setVoterIsChallengeParticipant] = React.useState(false); @@ -33,7 +33,7 @@ function JoinedAndDaysLeft ({ challengeWeVoteId, style }) { return ( {/* SVG, Joined, Dot, and Days Left */} - + {voterIsChallengeParticipant ? ( <> @@ -57,11 +57,13 @@ function JoinedAndDaysLeft ({ challengeWeVoteId, style }) { } JoinedAndDaysLeft.propTypes = { challengeWeVoteId: PropTypes.string.isRequired, - style: PropTypes.object, + borderSwitcher: PropTypes.bool, +}; +JoinedAndDaysLeft.defaultProps = { + borderSwitcher: true, // Default true shows border around the joined and days left info }; // Styled Components - const InfoIcon = styled('img')` height: 17px; margin-right: 5px; @@ -75,17 +77,19 @@ const InfoWrapper = styled('div')` width: 100%; `; -const JoinedInfoWrapper = styled('div')` +const JoinedInfoWrapper = styled('div', { + shouldForwardProp: (prop) => !['borderSwitcher'].includes(prop), +})(({ borderSwitcher }) => ` align-items: center; background-color: ${DesignTokenColors.whiteUI}; - border: 1px solid ${DesignTokenColors.gray100}; + border: ${borderSwitcher ? `1px solid ${DesignTokenColors.neutral100}` : 'none'}; border-radius: 20px; display: flex; height: auto; justify-content: center; padding: 5px 10px; width: auto; -`; +`); const JoinedIcon = styled('img')` height: 17px; @@ -94,20 +98,20 @@ const JoinedIcon = styled('img')` `; const JoinedText = styled('span')` - color: ${DesignTokenColors.gray900}; + color: ${DesignTokenColors.neutral900}; font-size: 13px; font-weight: 400; `; const DotSeparator = styled('span')` - color: ${DesignTokenColors.gray500}; + color: ${DesignTokenColors.neutral500}; font-size: 13px; font-weight: 400; margin: 0 5px; `; const DaysLeftText = styled('span')` - color: ${DesignTokenColors.gray900}; + color: ${DesignTokenColors.neutral900}; font-size: 13px; font-weight: 600; letter-spacing: -0.03em; diff --git a/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx b/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx index a895d3533..9f4eff22c 100644 --- a/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx +++ b/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx @@ -43,7 +43,7 @@ function ChallengeHeaderSimple (props) { {challengeTitle} {/* Joined and Days Left Info */} - From d7f1a52a635fae5092af60658773a3bc2e8e35a7 Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Mon, 14 Oct 2024 13:16:34 -0700 Subject: [PATCH 51/54] Improved display of invitees_who_viewed_plus. Redirecting to /ready page if sharedItem not found in database. --- .../common/components/Challenge/YourRankModal.jsx | 14 ++++++-------- .../ChallengeParticipantListItem.jsx | 10 ++++++---- src/js/common/stores/ShareStore.js | 7 ++++++- src/js/pages/SharedItemLanding.jsx | 12 +++++++++++- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/js/common/components/Challenge/YourRankModal.jsx b/src/js/common/components/Challenge/YourRankModal.jsx index 4e0e13ad9..450019ca1 100644 --- a/src/js/common/components/Challenge/YourRankModal.jsx +++ b/src/js/common/components/Challenge/YourRankModal.jsx @@ -7,7 +7,8 @@ import styled from 'styled-components'; import ChallengeParticipantListRoot from '../ChallengeParticipantListRoot/ChallengeParticipantListRoot'; const YourRankModal = ({ challengeWeVoteId, classes, show, toggleModal }) => { - const challengeName = `Mr. Beast's "Get Out the Vote"`; + // Consider including name of the challenge here + // const challengeName = `Mr. Beast's "Get Out the Vote"`; return ( { > - Ranking -  - {challengeName} -   - Challenge + Challenge Ranking ({ const DialogTitleWrapper = styled.div` display: flex; + justify-content: space-between; min-height: 30px; `; const Title = styled.h2` font-size: 16px; font-weight: bold; - margin: 0; - margin-top: 10px; + margin: 10px 0 0 0; text-align: left; - padding-left: 0px; + padding-left: 0; `; export default withStyles(styles)(YourRankModal); diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx index f1f60e20f..414e63583 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListItem.jsx @@ -27,10 +27,12 @@ const ChallengeParticipantListItem = ({ participant, isCurrentUser }) => {
{`${participant.invitees_count} invited, `} {`${participant.invitees_who_viewed} viewed challenge`} - {/* - {' '} - {`- ${participant.invitees_who_viewed_plus} total views`} - */} + {(participant.invitees_who_viewed_plus > 0 && participant.invitees_who_viewed !== participant.invitees_who_viewed_plus) && ( + <> + {' '} + {`- ${participant.invitees_who_viewed_plus} total views`} + + )}
); diff --git a/src/js/common/stores/ShareStore.js b/src/js/common/stores/ShareStore.js index 109ac635e..b582715fb 100644 --- a/src/js/common/stores/ShareStore.js +++ b/src/js/common/stores/ShareStore.js @@ -219,7 +219,12 @@ class ShareStore extends ReduceStore { sharedItem = action.res || {}; sharedItemDestinationFullUrl = action.res.destination_full_url || ''; sharedItemDestinationFullUrlLowerCase = sharedItemDestinationFullUrl.toLowerCase(); - allCachedSharedItemsByFullUrl[sharedItemDestinationFullUrlLowerCase] = sharedItem; + if (sharedItemDestinationFullUrlLowerCase !== '') { + allCachedSharedItemsByFullUrl[sharedItemDestinationFullUrlLowerCase] = sharedItem; + } + if (action.res.shared_item_code) { + allCachedSharedItemsBySharedItemCode[action.res.shared_item_code] = sharedItem; + } if (action.res.shared_item_code_no_opinions) { allCachedSharedItemsBySharedItemCode[action.res.shared_item_code_no_opinions] = sharedItem; } diff --git a/src/js/pages/SharedItemLanding.jsx b/src/js/pages/SharedItemLanding.jsx index dfd8e2802..195f3a6e3 100644 --- a/src/js/pages/SharedItemLanding.jsx +++ b/src/js/pages/SharedItemLanding.jsx @@ -16,6 +16,7 @@ export default class SharedItemLanding extends Component { this.state = { componentDidMount: false, customLinkString: '', + destinationBackupPath: '', destinationFullUrl: '', destinationFullUrlOverride: '', isBallotShare: false, @@ -100,6 +101,11 @@ export default class SharedItemLanding extends Component { sharedItemCodeRetrieved: true, waitForVoterDeviceId, }); + } else if (sharedItem && sharedItem.destination_path_backup && sharedItem.destination_path_backup !== '') { + this.setState({ + destinationBackupPath: sharedItem.destination_path_backup, + sharedItemCodeRetrieved: true, + }); } else { console.log('SharedItemLanding destination_full_url not found'); } @@ -120,7 +126,7 @@ export default class SharedItemLanding extends Component { render () { renderLog('SharedItemLanding'); // Set LOG_RENDER_EVENTS to log all renders const { - componentDidMount, destinationFullUrlOverride, + componentDidMount, destinationBackupPath, destinationFullUrlOverride, isBallotShare, isChallengeShare, sharedItemCodeAllOpinions, sharedItemCodeIncoming, sharedItemCodeRetrieved, } = this.state; @@ -140,6 +146,10 @@ export default class SharedItemLanding extends Component { // console.log('SharedItemLanding destinationFullUrl undefined, directing to /ready'); this.localHistoryPush('/ready'); return LoadingWheel; + } else if (destinationBackupPath !== '') { + console.log('If we receive a destinationBackupPath, then the shared item was not found:', destinationBackupPath); + this.localHistoryPush(destinationBackupPath); + return LoadingWheel; } else { // console.log('destinationFullUrl:', destinationFullUrl); const { hostname } = window.location; From f7907d5eb8f4e70fba948fc32b5a4dac89ca747a Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Tue, 15 Oct 2024 06:40:17 -0700 Subject: [PATCH 52/54] Gave different tips different chip colors. Changed visible "Twitter" references to "X". Bumped Join Challenge button above the fold on ChallengeHomePage. Turned off BallotMatchIndicator until we can get it to be driven by data. --- .../BoostLearnMoreModal.jsx | 2 +- .../InviteFriendsTips.jsx | 14 +++++++++----- .../components/SignIn/SignInOptionsPanel.jsx | 2 +- .../pages/Challenge/ChallengeHomePage.jsx | 16 ++++++++-------- .../Ballot/BallotScrollingContainer.jsx | 18 ++++++++++-------- src/js/components/Twitter/TwitterSignIn.jsx | 2 +- src/js/pages/HowItWorks.jsx | 4 ++-- src/js/pages/Intro/GetStarted2019.jsx | 4 ++-- src/js/pages/OpinionsFollowed.jsx | 2 +- src/js/pages/Values/OneValue.jsx | 2 +- src/js/pages/WelcomeForCampaigns.jsx | 2 +- src/js/pages/YourPage.jsx | 2 +- 12 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx index 409003bfd..4a5bb7bd9 100644 --- a/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx +++ b/src/js/common/components/ChallengeInviteFriends/BoostLearnMoreModal.jsx @@ -180,7 +180,7 @@ class BoostLearnMoreModal extends Component { // console.log('BoostLearnMoreModal render, voter_address_object: ', voter_address_object); const textFieldJSX = ( -
Learn more content here
+
Learn more coming soon
); diff --git a/src/js/common/components/ChallengeInviteFriends/InviteFriendsTips.jsx b/src/js/common/components/ChallengeInviteFriends/InviteFriendsTips.jsx index 2c4921bdb..26436371a 100644 --- a/src/js/common/components/ChallengeInviteFriends/InviteFriendsTips.jsx +++ b/src/js/common/components/ChallengeInviteFriends/InviteFriendsTips.jsx @@ -88,7 +88,7 @@ function InviteFriendsTips ({ challengeWeVoteId, startingTipName }) { } else if (tipToShow === 'sendMessage') { tipJsx = ( - +   Send the copied message {' '} @@ -104,7 +104,7 @@ function InviteFriendsTips ({ challengeWeVoteId, startingTipName }) { } else if (tipToShow === 'youWillGetPoints') { tipJsx = ( - +   When your friend views or joins this challenge {' '} @@ -147,12 +147,16 @@ const NextSpan = styled('span')` text-decoration:underline; `; -const StyledChip = styled(Chip)` - background-color: ${DesignTokenColors.confirmation700}; +const StyledChip = styled(Chip, { + shouldForwardProp: (prop) => !['colorOptionNumber'].includes(prop), +})(({ colorOptionNumber }) => (` + ${colorOptionNumber ? '' : `background-color: ${DesignTokenColors.confirmation700};`} + ${colorOptionNumber === 1 ? `background-color: ${DesignTokenColors.warning800};` : ''} + ${colorOptionNumber === 2 ? `background-color: ${DesignTokenColors.info900};` : ''} color: ${DesignTokenColors.whiteUI}; height: 20px; padding-top: 2px; padding-bottom: 2px; -`; +`)); export default withStyles(styles)(InviteFriendsTips); diff --git a/src/js/common/components/SignIn/SignInOptionsPanel.jsx b/src/js/common/components/SignIn/SignInOptionsPanel.jsx index 3eef78d1e..39315f346 100755 --- a/src/js/common/components/SignIn/SignInOptionsPanel.jsx +++ b/src/js/common/components/SignIn/SignInOptionsPanel.jsx @@ -447,7 +447,7 @@ export default class SignInOptionsPanel extends Component { {showRecommendedText && Recommended} + + }> + + + {challengeDescription && ( @@ -657,14 +665,6 @@ class ChallengeHomePage extends Component { )} - - }> - - - {challengeDataFound && ( diff --git a/src/js/components/Ballot/BallotScrollingContainer.jsx b/src/js/components/Ballot/BallotScrollingContainer.jsx index 05a77ae22..6353d6fe2 100644 --- a/src/js/components/Ballot/BallotScrollingContainer.jsx +++ b/src/js/components/Ballot/BallotScrollingContainer.jsx @@ -207,14 +207,16 @@ class BallotScrollingContainer extends Component { {candidatePartyText} - + {pigsCanFly && ( + + )} diff --git a/src/js/components/Twitter/TwitterSignIn.jsx b/src/js/components/Twitter/TwitterSignIn.jsx index a7452c58d..76318cd96 100644 --- a/src/js/components/Twitter/TwitterSignIn.jsx +++ b/src/js/components/Twitter/TwitterSignIn.jsx @@ -201,7 +201,7 @@ class TwitterSignIn extends Component { if (version) { const floatVersion = parseFloat(version); if (floatVersion < 13.0) { - console.log('Sign in with Twitter is not available on iOS < 13, this phone is running: ', floatVersion); + console.log('Sign in with X is not available on iOS < 13, this phone is running: ', floatVersion); twitterSignInButtonDisabled = true; buttonText = '(Requires iOS 13)'; } diff --git a/src/js/pages/HowItWorks.jsx b/src/js/pages/HowItWorks.jsx index b660ad557..5e78af2af 100644 --- a/src/js/pages/HowItWorks.jsx +++ b/src/js/pages/HowItWorks.jsx @@ -28,7 +28,7 @@ class HowItWorks extends Component { forCampaignsSteps: { Claim: { title: '1. Claim your campaign profile', - description: 'Sign in & verify your account using your official Twitter account or other secure method. WeVote takes verification very seriously. (No trolls allowed!)', + description: 'Sign in & verify your account using your official X account or other secure method. WeVote takes verification very seriously. (No trolls allowed!)', imgSrc: '/img/how-it-works/HowItWorksForCampaigns-Claim-20190516.gif?', index: 0, }, @@ -61,7 +61,7 @@ class HowItWorks extends Component { forOrganizationsSteps: { Claim: { title: '1. Claim your organization profile', - description: 'Sign in & verify your organization using your official Twitter account or other secure method. WeVote takes verification very seriously. (No trolls allowed!)', + description: 'Sign in & verify your organization using your official X account or other secure method. WeVote takes verification very seriously. (No trolls allowed!)', imgSrc: '/img/how-it-works/HowItWorksForOrgs-Claim-20190506.gif?', index: 0, }, diff --git a/src/js/pages/Intro/GetStarted2019.jsx b/src/js/pages/Intro/GetStarted2019.jsx index c753e8de2..c24531fcf 100644 --- a/src/js/pages/Intro/GetStarted2019.jsx +++ b/src/js/pages/Intro/GetStarted2019.jsx @@ -107,11 +107,11 @@ export default class GetStarted2019 extends Component {

- Sign in with Twitter to see + Sign in with X to see
the voter guides of everyone
- you follow on Twitter. + you follow.

diff --git a/src/js/pages/OpinionsFollowed.jsx b/src/js/pages/OpinionsFollowed.jsx index 94def089f..58fbb0a1a 100755 --- a/src/js/pages/OpinionsFollowed.jsx +++ b/src/js/pages/OpinionsFollowed.jsx @@ -93,7 +93,7 @@ export default class OpinionsFollowed extends Component { Empower your supporters to share your localized, responsive endorsement {' '} - experience with their friends and family on Facebook, Twitter, email and SMS. + experience with their friends and family on Facebook, X, email and SMS. diff --git a/src/js/pages/YourPage.jsx b/src/js/pages/YourPage.jsx index 47c68d48c..719226825 100644 --- a/src/js/pages/YourPage.jsx +++ b/src/js/pages/YourPage.jsx @@ -73,7 +73,7 @@ export default class YourPage extends Component {

- Enter your Twitter handle to create a public voter guide. + Enter your X handle to create a public voter guide.

From 332e85f821d6b8bce03c108574efffefe252028b Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Tue, 15 Oct 2024 07:29:51 -0700 Subject: [PATCH 53/54] Making challenges header tab and footer icon visible. --- src/js/components/Navigation/FooterBar.jsx | 6 +++--- src/js/components/Navigation/HeaderBar.jsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/js/components/Navigation/FooterBar.jsx b/src/js/components/Navigation/FooterBar.jsx index 8e8e1860b..a37facdae 100644 --- a/src/js/components/Navigation/FooterBar.jsx +++ b/src/js/components/Navigation/FooterBar.jsx @@ -17,12 +17,12 @@ import stringContains from '../../common/utils/stringContains'; import FriendStore from '../../stores/FriendStore'; import VoterStore from '../../stores/VoterStore'; import { cordovaFooterHeight } from '../../utils/cordovaOffsets'; -import webAppConfig from '../../config'; +// import webAppConfig from '../../config'; // It's not ideal to have two images, but this is a complex svg, and I couldn't figure out how to change the fill color with a variable const capitalBuilding = '/img/global/svg-icons/capital-building.svg'; const capitalBuildingSelected = '/img/global/svg-icons/capital-building-selected.svg'; -const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES; +// const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES; class FooterBar extends React.Component { constructor (props) { @@ -224,7 +224,7 @@ class FooterBar extends React.Component { let discussVisible; let donateVisible; const friendsVisible = false; // 2023-09-04 Dale We are turning off Friends footer icon for now - const squadsVisible = isWebApp() && nextReleaseFeaturesEnabled; + const squadsVisible = isWebApp(); // const squadsVisible = false; // let howItWorksVisible; const howItWorksVisible = false; diff --git a/src/js/components/Navigation/HeaderBar.jsx b/src/js/components/Navigation/HeaderBar.jsx index 73af658af..412cd3ce8 100644 --- a/src/js/components/Navigation/HeaderBar.jsx +++ b/src/js/components/Navigation/HeaderBar.jsx @@ -30,11 +30,11 @@ import FriendsTabs from './FriendsTabs'; import HeaderBarLogo from './HeaderBarLogo'; import HeaderBarModals from './HeaderBarModals'; import TabWithPushHistory from './TabWithPushHistory'; -import webAppConfig from '../../config'; +// import webAppConfig from '../../config'; const HeaderNotificationMenu = React.lazy(() => import(/* webpackChunkName: 'HeaderNotificationMenu' */ './HeaderNotificationMenu')); -const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES; +// const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES; /* global $ */ @@ -474,7 +474,7 @@ class HeaderBar extends Component { let donateVisible; const friendsVisible = false; // 2023-09-04 Dale We are turning off Friends header link for now let howItWorksValue; - const squadsVisible = isWebApp() && nextReleaseFeaturesEnabled; + const squadsVisible = isWebApp(); // const squadsVisible = false; let squadsValue; // let howItWorksVisible; From 66651ae26bf7ffeb415c4b3c554a350e135e73f6 Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Tue, 15 Oct 2024 11:45:50 -0700 Subject: [PATCH 54/54] Challenge Header fixes for very small phones. --- .../ConfirmYouSentInviteButton.jsx | 1 + .../InviteAgainButton.jsx | 1 + .../ChallengeParticipantListRoot.jsx | 2 +- .../Navigation/ChallengeHeaderSimple.jsx | 37 +++++++------ .../pages/Challenge/ChallengeHomePage.jsx | 53 ++++++------------- .../Politician/PoliticianDetailsPage.jsx | 6 +-- src/js/common/utils/challengeUtils.js | 1 + .../VoterGuide/OrganizationModal.jsx | 28 +++++----- 8 files changed, 55 insertions(+), 74 deletions(-) diff --git a/src/js/common/components/ChallengeInviteeListRoot/ConfirmYouSentInviteButton.jsx b/src/js/common/components/ChallengeInviteeListRoot/ConfirmYouSentInviteButton.jsx index bcfc0ad6b..b12cd3a16 100755 --- a/src/js/common/components/ChallengeInviteeListRoot/ConfirmYouSentInviteButton.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/ConfirmYouSentInviteButton.jsx @@ -66,6 +66,7 @@ const styles = () => ({ padding: '2px 10px', borderRadius: 20, fontSize: 14, + lineHeight: '1.2', }, }); diff --git a/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx b/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx index 1eaa95eb5..29e38f531 100755 --- a/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx +++ b/src/js/common/components/ChallengeInviteeListRoot/InviteAgainButton.jsx @@ -149,6 +149,7 @@ const styles = () => ({ boxShadow: 'none !important', color: `${DesignTokenColors.primary500}`, fontSize: 14, + lineHeight: '1.2', marginRight: '-5px', padding: '0 20px', textTransform: 'none', diff --git a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx index e7c9714c2..6736298e2 100644 --- a/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx +++ b/src/js/common/components/ChallengeParticipantListRoot/ChallengeParticipantListRoot.jsx @@ -184,7 +184,7 @@ const TopSection = styled.div` align-items: center; background-color: white; box-shadow: 0px 6px 6px -2px rgba(0, 0, 0, 0.1); - z-index: 1; + // z-index: 1; position: sticky; top: 0; padding: 10px; diff --git a/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx b/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx index 9f4eff22c..f44ae58ab 100644 --- a/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx +++ b/src/js/common/components/Navigation/ChallengeHeaderSimple.jsx @@ -23,7 +23,7 @@ const ImageHandler = React.lazy(() => import(/* webpackChunkName: 'ImageHandler' // React functional component example function ChallengeHeaderSimple (props) { renderLog('ChallengeHeaderSimple'); // Set LOG_RENDER_EVENTS to log all renders - const { challengeTitle, challengeWeVoteId, classes, challengePhotoLargeUrl, goToChallengeHome } = props; + const { challengeTitle, challengeWeVoteId, classes, challengePhotoLargeUrl, goToChallengeHome, hideCloseIcon } = props; return ( @@ -31,7 +31,7 @@ function ChallengeHeaderSimple (props) { {/* Challenge Image */} {challengePhotoLargeUrl && ( @@ -49,21 +49,23 @@ function ChallengeHeaderSimple (props) { /> - -
- - - - - -
-
+ {!hideCloseIcon && ( + +
+ + + + + +
+
+ )}
@@ -76,6 +78,7 @@ ChallengeHeaderSimple.propTypes = { challengeWeVoteId: PropTypes.string, classes: PropTypes.object, challengePhotoLargeUrl: PropTypes.string, + hideCloseIcon: PropTypes.bool, }; const styles = () => ({ diff --git a/src/js/common/pages/Challenge/ChallengeHomePage.jsx b/src/js/common/pages/Challenge/ChallengeHomePage.jsx index 607b71a05..577a0a67c 100644 --- a/src/js/common/pages/Challenge/ChallengeHomePage.jsx +++ b/src/js/common/pages/Challenge/ChallengeHomePage.jsx @@ -16,7 +16,6 @@ import ChallengeParticipantStore from '../../stores/ChallengeParticipantStore'; import ChallengeStore from '../../stores/ChallengeStore'; import VoterStore from '../../../stores/VoterStore'; import CompleteYourProfileModalController from '../../components/Settings/CompleteYourProfileModalController'; -import { Candidate, CandidateNameH4, CandidateNameAndPartyWrapper, CandidateTopRow } from '../../../components/Style/BallotStyles'; import { CampaignDescriptionDesktop, CampaignDescriptionDesktopWrapper, CampaignDescriptionWrapper, CampaignSubSectionSeeAll, CampaignSubSectionTitle, CampaignSubSectionTitleWrapper, @@ -40,22 +39,20 @@ import standardBoxShadow from '../../components/Style/standardBoxShadow'; import { cordovaBallotFilterTopMargin } from '../../../utils/cordovaOffsets'; import { headroomWrapperOffset } from '../../../utils/cordovaCalculatedOffsets'; import { getPageKey } from '../../../utils/cordovaPageUtils'; -import normalizedImagePath from '../../utils/normalizedImagePath'; import ChallengeAbout from '../../components/Challenge/ChallengeAbout'; import ChallengeParticipantListRoot from '../../components/ChallengeParticipantListRoot/ChallengeParticipantListRoot'; import ChallengeInviteeListRoot from '../../components/ChallengeInviteeListRoot/ChallengeInviteeListRoot'; import ThanksForViewingChallenge from '../../components/Challenge/ThanksForViewingChallenge'; import ShareStore from '../../stores/ShareStore'; +import ChallengeHeaderSimple from '../../components/Navigation/ChallengeHeaderSimple'; const ChallengeCardForList = React.lazy(() => import(/* webpackChunkName: 'ChallengeCardForList' */ '../../components/ChallengeListRoot/ChallengeCardForList')); // const ChallengeCommentsList = React.lazy(() => import(/* webpackChunkName: 'ChallengeCommentsList' */ '../../components/Challenge/ChallengeCommentsList')); const ChallengeRetrieveController = React.lazy(() => import(/* webpackChunkName: 'ChallengeRetrieveController' */ '../../components/Challenge/ChallengeRetrieveController')); // const ChallengeNewsItemList = React.lazy(() => import(/* webpackChunkName: 'ChallengeNewsItemList' */ '../../components/Challenge/ChallengeNewsItemList')); // const ChallengeShareChunk = React.lazy(() => import(/* webpackChunkName: 'ChallengeShareChunk' */ '../../components/Challenge/ChallengeShareChunk')); -const ImageHandler = React.lazy(() => import(/* webpackChunkName: 'ImageHandler' */ '../../../components/ImageHandler')); const JoinChallengeButton = React.lazy(() => import(/* webpackChunkName: 'JoinChallengeButton' */ '../../components/Challenge/JoinChallengeButton')); const ReadMore = React.lazy(() => import(/* webpackChunkName: 'ReadMore' */ '../../components/Widgets/ReadMore')); -const UpdateChallengeInformation = React.lazy(() => import(/* webpackChunkName: 'UpdateChallengeInformation' */ '../../components/Challenge/UpdateChallengeInformation')); const futureFeaturesDisabled = true; const nextReleaseFeaturesEnabled = webAppConfig.ENABLE_NEXT_RELEASE_FEATURES === undefined ? false : webAppConfig.ENABLE_NEXT_RELEASE_FEATURES; @@ -103,6 +100,7 @@ class ChallengeHomePage extends Component { challengeDataFound: false, challengeDataNotFound: false, challengeDescription: '', + challengePhotoLargeUrl: '', challengeSEOFriendlyPath: '', challengeSEOFriendlyPathForDisplay: '', // Value for challenge already received challengeTitle: '', @@ -339,6 +337,7 @@ class ChallengeHomePage extends Component { const { challengeDescription, challengePhotoLargeUrl, + challengePhotoMediumUrl, challengeSEOFriendlyPath, challengeTitle, challengeWeVoteId, @@ -373,6 +372,7 @@ class ChallengeHomePage extends Component { challengeDescription, challengeDescriptionLimited, challengePhotoLargeUrl, + challengePhotoMediumUrl, challengeTitle, finalElectionDateInPast, isBlockedByWeVote, @@ -406,12 +406,11 @@ class ChallengeHomePage extends Component { finalElectionDateInPast: false, // isSupportersCountMinimumExceeded: false, challengeWeVoteId: '', - politicalParty: '', challengeDataFound: false, challengeDataNotFound: false, challengeDescription: '', challengeDescriptionLimited: '', - challengeImageUrlLarge: '', + challengePhotoLargeUrl: '', challengeTitle: '', challengeWeVoteIdForDisplay: '', // We don't clear challengeWeVoteId because we may need it to load next challenge challengeSEOFriendlyPathForDisplay: '', // We don't clear challengeSEOFriendlyPath because we may need it to load next challenge @@ -472,7 +471,7 @@ class ChallengeHomePage extends Component { chosenWebsiteName, challengeWeVoteId, loadSlow, challengeDataFound, challengeDataNotFound, - challengeDescription, challengeDescriptionLimited, challengeImageUrlLarge, + challengeDescription, challengeDescriptionLimited, challengePhotoLargeUrl, challengeSEOFriendlyPath, challengeSEOFriendlyPathForDisplay, challengeTitle, challengeWeVoteIdForDisplay, scrolledDown, sharedByDisplayName, thanksForViewingChallengeOn, @@ -481,8 +480,6 @@ class ChallengeHomePage extends Component { // console.log('ChallengeHomePage render challengeSEOFriendlyPath: ', challengeSEOFriendlyPath, ', challengeSEOFriendlyPathForDisplay: ', challengeSEOFriendlyPathForDisplay); const challengeAdminEditUrl = `${webAppConfig.WE_VOTE_SERVER_ROOT_URL}challenge/${challengeWeVoteId}/summary`; // const candidateWeVoteId = CandidateStore.getCandidateWeVoteIdRunningFromChallengeWeVoteId(challengeWeVoteId); - const avatarBackgroundImage = normalizedImagePath('../img/global/svg-icons/avatar-generic.svg'); - const avatarCompressed = 'card-main__avatar-compressed'; if (challengeDataNotFound) { return ( @@ -549,29 +546,14 @@ class ChallengeHomePage extends Component { - - - {/* Challenge Image */} - }> - - - {/* Challenge Name */} - - - {challengeTitle} - - - - + @@ -792,11 +774,6 @@ const styles = (theme) => ({ }, }); -const AboutAndEditFlex = styled('div')` - display: flex; - justify-content: space-between; -`; - const AboutSectionWrapper = styled('div')` `; @@ -858,7 +835,7 @@ const slideDown = keyframes` `; const MobileHeaderContentContainer = styled('div')(({ theme }) => (` - padding: 15px 15px 0 15px; + // padding: 15px 15px 0 15px; margin: ${() => cordovaBallotFilterTopMargin()} auto 0 auto; position: relative; max-width: 960px; diff --git a/src/js/common/pages/Politician/PoliticianDetailsPage.jsx b/src/js/common/pages/Politician/PoliticianDetailsPage.jsx index f094d19ba..dabd9a06d 100644 --- a/src/js/common/pages/Politician/PoliticianDetailsPage.jsx +++ b/src/js/common/pages/Politician/PoliticianDetailsPage.jsx @@ -919,7 +919,7 @@ class PoliticianDetailsPage extends Component { {/* Candidate Image */} }> @@ -1385,10 +1385,10 @@ const MissingPoliticianText = styled('p')(({ theme }) => (` `)); const slideIn = keyframes` - from { + from { transform: translateY(-100%); } - to { + to { transform: translateY(0); } `; diff --git a/src/js/common/utils/challengeUtils.js b/src/js/common/utils/challengeUtils.js index c5c6deb74..dac7f22b0 100644 --- a/src/js/common/utils/challengeUtils.js +++ b/src/js/common/utils/challengeUtils.js @@ -46,6 +46,7 @@ export function getChallengeValuesFromIdentifiers (challengeSEOFriendlyPath, cha we_vote_hosted_challenge_photo_small_url: challengePhotoSmallUrl, we_vote_hosted_profile_image_url_large: weVoteHostedProfileImageUrlLarge, } = challenge); + // console.log('getChallengeValuesFromIdentifiers, challenge:', challenge); challengePoliticianList = ChallengeStore.getChallengePoliticianList(challengeWeVoteIdFromObject); } // console.log('getChallengeValuesFromIdentifiers, challenge: ', challenge, ', challengeWeVoteIdFromObject:', challengeWeVoteIdFromObject, ', challengeTitle:', challengeTitle); diff --git a/src/js/components/VoterGuide/OrganizationModal.jsx b/src/js/components/VoterGuide/OrganizationModal.jsx index 8f97162e5..a4f8a2fb0 100644 --- a/src/js/components/VoterGuide/OrganizationModal.jsx +++ b/src/js/components/VoterGuide/OrganizationModal.jsx @@ -283,8 +283,6 @@ class OrganizationModal extends Component { } } - - // handleResizeLocal () { // if (handleResize('Footer')) { // // console.log('Footer handleResizeEntry update'); @@ -385,16 +383,16 @@ class OrganizationModal extends Component { }> @@ -409,11 +407,11 @@ class OrganizationModal extends Component {
@@ -425,7 +423,7 @@ class OrganizationModal extends Component {  }>