From 8980bfa610d572e4e02bbdec361952a9e8881088 Mon Sep 17 00:00:00 2001
From: Alexandru Munteanu <alexandru.munt@gmail.com>
Date: Thu, 16 Aug 2018 12:47:23 +0300
Subject: [PATCH] feat(styleguide): add activity indicator

---
 packages/component-faraday-ui/src/AppBar.md   |  25 +++-
 .../src/AutosaveIndicator.js                  | 114 ++++++++++++++++++
 .../src/AutosaveIndicator.md                  |  33 +++++
 packages/component-faraday-ui/src/Text.js     |   6 +
 4 files changed, 173 insertions(+), 5 deletions(-)
 create mode 100644 packages/component-faraday-ui/src/AutosaveIndicator.js
 create mode 100644 packages/component-faraday-ui/src/AutosaveIndicator.md

diff --git a/packages/component-faraday-ui/src/AppBar.md b/packages/component-faraday-ui/src/AppBar.md
index 7348050a0..998fc578b 100644
--- a/packages/component-faraday-ui/src/AppBar.md
+++ b/packages/component-faraday-ui/src/AppBar.md
@@ -10,6 +10,10 @@ const currentUser = {
   }
 };
 
+const autosave = {
+  isFetching: true
+};
+
 const HindawiLogo = () => <Logo
   onClick={() => console.log('Hindawi best publish!')}
   title="Hindawi"
@@ -17,12 +21,15 @@ const HindawiLogo = () => <Logo
 />;
 
 const MenuComponent = () => <AppBarMenu
-  currentUser={currentUser}
-  goTo={path => console.log(`navigating to ${path}`)}
-  logout={() => console.log('logging out')}
+    currentUser={currentUser}
+    goTo={path => console.log(`navigating to ${path}`)}
+    logout={() => console.log('logging out')}
   />;
 
-const AutosaveComponent = () => <div>AUTOSAVE</div>;
+const AutosaveComponent = () => <AutosaveIndicator
+    isVisible
+    autosave={autosave}
+  />;
 
 <AppBar
   autosave={AutosaveComponent}
@@ -54,13 +61,21 @@ const HindawiLogo = () => <Logo
   src="https://upload.wikimedia.org/wikipedia/en/thumb/c/ca/Hindawi.svg/1200px-Hindawi.svg.png"
 />;
 
+const autosave = {
+  isFetching: false,
+  lastUpdate: new Date(),
+};
+
 const MenuComponent = () => <AppBarMenu
   currentUser={currentUser}
   goTo={path => console.log(`navigating to ${path}`)}
   logout={() => console.log('logging out')}
   />;
 
-const AutosaveComponent = () => <div>AUTOSAVE</div>;
+const AutosaveComponent = () => <AutosaveIndicator
+    isVisible
+    autosave={autosave}
+  />;
 
 <AppBar
   autosave={AutosaveComponent}
diff --git a/packages/component-faraday-ui/src/AutosaveIndicator.js b/packages/component-faraday-ui/src/AutosaveIndicator.js
new file mode 100644
index 000000000..17e7be261
--- /dev/null
+++ b/packages/component-faraday-ui/src/AutosaveIndicator.js
@@ -0,0 +1,114 @@
+/* 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()
+    }
+  }
+
+  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
diff --git a/packages/component-faraday-ui/src/AutosaveIndicator.md b/packages/component-faraday-ui/src/AutosaveIndicator.md
new file mode 100644
index 000000000..4c7f96553
--- /dev/null
+++ b/packages/component-faraday-ui/src/AutosaveIndicator.md
@@ -0,0 +1,33 @@
+Display the status of the form (Saving in progress, Saved or Error while saving)
+
+Saving in progress. The indicator will be hidden after a certain delay.
+
+```js
+const autosave = {
+  isFetching: true
+};
+ 
+<AutosaveIndicator delay={4000} autosave={autosave} />
+```
+
+Changes saved.
+
+```js
+const autosave = {
+  isFetching: false,
+  lastUpdate: new Date(),
+};
+
+<AutosaveIndicator autosave={autosave} />
+```
+
+Error saving changes.
+
+```js
+const autosave = {
+  isFetching: false,
+  error: 'Something went wrong...',
+};
+
+<AutosaveIndicator autosave={autosave} />
+```
\ No newline at end of file
diff --git a/packages/component-faraday-ui/src/Text.js b/packages/component-faraday-ui/src/Text.js
index a512f96ff..d36c9b262 100644
--- a/packages/component-faraday-ui/src/Text.js
+++ b/packages/component-faraday-ui/src/Text.js
@@ -9,6 +9,12 @@ const textHelper = props => {
       font-family: ${th('fontReading')};
     `
   }
+  if (has(props, 'error')) {
+    return css`
+      color: ${th('colorError')};
+      font-family: ${th('fontReading')};
+    `
+  }
   if (has(props, 'customId')) {
     return css`
       color: ${th('colorPrimary')};
-- 
GitLab