UNPKG

react-cm-ui

Version:
603 lines (567 loc) 18 kB
import { find, isEmpty, isNil, trimStart, includes, } from 'lodash'; import ClassNames from 'classnames'; import moment from 'moment-timezone'; import PropTypes from 'prop-types'; import React, { useEffect, useState } from 'react'; import { BEM_BLOCK_NAME, GENDER_PROP_TYPE, RECORD_TYPE_COLOR, RECORD_TYPE_PROP_TYPE, } from './personPanelConstants'; import KeyCode from '../../global/keyCode'; import { UI_CLASS_NAME } from '../../global/constants'; import Grid from '../../layout/grid/index'; import Image from '../image/index'; import makeStyles from '../../styles/makeStyles'; import PersonContactInfo from '../personContactInfo/personContactInfo'; import Typography from '../typography/typography'; const propTypes = { /** * Override or extend the styles applied to PersonPanelSummary. */ classes: PropTypes.shape({ root: PropTypes.string, avatar: PropTypes.string, avatarColumn: PropTypes.string, contactInfoColumn: PropTypes.string, expanded: PropTypes.string, grid: PropTypes.string, gridRow: PropTypes.string, metaInfo: PropTypes.string, nameColumn: PropTypes.string, personIdColumn: PropTypes.string, personId: PropTypes.string, }), /** * Assign additional class names to PersonPanelSummary. */ className: PropTypes.string, /** * The data that the PersonPanelSummary uses to build the UI. */ data: PropTypes.shape({ avatar: PropTypes.string, birthdate: PropTypes.number, campus: PropTypes.string, emails: PropTypes.arrayOf( PropTypes.shape({ value: PropTypes.string, isPrimary: PropTypes.bool, }), ), emergencyContactEmail: PropTypes.string, emergencyContactPhone: PropTypes.string, emergencyContactPreferredMethod: PropTypes.string, emergencyContactRelationshipName: PropTypes.string, firstName: PropTypes.string, gender: GENDER_PROP_TYPE, gradeLevel: PropTypes.oneOf([ 'none', 'preK', 'kindergarten', 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth', null, ]), isDoNotContact: PropTypes.bool, isDoNotEmail: PropTypes.bool, isDoNotMail: PropTypes.bool, isDoNotPhone: PropTypes.bool, isDoNotText: PropTypes.bool, lastName: PropTypes.string, maritalStatus: PropTypes.string, nickName: PropTypes.string, personId: PropTypes.number, phones: PropTypes.arrayOf( PropTypes.shape({ value: PropTypes.string, isPrimary: PropTypes.bool, }), ), preferredMethod: PropTypes.string, prefix: PropTypes.string, recordType: RECORD_TYPE_PROP_TYPE, suffix: PropTypes.string, }), /** * The `id` of the PersonPanelSummary. */ id: PropTypes.string, /** * If `true`, expand PersonPanelSummary, otherwise collapse it. */ isExpanded: PropTypes.bool, /** * Event handler when clicking on the PersonPanelSummary container. */ onClick: PropTypes.func, /** * Indicates whether or not the PersonPanelSummary can be focused. */ tabIndex: PropTypes.number, }; const defaultProps = { classes: null, className: null, data: {}, id: null, isExpanded: false, onClick: () => {}, tabIndex: -1, }; const ageText = ({ birthdate }) => { if (!isEmpty(birthdate)) { return ''; } return `${moment().diff(moment.unix(birthdate).utc(), 'years')}yr`; }; const birthdateText = ({ birthdate }) => { if (!isEmpty(birthdate)) { return ''; } return moment.unix(birthdate).utc().format('MM/DD/YY'); }; const genderText = ({ gender }) => { switch (gender) { case 'f': case 'F': return 'Female'; case 'm': case 'M': return 'Male'; default: return ''; } }; const gradeLevelText = ({ gradeLevel }) => { switch (gradeLevel) { case 'PreK': return 'PK'; case 'Kindergarten': return 'K'; case 'First': return '1'; case 'Second': return '2'; case 'Third': return '3'; case 'Fourth': return '4'; case 'Fifth': return '5'; case 'Sixth': return '6'; case 'Seventh': return '7'; case 'Eighth': return '8'; case 'Ninth': return '9'; case 'Tenth': return '10'; case 'Eleventh': return '11'; case 'Twelfth': return '12'; default: return gradeLevel; } }; const BEM_CLASS_NAME = `${BEM_BLOCK_NAME}--summary`; const useStyles = makeStyles((theme) => { const { palette, shape: { borderRadius, }, } = theme; const transitionDuration = '200ms'; const colorTransition = `color ${transitionDuration} ease-out`; return { root: { alignItems: 'center', backgroundColor: palette.background.light, borderRadius: borderRadius, color: palette.text.primary, cursor: 'pointer', display: 'flex', flexGrow: 1, minHeight: 70, outline: 'none', position: 'relative', transition: colorTransition, userSelect: 'none', width: '100%', '&::before, &::after': { bottom: 0, content: '""', left: 0, position: 'absolute', top: 0, transition: `opacity ${transitionDuration} ease-in-out`, zIndex: 1, }, '&::before': { borderRadius: `${borderRadius}px 0 0 ${borderRadius}px`, opacity: 1, width: '5px', transition: `width ${transitionDuration} ease-in-out`, }, [`& a.${UI_CLASS_NAME}`]: { transition: colorTransition, }, '&$isAdult': { '&$genderFemale::before': { backgroundColor: `${RECORD_TYPE_COLOR({ gender: 'f', recordType: 'adult', theme })} !important`, }, '&$genderMale::before': { backgroundColor: `${RECORD_TYPE_COLOR({ gender: 'm', recordType: 'adult', theme })} !important`, }, '&$genderUndefined::before': { backgroundColor: `${RECORD_TYPE_COLOR({ recordType: 'adult', theme })} !important`, }, }, '&$isChild::before': { backgroundColor: `${RECORD_TYPE_COLOR({ recordType: 'child', theme })} !important`, }, '&$isStudent::before': { backgroundColor: `${RECORD_TYPE_COLOR({ recordType: 'student', theme })} !important`, }, '&$isExpanded': { color: palette.text.contrastText, borderRadius: `${borderRadius}px ${borderRadius}px 0 0`, '&::before': { borderRadius: `${borderRadius}px ${borderRadius}px 0 0`, width: '100%', }, [`& a.${UI_CLASS_NAME}, h5`]: { color: palette.text.contrastText, }, '&$isAdult': { '&$genderFemale::before': { backgroundImage: `${RECORD_TYPE_COLOR({ gender: 'f', isGradient: true, recordType: 'adult', theme, })} !important`, }, '&$genderMale::before': { backgroundImage: `${RECORD_TYPE_COLOR({ gender: 'm', isGradient: true, recordType: 'adult', theme, })} !important`, }, '&$genderUndefined::before': { backgroundImage: `${RECORD_TYPE_COLOR({ isGradient: true, recordType: 'adult', theme })} !important`, }, }, '&$isChild::before': { backgroundImage: `${RECORD_TYPE_COLOR({ isGradient: true, recordType: 'child', theme })} !important`, }, '&$isStudent::before': { backgroundImage: `${RECORD_TYPE_COLOR({ isGradient: true, recordType: 'student', theme })} !important`, }, }, }, avatar: { boxShadow: `inset 0 0 0 1px ${palette.border.primary} !important`, }, avatarColumn: { maxWidth: 55, minWidth: 55, padding: [[theme.spacing(1), 0, theme.spacing(1), theme.spacing(1)]], width: 'auto !important', }, contactInfoColumn: { display: 'none', padding: theme.spacing(1), textAlign: 'right', width: 'auto !important', '&$hasContactInfo': { marginLeft: 'auto', }, [theme.breakpoints.up(900)]: { display: 'block', }, }, isExpanded: {}, hasContactInfo: {}, grid: { position: 'relative', zIndex: 2, }, gridRow: { alignItems: 'center !important', flexWrap: 'nowrap !important', margin: '-11px 0 !important', }, metaInfo: {}, nameColumn: { marginRight: 'auto', padding: theme.spacing(1), width: 'auto !important', }, noContactInfo: {}, personIdColumn: { padding: theme.spacing(1), textAlign: 'right', width: 'auto !important', '&$noContactInfo': { marginLeft: 'auto', }, }, personId: { color: (props) => ( props.isExpanded ? palette.text.contrastText : palette.text.secondary ), transitionDelay: (props) => ( props.isExpanded ? '100ms' : null ), }, genderFemale: {}, genderMale: {}, genderUndefined: {}, isAdult: {}, isChild: {}, isStudent: {}, }; }); function PersonPanelSummary(props) { const { className, data, id, isExpanded, onClick: onClickProp, tabIndex, } = props; const classes = useStyles(props); const [metaInfoText, setMetaInfoText] = useState(''); const [renderContactInfo, setRenderContactInfo] = useState(null); const { avatar, birthdate, campus, emails, emergencyContactEmail, emergencyContactPhone, emergencyContactPreferredMethod, emergencyContactRelationshipName, firstName, gender, gradeLevel, isDoNotContact, isDoNotEmail, isDoNotMail, isDoNotPhone, isDoNotText, lastName, maritalStatus, nickName, personId, phones, prefix, preferredMethod, recordType, suffix, } = data; const primaryPhone = find(phones, 'isPrimary'); const primaryEmail = find(emails, 'isPrimary'); const phone = (primaryPhone && primaryPhone.value) || 'N/A'; const email = (primaryEmail && primaryEmail.value) || 'N/A'; const isAdult = isNil(recordType) || recordType === 'adult'; const isChild = recordType === 'child'; const isStudent = recordType === 'student'; useEffect(() => { let text = ''; if (gender) { text += genderText({ gender }); } if (isAdult && maritalStatus) { text += ` | ${maritalStatus}`; } if ((isChild || isStudent) && birthdate) { text += ` | ${ageText({ birthdate })} ${birthdateText({ birthdate })}`; } if ((isChild || isStudent) && gradeLevel) { text += ` | gr ${gradeLevelText({ gradeLevel })}`; } if (campus) { text += ` | ${campus}`; } text = trimStart(text, '| '); setMetaInfoText(text); // eslint-disable-next-line react-hooks/exhaustive-deps }, [ birthdate, campus, gender, gradeLevel, maritalStatus, recordType, ]); useEffect(() => { setRenderContactInfo( <PersonContactInfo emergencyContactEmail={emergencyContactEmail} emergencyContactPhone={emergencyContactPhone} emergencyContactPreferredMethod={emergencyContactPreferredMethod} emergencyContactRelationshipName={emergencyContactRelationshipName} isDoNotContact={isDoNotContact} isDoNotEmail={isDoNotEmail} isDoNotMail={isDoNotMail} isDoNotPhone={isDoNotPhone} isDoNotText={isDoNotText} isExpanded={isExpanded} preferredMethod={preferredMethod} email={email} phone={phone} recordType={recordType} />, ); }, [ email, emergencyContactEmail, emergencyContactPhone, emergencyContactPreferredMethod, emergencyContactRelationshipName, isDoNotContact, isDoNotEmail, isDoNotMail, isDoNotPhone, isDoNotText, isExpanded, phone, preferredMethod, recordType, ]); const onClick = (event) => { onClickProp(event); }; const onKeyDown = (event) => { if (event.keyCode === KeyCode.Enter) { onClickProp(event); } }; const rootClasses = ClassNames( classes.root, UI_CLASS_NAME, [`${BEM_CLASS_NAME}`], className, { [classes.isExpanded]: isExpanded, [classes.genderFemale]: includes(['f', 'F'], gender), [classes.genderMale]: includes(['m', 'M'], gender), [classes.genderUndefined]: !includes(['f', 'F', 'm', 'M'], gender), [classes.isAdult]: isAdult, [classes.isChild]: isChild, [classes.isStudent]: isStudent, }, ); const metaInfoClasses = ClassNames(classes.metaInfo); const contactInfoColumnClasses = ClassNames( classes.contactInfoColumn, { [classes.hasContactInfo]: !!renderContactInfo, }, ); const personIdColumnClasses = ClassNames( classes.personIdColumn, { [classes.noContactInfo]: !renderContactInfo, }, ); return ( <div className={rootClasses} id={id} onClick={onClick} onKeyDown={onKeyDown} tabIndex={tabIndex} role="button" > <Grid alignItems="center" className={classes.grid} spacing={0} wrap="nowrap" > <Grid.Column className={classes.avatarColumn} > <Image className={classes.avatar} name={firstName && lastName ? `${firstName} ${lastName}` : null} size={44} src={avatar} type="person" /> </Grid.Column> <Grid.Column className={classes.nameColumn} > <Typography variant="h4" > {`${prefix || ''} ${firstName} ${(nickName && `(${nickName})`) || ''} ${lastName} ${suffix || ''}`} </Typography> <Typography className={metaInfoClasses} color={isExpanded ? 'inherit' : 'textSecondary'} variant="caption" > {metaInfoText} </Typography> </Grid.Column> {renderContactInfo && ( <Grid.Column className={contactInfoColumnClasses} textAlign="right" > {renderContactInfo} </Grid.Column> )} {personId && ( <Grid.Column className={personIdColumnClasses} textAlign="right" > <Typography className={classes.personId} variant="caption" > {`Id: ${personId}`} </Typography> </Grid.Column> )} </Grid> </div> ); } PersonPanelSummary.propTypes = propTypes; PersonPanelSummary.defaultProps = defaultProps; export default PersonPanelSummary;