forked from wevote/WebApp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request wevote#4121 from pbnjcub/WV-600
WV 600 Added You're Rank to Leaderboard and more info modal about points TEAM REVIEW
- Loading branch information
Showing
4 changed files
with
372 additions
and
54 deletions.
There are no files selected for viewing
250 changes: 250 additions & 0 deletions
250
src/js/common/components/Challenge/PointsExplanationModal.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
import withStyles from '@mui/styles/withStyles'; | ||
import withTheme from '@mui/styles/withTheme'; | ||
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import styled from 'styled-components'; | ||
import DesignTokenColors from '../Style/DesignTokenColors'; | ||
import ModalDisplayTemplateA, { templateAStyles, TextFieldWrapper } from '../../../components/Widgets/ModalDisplayTemplateA'; | ||
import { DialogTitle, DialogTitleText } from '@mui/material'; | ||
import { renderLog } from '../../utils/logging'; | ||
|
||
class PointsExplanationModal extends Component { | ||
constructor (props) { | ||
super(props); | ||
this.state = { | ||
showTerms: false, | ||
}; | ||
} | ||
|
||
toggleTerms = () => { | ||
this.setState({ showTerms: !this.state.showTerms }); | ||
}; | ||
|
||
render() { | ||
renderLog('PointsExplanationModalModal'); | ||
const { show, toggleModal } = this.props; | ||
const { showTerms } = this.state; | ||
|
||
const dialogTitleText = ''; | ||
|
||
const textFieldJSX = ( | ||
<PointsWrapper> | ||
<CardRowsWrapper> | ||
<CardForListRow> | ||
<FlexDivLeft> | ||
<HowWeCalculateDiv> | ||
<span>How we calculate the challenge leaderboard ranking</span> | ||
</HowWeCalculateDiv> | ||
</FlexDivLeft> | ||
</CardForListRow> | ||
<CardForListRow> | ||
<FlexDivLeft> | ||
<AtTheEndDiv> | ||
<span>At the end of a challenge, the participant who has the most points is ranked as #1 and wins the challenge.</span> | ||
</AtTheEndDiv> | ||
</FlexDivLeft> | ||
</CardForListRow> | ||
<CardForListRow> | ||
<FlexDivLeft> | ||
<HowYouEarnPointsDiv> | ||
<span>How you earn points</span> | ||
</HowYouEarnPointsDiv> | ||
</FlexDivLeft> | ||
</CardForListRow> | ||
</CardRowsWrapper> | ||
<Table> | ||
<thead> | ||
<tr> | ||
<Th>ACTION</Th> | ||
<Th>POINTS EARNED</Th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<Tr> | ||
<Td>Friend you invited joins a challenge</Td> | ||
<Td>10</Td> | ||
</Tr> | ||
<Tr> | ||
<Td>Friend you invited clicks the invitation link</Td> | ||
<Td>5</Td> | ||
</Tr> | ||
<Tr> | ||
<Td>Adding a photo to your profile</Td> | ||
<Td>5</Td> | ||
</Tr> | ||
<Tr> | ||
<Td>Sending a challenge invitation to a friend</Td> | ||
<Td>2</Td> | ||
</Tr> | ||
<Tr> | ||
<Td>Every time a friend you invited earns 5 points</Td> | ||
<Td>1</Td> | ||
</Tr> | ||
</tbody> | ||
</Table> | ||
<CardRowsWrapper> | ||
<CardForListRow> | ||
<FlexDivLeft> | ||
<ViewContestTermsDiv> | ||
<ViewContestTermsLink onClick={this.toggleTerms}> | ||
<span>{showTerms ? 'Hide contest terms' : 'View contest terms'}</span> | ||
</ViewContestTermsLink> | ||
</ViewContestTermsDiv> | ||
</FlexDivLeft> | ||
</CardForListRow> | ||
|
||
{showTerms && ( | ||
<> | ||
<CardForListRow> | ||
<FlexDivLeft> | ||
<ContestTermDiv> | ||
<span>Contest terms</span> | ||
</ContestTermDiv> | ||
</FlexDivLeft> | ||
</CardForListRow> | ||
<Ul> | ||
<li>Sponsor: WeVote USA</li> | ||
<li>Eligibility: Open to residents of the USA who are 18 years or older.</li> | ||
<li>Entry Period: see challenge homepage</li> | ||
<li>How to Enter: To enter, simply [Describe entry method].</li> | ||
<li>Price: One lucky winner will receive [Price Description].</li> | ||
<li>Odds of Winning: Odds of winning depend on the number of eligible entries received.</li> | ||
<li>No Purchase necessary: No purchase is necessary to enter or win.</li> | ||
<li>Alternative Method of Entry: To enter without purchasing, send a handwritten letter to [Address].</li> | ||
<li>Taxes: Winner is responsible for all applicable taxes.</li> | ||
<li>Winner Notification: Winners will be notified by email or phone.</li> | ||
<li>Rules and Regulations: For a complete set of rules, please visit [Link to Rules].</li> | ||
</Ul> | ||
</> | ||
)} | ||
</CardRowsWrapper> | ||
</PointsWrapper> | ||
|
||
); | ||
|
||
return ( | ||
<ModalDisplayTemplateA | ||
dialogTitleJSX={<DialogTitle>{dialogTitleText}</DialogTitle>} | ||
textFieldJSX={textFieldJSX} | ||
show={show} | ||
tallMode | ||
toggleModal={toggleModal} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
PointsExplanationModal.propTypes = { | ||
show: PropTypes.bool.isRequired, | ||
toggleModal: PropTypes.func.isRequired, | ||
}; | ||
|
||
const styles = () => ({ | ||
howToVoteRoot: { | ||
color: '#999', | ||
height: 18, | ||
width: 18, | ||
}, | ||
}); | ||
|
||
const PointsWrapper = styled('div')` | ||
white-space: normal; | ||
`; | ||
|
||
export const CardRowsWrapper = styled('div')` | ||
margin-top: 2px; | ||
`; | ||
|
||
export const CardForListRow = styled('div')` | ||
color: ${DesignTokenColors.neutral900}; | ||
font-size: 12px; | ||
line-height: 1.5; | ||
padding-bottom: 8px; | ||
&:First-child { | ||
border-bottom: 1px solid ${DesignTokenColors.neutral300}; | ||
} | ||
&:nth-child(2) { | ||
padding-top: 8px; | ||
} | ||
`; | ||
|
||
export const FlexDivLeft = styled('div')` | ||
align-items: flex-start; | ||
display: flex; | ||
justify-content: start; | ||
`; | ||
|
||
export const HowWeCalculateDiv = styled('div')` | ||
font-size: 10px; | ||
`; | ||
|
||
export const AtTheEndDiv = styled('div')` | ||
font-weight: bold; | ||
font-size: 10px; | ||
`; | ||
|
||
export const HowYouEarnPointsDiv = styled('div')` | ||
font-size: 12px; | ||
`; | ||
|
||
export const ViewContestTermsDiv = styled('div')` | ||
font-size: 8px; | ||
`; | ||
|
||
const Table = styled('table')` | ||
width: 100%; | ||
border-collapse: collapse; | ||
`; | ||
|
||
const Th = styled('th')` | ||
text-align: left; | ||
color: ${DesignTokenColors.neutral900}; | ||
font-size: 8px; | ||
padding-top: 8px; | ||
&:nth-child(2) { | ||
text-align: right; | ||
} | ||
`; | ||
|
||
const Tr = styled('tr')` | ||
background-color: white; | ||
&:last-child { | ||
td { | ||
border-bottom: none; | ||
} | ||
`; | ||
|
||
const Td = styled('td')` | ||
color: ${DesignTokenColors.neutral900}; | ||
font-size: 10px; | ||
padding: 2px; | ||
border-bottom: 1px solid ${DesignTokenColors.neutral300}; | ||
&:nth-child(2) { | ||
text-align: right; | ||
} | ||
`; | ||
|
||
const ViewContestTermsLink = styled('span')` | ||
color: ${DesignTokenColors.accent500}; | ||
cursor: pointer; | ||
text-decoration: underline; | ||
`; | ||
|
||
export const ContestTermDiv = styled('div')` | ||
font-size: 12px; | ||
`; | ||
|
||
const Ul = styled('ul')` | ||
font-size: 10px; | ||
line-height: 1.5; | ||
text-align: left; | ||
padding-left: 10px; | ||
`; | ||
|
||
export default withTheme(withStyles(templateAStyles)(PointsExplanationModal)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import React, { PureComponent, Suspense } from 'react'; | ||
import styled from 'styled-components'; | ||
import PropTypes from 'prop-types'; | ||
import DesignTokenColors from '../Style/DesignTokenColors'; | ||
import { InfoOutlined } from '@mui/icons-material'; | ||
|
||
const PointsExplanationModal = React.lazy(() => import(/* webpackChunkName: 'PointsExplanationModal' */ './PointsExplanationModal')); // eslint-disable-line import/no-cycle | ||
|
||
class YourRankOutOf extends PureComponent { | ||
constructor (props) { | ||
super(props); | ||
this.state = { | ||
pointsExplanationModalOpen: false, | ||
moreInfoIconHovered: false, | ||
}; | ||
} | ||
|
||
openPointsExplanationModal = () => { | ||
this.setState({ | ||
pointsExplanationModalOpen: true, | ||
}); | ||
}; | ||
|
||
toggleYourRankFunction = () => { | ||
const { pointsExplanationModalOpen } = this.state; | ||
this.setState({ | ||
pointsExplanationModalOpen: !pointsExplanationModalOpen, | ||
}); | ||
}; | ||
|
||
handleMoreInfoIconHover = () => { | ||
this.setState({ | ||
moreInfoIconHovered: true, | ||
}); | ||
} | ||
|
||
handleMoreInfoIconLeave = () => { | ||
this.setState({ | ||
moreInfoIconHovered: false, | ||
}); | ||
} | ||
|
||
|
||
render() { | ||
const { rankOfVoter, participantsCount } = this.props; | ||
const { pointsExplanationModalOpen, moreInfoIconHovered } = this.state; | ||
|
||
return ( | ||
<RankContainer> | ||
<RankText>You're</RankText> | ||
{' '} | ||
<RankNumber> | ||
# | ||
{rankOfVoter} | ||
</RankNumber> | ||
{' '} | ||
<RankDetails> | ||
(of | ||
{' '} | ||
{participantsCount} | ||
) | ||
</RankDetails> | ||
{' '} | ||
<InfoOutlined | ||
style={{ color: moreInfoIconHovered ? DesignTokenColors.primary500 : DesignTokenColors.neutral600, cursor: 'pointer' }} | ||
onMouseEnter={() => this.handleMoreInfoIconHover()} | ||
onMouseLeave={() => this.handleMoreInfoIconLeave()} | ||
onClick={() => this.openPointsExplanationModal()} | ||
/> | ||
{pointsExplanationModalOpen && ( | ||
<Suspense fallback={<div>Loading...</div>}> | ||
<PointsExplanationModal | ||
show={this.state.pointsExplanationModalOpen} | ||
toggleModal={this.toggleYourRankFunction}/> | ||
</Suspense> | ||
)} | ||
</RankContainer> | ||
); | ||
} | ||
} | ||
|
||
YourRankOutOf.propTypes = { | ||
rankOfVoter: PropTypes.number.isRequired, | ||
participantsCount: PropTypes.number.isRequired, | ||
}; | ||
|
||
// Styles | ||
const RankContainer = styled.div` | ||
font-size: 16px; | ||
color: ${DesignTokenColors.neutral900}; /* Default color */ | ||
`; | ||
|
||
const RankText = styled.span` | ||
font-weight: bold; | ||
color: ${DesignTokenColors.neutral900}; /* Color for "You're" */ | ||
`; | ||
|
||
const RankNumber = styled.span` | ||
font-weight: bold; | ||
color: ${DesignTokenColors.accent500}; /* Accent color for the rank number */ | ||
`; | ||
|
||
const RankDetails = styled.span` | ||
color: ${DesignTokenColors.neutral600}; /* Subdued color for "(of 6441)" */ | ||
`; | ||
|
||
export default YourRankOutOf; |
Oops, something went wrong.