diff --git a/src/js/common/components/Campaign/CampaignCommentForList.jsx b/src/js/common/components/Campaign/CampaignCommentForList.jsx index b03b5b2e5..da354d850 100644 --- a/src/js/common/components/Campaign/CampaignCommentForList.jsx +++ b/src/js/common/components/Campaign/CampaignCommentForList.jsx @@ -1,4 +1,4 @@ -import { AccountCircle } from '@mui/icons-material'; +import { Avatar } from '@mui/material'; import withStyles from '@mui/styles/withStyles'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; @@ -20,6 +20,7 @@ import stringContains from '../../utils/stringContains'; import CampaignStore from '../../stores/CampaignStore'; import CampaignSupporterStore from '../../stores/CampaignSupporterStore'; import VoterStore from '../../../stores/VoterStore'; +import speakerDisplayNameToInitials from '../../utils/speakerDisplayNameToInitials'; class CampaignCommentForList extends Component { constructor (props) { @@ -94,7 +95,6 @@ class CampaignCommentForList extends Component { if (isCordova()) { console.log(`CampaignCommentForList window.location.href: ${window.location.href}`); } - const { classes } = this.props; const { campaignXSupporter, pathToUseToEditSupporterEndorsement, showFullSupporterEndorsement, voterWeVoteId } = this.state; if (!campaignXSupporter || !('id' in campaignXSupporter)) { return null; @@ -107,6 +107,7 @@ class CampaignCommentForList extends Component { voter_we_vote_id: supporterVoterWeVoteId, we_vote_hosted_profile_image_url_tiny: voterPhotoUrlTiny, } = campaignXSupporter; + const { sx, children } = speakerDisplayNameToInitials(supporterName); // console.log('supporterVoterWeVoteId:', supporterVoterWeVoteId); return ( @@ -124,7 +125,7 @@ class CampaignCommentForList extends Component { alt="Your Settings" /> ) : ( - + {children} )} diff --git a/src/js/common/components/Campaign/CampaignNewsItemForList.jsx b/src/js/common/components/Campaign/CampaignNewsItemForList.jsx index 8f552ba3d..57d212655 100644 --- a/src/js/common/components/Campaign/CampaignNewsItemForList.jsx +++ b/src/js/common/components/Campaign/CampaignNewsItemForList.jsx @@ -1,9 +1,9 @@ -import { AccountCircle } from '@mui/icons-material'; import styled from 'styled-components'; import withStyles from '@mui/styles/withStyles'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import TruncateMarkup from 'react-truncate-markup'; +import { Avatar } from '@mui/material'; import { avatarGeneric } from '../../../utils/applicationUtils'; import LazyImage from '../LazyImage'; import { timeFromDate } from '../../utils/dateFormat'; @@ -13,6 +13,7 @@ import stringContains from '../../utils/stringContains'; import CampaignStore from '../../stores/CampaignStore'; import { ReadMoreSpan, SpeakerAndPhotoOuterWrapper, SpeakerName, SpeakerVoterPhotoWrapper } from '../Style/CampaignDetailsStyles'; import { BlockedIndicator, DraftModeIndicator, EditIndicator, IndicatorButtonWrapper, IndicatorDefaultButtonWrapper, IndicatorRow } from '../Style/CampaignIndicatorStyles'; +import speakerDisplayNameToInitials from '../../utils/speakerDisplayNameToInitials'; class CampaignNewsItemForList extends Component { constructor (props) { @@ -124,7 +125,7 @@ class CampaignNewsItemForList extends Component { render () { renderLog('CampaignNewsItemForList'); // Set LOG_RENDER_EVENTS to log all renders - const { campaignXNewsItemWeVoteId, classes } = this.props; + const { campaignXNewsItemWeVoteId } = this.props; const { campaignNewsSubject, campaignNewsText, @@ -135,6 +136,7 @@ class CampaignNewsItemForList extends Component { speakerProfileImageUrlTiny, voterCanEditThisCampaign, } = this.state; + const { sx, children } = speakerDisplayNameToInitials(speakerName); if (!campaignNewsSubject && !campaignNewsText) { return null; } @@ -182,7 +184,7 @@ class CampaignNewsItemForList extends Component { alt="Your Settings" /> ) : ( - + {children} )} diff --git a/src/js/common/components/CampaignSupport/MostRecentCampaignSupport.jsx b/src/js/common/components/CampaignSupport/MostRecentCampaignSupport.jsx index d7bd617d8..4d011fb43 100644 --- a/src/js/common/components/CampaignSupport/MostRecentCampaignSupport.jsx +++ b/src/js/common/components/CampaignSupport/MostRecentCampaignSupport.jsx @@ -1,9 +1,9 @@ -import { AccountCircle } from '@mui/icons-material'; import withStyles from '@mui/styles/withStyles'; import PropTypes from 'prop-types'; import React, { createRef } from 'react'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; +import { Avatar } from '@mui/material'; import { avatarGeneric } from '../../../utils/applicationUtils'; import LazyImage from '../LazyImage'; import { @@ -18,6 +18,8 @@ import stringContains from '../../utils/stringContains'; import CampaignStore from '../../stores/CampaignStore'; import CampaignSupporterStore from '../../stores/CampaignSupporterStore'; import VoterStore from '../../../stores/VoterStore'; +import speakerDisplayNameToInitials from '../../utils/speakerDisplayNameToInitials'; +import speakerDisplayNameToAvatarColor from '../../utils/speakerDisplayNameToAvatarColor'; class MostRecentCampaignSupport extends React.Component { constructor (props) { @@ -255,7 +257,6 @@ class MostRecentCampaignSupport extends React.Component { render () { renderLog('MostRecentCampaignSupport'); // Set LOG_RENDER_EVENTS to log all renders - const { classes } = this.props; const { supportersOnStageNow, voterWeVoteId } = this.state; // console.log('MostRecentCampaignSupport render voterWeVoteId: ', voterWeVoteId, ', supportersOnStageNow:', supportersOnStageNow); @@ -267,7 +268,7 @@ class MostRecentCampaignSupport extends React.Component { ref={this.commentsWrapperDiv} onScroll={() => this.handleScroll()} > - {supportersOnStageNow.map((comment) => ( + {supportersOnStageNow.map((comment) => ( {comment.we_vote_hosted_profile_image_url_medium ? ( @@ -280,7 +281,9 @@ class MostRecentCampaignSupport extends React.Component { alt="Your Settings" /> ) : ( - + + {speakerDisplayNameToInitials(comment.supporter_name)} + )} diff --git a/src/js/common/components/Politician/PoliticianEndorsementForList.jsx b/src/js/common/components/Politician/PoliticianEndorsementForList.jsx index 61f247395..a9acc9fde 100644 --- a/src/js/common/components/Politician/PoliticianEndorsementForList.jsx +++ b/src/js/common/components/Politician/PoliticianEndorsementForList.jsx @@ -1,10 +1,10 @@ -import { AccountCircle } from '@mui/icons-material'; import withStyles from '@mui/styles/withStyles'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { Link } from 'react-router-dom'; import TruncateMarkup from 'react-truncate-markup'; import styled from 'styled-components'; +import { Avatar } from '@mui/material'; import { avatarGeneric } from '../../../utils/applicationUtils'; import LazyImage from '../LazyImage'; import { @@ -20,6 +20,8 @@ import { renderLog } from '../../utils/logging'; import stringContains from '../../utils/stringContains'; import PoliticianStore from '../../stores/PoliticianStore'; import VoterStore from '../../../stores/VoterStore'; +import speakerDisplayNameToInitials from '../../utils/speakerDisplayNameToInitials'; + class PoliticianEndorsementForList extends Component { constructor (props) { @@ -78,7 +80,7 @@ class PoliticianEndorsementForList extends Component { if (isCordova()) { console.log(`PoliticianEndorsementForList window.location.href: ${window.location.href}`); } - const { classes, position } = this.props; + const { position } = this.props; const { pathToUseToEditSupporterEndorsement, showFullSupporterEndorsement, todayAsInteger, voterWeVoteId } = this.state; if (!position || !('position_we_vote_id' in position)) { return null; @@ -95,6 +97,7 @@ class PoliticianEndorsementForList extends Component { speaker_image_url_https_medium: speakerImageMedium, twitter_followers_count: twitterFollowersCount, } = position; + const { sx, children } = speakerDisplayNameToInitials(speakerDisplayName); let howLongAgoOrThisYear = ''; const currentYear = new Date().getFullYear(); // console.log('currentYear', currentYear, ', positionYear', positionYear); @@ -124,7 +127,7 @@ class PoliticianEndorsementForList extends Component { alt="" /> ) : ( - + {children} )} diff --git a/src/js/common/components/Style/DesignTokenColors.js b/src/js/common/components/Style/DesignTokenColors.js index 1cecf7ed0..10aa15767 100644 --- a/src/js/common/components/Style/DesignTokenColors.js +++ b/src/js/common/components/Style/DesignTokenColors.js @@ -19,7 +19,6 @@ const primitiveColorNames = { blueUI700: '#1073D4', blueUI800: '#0E62C2', blueUI900: '#0943A3', - gray50: '#F2F2F0', gray100: '#D2D2D2', gray200: '#B7B7B7', @@ -40,7 +39,6 @@ const primitiveColorNames = { grayUI700: '#575757', grayUI800: '#4A4A4A', grayUI900: '#3D3D3D', - greenUI50: '#E5F4E3', greenUI100: '#C1E4BB', greenUI200: '#9CD299', @@ -51,7 +49,6 @@ const primitiveColorNames = { greenUI700: '#008900', greenUI800: '#007800', greenUI900: '#005A00', - orange50: '#FCEFE4', orange100: '#FBC89C', orange200: '#FBA255', @@ -72,7 +69,6 @@ const primitiveColorNames = { orangeUI700: '#E4531B', orangeUI800: '#D74C19', orangeUI900: '#BE3E14', - redUI50: '#FFE8EB', redUI100: '#FEC8CC', redUI200: '#F4908E', @@ -93,7 +89,6 @@ const primitiveColorNames = { red700: '#8B1A32', red800: '#74162A', red900: '#53101E', - steel50: '#ECF2F7', steel100: '#C8D4DF', steel200: '#A7BACD', @@ -104,9 +99,7 @@ const primitiveColorNames = { steel700: '#2C4A66', steel800: '#1F3A53', steel900: '#142B41', - white: '#FFFFFF', - yellowUI50: '#FBF6DF', yellowUI100: '#FAE8AE', yellowUI200: '#F6DA79', @@ -119,6 +112,8 @@ const primitiveColorNames = { yellowUI900: '#9E7100', }; + + // These are semanticColorNames const DesignTokenColors = { accent50: primitiveColorNames.orange50, @@ -131,18 +126,27 @@ const DesignTokenColors = { accent700: primitiveColorNames.orange700, accent800: primitiveColorNames.orange800, accent900: primitiveColorNames.orange900, - alert50: primitiveColorNames.redUI50, alert100: primitiveColorNames.redUI100, alert200: primitiveColorNames.redUI200, alert300: primitiveColorNames.redUI300, alert400: primitiveColorNames.redUI400, alert500: primitiveColorNames.redUI500, + avatarBlue700: primitiveColorNames.blueUI700, + avatarBlue900: primitiveColorNames.blueUI900, + avatarBlue200: primitiveColorNames.blueUI200, + avatarGreen400: primitiveColorNames.greenUI400, + avatarGreen900: primitiveColorNames.greenUI900, + avatarOrange400: primitiveColorNames.orangeUI400, + avatarRed400: primitiveColorNames.redUI400, + avatarRed800: primitiveColorNames.redUI800, + avatarYellow700: primitiveColorNames.yellowUI700, + avatarYellow900: primitiveColorNames.yellowUI900, + avatargray600: primitiveColorNames.grayUI600, alert600: primitiveColorNames.redUI600, alert700: primitiveColorNames.redUI700, alert800: primitiveColorNames.redUI800, alert900: primitiveColorNames.redUI900, - caution50: primitiveColorNames.yellowUI50, caution100: primitiveColorNames.yellowUI100, caution200: primitiveColorNames.yellowUI200, @@ -153,7 +157,6 @@ const DesignTokenColors = { caution700: primitiveColorNames.yellowUI700, caution800: primitiveColorNames.yellowUI800, caution900: primitiveColorNames.yellowUI900, - confirmation50: primitiveColorNames.greenUI50, confirmation100: primitiveColorNames.greenUI100, confirmation200: primitiveColorNames.greenUI200, @@ -164,7 +167,6 @@ const DesignTokenColors = { confirmation700: primitiveColorNames.greenUI700, confirmation800: primitiveColorNames.greenUI800, confirmation900: primitiveColorNames.greenUI900, - info50: primitiveColorNames.blueUI50, info100: primitiveColorNames.blueUI100, info200: primitiveColorNames.blueUI200, @@ -175,7 +177,6 @@ const DesignTokenColors = { info700: primitiveColorNames.blueUI700, info800: primitiveColorNames.blueUI800, info900: primitiveColorNames.blueUI900, - neutral50: primitiveColorNames.gray50, neutral100: primitiveColorNames.gray100, neutral200: primitiveColorNames.gray200, @@ -186,7 +187,6 @@ const DesignTokenColors = { neutral700: primitiveColorNames.gray700, neutral800: primitiveColorNames.gray800, neutral900: primitiveColorNames.gray900, - neutralUI50: primitiveColorNames.grayUI50, neutralUI100: primitiveColorNames.grayUI100, neutralUI200: primitiveColorNames.grayUI200, @@ -197,7 +197,6 @@ const DesignTokenColors = { neutralUI700: primitiveColorNames.grayUI700, neutralUI800: primitiveColorNames.grayUI800, neutralUI900: primitiveColorNames.grayUI900, - primary50: primitiveColorNames.blue50, primary100: primitiveColorNames.blue100, primary200: primitiveColorNames.blue200, @@ -208,7 +207,6 @@ const DesignTokenColors = { primary700: primitiveColorNames.blue700, primary800: primitiveColorNames.blue800, primary900: primitiveColorNames.blue900, - secondary50: primitiveColorNames.steel50, secondary100: primitiveColorNames.steel100, secondary200: primitiveColorNames.steel200, @@ -219,7 +217,6 @@ const DesignTokenColors = { secondary700: primitiveColorNames.steel700, secondary800: primitiveColorNames.steel800, secondary900: primitiveColorNames.steel900, - tertiary50: primitiveColorNames.red50, tertiary100: primitiveColorNames.red100, tertiary200: primitiveColorNames.red200, @@ -230,7 +227,6 @@ const DesignTokenColors = { tertiary700: primitiveColorNames.red700, tertiary800: primitiveColorNames.red800, tertiary900: primitiveColorNames.red900, - warning50: primitiveColorNames.orangeUI50, warning100: primitiveColorNames.orangeUI100, warning200: primitiveColorNames.orangeUI200, @@ -241,7 +237,6 @@ const DesignTokenColors = { warning700: primitiveColorNames.orangeUI700, warning800: primitiveColorNames.orangeUI800, warning900: primitiveColorNames.orangeUI900, - whiteUI: primitiveColorNames.white, }; diff --git a/src/js/common/pages/Campaign/CampaignNewsItemDetailsPage.jsx b/src/js/common/pages/Campaign/CampaignNewsItemDetailsPage.jsx index 8642a68b5..6951d8904 100644 --- a/src/js/common/pages/Campaign/CampaignNewsItemDetailsPage.jsx +++ b/src/js/common/pages/Campaign/CampaignNewsItemDetailsPage.jsx @@ -1,5 +1,5 @@ -import { AccountCircle, ArrowBack } from '@mui/icons-material'; -import { Button } from '@mui/material'; +import { ArrowBack } from '@mui/icons-material'; +import { Avatar, Button } from '@mui/material'; import withStyles from '@mui/styles/withStyles'; import PropTypes from 'prop-types'; import React, { Component, Suspense } from 'react'; @@ -29,6 +29,7 @@ import keepHelpingDestination from '../../utils/keepHelpingDestination'; import { renderLog } from '../../utils/logging'; import returnFirstXWords from '../../utils/returnFirstXWords'; import stringContains from '../../utils/stringContains'; +import speakerDisplayNameToInitials from '../../utils/speakerDisplayNameToInitials'; const CampaignCommentsList = React.lazy(() => import(/* webpackChunkName: 'CampaignCommentsList' */ '../../components/Campaign/CampaignCommentsList')); const CampaignDetailsActionSideBox = React.lazy(() => import(/* webpackChunkName: 'CampaignDetailsActionSideBox' */ '../../components/CampaignSupport/CampaignDetailsActionSideBox')); @@ -318,6 +319,7 @@ class CampaignNewsItemDetailsPage extends Component { speakerName, speakerProfileImageUrlTiny, voterCanEditThisCampaign, weVoteHostedProfileImageUrlLarge, } = this.state; + const { sx, children } = speakerDisplayNameToInitials(speakerName); const htmlTitle = `${campaignTitle} - ${chosenWebsiteName}`; if (isBlockedByWeVote && !voterCanEditThisCampaign) { return ( @@ -372,7 +374,7 @@ class CampaignNewsItemDetailsPage extends Component { alt={speakerName} /> ) : ( - + {children} )} diff --git a/src/js/common/utils/speakerDisplayNameToAvatarColor.js b/src/js/common/utils/speakerDisplayNameToAvatarColor.js new file mode 100644 index 000000000..08a7cb83f --- /dev/null +++ b/src/js/common/utils/speakerDisplayNameToAvatarColor.js @@ -0,0 +1,22 @@ +import DesignTokenColors from '../components/Style/DesignTokenColors'; + +function speakerDisplayNameToAvatarColor (speakerDisplayName) { + let hashForRandomIndexValue = 0; + /* eslint-disable no-bitwise */ + for (let i = 0; i < speakerDisplayName.length; i += 1) { + hashForRandomIndexValue = + speakerDisplayName.charCodeAt(i) + + ((hashForRandomIndexValue << 5) - hashForRandomIndexValue); + } + const avatarColorKeys = Object.keys(DesignTokenColors).filter((key) => key.startsWith('avatar')); + /* eslint-enable no-bitwise */ + if (avatarColorKeys.length === 0) { + console.error('No avatar colors found in DesignTokenColors.'); + return DesignTokenColors.avatarBlue700; + } + const colorIndex = Math.abs(hashForRandomIndexValue) % avatarColorKeys.length; + const colorKey = avatarColorKeys[colorIndex]; + return DesignTokenColors[colorKey]; +} + +export default speakerDisplayNameToAvatarColor; diff --git a/src/js/common/utils/speakerDisplayNameToInitials.js b/src/js/common/utils/speakerDisplayNameToInitials.js new file mode 100644 index 000000000..2885e1790 --- /dev/null +++ b/src/js/common/utils/speakerDisplayNameToInitials.js @@ -0,0 +1,16 @@ +import speakerDisplayNameToAvatarColor from './speakerDisplayNameToAvatarColor'; + +function speakerDisplayNameToInitials (speakerDisplayName) { + const nameParts = speakerDisplayName.split(' '); + const initials = + nameParts.length > 1 ? + `${nameParts[0][0]}${nameParts[1][0]}` : + `${nameParts[0][0]}`; + return { + sx: { + bgcolor: speakerDisplayNameToAvatarColor(speakerDisplayName), + }, + children: initials, + }; +} +export default speakerDisplayNameToInitials; diff --git a/src/js/components/Activity/ActivityCommentAdd.jsx b/src/js/components/Activity/ActivityCommentAdd.jsx index aca62af4a..a07d2dac5 100644 --- a/src/js/components/Activity/ActivityCommentAdd.jsx +++ b/src/js/components/Activity/ActivityCommentAdd.jsx @@ -1,5 +1,5 @@ -import { AccountCircle, Send } from '@mui/icons-material'; -import { FormControl, IconButton, InputAdornment, TextField } from '@mui/material'; +import { Send } from '@mui/icons-material'; +import { Avatar, FormControl, IconButton, InputAdornment, TextField } from '@mui/material'; import withStyles from '@mui/styles/withStyles'; import withTheme from '@mui/styles/withTheme'; import PropTypes from 'prop-types'; @@ -11,6 +11,7 @@ import { renderLog } from '../../common/utils/logging'; import ActivityStore from '../../stores/ActivityStore'; import AppObservableStore from '../../common/stores/AppObservableStore'; import VoterStore from '../../stores/VoterStore'; +import speakerDisplayNameToInitials from '../../common/utils/speakerDisplayNameToInitials'; class ActivityCommentAdd extends Component { @@ -96,6 +97,7 @@ class ActivityCommentAdd extends Component { renderLog('ActivityCommentAdd'); // Set LOG_RENDER_EVENTS to log all renders const { activityCommentWeVoteId, activityTidbitWeVoteId, classes, hidePhotoFromTextField, inEditMode } = this.props; const { statementText, activityCommentCount, voterFullName, voterPhotoUrlTiny } = this.state; + const { sx, children } = speakerDisplayNameToInitials(voterFullName); if (!activityTidbitWeVoteId) { return null; } @@ -128,7 +130,7 @@ class ActivityCommentAdd extends Component { ) : ( - + {children} )} diff --git a/src/js/components/Activity/ActivityTidbitComments.jsx b/src/js/components/Activity/ActivityTidbitComments.jsx index 8c8a8982d..6b855b8eb 100644 --- a/src/js/components/Activity/ActivityTidbitComments.jsx +++ b/src/js/components/Activity/ActivityTidbitComments.jsx @@ -1,5 +1,5 @@ -import { AccountCircle, MoreHoriz } from '@mui/icons-material'; -import { IconButton } from '@mui/material'; +import { MoreHoriz } from '@mui/icons-material'; +import { Avatar, IconButton } from '@mui/material'; import styled from 'styled-components'; import withStyles from '@mui/styles/withStyles'; import withTheme from '@mui/styles/withTheme'; @@ -14,6 +14,8 @@ import ReactionStore from '../../stores/ReactionStore'; import VoterStore from '../../stores/VoterStore'; import ActivityCommentAdd from './ActivityCommentAdd'; import ChildCommentList from './ChildCommentList'; +import speakerDisplayNameToAvatarColor from '../../common/utils/speakerDisplayNameToAvatarColor'; +import speakerDisplayNameToInitials from '../../common/utils/speakerDisplayNameToInitials'; const STARTING_NUMBER_OF_PARENT_COMMENTS_TO_DISPLAY = 1; @@ -237,7 +239,9 @@ class ActivityTidbitComments extends Component { ) : ( - + + {speakerDisplayNameToInitials(parentComment.commenter_name)} + )} diff --git a/src/js/components/Activity/ChildCommentList.jsx b/src/js/components/Activity/ChildCommentList.jsx index 5900864ad..31f1e7f3a 100644 --- a/src/js/components/Activity/ChildCommentList.jsx +++ b/src/js/components/Activity/ChildCommentList.jsx @@ -1,5 +1,5 @@ -import { AccountCircle, MoreHoriz } from '@mui/icons-material'; -import { IconButton } from '@mui/material'; +import { MoreHoriz } from '@mui/icons-material'; +import { Avatar, IconButton } from '@mui/material'; import styled from 'styled-components'; import withStyles from '@mui/styles/withStyles'; import withTheme from '@mui/styles/withTheme'; @@ -13,6 +13,8 @@ import AppObservableStore from '../../common/stores/AppObservableStore'; import ReactionStore from '../../stores/ReactionStore'; import VoterStore from '../../stores/VoterStore'; import ActivityCommentAdd from './ActivityCommentAdd'; +import speakerDisplayNameToAvatarColor from '../../common/utils/speakerDisplayNameToAvatarColor'; +import speakerDisplayNameToInitials from '../../common/utils/speakerDisplayNameToInitials'; const STARTING_NUMBER_OF_PARENT_COMMENTS_TO_DISPLAY = 1; @@ -210,7 +212,9 @@ class ChildCommentList extends Component { ) : ( - + + {speakerDisplayNameToInitials(childComment.commenter_name)} + )}