Skip to content
Snippets Groups Projects
AutosaveIndicator.js 2.72 KiB
Newer Older
/* eslint-disable react/prefer-stateless-function */

import React, { Component } from 'react'
import { isEqual } from 'lodash'
import styled from 'styled-components'
import { th } from '@pubsweet/ui-toolkit'
import { Icon, Spinner } from '@pubsweet/ui'
import { compose, setDisplayName, withStateHandlers } from 'recompose'

import Text from './Text'

class AutosaveIndicator extends Component {
  constructor(props) {
    super(props)
    this.timer = null
  }

  componentDidMount() {
    this.setTimer()
  }

  componentWillReceiveProps({ autosave: nextAutosave }) {
    const { autosave, toggleVisible } = this.props
    if (!isEqual(autosave, nextAutosave)) {
      toggleVisible()
      this.setTimer()
    }
  }

  componentWillUnmount() {
    clearTimeout(this.timer)
  }

  setTimer = () => {
    const { toggleVisible, delay = 2000 } = this.props
    if (this.timer) {
      clearTimeout(this.timer)
    }
    this.timer = setTimeout(toggleVisible, delay)
  }

  render() {
    const {
      isVisible,
      successText = 'Changes saved',
      errorText = 'Changes not saved',
      progressText = 'Saving changes...',
      autosave: { isFetching, error, lastUpdate },
    } = this.props
    return isVisible ? (
      <Root className="autosave-indicator">
        {isFetching && (
          <AutoSaveContainer>
            <Spinner icon="loader" size={2} />
            <Text>{progressText}</Text>
          </AutoSaveContainer>
        )}

        {!isFetching &&
          lastUpdate && (
            <AutoSaveContainer>
              <IconContainer>
                <Icon primary size={2}>
                  check-circle
                </Icon>
              </IconContainer>
              <Text>{successText}</Text>
            </AutoSaveContainer>
          )}
        {!isFetching &&
          error && (
            <AutoSaveContainer>
              <IconContainer>
                <Icon error size={2}>
                  alert-triangle
                </Icon>
              </IconContainer>
              <Text error title={error}>
                {errorText}
              </Text>
            </AutoSaveContainer>
          )}
      </Root>
    ) : (
      <span />
    )
  }
}

export default compose(
  withStateHandlers(
    { isVisible: true },
    {
      toggleVisible: ({ isVisible }, props) => () => ({
        isVisible: !isVisible,
      }),
    },
  ),
  setDisplayName('AutosaveIndicator'),
)(AutosaveIndicator)

// #region styles
const Root = styled.div`
  align-items: center;
  display: flex;
  justify-content: flex-end;
`
const AutoSaveContainer = styled.div`
  align-items: center;
  display: flex;
  padding: ${th('gridUnit')};
`
const IconContainer = styled.div`
  align-items: center;
  display: flex;
  justify-content: center;
`
// #endregion