Skip to content
Snippets Groups Projects
Commit deb42006 authored by Bogdan Cochior's avatar Bogdan Cochior
Browse files

refactor(component): prepare for submission

parent 8467d9ab
No related branches found
No related tags found
No related merge requests found
Showing
with 158 additions and 179 deletions
...@@ -2,22 +2,31 @@ ...@@ -2,22 +2,31 @@
"name": "pubsweet-component-wizard", "name": "pubsweet-component-wizard",
"version": "0.0.1", "version": "0.0.1",
"main": "src", "main": "src",
"author": "Collaborative Knowledge Foundation",
"license": "MIT", "license": "MIT",
"files": [
"src",
"dist"
],
"dependencies": { "dependencies": {
"@pubsweet/ui": "^0.1.1", "@pubsweet/ui": "^0.1.1",
"moment": "^2.20.1", "moment": "^2.20.1",
"prop-types": "^15.5.10",
"react": "^15.6.1",
"react-dnd": "^2.5.4", "react-dnd": "^2.5.4",
"react-dnd-html5-backend": "^2.5.4", "react-dnd-html5-backend": "^2.5.4",
"react-dom": "^15.6.1", "react-dom": "^15.6.1",
"react-router-dom": "^4.2.2", "react-router-dom": "^4.2.2",
"recompose": "^0.26.0",
"redux": "^3.6.0", "redux": "^3.6.0",
"redux-form": "^7.0.3" "redux-form": "^7.0.3",
"recompose": "^0.26.0",
"xpub-validators": "^0.0.2",
"xpub-connect": "^0.0.2",
"xpub-journal": "^0.0.2",
"xpub-selectors": "^0.0.2",
"styled-components": "^3.1.6"
}, },
"peerDependencies": { "peerDependencies": {
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"pubsweet-client": "^1.0.0-beta.8",
"react": "^15.6.1", "react": "^15.6.1",
"react-dom": "^15.6.1", "react-dom": "^15.6.1",
"react-redux": "^5.0.2", "react-redux": "^5.0.2",
......
import React from 'react' import React from 'react'
import moment from 'moment' import moment from 'moment'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import classnames from 'classnames'
import { compose, withProps } from 'recompose' import { compose, withProps } from 'recompose'
// import { Icon, Spinner } from '@pubsweet/ui'
import { Icon } from '@pubsweet/ui' import { Icon } from '@pubsweet/ui'
import styled from 'styled-components'
import { getFormValues } from 'redux-form' import { getFormValues } from 'redux-form'
import Spinner from 'pubsweet-components-faraday/src/components/UIComponents/Spinner'
import { getAutosave } from '../redux/autosave' import { getAutosave } from '../redux/autosave'
import classes from './AutosaveIndicator.local.scss'
const durationParser = lastUpdate => { const durationParser = lastUpdate => {
const today = moment() const today = moment()
const last = moment(lastUpdate) const last = moment(lastUpdate)
...@@ -19,42 +19,43 @@ const durationParser = lastUpdate => { ...@@ -19,42 +19,43 @@ const durationParser = lastUpdate => {
const Indicator = ({ const Indicator = ({
isVisibile, isVisibile,
progressText = 'Saving changes...',
errorText = 'Changes not saved',
successText,
autosave: { isFetching, error, lastUpdate }, autosave: { isFetching, error, lastUpdate },
}) => }) =>
isVisibile ? ( isVisibile ? (
<div className={classnames(classes.container)}> <Root>
{isFetching && ( {isFetching && (
<div className={classnames(classes['icon-container'])}> <AutoSaveContainer>
<div className={classnames(classes.rotate, classes.icon)}> <Spinner icon="loader" size={16} />
<Icon size={16}>loader</Icon> <Info>{progressText}</Info>
</div> </AutoSaveContainer>
<span>Saving changes...</span>
</div>
)} )}
{!isFetching && {!isFetching &&
lastUpdate && ( lastUpdate && (
<div className={classnames(classes['icon-container'])}> <AutoSaveContainer>
<div className={classnames(classes.icon)}> <IconContainer>
<Icon size={16}>check-circle</Icon> <Icon size={16}>check-circle</Icon>
</div> </IconContainer>
<span>{durationParser(lastUpdate)}</span> <Info>{successText || durationParser(lastUpdate)}</Info>
</div> </AutoSaveContainer>
)} )}
{!isFetching && {!isFetching &&
error && ( error && (
<div className={classnames(classes['icon-container'])}> <AutoSaveContainer>
<div className={classnames(classes.icon)}> <IconContainer>
<Icon color="red" size={16}> <Icon color="var(--color-danger)" size={16}>
alert-triangle alert-triangle
</Icon> </Icon>
</div> </IconContainer>
<span className={classnames(classes['error-text'])} title={error}> <Info error="var(--color-danger)" title={error}>
Changes not saved {errorText}
</span> </Info>
</div> </AutoSaveContainer>
)} )}
</div> </Root>
) : null ) : null
export default compose( export default compose(
...@@ -66,3 +67,24 @@ export default compose( ...@@ -66,3 +67,24 @@ export default compose(
isVisibile: form && Boolean(isFetching || lastUpdate || error), isVisibile: form && Boolean(isFetching || lastUpdate || error),
})), })),
)(Indicator) )(Indicator)
const Root = styled.div`
align-items: center;
display: flex;
justify-content: flex-end;
`
const AutoSaveContainer = styled.div`
align-items: center;
display: flex;
padding: 5px;
`
const IconContainer = styled.div`
align-items: center;
display: flex;
justify-content: center;
`
const Info = styled.span`
font-size: 12px;
margin-left: 5px;
color: ${({ error }) => error || ''};
`
.container {
align-items: center;
display: flex;
justify-content: flex-end;
}
@keyframes rotating {
from {
-o-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-o-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-webkit-keyframes rotating {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.rotate {
-webkit-animation: rotating 1.2s linear infinite;
-moz-animation: rotating 1.2s linear infinite;
-ms-animation: rotating 1.2s linear infinite;
-o-animation: rotating 1.2s linear infinite;
animation: rotating 1.2s linear infinite;
}
.icon-container {
align-items: center;
display: flex;
padding: 5px;
.icon {
align-items: center;
display: flex;
justify-content: center;
margin: 0 5px 0 0;
}
span {
font-size: 12px;
}
}
.error-text {
color: red;
font-size: 12px;
font-weight: 400;
}
# AutoSave indicator
Display the status of the form (Saving in progress, Saved or Error while saving)
## Props
| Prop | Description | Required | Default | Type |
| :---: | :--------------------------------------------------------------------------: | :------: | :------: | :----: |
| formName | Redux Form name | false | 'wizard' | string |
| progressText | Text to show while API returns | false | 'Saving changes... ' | string |
| errorText | Text to show on error | false | 'Changes not saved ' | string |
| successText | Text to show on success | false | 'Progress saved ${duration.humanize()} ago.' | string |
## Examples
```js
<AutosaveIndicator />
```
```js
<AutosaveIndicator formName="authors" progressText='Saving...' successText='Saved' errorText='Something went wrong!' />
```
\ No newline at end of file
import React from 'react' import React from 'react'
import classnames from 'classnames' import styled from 'styled-components'
import { Steps } from 'pubsweet-components-faraday/src/components' import { Steps } from 'pubsweet-components-faraday/src/components'
// import { Steps } from '@pubsweet/ui'
import classes from './Wizard.local.scss'
import WizardFormStep from './WizardFormStep' import WizardFormStep from './WizardFormStep'
export default ({ export default ({
...@@ -12,7 +12,7 @@ export default ({ ...@@ -12,7 +12,7 @@ export default ({
prevStep, prevStep,
step, step,
}) => ( }) => (
<div className={classnames(classes.container)}> <Root>
{showProgress && ( {showProgress && (
<Steps currentStep={step} margin="0 20px 60px 0"> <Steps currentStep={step} margin="0 20px 60px 0">
{getSteps().map((step, index) => ( {getSteps().map((step, index) => (
...@@ -21,5 +21,12 @@ export default ({ ...@@ -21,5 +21,12 @@ export default ({
</Steps> </Steps>
)} )}
<WizardFormStep {...steps[step]} nextStep={nextStep} prevStep={prevStep} /> <WizardFormStep {...steps[step]} nextStep={nextStep} prevStep={prevStep} />
</div> </Root>
) )
const Root = styled.div`
align-items: center;
display: flex;
flex-direction: column;
margin: 0 auto;
`
.container {
align-items: center;
display: flex;
flex-direction: column;
margin: 0 auto;
width: 900px;
}
import React from 'react' import React from 'react'
import { get } from 'lodash' import { get } from 'lodash'
import classnames from 'classnames' import styled from 'styled-components'
import { ValidatedField, Button } from '@pubsweet/ui' import { ValidatedField, Button } from '@pubsweet/ui'
import classes from './WizardStep.local.scss'
import AutosaveIndicator from './AutosaveIndicator' import AutosaveIndicator from './AutosaveIndicator'
export default ({ export default ({
...@@ -25,12 +24,11 @@ export default ({ ...@@ -25,12 +24,11 @@ export default ({
wizard: { confirmationModal: ConfirmationModal }, wizard: { confirmationModal: ConfirmationModal },
...rest ...rest
}) => ( }) => (
<div className={classnames(classes.step)}> <Root width="700px">
<form className={classnames(classes.form)} onSubmit={handleSubmit}> <FormContainer onSubmit={handleSubmit}>
<h3 className={classnames(classes.title)}>{title}</h3> <Title>{title}</Title>
{subtitle && ( {subtitle && (
<div <Subtitle
className={classnames(classes.subtitle)}
dangerouslySetInnerHTML={{ __html: subtitle }} // eslint-disable-line dangerouslySetInnerHTML={{ __html: subtitle }} // eslint-disable-line
/> />
)} )}
...@@ -65,7 +63,7 @@ export default ({ ...@@ -65,7 +63,7 @@ export default ({
) )
}, },
)} )}
<div className={classnames(classes.buttons)}> <ButtonContainer>
<Button onClick={isFirst ? () => history.push('/') : prevStep}> <Button onClick={isFirst ? () => history.push('/') : prevStep}>
{isFirst {isFirst
? `${wizard.cancelText || 'Cancel'}` ? `${wizard.cancelText || 'Cancel'}`
...@@ -76,13 +74,57 @@ export default ({ ...@@ -76,13 +74,57 @@ export default ({
? `${wizard.submitText || 'Submit Manuscript'}` ? `${wizard.submitText || 'Submit Manuscript'}`
: `${wizard.nextText || 'Next'}`} : `${wizard.nextText || 'Next'}`}
</Button> </Button>
</div> </ButtonContainer>
{confirmation && ( {confirmation && (
<div className={classnames(classes.modal)}> <ModalContainer>
<ConfirmationModal toggleConfirming={toggleConfirmation} /> <ConfirmationModal toggleConfirming={toggleConfirmation} />
</div> </ModalContainer>
)} )}
</form> </FormContainer>
<AutosaveIndicator /> <AutosaveIndicator />
</div> </Root>
) )
const Root = styled.div`
align-items: stretch;
border: 1px solid var(--color-pending);
display: flex;
flex-direction: column;
justify-content: flex-start;
padding: 0 20px;
width: ${({ width }) => width || '700px'};
`
const FormContainer = styled.form`
display: flex;
flex-direction: column;
`
const Title = styled.h3`
align-self: center;
`
const Subtitle = styled.div`
align-self: center;
margin-bottom: 25px;
`
const ButtonContainer = styled.div`
align-items: center;
align-self: center;
display: flex;
justify-content: space-around;
margin: 15px 0;
width: ${({ width }) => width || '400px'};
`
const ModalContainer = styled.div`
align-items: center;
background: rgba(255, 255, 255, 0.95);
bottom: 0;
display: flex;
justify-content: center;
left: 0;
position: fixed;
right: 0;
top: 0;
`
.step {
align-items: stretch;
border: 1px solid #222;
display: flex;
flex-direction: column;
justify-content: flex-start;
padding: 0 20px;
width: 700px;
.title {
align-self: center;
}
.subtitle {
align-self: center;
margin-bottom: 25px;
}
}
.form {
display: flex;
flex-direction: column;
}
.buttons {
align-items: center;
align-self: center;
display: flex;
justify-content: space-around;
margin: 15px 0;
width: 400px;
}
.modal {
align-items: center;
background: rgba(255, 255, 255, 0.95);
bottom: 0;
display: flex;
justify-content: center;
left: 0;
position: fixed;
right: 0;
top: 0;
}
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import styled from 'styled-components'
import classes from './Admin.local.scss' const Admin = ({ users = [] }) => (
<Root>
const Admin = ({ users }) => (
<div className={classes.root}>
<h2>Admin</h2> <h2>Admin</h2>
<ul> <ul>
{users.map((u, i) => ( {users.map((u, i) => (
<li key={i}> <li key={u.id}>
{u.username} - {u.email} {u.username} - {u.email}
</li> </li>
))} ))}
</ul> </ul>
</div> </Root>
) )
Admin.propTypes = {}
export default Admin export default Admin
const Root = styled.div`
display: flex;
flex-direction: column;
margin: auto;
max-width: 60em;
`
.root {
display: flex;
flex-direction: column;
margin: auto;
max-width: 60em;
}
import { get } from 'lodash' import { get } from 'lodash'
import PropTypes from 'prop-types'
import { compose } from 'recompose' import { compose } from 'recompose'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { actions } from 'pubsweet-client' import { actions } from 'pubsweet-client'
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment