Client: display activity date with user timezone - #11

This commit is contained in:
Sam 2018-06-11 15:24:34 +02:00
parent fe91040370
commit 31d23da473
11 changed files with 69 additions and 30 deletions

View File

@ -2,8 +2,10 @@ import { format } from 'date-fns'
import React from 'react' import React from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { getDateWithTZ } from '../../utils'
export default function ActivitiesList (props) { export default function ActivitiesList (props) {
const { activities, sports } = props const { activities, sports, user } = props
return ( return (
<div className="card"> <div className="card">
<div className="card-body"> <div className="card-body">
@ -36,7 +38,12 @@ export default function ActivitiesList (props) {
{activity.title} {activity.title}
</Link> </Link>
</td> </td>
<td>{format(activity.activity_date, 'DD/MM/YYYY HH:mm')}</td> <td>
{format(
getDateWithTZ(activity.activity_date, user.timezone),
'DD/MM/YYYY HH:mm'
)}
</td>
<td className="text-right"> <td className="text-right">
{Number(activity.distance).toFixed(2)} km {Number(activity.distance).toFixed(2)} km
</td> </td>

View File

@ -36,7 +36,7 @@ class Activities extends React.Component {
} }
render() { render() {
const { const {
activities, loadActivities, loadMoreActivities, message, sports activities, loadActivities, loadMoreActivities, message, sports, user
} = this.props } = this.props
const { params } = this.state const { params } = this.state
const paginationEnd = activities.length > 0 const paginationEnd = activities.length > 0
@ -63,6 +63,7 @@ class Activities extends React.Component {
<ActivitiesList <ActivitiesList
activities={activities} activities={activities}
sports={sports} sports={sports}
user={user}
/> />
{!paginationEnd && {!paginationEnd &&
<input <input
@ -100,6 +101,7 @@ export default connect(
activities: state.activities.data, activities: state.activities.data,
message: state.message, message: state.message,
sports: state.sports.data, sports: state.sports.data,
user: state.user,
}), }),
dispatch => ({ dispatch => ({
loadActivities: params => { loadActivities: params => {

View File

@ -1,13 +1,15 @@
import React from 'react' import React from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { formatActivityDate } from '../../../utils' import { formatActivityDate, getDateWithTZ } from '../../../utils'
export default function ActivityCardHeader(props) { export default function ActivityCardHeader(props) {
const { activity, displayModal, sport, title } = props const { activity, displayModal, sport, title, user } = props
const activityDate = activity const activityDate = activity
? formatActivityDate(activity.activity_date) ? formatActivityDate(
getDateWithTZ(activity.activity_date, user.timezone)
)
: null : null
return ( return (
<div className="container"> <div className="container">

View File

@ -34,7 +34,7 @@ class ActivityDisplay extends React.Component {
} }
render() { render() {
const { activities, message, onDeleteActivity, sports } = this.props const { activities, message, onDeleteActivity, sports, user } = this.props
const { displayModal } = this.state const { displayModal } = this.state
const [activity] = activities const [activity] = activities
const title = activity ? activity.title : 'Activity' const title = activity ? activity.title : 'Activity'
@ -71,6 +71,7 @@ class ActivityDisplay extends React.Component {
activity={activity} activity={activity}
sport={sport} sport={sport}
title={title} title={title}
user={user}
displayModal={() => this.displayModal(true)} displayModal={() => this.displayModal(true)}
/> />
</div> </div>

View File

@ -2,10 +2,10 @@ import { format } from 'date-fns'
import React from 'react' import React from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { apiUrl } from '../../utils' import { apiUrl, getDateWithTZ } from '../../utils'
export default function ActivityCard (props) { export default function ActivityCard (props) {
const { activity, sports } = props const { activity, sports, user } = props
return ( return (
<div className="card activity-card text-center"> <div className="card activity-card text-center">
@ -13,7 +13,10 @@ export default function ActivityCard (props) {
<Link to={`/activities/${activity.id}`}> <Link to={`/activities/${activity.id}`}>
{sports.filter(sport => sport.id === activity.sport_id) {sports.filter(sport => sport.id === activity.sport_id)
.map(sport => sport.label)} -{' '} .map(sport => sport.label)} -{' '}
{format(activity.activity_date, 'DD/MM/YYYY HH:mm')} {format(
getDateWithTZ(activity.activity_date, user.timezone),
'DD/MM/YYYY HH:mm'
)}
</Link> </Link>
</div> </div>
<div className="card-body"> <div className="card-body">

View File

@ -4,7 +4,7 @@ import { Link } from 'react-router-dom'
import { formatRecord } from '../../utils' import { formatRecord } from '../../utils'
export default function RecordsCard (props) { export default function RecordsCard (props) {
const { records, sports } = props const { records, sports, user } = props
const recordsBySport = records.reduce((sportList, record) => { const recordsBySport = records.reduce((sportList, record) => {
const sport = sports.find(s => s.id === record.sport_id) const sport = sports.find(s => s.id === record.sport_id)
if (sportList[sport.label] === void 0) { if (sportList[sport.label] === void 0) {
@ -13,7 +13,7 @@ export default function RecordsCard (props) {
records: [], records: [],
} }
} }
sportList[sport.label].records.push(formatRecord(record)) sportList[sport.label].records.push(formatRecord(record, user.timezone))
return sportList return sportList
}, {}) }, {})

View File

@ -45,7 +45,7 @@ class DashBoard extends React.Component {
<div className="row"> <div className="row">
<div className="col-md-4"> <div className="col-md-4">
<Statistics /> <Statistics />
<Records records={records} sports={sports} /> <Records records={records} sports={sports} user={user} />
</div> </div>
<div className="col-md-8"> <div className="col-md-8">
<Calendar /> <Calendar />
@ -55,6 +55,7 @@ class DashBoard extends React.Component {
activity={activity} activity={activity}
key={activity.id} key={activity.id}
sports={sports} sports={sports}
user={user}
/>) />)
)) : ( )) : (
<div className="card text-center"> <div className="card text-center">

View File

@ -6,6 +6,7 @@ import { connect } from 'react-redux'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { getMonthActivities } from '../../actions/activities' import { getMonthActivities } from '../../actions/activities'
import { getDateWithTZ } from '../../utils'
const getStartAndEndMonth = date => { const getStartAndEndMonth = date => {
const monthStart = dateFns.startOfMonth(date) const monthStart = dateFns.startOfMonth(date)
@ -73,10 +74,13 @@ class Calendar extends React.Component {
} }
filterActivities(day) { filterActivities(day) {
const { activities } = this.props const { activities, user } = this.props
if (activities) { if (activities) {
return activities return activities
.filter(act => dateFns.isSameDay(act.activity_date, day)) .filter(act => dateFns.isSameDay(
getDateWithTZ(act.activity_date, user.timezone),
day
))
} }
return [] return []
} }
@ -108,11 +112,12 @@ class Calendar extends React.Component {
{dayActivities.map(act => ( {dayActivities.map(act => (
<Link key={act.id} to={`/activities/${act.id}`}> <Link key={act.id} to={`/activities/${act.id}`}>
<img <img
alt="activity sport logo"
className={`activity-sport ${isDisabled}`} className={`activity-sport ${isDisabled}`}
src={sports src={sports
.filter(s => s.id === act.sport_id) .filter(s => s.id === act.sport_id)
.map(s => s.img)} .map(s => s.img)}
alt="activity sport logo" title={act.title}
/> />
</Link> </Link>
))} ))}
@ -167,6 +172,7 @@ export default connect(
state => ({ state => ({
activities: state.calendarActivities.data, activities: state.calendarActivities.data,
sports: state.sports.data, sports: state.sports.data,
user: state.user,
}), }),
dispatch => ({ dispatch => ({
loadMonthActivities: (start, end) => { loadMonthActivities: (start, end) => {

View File

@ -1,5 +1,6 @@
import togeojson from '@mapbox/togeojson' import togeojson from '@mapbox/togeojson'
import { addDays, format, parse, startOfWeek, subHours } from 'date-fns' import { addDays, format, parse, startOfWeek, subHours } from 'date-fns'
import { DateTime } from 'luxon'
export const apiUrl = `${process.env.REACT_APP_API_URL}/api/` export const apiUrl = `${process.env.REACT_APP_API_URL}/api/`
export const thunderforestApiKey = `${ export const thunderforestApiKey = `${
@ -63,24 +64,33 @@ export const getGeoJson = gpxContent => {
return { jsonData } return { jsonData }
} }
export const formatActivityDate = (activityDateTime, dateFormat = null) => {
if (activityDateTime) { export const getDateWithTZ = (date, tz) => {
const dateTime = parse(activityDateTime) if (!date) {
return { return ''
activity_date: format( }
dateTime, const dt = DateTime.fromISO(format(date)).setZone(tz)
dateFormat ? dateFormat : 'DD/MM/YYYY' return parse(dt.toFormat('yyyy-MM-dd HH:mm:ss'))
), }
activity_time: activityDateTime.match(/[0-2][0-9]:[0-5][0-9]/)[0]
} export const formatActivityDate = (
dateTime,
dateFormat = null,
timeFormat = null,
) => {
if (!dateFormat) {
dateFormat = 'DD/MM/YYYY'
}
if (!timeFormat) {
timeFormat = 'HH:mm'
} }
return { return {
activity_date: null, activity_date: dateTime ? format(dateTime, dateFormat) : null,
activity_time: null, activity_time: dateTime ? format(dateTime, timeFormat) : null,
} }
} }
export const formatRecord = record => { export const formatRecord = (record, tz) => {
let value, recordType = null let value, recordType = null
switch (record.record_type) { switch (record.record_type) {
case 'AS': case 'AS':
@ -97,7 +107,9 @@ export const formatRecord = record => {
recordType = 'Longest duration' recordType = 'Longest duration'
} }
return { return {
activity_date: formatActivityDate(record.activity_date).activity_date, activity_date: formatActivityDate(
getDateWithTZ(record.activity_date, tz)
).activity_date,
activity_id: record.activity_id, activity_id: record.activity_id,
id: record.id, id: record.id,
record_type: recordType, record_type: recordType,

View File

@ -8,6 +8,7 @@
"date-fns": "^1.29.0", "date-fns": "^1.29.0",
"history": "^4.7.2", "history": "^4.7.2",
"leaflet": "^1.3.1", "leaflet": "^1.3.1",
"luxon": "^1.2.1",
"object-hash": "^1.3.0", "object-hash": "^1.3.0",
"react": "^16.4.0", "react": "^16.4.0",
"react-dom": "^16.4.0", "react-dom": "^16.4.0",

View File

@ -5669,6 +5669,10 @@ lru-cache@^3.2.0:
dependencies: dependencies:
pseudomap "^1.0.1" pseudomap "^1.0.1"
luxon@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.2.1.tgz#5c4948d141939c2b2820f0c3a99276932245efb1"
macaddress@^0.2.8: macaddress@^0.2.8:
version "0.2.8" version "0.2.8"
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"