UNPKG

cspace-ui

Version:
262 lines (219 loc) 5.97 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Immutable from 'immutable'; import { defineMessages, FormattedMessage, FormattedDate, FormattedRelative, FormattedTime, } from 'react-intl'; import { Popover } from 'cspace-layout'; import { getUpdatedTimestamp, getUpdatedUser, getCreatedTimestamp, getCreatedUser, } from '../../helpers/recordDataHelpers'; import AccountLabel from '../user/AccountLabel'; import styles from '../../../styles/cspace-ui/RecordHistory.css'; const messages = defineMessages({ updated: { id: 'recordHistory.updated', defaultMessage: `{style, select, full {Updated {date} {time} by {user}} dateTime {Updated {date} {time}} }`, }, created: { id: 'recordHistory.created', defaultMessage: `{style, select, full {Created {date} {time} by {user}} dateTime {Created {date} {time}} }`, }, savedRelative: { id: 'recordHistory.savedRelative', defaultMessage: 'Saved {relativeTime}', }, editing: { id: 'recordHistory.editing', defaultMessage: 'Editing', }, saving: { id: 'recordHistory.saving', defaultMessage: 'Saving', }, }); const formatDate = (timestamp) => ( timestamp ? <FormattedDate value={timestamp} day="numeric" month="short" year="numeric" /> : null ); const formatTime = (timestamp) => ( timestamp ? <FormattedTime value={timestamp} hour="numeric" minute="numeric" second="numeric" /> : null ); const formatTimeRelative = (timestamp) => ( timestamp ? <FormattedRelative value={timestamp} /> : null ); const formatUserId = (userId) => ( userId ? <AccountLabel userId={userId} /> : '' ); const propTypes = { data: PropTypes.instanceOf(Immutable.Map), isModified: PropTypes.bool, isSavePending: PropTypes.bool, }; export default class RecordHistory extends Component { constructor() { super(); this.renderHistory = this.renderHistory.bind(this); this.handlePopoverBeforeClose = this.handlePopoverBeforeClose.bind(this); this.handlePopoverBeforeOpen = this.handlePopoverBeforeOpen.bind(this); // The header shows last saved time as a FormattedRelative that gets automatically updated at // most every ten seconds. The popup content also shows last saved time as a FormattedRelative, // but since it is mounted at a different time than the one in the header, the two can easily // be out of sync. // This is fixed by unmounting the one in the header when the popup is open, and // remounting it when the popup is closed, in order to force it to update to the same (or // greater) value as was shown in the popup. this.state = { showHeader: true, }; } handlePopoverBeforeClose() { this.setState({ showHeader: true, }); } handlePopoverBeforeOpen() { this.setState({ showHeader: false, }); } renderCurrentState() { const { data, isModified, isSavePending, } = this.props; if (isSavePending) { return ( <FormattedMessage {...messages.saving} /> ); } if (isModified) { return ( <FormattedMessage {...messages.editing} /> ); } const updatedTimestamp = getUpdatedTimestamp(data); if (updatedTimestamp) { return ( <FormattedMessage {...messages.savedRelative} key="saved" values={{ relativeTime: formatTimeRelative(updatedTimestamp), }} /> ); } const createdTimestamp = getCreatedTimestamp(data); if (createdTimestamp) { return ( <FormattedMessage {...messages.savedRelative} key="saved" values={{ relativeTime: formatTimeRelative(createdTimestamp), }} /> ); } return null; } renderHistory() { const { data, } = this.props; const currentState = this.renderCurrentState(); const updatedTimestamp = getUpdatedTimestamp(data); const updatedUserId = getUpdatedUser(data); let updated = null; if (updatedTimestamp) { updated = ( <FormattedMessage {...messages.updated} key="updated" values={{ date: formatDate(updatedTimestamp), time: formatTime(updatedTimestamp), user: formatUserId(updatedUserId), style: updatedUserId ? 'full' : 'dateTime', }} /> ); } const createdTimestamp = getCreatedTimestamp(data); const createdUserId = getCreatedUser(data); let created = null; if (createdTimestamp) { created = ( <FormattedMessage {...messages.created} key="created" values={{ date: formatDate(createdTimestamp), time: formatTime(createdTimestamp), user: formatUserId(createdUserId), style: createdUserId ? 'full' : 'dateTime', }} /> ); } const items = [currentState, updated, created].filter((item) => !!item); return ( <ul> {items.map((item) => <li key={item.key}>{item}</li>)} </ul> ); } renderHeader() { const { showHeader, } = this.state; return (showHeader ? this.renderCurrentState() : <br />); } render() { const { data, } = this.props; let content; if (getUpdatedTimestamp(data) || getCreatedTimestamp(data)) { content = ( <Popover align="right" header={this.renderHeader()} renderContent={this.renderHistory} onBeforeOpen={this.handlePopoverBeforeOpen} onBeforeClose={this.handlePopoverBeforeClose} /> ); } else { content = this.renderCurrentState(); } return ( <div className={styles.common}> {content} </div> ); } } RecordHistory.propTypes = propTypes;