UNPKG

box-ui-elements-mlh

Version:
297 lines (247 loc) 9.41 kB
/** * @flow * @file Versions Sidebar container * @author Box */ import React from 'react'; import flow from 'lodash/flow'; import getProp from 'lodash/get'; import merge from 'lodash/merge'; import noop from 'lodash/noop'; import { generatePath, withRouter } from 'react-router-dom'; import type { Match, RouterHistory } from 'react-router-dom'; import type { MessageDescriptor } from 'react-intl'; import API from '../../../api'; import messages from './messages'; import openUrlInsideIframe from '../../../utils/iframe'; import VersionsSidebar from './VersionsSidebar'; import VersionsSidebarAPI from './VersionsSidebarAPI'; import { withAPIContext } from '../../common/api-context'; import type { VersionActionCallback, VersionChangeCallback } from './flowTypes'; import type { BoxItemVersion, BoxItem, FileVersions } from '../../../common/types/core'; type Props = { api: API, fileId: string, hasSidebarInitialized?: boolean, history: RouterHistory, match: Match, onVersionChange: VersionChangeCallback, onVersionDelete: VersionActionCallback, onVersionDownload: VersionActionCallback, onVersionPreview: VersionActionCallback, onVersionPromote: VersionActionCallback, onVersionRestore: VersionActionCallback, parentName: string, versionId?: string, }; type State = { error?: MessageDescriptor, isLoading: boolean, isWatermarked: boolean, versionCount: number, versionLimit: number, versions: Array<BoxItemVersion>, }; class VersionsSidebarContainer extends React.Component<Props, State> { static defaultProps = { onVersionChange: noop, onVersionDelete: noop, onVersionDownload: noop, onVersionPreview: noop, onVersionPromote: noop, onVersionRestore: noop, parentName: '', }; api: VersionsSidebarAPI; props: Props; state: State = { isLoading: true, isWatermarked: false, versionCount: Infinity, versionLimit: Infinity, versions: [], }; window: any = window; componentDidMount() { this.initialize(); this.fetchData(); } componentDidUpdate({ fileId: prevFileId, versionId: prevVersionId }: Props) { const { fileId, versionId } = this.props; if (fileId !== prevFileId) { this.refresh(); } if (versionId !== prevVersionId) { this.verifyVersion(); } } componentWillUnmount() { // Reset the current version id since the wrapping route is no longer active this.props.onVersionChange(null); } handleActionDelete = (versionId: string): Promise<void> => { this.setState({ isLoading: true }); return this.api .deleteVersion(this.findVersion(versionId)) .then(() => this.api.fetchVersion(versionId)) .then(this.handleDeleteSuccess) .then(() => this.props.onVersionDelete(versionId)) .catch(() => this.handleActionError(messages.versionActionDeleteError)); }; handleActionDownload = (versionId: string): Promise<void> => { return this.api .fetchDownloadUrl(this.findVersion(versionId)) .then(openUrlInsideIframe) .then(() => this.props.onVersionDownload(versionId)) .catch(() => this.handleActionError(messages.versionActionDownloadError)); }; handleActionPreview = (versionId: string): void => { this.updateVersion(versionId); this.props.onVersionPreview(versionId); }; handleActionPromote = (versionId: string): Promise<void> => { this.setState({ isLoading: true }); return this.api .promoteVersion(this.findVersion(versionId)) .then(this.api.fetchData) .then(this.handleFetchSuccess) .then(this.handlePromoteSuccess) .then(() => this.props.onVersionPromote(versionId)) .catch(() => this.handleActionError(messages.versionActionPromoteError)); }; handleActionRestore = (versionId: string): Promise<void> => { this.setState({ isLoading: true }); return this.api .restoreVersion(this.findVersion(versionId)) .then(() => this.api.fetchVersion(versionId)) .then(this.handleRestoreSuccess) .then(() => this.props.onVersionRestore(versionId)) .catch(() => this.handleActionError(messages.versionActionRestoreError)); }; handleActionError = (message: MessageDescriptor): void => { this.setState({ error: message, isLoading: false, }); }; handleDeleteSuccess = (data: BoxItemVersion): void => { const { versionId: selectedVersionId } = this.props; const { id: versionId } = data; this.mergeResponse(data); // Bump the user to the current version if they deleted their selected version if (versionId === selectedVersionId) { this.updateVersionToCurrent(); } }; handleRestoreSuccess = (data: BoxItemVersion): void => { this.mergeResponse(data); }; handleFetchError = (): void => { this.setState({ error: messages.versionFetchError, isLoading: false, isWatermarked: false, versionCount: 0, versions: [], }); }; handleFetchSuccess = ([fileResponse, versionsResponse]): [BoxItem, FileVersions] => { const { api } = this.props; const { version_limit } = fileResponse; const isWatermarked = getProp(fileResponse, 'watermark_info.is_watermarked', false); const versionLimit = version_limit !== null && version_limit !== undefined ? version_limit : Infinity; const versionsWithPermissions = api.getVersionsAPI(false).addPermissions(versionsResponse, fileResponse) || {}; const { entries: versions, total_count: versionCount } = versionsWithPermissions; this.setState( { error: undefined, isLoading: false, isWatermarked, versionCount, versionLimit, versions: this.sortVersions(versions), }, this.verifyVersion, ); return [fileResponse, versionsResponse]; }; handlePromoteSuccess = ([file]: [BoxItem, FileVersions]): void => { const { file_version: fileVersion } = file; if (fileVersion) { this.updateVersion(fileVersion.id); } }; initialize = (): void => { this.api = new VersionsSidebarAPI(this.props); }; fetchData = (): void => { this.api .fetchData() .then(this.handleFetchSuccess) .catch(this.handleFetchError); }; findVersion = (versionId: ?string): ?BoxItemVersion => { const { versions } = this.state; return versions.find(version => version.id === versionId); }; getCurrentVersionId = (): ?string => { const { versions } = this.state; return versions[0] ? versions[0].id : null; }; mergeVersions = (newVersion: BoxItemVersion): Array<BoxItemVersion> => { const { versions } = this.state; const newVersionId = newVersion ? newVersion.id : ''; return versions.map(version => (version.id === newVersionId ? merge({ ...version }, newVersion) : version)); }; mergeResponse = (data: BoxItemVersion): void => { const newVersions = this.mergeVersions(data); this.setState({ error: undefined, isLoading: false, versions: newVersions, }); }; refresh(): void { this.initialize(); this.setState({ isLoading: true }, this.fetchData); } sortVersions(versions?: Array<BoxItemVersion> = []): Array<BoxItemVersion> { return [...versions].sort((a, b) => Date.parse(b.created_at) - Date.parse(a.created_at)); } updateVersion = (versionId?: ?string): void => { const { history, match } = this.props; return history.push(generatePath(match.path, { ...match.params, versionId })); }; updateVersionToCurrent = (): void => { this.updateVersion(this.getCurrentVersionId()); }; verifyVersion = () => { const { onVersionChange, versionId } = this.props; const selectedVersion = this.findVersion(versionId); if (selectedVersion) { onVersionChange(selectedVersion, { currentVersionId: this.getCurrentVersionId(), updateVersionToCurrent: this.updateVersionToCurrent, }); } else { this.updateVersionToCurrent(); } }; render() { const { fileId, parentName } = this.props; return ( <VersionsSidebar fileId={fileId} onDelete={this.handleActionDelete} onDownload={this.handleActionDownload} onPreview={this.handleActionPreview} onPromote={this.handleActionPromote} onRestore={this.handleActionRestore} parentName={parentName} {...this.state} /> ); } } export type VersionsSidebarProps = Props; export default flow([withRouter, withAPIContext])(VersionsSidebarContainer);