cspace-ui
Version:
CollectionSpace user interface for browsers
262 lines (219 loc) • 5.97 kB
JSX
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;