Skip to content
This repository has been archived by the owner on May 4, 2019. It is now read-only.

[RFR][Do not merge] Migrate to react-admin #29

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "admin-on-rest-demo",
"version": "1.2.0",
"version": "2.0.0",
"private": true,
"devDependencies": {
"babel-eslint": "^7.1.1",
Expand All @@ -16,19 +16,22 @@
"fakerest": "^1.2.1",
"fetch-mock": "^5.5.0",
"gh-pages": "^0.12.0",
"react-scripts": "1.0.5"
"react-scripts": "1.0.5",
"react-test-renderer": "~16.0.0"
},
"dependencies": {
"admin-on-rest": "~1.3.2",
"aor-language-french": "^1.8.0",
"aor-rich-text-input": "^1.0.0",
"material-ui": "~0.19.0",
"recompose": "~0.25.0",
"react-admin": "~2.0.0-alpha3",
"ra-data-simple-rest": "~2.0.0-alpha3",
"ra-language-french": "~2.0.0-alpha3",
"ra-input-rich-text": "~2.0.0-alpha3",
"material-ui": "~1.0.0-beta.17",
"material-ui-icons": "~1.0.0-beta.17",
"prop-types": "~15.5.7",
"react": "~15.5.4",
"react-dom": "~15.5.4",
"react": "~16.0.0",
"react-dom": "~16.0.0",
"react-redux": "~5.0.4",
"react-router-dom": "~4.1.0",
"react-tap-event-plugin": "~2.0.1",
"react-router-dom": "~4.2.2",
"redux-form": "~7.0.3",
"redux-saga": "~0.15.0"
},
Expand Down
62 changes: 52 additions & 10 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'babel-polyfill';
import React, { Component } from 'react';
import { Admin, Delete, Resource } from 'admin-on-rest';
import { Admin, Delete, Resource } from 'react-admin';

import './App.css';

Expand All @@ -14,13 +14,23 @@ import { Dashboard } from './dashboard';
import customRoutes from './routes';
import translations from './i18n';

import { VisitorList, VisitorEdit, VisitorDelete, VisitorIcon } from './visitors';
import {
VisitorList,
VisitorEdit,
VisitorDelete,
VisitorIcon,
} from './visitors';
import { CommandList, CommandEdit, CommandIcon } from './commands';
import { ProductList, ProductCreate, ProductEdit, ProductIcon } from './products';
import {
ProductList,
ProductCreate,
ProductEdit,
ProductIcon,
} from './products';
import { CategoryList, CategoryEdit, CategoryIcon } from './categories';
import { ReviewList, ReviewEdit, ReviewIcon } from './reviews';

import restClient from './restClient';
import dataProvider from './dataProvider';
import fakeRestServer from './restServer';

class App extends Component {
Expand All @@ -36,7 +46,7 @@ class App extends Component {
return (
<Admin
title="Posters Galore Admin"
restClient={restClient}
dataProvider={dataProvider}
customReducers={{ theme: themeReducer }}
customSagas={sagas}
customRoutes={customRoutes}
Expand All @@ -47,11 +57,43 @@ class App extends Component {
menu={Menu}
messages={translations}
>
<Resource name="customers" list={VisitorList} edit={VisitorEdit} remove={VisitorDelete} icon={VisitorIcon} />
<Resource name="commands" list={CommandList} edit={CommandEdit} remove={Delete} icon={CommandIcon} options={{ label: 'Orders' }}/>
<Resource name="products" list={ProductList} create={ProductCreate} edit={ProductEdit} remove={Delete} icon={ProductIcon} />
<Resource name="categories" list={CategoryList} edit={CategoryEdit} remove={Delete} icon={CategoryIcon} />
<Resource name="reviews" list={ReviewList} edit={ReviewEdit} icon={ReviewIcon} />
<Resource
name="customers"
list={VisitorList}
edit={VisitorEdit}
remove={VisitorDelete}
icon={VisitorIcon}
/>
<Resource
name="commands"
list={CommandList}
edit={CommandEdit}
remove={Delete}
icon={CommandIcon}
options={{ label: 'Orders' }}
/>
<Resource
name="products"
list={ProductList}
create={ProductCreate}
edit={ProductEdit}
remove={Delete}
icon={ProductIcon}
/>
<Resource
name="categories"
list={CategoryList}
edit={CategoryEdit}
remove={Delete}
icon={CategoryIcon}
/>
<Resource
name="reviews"
list={ReviewList}
edit={ReviewEdit}
remove={Delete}
icon={ReviewIcon}
/>
</Admin>
);
}
Expand Down
11 changes: 8 additions & 3 deletions src/Layout.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { connect } from 'react-redux';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import { Layout, defaultTheme } from 'admin-on-rest';
import { Layout } from 'react-admin';

const darkTheme = {
palette: {
type: 'dark', // Switching the dark mode on is a single property value change.
},
};

export default connect(state => ({
theme: state.theme === 'dark' ? darkBaseTheme : defaultTheme,
theme: state.theme === 'dark' ? darkTheme : {},
}))(Layout);
171 changes: 94 additions & 77 deletions src/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,125 +4,137 @@ import { propTypes, reduxForm, Field } from 'redux-form';
import { connect } from 'react-redux';
import compose from 'recompose/compose';

import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { Card, CardActions } from 'material-ui/Card';
import Card, { CardActions } from 'material-ui/Card';
import Avatar from 'material-ui/Avatar';
import RaisedButton from 'material-ui/RaisedButton';
import Button from 'material-ui/Button';
import TextField from 'material-ui/TextField';
import LockIcon from 'material-ui/svg-icons/action/lock-outline';
import { cyan500, pinkA200 } from 'material-ui/styles/colors';
import { CircularProgress } from 'material-ui/Progress';
import LockIcon from 'material-ui-icons/LockOutline';
import { withStyles } from 'material-ui/styles';

import { Notification, translate, userLogin as userLoginAction } from 'admin-on-rest';
import { Notification, translate, userLogin } from 'react-admin';

const styles = {
const styles = theme => ({
main: {
display: 'flex',
flexDirection: 'column',
minHeight: '100vh',
alignItems: 'center',
justifyContent: 'center',
justifyContent: 'flex-start',
background: 'url(https://source.unsplash.com/random/1600x900)',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
},
card: {
minWidth: 300,
marginTop: '6em',
},
avatar: {
margin: '1em',
textAlign: 'center ',
display: 'flex',
justifyContent: 'center',
},
icon: {
backgroundColor: theme.palette.secondary[500],
},
form: {
padding: '0 1em 1em 1em',
},
input: {
display: 'flex',
},
hint: {
textAlign: 'center',
marginTop: '1em',
color: '#ccc',
},
};

function getColorsFromTheme(theme) {
if (!theme) return { primary1Color: cyan500, accent1Color: pinkA200 };
const {
palette: {
primary1Color,
accent1Color,
},
} = theme;
return { primary1Color, accent1Color };
}
button: {
width: '100%',
},
});

// see http://redux-form.com/6.4.3/examples/material-ui/
const renderInput = ({ meta: { touched, error } = {}, input: { ...inputProps }, ...props }) =>
const renderInput = ({
meta: { touched, error } = {},
input: { ...inputProps },
...props
}) => (
<TextField
errorText={touched && error}
error={!!(touched && error)}
helperText={touched && error}
{...inputProps}
{...props}
fullWidth
/>;
/>
);

class Login extends Component {

login = ({ username, password }) => {
const { userLogin, location } = this.props;
userLogin({ username, password }, location.state ? location.state.nextPathname : '/');
}
login = auth =>
this.props.userLogin(
Copy link
Contributor

@djhi djhi Nov 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less readable imho. I prefer when props are deconstructed

auth,
this.props.location.state
? this.props.location.state.nextPathname
: '/',
);

render() {
const { handleSubmit, submitting, theme, translate } = this.props;
const muiTheme = getMuiTheme(theme);
const { primary1Color, accent1Color } = getColorsFromTheme(muiTheme);
const { classes, handleSubmit, isLoading, translate } = this.props;
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div style={{ ...styles.main, backgroundColor: primary1Color }}>
<Card style={styles.card}>
<div style={styles.avatar}>
<Avatar backgroundColor={accent1Color} icon={<LockIcon />} size={60} />
</div>
<form onSubmit={handleSubmit(this.login)}>
<div style={styles.form}>
<p style={styles.hint}>Hint: demo / demo</p>
<div style={styles.input} >
<Field
name="username"
component={renderInput}
floatingLabelText={translate('aor.auth.username')}
/>
</div>
<div style={styles.input}>
<Field
name="password"
component={renderInput}
floatingLabelText={translate('aor.auth.password')}
type="password"
/>
</div>
<div className={classes.main}>
<Card className={classes.card}>
<div className={classes.avatar}>
<Avatar className={classes.icon}>
<LockIcon />
</Avatar>
</div>
<form onSubmit={handleSubmit(this.login)}>
<p>Hint: demo / demo</p>
<div className={classes.form}>
<div className={classes.input}>
<Field
name="username"
component={renderInput}
label={translate('ra.auth.username')}
disabled={isLoading}
/>
</div>
<div className={classes.input}>
<Field
name="password"
component={renderInput}
label={translate('ra.auth.password')}
type="password"
disabled={isLoading}
/>
</div>
<CardActions>
<RaisedButton type="submit" primary disabled={submitting} label={translate('aor.auth.sign_in')} fullWidth />
</CardActions>
</form>
</Card>
<Notification />
</div>
</MuiThemeProvider>
</div>
<CardActions>
<Button
raised
type="submit"
color="primary"
disabled={isLoading}
className={classes.button}
>
{isLoading && (
<CircularProgress size={25} thickness={2} />
)}
{translate('ra.auth.sign_in')}
</Button>
</CardActions>
</form>
</Card>
<Notification />
</div>
);
}
}

Login.propTypes = {
...propTypes,
authClient: PropTypes.func,
classes: PropTypes.object,
previousRoute: PropTypes.string,
theme: PropTypes.object.isRequired,
translate: PropTypes.func.isRequired,
userLogin: PropTypes.func.isRequired,
};

Login.defaultProps = {
theme: {},
};
const mapStateToProps = state => ({ isLoading: state.admin.loading > 0 });

const enhance = compose(
translate,
Expand All @@ -131,12 +143,17 @@ const enhance = compose(
validate: (values, props) => {
const errors = {};
const { translate } = props;
if (!values.username) errors.username = translate('aor.validation.required');
if (!values.password) errors.password = translate('aor.validation.required');
if (!values.username) {
errors.username = translate('ra.validation.required');
}
if (!values.password) {
errors.password = translate('ra.validation.required');
}
return errors;
},
}),
connect(null, { userLogin: userLoginAction }),
connect(mapStateToProps, { userLogin }),
withStyles(styles),
);

export default enhance(Login);
Loading