streetmix/streetmix

View on GitHub
client/src/app/DateTimeRelative.jsx

Summary

Maintainability
D
1 day
Test Coverage
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage, FormattedDate, FormattedTime } from 'react-intl'

const MINUTES_AGO = 1000 * 60 * 10
const SECONDS_AGO = 1000 * 60

/**
 * Compares two date objects to see if they are the same day
 *
 * @param {Date} a - first date to compare
 * @param {Date} b - second date to compare
 */
function isSameDay (a, b) {
  return (
    a.getFullYear() === b.getFullYear() &&
    a.getMonth() === b.getMonth() &&
    a.getDate() === b.getDate()
  )
}

export default function DateTimeRelative (props) {
  const now = new Date()
  const date = new Date(props.value)
  const diff = now - date

  if (diff >= 0) {
    if (diff < SECONDS_AGO) {
      return (
        <time dateTime={props.value} title={props.value}>
          <FormattedMessage
            id="datetime.seconds-ago"
            defaultMessage="A few seconds ago"
          />
        </time>
      )
    }

    if (diff < MINUTES_AGO) {
      return (
        <time dateTime={props.value} title={props.value}>
          <FormattedMessage
            id="datetime.minutes-ago"
            defaultMessage="A few minutes ago"
          />
        </time>
      )
    }
  }

  if (isSameDay(date, now)) {
    return (
      <FormattedMessage
        id="datetime.today"
        defaultMessage="Today at {time}"
        values={{
          time: (
            <time dateTime={props.value} title={props.value}>
              <FormattedTime
                timeZone={props.timezone}
                value={props.value}
                hour="numeric"
                minute="numeric"
              />
            </time>
          )
        }}
      />
    )
  }

  const yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24)

  if (isSameDay(date, yesterday)) {
    return (
      <FormattedMessage
        id="datetime.yesterday"
        defaultMessage="Yesterday at {time}"
        values={{
          time: (
            <time dateTime={props.value} title={props.value}>
              <FormattedTime
                timeZone={props.timezone}
                value={props.value}
                hour="numeric"
                minute="numeric"
              />
            </time>
          )
        }}
      />
    )
  }

  // Same year
  if (now.getFullYear() === date.getFullYear()) {
    return (
      <time dateTime={props.value} title={props.value}>
        <FormattedDate value={props.value} month="long" day="numeric" />
      </time>
    )
  }

  return (
    <time dateTime={props.value} title={props.value}>
      <FormattedDate
        value={props.value}
        year="numeric"
        month="long"
        day="numeric"
      />
    </time>
  )
}

DateTimeRelative.propTypes = {
  // prop should match an ISO date string, e.g. "2018-04-24T23:37:55.21Z"
  value: (props, propName, componentName) => {
    if (
      !/^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+Z$/.test(
        props[propName]
      ) &&
      typeof props[propName] !== 'undefined'
    ) {
      return new Error(
        'Invalid prop `' +
          propName +
          '` supplied to' +
          ' `' +
          componentName +
          '`. It should be an ISO date string.' +
          ' Validation failed. Value: `' +
          props[propName] +
          '`'
      )
    }
  },
  timezone: PropTypes.string
}