Skip to content

Commit

Permalink
Merge pull request #323 from hackforla/client/schedule-info
Browse files Browse the repository at this point in the history
Client/schedule info
  • Loading branch information
jmensch1 committed Dec 17, 2020
2 parents af4f12c + 34bd880 commit 437ae79
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 49 deletions.
2 changes: 1 addition & 1 deletion client/web/src/assets/icons/new-window.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
alignItems: 'center',
marginBottom: 12,
marginBottom: 8,
},
iconCell: {
width: 50,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import React from 'react'
import PropTypes from 'prop-types'
import { makeStyles, useTheme } from '@material-ui/core/styles'
import LocationIcon from 'components/shared/LocationIcon'
import { ReactComponent as WheelchairIcon } from 'assets/icons/wheelchair.svg'
// import { ReactComponent as WheelchairIcon } from 'assets/icons/wheelchair.svg'

const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
alignItems: 'center',
marginBottom: 12,
marginBottom: 4,
},
iconCell: {
width: 50,
Expand Down Expand Up @@ -52,11 +52,11 @@ const LocationName = ({ location, isSelected }) => {
</div>
<div className={classes.textCell}>
<div className={classes.locationName}>{location.name}</div>
<div className={classes.dropOff}>Drop off (outside)</div>
{/*<div className={classes.dropOff}>Drop off (outside)</div>*/}
</div>
{location.isHandicapAccessible === 'Y' && (
{/*{location.isHandicapAccessible === 'Y' && (
<WheelchairIcon className={classes.wheelchair} />
)}
)}*/}
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { useState, useEffect, useMemo, useCallback } from 'react'
import PropTypes from 'prop-types'
import { makeStyles } from '@material-ui/core/styles'
import Collapse from '@material-ui/core/Collapse'
import moment from 'moment'

const useStyles = makeStyles((theme) => ({
today: {
'& b': {
display: 'inline-block',
marginRight: 14,
fontWeight: 400,
},
},
table: {
marginTop: 10,
'& td, th': {
padding: '2px 0',
},
},
toggle: {
color: theme.palette.primary.main,
textDecoration: 'underline',
userSelect: 'none',
cursor: 'pointer',
display: 'inline-block',
marginLeft: 16,
},
}))

function formatTime(time) {
let [hours, minutes] = time.split(':')
hours = +hours
const isPm = hours >= 12
hours = (hours > 12 ? hours - 12 : hours).toString()
hours = hours.replace(/^0/, '')
return `${hours}:${minutes}${isPm ? 'p' : 'a'}`
}

const Hours = ({ location, expandable }) => {
const classes = useStyles()
const [showDetails, setShowDetails] = useState(false)

useEffect(() => {
setShowDetails(false)
}, [location])

const toggle = useCallback(() => {
setShowDetails(!showDetails)
}, [showDetails])

const hours = useMemo(() => {
return location.hours
.map((hour) => ({
beginDate: moment(hour.beginDate),
endDate: moment(hour.endDate),
openTime: formatTime(hour.openTime),
closeTime: formatTime(hour.closeTime),
}))
.sort((a, b) => (b.beginDate.isBefore(a.beginDate) ? 1 : -1))
}, [location])

const today = useMemo(() => {
const now = moment()
return hours.find(
(hour) =>
hour.beginDate.isSameOrBefore(now) && hour.endDate.isSameOrAfter(now)
)
}, [hours])

return (
<>
<div className={classes.today}>
{today ? (
<span>
<b>Open Today</b>
{today.openTime} - {today.closeTime}
</span>
) : (
<span>Closed Today</span>
)}
{expandable && (
<span className={classes.toggle} onClick={toggle}>
{showDetails ? 'less' : 'more'}
</span>
)}
</div>
<Collapse in={showDetails} timeout="auto" unmountOnExit>
<table className={classes.table}>
<thead>
<tr>
<th>Date(s)</th>
<th style={{ paddingLeft: 30 }}>Hours</th>
</tr>
</thead>
<tbody>
{hours.map((hour) => {
const dateString = hour.beginDate.isSame(hour.endDate)
? hour.beginDate.format('M/DD')
: `${hour.beginDate.format('M/DD')} - ${hour.endDate.format(
'M/DD'
)}`
return (
<tr>
<td>{dateString}</td>
<td style={{ paddingLeft: 30 }}>
{hour.openTime} - {hour.closeTime}
</td>
</tr>
)
})}
</tbody>
</table>
</Collapse>
</>
)
}

export default Hours

Hours.propTypes = {
location: PropTypes.shape({}).isRequired,
expandable: PropTypes.bool,
}

Hours.defaultProps = {
expandable: false,
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { useState, useEffect, useCallback } from 'react'
import React from 'react'
import PropTypes from 'prop-types'
import { makeStyles } from '@material-ui/core/styles'
import { ReactComponent as ClockIcon } from 'assets/icons/clock.svg'
import Collapse from '@material-ui/core/Collapse'
import Hours from './Hours'
import moment from 'moment'

const useStyles = makeStyles((theme) => ({
root: {},
root: {
marginBottom: 8,
},
summary: {
display: 'flex',
alignItems: 'center',
alignItems: 'flex-start',
},
iconCell: {
width: 50,
Expand All @@ -17,7 +20,11 @@ const useStyles = makeStyles((theme) => ({
alignItems: 'center',
justifyContent: 'center',
},
textCell: {},
textCell: {
paddingTop: 1,
fontSize: 16,
fontWeight: 400,
},
openStatus: {
color: '#63A375',
fontWeight: 600,
Expand Down Expand Up @@ -49,55 +56,58 @@ const useStyles = makeStyles((theme) => ({
marginLeft: 50,
marginTop: 10,
},
info: {},
}))

const LocationHours = ({ location, expandable }) => {
const classes = useStyles()
const [expanded, setExpanded] = useState(false)
const Continuous = ({ location }) => {
const startDate = moment(location.continuousOpenDate)
const now = moment()

const toggleDetails = useCallback(() => {
setExpanded(!expanded)
}, [expanded])
const startText = startDate.isSameOrAfter(now)
? ` starting ${startDate.format('MM/D/YY')}`
: ''

useEffect(() => {
setExpanded(false)
}, [location])
return <span>Open 24/7{startText}</span>
}

const Description = ({ location }) => {
return <span>{location.scheduleDescription}</span>
}

const LocationSchedule = ({ location, expandable }) => {
const classes = useStyles()
return (
<div className={classes.root}>
<div className={classes.summary}>
<div className={classes.iconCell}>
<ClockIcon />
</div>
<div className={classes.textCell}>
<span className={classes.openStatus}>Open now</span>
<span className={classes.openUntil}>until 9pm</span>
<span className={classes.timezone}>(PDT)</span>
{expandable && (
<span className={classes.toggle} onClick={toggleDetails}>
{expanded ? 'Less' : 'More'}
</span>
)}
{(() => {
switch (location.scheduleType) {
case 'continuous':
return <Continuous location={location} />
case 'description':
return <Description location={location} />
case 'hours':
return <Hours location={location} expandable={expandable} />
default:
return <span>Unknown</span>
}
})()}
</div>
</div>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<div className={classes.details}>
{Array.from({ length: 10 }).map((el, idx) => (
<div key={idx.toString()}>time (to do)</div>
))}
</div>
</Collapse>
</div>
)
}

export default LocationHours
export default LocationSchedule

LocationHours.propTypes = {
LocationSchedule.propTypes = {
location: PropTypes.shape({}).isRequired,
expandable: PropTypes.bool,
}

LocationHours.defaultProps = {
LocationSchedule.defaultProps = {
expandable: false,
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import React from 'react'
import PropTypes from 'prop-types'
import LocationName from './LocationName'
import LocationAddress from './LocationAddress'
import LocationHours from './LocationHours'
import LocationSchedule from './LocationSchedule'

const LocationCard = ({ location, isSelected, hoursExpandable }) => {
return (
<div style={{ marginLeft: -10 }}>
<LocationName location={location} isSelected={isSelected} />
<LocationAddress location={location} />
<LocationHours location={location} expandable={hoursExpandable} />
<LocationSchedule location={location} expandable={hoursExpandable} />
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react'
import PropTypes from 'prop-types'
import { makeStyles } from '@material-ui/core/styles'
import InfoIcon from '@material-ui/icons/Info'

const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
alignItems: 'center',
marginBottom: 12,
marginLeft: -10,
},
iconCell: {
width: 50,
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
textCell: {
flex: 1,
fontWeight: 400,
fontStyle: 'italic',
},
}))

const DisplayNote = ({ location }) => {
const classes = useStyles()

if (!location.displayNote) return null
return (
<div className={classes.root}>
<div className={classes.iconCell}>
<InfoIcon color="primary" />
</div>
<div className={classes.textCell}>{location.displayNote}</div>
</div>
)
}

export default DisplayNote

DisplayNote.propTypes = {
location: PropTypes.shape({}).isRequired,
showDistanceDetails: PropTypes.bool,
}

DisplayNote.defaultProps = {
showDistanceDetails: false,
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ const VerifyBox = ({ location, jurisdiction }) => {
if (!jurisdiction) return null
const { phones, urls } = jurisdiction

// TODO: use type names instead of type ids
const phone = phones.find((ph) => ph.phoneNumberTypeId === 1)?.phoneNumber
const url = urls.find((url) => url.urlTypeId === 10)?.url
const nonEmailUrls = urls.filter((url) => !url.urlType.isEmail)

if (!phone && !url) return null
if (!phone && nonEmailUrls.length === 0) return null
return (
<div className={classes.root}>
<div className={classes.title}>To Verify</div>
Expand All @@ -57,12 +56,14 @@ const VerifyBox = ({ location, jurisdiction }) => {
<a href={`tel:${phone}`}>{phone}</a>
</div>
)}
{url && (
{nonEmailUrls.map(({ url, name }) => (
<div className={classes.infoItem}>
<NewWindowIcon />
<a href={url}>{url}</a>
<a target="_blank" rel="noreferrer" href={url}>
{name}
</a>
</div>
)}
))}
</div>
</div>
)
Expand Down
Loading

0 comments on commit 437ae79

Please sign in to comment.