├── .gitattributes
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── src
├── actions
│ ├── auth_actions.js
│ ├── index.js
│ └── types.js
├── components
│ ├── AccountMenu.js
│ ├── Auth
│ │ ├── RequireAuth.js
│ │ ├── SignIn.js
│ │ ├── SignInForm.js
│ │ ├── SignUp.js
│ │ └── SignUpForm.js
│ ├── GraphSection.js
│ ├── HCard.js
│ ├── Header.js
│ ├── LatestSection.js
│ ├── MenuItem.js
│ ├── NavBar.js
│ └── Overview.js
├── config
│ ├── firebase.js
│ └── index.js
├── containers
│ ├── Analytics.js
│ ├── App.js
│ ├── Customers.js
│ ├── Dashboard.js
│ ├── Home.js
│ ├── Main.js
│ ├── Menu.js
│ ├── Orders.js
│ ├── Products.js
│ ├── Profile.js
│ ├── Root.js
│ ├── Root.test.js
│ ├── Settings.js
│ ├── Shop.js
│ └── __snapshots__
│ │ └── Root.test.js.snap
├── images
│ └── screenshot.jpg
├── index.js
├── reducers
│ ├── auth_reducer.js
│ └── index.js
├── store
│ └── index.js
├── styles
│ ├── _base.scss
│ ├── _bootstrap.css
│ ├── _colors.scss
│ ├── _fonts.scss
│ ├── components
│ │ ├── _authform.scss
│ │ ├── _buttons.scss
│ │ ├── _card.scss
│ │ ├── _container.scss
│ │ ├── _header.scss
│ │ ├── _main.scss
│ │ ├── _menu.scss
│ │ ├── _panel.scss
│ │ └── _welcome.scss
│ ├── index.css
│ └── index.scss
└── utils
│ ├── colors.js
│ └── registerServiceWorker.js
└── yarn.lock
/.gitattributes:
--------------------------------------------------------------------------------
1 | * linguist-vendored
2 | *.js linguist-vendored=false
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
23 | .vscode
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Admin Dashboard
2 | Basic Admin UI With Firebase
3 |
4 | 
5 |
6 | ## Require step:
7 | - [Create a Firebase project for your app](https://firebase.google.com/docs/web/setup)
8 | - update your Firebase credentials in `src/config/firebase.js`
9 |
10 | ## Available Scripts
11 |
12 | - In the project directory, you can run: `npm install` or `yarn install`
13 | - Run `npm start` or `yarn start`
14 | - Open [http://localhost:3000](http://localhost:3000) to view it in the browser
15 | - To watch for changes in SCSS files, run `npm run watch-css` or `yarn run watch-css`
16 |
17 | ## Dependencies
18 |
19 | - [Create React App](https://github.com/facebookincubator/create-react-app)
20 | - [React Redux](https://github.com/reactjs/redux)
21 | - [React Router](https://github.com/ReactTraining/react-router)
22 | - [Redux Form](http://redux-form.com/)
23 | - [Firebase](https://firebase.google.com/)
24 | - [Semantic UI React](https://react.semantic-ui.com)
25 | - [Recharts](http://recharts.org/#/en-US/)
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-admin-dashboard",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "firebase": "^4.0.0",
7 | "moment": "^2.19.3",
8 | "prop-types": "^15.5.10",
9 | "react": "^15.5.4",
10 | "react-count-to": "^0.8.0",
11 | "react-dom": "^15.5.4",
12 | "react-fontawesome": "^1.6.1",
13 | "react-redux": "^5.0.5",
14 | "react-router": "^4.1.1",
15 | "react-router-dom": "^4.1.1",
16 | "react-router-redux": "^4.0.8",
17 | "recharts": "^1.3.3",
18 | "redux": "^3.6.0",
19 | "redux-form": "^6.7.0",
20 | "redux-logger": "^3.0.6",
21 | "redux-thunk": "^2.2.0",
22 | "semantic-ui-react": "^0.83.0"
23 | },
24 | "devDependencies": {
25 | "faker": "^4.1.0",
26 | "node-sass-chokidar": "0.0.1",
27 | "react-scripts": "1.0.6",
28 | "react-test-renderer": "^15.5.4"
29 | },
30 | "scripts": {
31 | "build-css": "node-sass-chokidar src/ -o src/",
32 | "watch-css": "yarn run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
33 | "start": "react-scripts start",
34 | "build": "react-scripts build",
35 | "test": "react-scripts test --env=jsdom",
36 | "eject": "react-scripts eject"
37 | },
38 | "jest": {}
39 | }
40 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lannify/react-admin-dashboard/7721438cc9d8c36078e5e0f9160aa96d4759e36d/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | React Admin Dashboard
13 |
14 |
15 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/actions/auth_actions.js:
--------------------------------------------------------------------------------
1 | import firebase from 'firebase';
2 |
3 | import {
4 | LOGIN_SUCCESS,
5 | LOGIN_FAIL,
6 | LOGOUT,
7 | CREATE_USER_SUCCESS,
8 | CREATE_USER_FAIL
9 | } from './types';
10 |
11 | export const createUser = (values) => async (dispatch) => {
12 | const { name, email, password } = values;
13 |
14 | try {
15 | let authUser = await firebase.auth().createUserWithEmailAndPassword(email, password);
16 |
17 | await firebase.database().ref(`users/${authUser.uid}`).set({
18 | email,
19 | name
20 | });
21 |
22 | dispatch({ type: CREATE_USER_SUCCESS, payload: authUser });
23 |
24 | } catch (err) {
25 | console.log(err)
26 | let errorMessage = '';
27 |
28 | switch (err.code) {
29 | case 'auth/email-already-in-use':
30 | errorMessage = 'Email is already in use.'
31 | break;
32 | default:
33 | errorMessage = 'Cannot create new account. Please try again.';
34 | }
35 |
36 | dispatch({ type: CREATE_USER_FAIL, payload: errorMessage });
37 | }
38 | };
39 |
40 | export const signIn = (values) => async (dispatch) => {
41 | const { email, password } = values;
42 |
43 | try {
44 | let user = await firebase.auth().signInWithEmailAndPassword(email, password);
45 |
46 | dispatch({ type: LOGIN_SUCCESS, payload: user });
47 |
48 | } catch (err) {
49 | console.log(err);
50 |
51 | dispatch({ type: LOGIN_FAIL, payload: err});
52 | }
53 | };
54 |
55 | export const signOut = () => dispatch => {
56 | firebase.auth().signOut();
57 | dispatch({ type: LOGOUT });
58 | }
--------------------------------------------------------------------------------
/src/actions/index.js:
--------------------------------------------------------------------------------
1 | export * from './auth_actions';
--------------------------------------------------------------------------------
/src/actions/types.js:
--------------------------------------------------------------------------------
1 | export const LOGIN_SUCCESS = 'login_success';
2 | export const LOGIN_FAIL = 'login_fail';
3 | export const LOGOUT = 'logout';
4 |
5 | export const CREATE_USER_SUCCESS = 'create_user_success';
6 | export const CREATE_USER_FAIL = 'create_user_fail';
7 |
--------------------------------------------------------------------------------
/src/components/AccountMenu.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 |
4 | import { signOut } from '../actions';
5 |
6 | class AccountMenu extends React.Component {
7 |
8 | signOut = () => this.props.signOut();
9 |
10 | render() {
11 | return (
12 |
13 |
14 |
15 | );
16 | }
17 | }
18 |
19 | const mapsStateToProps = state => ({
20 | auth: state.auth
21 | });
22 |
23 | export default connect(mapsStateToProps, {signOut})(AccountMenu);
--------------------------------------------------------------------------------
/src/components/Auth/RequireAuth.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lannify/react-admin-dashboard/7721438cc9d8c36078e5e0f9160aa96d4759e36d/src/components/Auth/RequireAuth.js
--------------------------------------------------------------------------------
/src/components/Auth/SignIn.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import {
4 | Card,
5 | Divider
6 | } from 'semantic-ui-react';
7 |
8 | import { signIn } from '../../actions';
9 |
10 | import NavBar from '../NavBar';
11 | import SignInForm from './SignInForm';
12 |
13 | class SignIn extends React.Component {
14 |
15 | state = { loading: false, error: '' };
16 |
17 | onSubmit = (values) => {
18 | this.setState({ loading: true });
19 | this.props.signIn(values);
20 | }
21 |
22 | componentWillReceiveProps(nextProps) {
23 | const { loggedIn } = nextProps.auth;
24 |
25 | if (!loggedIn) {
26 | this.setState({ error: nextProps.auth.error });
27 | }
28 | }
29 |
30 | renderError = () => {
31 | if (this.state.error !== '') {
32 | return {this.state.error}
;
33 | }
34 | }
35 |
36 | render() {
37 | return (
38 |
39 |
40 |
41 |
42 |
43 | Sign In
44 |
45 | {this.renderError()}
46 |
47 |
48 |
49 |
50 |
51 | );
52 | }
53 | }
54 |
55 | const mapStateToProps = state => ({
56 | form: state.form,
57 | auth: state.auth
58 | })
59 |
60 | export default connect(mapStateToProps, { signIn } )(SignIn);
--------------------------------------------------------------------------------
/src/components/Auth/SignInForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Form,
4 | Button
5 | } from 'semantic-ui-react';
6 | import { Field, reduxForm } from 'redux-form';
7 |
8 | class SignInForm extends React.Component {
9 | render() {
10 | const { handleSubmit, submitting } = this.props;
11 |
12 | return (
13 |
40 | );
41 | }
42 | }
43 |
44 | const validate = values => {
45 | const errors = {};
46 |
47 | if (!values.email) {
48 | errors.email = 'Required';
49 | } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
50 | errors.email = 'Invalid Email Address';
51 | }
52 |
53 | if (!values.password) {
54 | errors.password = 'Required';
55 | } else if (values.password.length < 6) {
56 | errors.password = 'Minimum 6 characters';
57 | }
58 |
59 | return errors;
60 | }
61 |
62 | const renderField = ({ input, label, type, meta: { touched, error } }) => (
63 |
64 |
65 |
66 | {touched && (error &&
{error}
)}
67 |
68 | )
69 |
70 | SignInForm = reduxForm({
71 | form: 'SignInForm',
72 | validate
73 | })(SignInForm);
74 |
75 | export default SignInForm;
--------------------------------------------------------------------------------
/src/components/Auth/SignUp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import {
4 | Card,
5 | Divider
6 | } from 'semantic-ui-react';
7 |
8 | import { createUser } from '../../actions';
9 |
10 | import NavBar from '../NavBar';
11 | import SignUpForm from './SignUpForm';
12 |
13 | class SignUp extends React.Component {
14 |
15 | state = { loading: false, error: '' };
16 |
17 | onSubmit = (values) => {
18 | this.setState({ loading: true });
19 | this.props.createUser(values);
20 | }
21 |
22 | componentWillReceiveProps(nextProps) {
23 | const { loggedIn } = nextProps.auth;
24 |
25 | if (!loggedIn) {
26 | this.setState({ error: nextProps.auth.error });
27 | }
28 | }
29 |
30 | renderError = () => {
31 | if (this.state.error !== '') {
32 | return {this.state.error}
;
33 | }
34 | }
35 |
36 | render() {
37 | return (
38 |
39 |
40 |
41 |
42 |
43 | Sign Up
44 |
45 | {this.renderError()}
46 |
47 |
48 |
49 |
50 |
51 | );
52 | }
53 | }
54 |
55 | const mapStateToProps = state => ({
56 | form: state.form,
57 | auth: state.auth
58 | })
59 |
60 | export default connect(mapStateToProps, { createUser } )(SignUp);
--------------------------------------------------------------------------------
/src/components/Auth/SignUpForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Form,
4 | Button
5 | } from 'semantic-ui-react';
6 | import { Field, reduxForm } from 'redux-form';
7 |
8 | class SignUpForm extends React.Component {
9 | render() {
10 | const { handleSubmit, submitting } = this.props;
11 |
12 | return (
13 |
49 | );
50 | }
51 | }
52 |
53 | const validate = values => {
54 | const errors = {};
55 |
56 | if (!values.name) {
57 | errors.name = 'Required';
58 | } else if (values.name.length < 2) {
59 | errors.name = 'Minimum 2 characters';
60 | }
61 |
62 | if (!values.email) {
63 | errors.email = 'Required';
64 | } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
65 | errors.email = 'Invalid Email Address';
66 | }
67 |
68 | if (!values.password) {
69 | errors.password = 'Required';
70 | } else if (values.password.length < 6) {
71 | errors.password = 'Minimum 6 characters';
72 | }
73 |
74 | return errors;
75 | }
76 |
77 | const renderField = ({ input, label, type, meta: { touched, error } }) => (
78 |
79 |
80 |
81 | {touched && (error &&
{error}
)}
82 |
83 | )
84 |
85 | SignUpForm = reduxForm({
86 | form: 'SignUpForm',
87 | validate
88 | })(SignUpForm);
89 |
90 | export default SignUpForm;
--------------------------------------------------------------------------------
/src/components/GraphSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | ComposedChart,
4 | Area,
5 | Bar,
6 | XAxis,
7 | YAxis,
8 | CartesianGrid,
9 | Tooltip,
10 | Legend,
11 | ResponsiveContainer,
12 | AreaChart
13 | } from 'recharts';
14 |
15 | const DATA = [
16 | { month: 'Jan', revenue: 125123, visitors: 171282 },
17 | { month: 'Feb', revenue: 105467, visitors: 152382 },
18 | { month: 'Mar', revenue: 86345, visitors: 256222 },
19 | { month: 'Apr', revenue: 192567, visitors: 302823 },
20 | { month: 'May', revenue: 135836, visitors: 223563 },
21 | { month: 'Jun', revenue: 93536, visitors: 234674 },
22 | { month: 'Jul', revenue: 182576, visitors: 345143 },
23 | { month: 'Aug', revenue: 76737, visitors: 176332 },
24 | { month: 'Sep', revenue: 162342, visitors: 223425 },
25 | { month: 'Oct', revenue: 114764, visitors: 340289 },
26 | { month: 'Nov', revenue: 204695, visitors: 426264 },
27 | { month: 'Dec', revenue: 232687, visitors: 456292 }
28 | ];
29 |
30 | const PRODUCTS = [
31 | { month: 'Jan', accessories: 234, phones: 178, laptops: 112 },
32 | { month: 'Feb', accessories: 325, phones: 155, laptops: 161 },
33 | { month: 'Mar', accessories: 202, phones: 145, laptops: 191 },
34 | { month: 'Apr', accessories: 228, phones: 168, laptops: 111 },
35 | { month: 'May', accessories: 347, phones: 171, laptops: 114 },
36 | { month: 'Jun', accessories: 304, phones: 158, laptops: 111 }
37 | ];
38 |
39 | const getPercent = (value, total) => {
40 | const ratio = total > 0 ? value / total : 0;
41 |
42 | return toPercent(ratio, 2);
43 | };
44 |
45 | const toPercent = (decimal, fixed = 0) => {
46 | return `${(decimal * 100).toFixed(fixed)}%`;
47 | };
48 |
49 | const renderTooltipContent = (o) => {
50 | const { payload, label } = o;
51 | const total = payload.reduce((result, entry) => (result + entry.value), 0);
52 |
53 | return (
54 |
55 |
{`${label} (Total: ${total})`}
56 |
57 | {
58 | payload.map((entry, index) => (
59 | -
60 | {`${entry.name}: ${entry.value}(${getPercent(entry.value, total)})`}
61 |
62 | ))
63 | }
64 |
65 |
66 | );
67 | };
68 |
69 | class GraphSection extends React.Component {
70 |
71 | render() {
72 | return (
73 |
74 |
75 |
76 |
Revenue and Traffic
77 |
78 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
Product Sales
94 |
95 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | );
111 | }
112 | }
113 |
114 | export default GraphSection;
--------------------------------------------------------------------------------
/src/components/HCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import FontAwesome from 'react-fontawesome';
3 | import CountTo from 'react-count-to';
4 |
5 | export default class HCard extends React.Component {
6 | render() {
7 | let iconClass = `iconWrapper ${this.props.backgroundColor}`;
8 | return(
9 |
10 |
11 |
12 |
13 |
14 |
{this.props.prefix}{this.props.suffix}
15 |
{this.props.label}
16 |
17 |
18 | );
19 | }
20 | }
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AccountMenu from './AccountMenu';
3 |
4 | class Header extends React.Component {
5 | render() {
6 | return (
7 |
8 |
{this.props.pageTitle}
9 |
12 |
13 |
14 | );
15 | }
16 | }
17 |
18 | export default Header;
--------------------------------------------------------------------------------
/src/components/LatestSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class LatestSection extends React.Component {
4 |
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
Latest Orders
11 |
12 |
13 |
Latest Visitors
14 |
15 |
16 |
17 | );
18 | }
19 | }
--------------------------------------------------------------------------------
/src/components/MenuItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import FontAwesome from 'react-fontawesome';
4 |
5 | export default class MenuItem extends React.Component {
6 | state = { open: false };
7 |
8 | renderItem() {
9 | let classes = this.state.open ? 'menuItem open' : 'menuItem';
10 |
11 | return(
12 |
13 | {this.props.children}
14 |
15 | );
16 | }
17 |
18 | render() {
19 | if (this.props.children) {
20 | return(
21 |
22 |
23 |
24 | );
25 | } else {
26 | return(
27 |
28 |
29 |
30 | {this.props.linkText}
31 |
32 |
33 | );
34 | }
35 |
36 | }
37 | }
--------------------------------------------------------------------------------
/src/components/NavBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { NavLink} from 'react-router-dom';
3 |
4 | class NavBar extends React.Component {
5 |
6 | render() {
7 | return (
8 |
19 | );
20 | }
21 | }
22 |
23 | export default NavBar;
--------------------------------------------------------------------------------
/src/components/Overview.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import HCard from './HCard';
3 |
4 | class Overview extends React.Component {
5 |
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | )
25 | }
26 | }
27 |
28 | export default Overview;
--------------------------------------------------------------------------------
/src/config/firebase.js:
--------------------------------------------------------------------------------
1 | // Replace these credentials with your Firebase credentials
2 |
3 | export const firebaseConfig = {
4 | apiKey: "YOUR_FIREBASE_API_KEY",
5 | authDomain: "YOUR_DOMAIN.firebaseapp.com",
6 | databaseURL: "https://YOUR_DOMAIN.firebaseio.com",
7 | projectId: "YOUR_PROJECT_ID",
8 | storageBucket: "YOUR_BUCKET.appspot.com",
9 | messagingSenderId: "YOUR_SENDER_ID"
10 | };
11 |
--------------------------------------------------------------------------------
/src/config/index.js:
--------------------------------------------------------------------------------
1 | export * from './firebase';
--------------------------------------------------------------------------------
/src/containers/Analytics.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from '../components/Header';
3 |
4 | const Analytics = () =>
5 |
6 |
7 |
8 |
This is Analytics
9 |
10 |
;
11 |
12 | export default Analytics;
--------------------------------------------------------------------------------
/src/containers/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { Route, withRouter, Redirect } from 'react-router-dom';
4 | import firebase from 'firebase';
5 | import { Loader } from 'semantic-ui-react';
6 |
7 | import { firebaseConfig } from '../config';
8 |
9 | import Home from './Home';
10 | import Dashboard from './Dashboard';
11 | import SignIn from '../components/Auth/SignIn';
12 | import SignUp from '../components/Auth/SignUp';
13 |
14 |
15 | const ProtectedRoute = ({ component: Component, authed, ...rest }) => {
16 | return (
17 | authed === true
20 | ?
21 | : }
22 | />
23 | );
24 | }
25 |
26 | const PublicRoute = ({ component: Component, authed, ...rest }) => {
27 | return (
28 | authed === false
31 | ?
32 | : }
33 | />
34 | );
35 | }
36 |
37 | class App extends React.Component {
38 |
39 | state = { loggedIn: false, loading: true }
40 |
41 | componentDidMount() {
42 | firebase.initializeApp(firebaseConfig);
43 | firebase.auth().onAuthStateChanged((user) => {
44 | if (user !== null) {
45 | this.setState({ loggedIn: true, loading: false });
46 | } else {
47 | this.setState({ loggedIn: false, loading: false });
48 | }
49 | });
50 | }
51 |
52 | render() {
53 | if (this.state.loading) {
54 | return ;
55 | } else {
56 | return (
57 |
63 | )
64 | }
65 | }
66 | }
67 |
68 | const mapStateToProps = (state) => ({
69 | auth: state.auth
70 | });
71 |
72 | /**
73 | * withRouter is a HOC to work around the issue of connect() conflict
74 | * with the current version of React Router.
75 | * This might change in future releases
76 | */
77 |
78 | export default withRouter(connect(mapStateToProps)(App));
--------------------------------------------------------------------------------
/src/containers/Customers.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from '../components/Header';
3 |
4 | const Customers = () =>
5 |
6 |
7 |
8 |
This is Customers
9 |
10 |
;
11 |
12 | export default Customers;
--------------------------------------------------------------------------------
/src/containers/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route } from 'react-router-dom';
3 |
4 | import Menu from './Menu';
5 | import Main from './Main';
6 | import Profile from './Profile';
7 | import Products from './Products';
8 | import Shop from './Shop';
9 | import Customers from './Customers';
10 | import Orders from './Orders';
11 | import Analytics from './Analytics';
12 | import Settings from './Settings';
13 |
14 | const Dashboard = () =>
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
;
34 |
35 | export default Dashboard;
--------------------------------------------------------------------------------
/src/containers/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | import NavBar from '../components/NavBar';
5 |
6 | export default class Home extends React.Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
Welcome to React
Admin Dashboard
15 | CREATE AN ACCOUNT
16 |
17 |
18 |
19 |
20 | );
21 | }
22 | }
--------------------------------------------------------------------------------
/src/containers/Main.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Header from '../components/Header';
4 | import Overview from '../components/Overview';
5 | import GraphSection from '../components/GraphSection';
6 | import LatestSection from '../components/LatestSection';
7 |
8 | class Main extends React.Component {
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default Main;
--------------------------------------------------------------------------------
/src/containers/Menu.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import MenuItem from '../components/MenuItem';
4 |
5 | class Menu extends React.Component {
6 |
7 | state = { open: false };
8 |
9 | render() {
10 | return (
11 |
12 |
13 |
React Admin
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 | }
29 | }
30 |
31 | export default Menu;
--------------------------------------------------------------------------------
/src/containers/Orders.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from '../components/Header';
3 |
4 | const Orders = () =>
5 |
6 |
7 |
8 |
This is Orders
9 |
10 |
;
11 |
12 | export default Orders;
--------------------------------------------------------------------------------
/src/containers/Products.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from '../components/Header';
3 |
4 | const Products = () =>
5 |
6 |
7 |
8 |
This is Products
9 |
10 |
;
11 |
12 | export default Products;
--------------------------------------------------------------------------------
/src/containers/Profile.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from '../components/Header';
3 |
4 | const Profile = () =>
5 |
6 |
7 |
8 |
This is Profile
9 |
10 |
;
11 |
12 | export default Profile;
--------------------------------------------------------------------------------
/src/containers/Root.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | BrowserRouter as Router
4 | } from 'react-router-dom';
5 |
6 | import createHistory from 'history/createBrowserHistory';
7 | import { Provider } from 'react-redux';
8 |
9 | import store from '../store';
10 |
11 | import App from './App';
12 |
13 | const history = createHistory();
14 |
15 | class Root extends React.Component {
16 | render() {
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 | }
26 | }
27 |
28 | export default Root;
--------------------------------------------------------------------------------
/src/containers/Root.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Root from '../containers/Root';
4 |
5 | describe('Root container', () => {
6 | it('renders correctly', () => {
7 | const tree = renderer.create(
8 |
9 | ).toJSON();
10 |
11 | expect(tree).toMatchSnapshot();
12 | });
13 | });
--------------------------------------------------------------------------------
/src/containers/Settings.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from '../components/Header';
3 |
4 | const Settings = () =>
5 |
6 |
7 |
8 |
This is Settings
9 |
10 |
;
11 |
12 | export default Settings;
--------------------------------------------------------------------------------
/src/containers/Shop.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from '../components/Header';
3 |
4 | const Shop = () =>
5 |
6 |
7 |
8 |
This is Shop
9 |
10 |
;
11 |
12 | export default Shop;
--------------------------------------------------------------------------------
/src/containers/__snapshots__/Root.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Root container renders correctly 1`] = `
4 |
7 | `;
8 |
--------------------------------------------------------------------------------
/src/images/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lannify/react-admin-dashboard/7721438cc9d8c36078e5e0f9160aa96d4759e36d/src/images/screenshot.jpg
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import registerServiceWorker from './utils/registerServiceWorker';
4 |
5 | import Root from './containers/Root';
6 | import './styles/index.css';
7 |
8 | ReactDOM.render(, document.getElementById('root'));
9 | registerServiceWorker();
10 |
--------------------------------------------------------------------------------
/src/reducers/auth_reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | LOGIN_SUCCESS,
3 | LOGIN_FAIL,
4 | LOGOUT,
5 | CREATE_USER_SUCCESS,
6 | CREATE_USER_FAIL
7 | } from '../actions/types';
8 |
9 | const initialState = {
10 | loggedIn: false,
11 | user: null,
12 | error: ''
13 | }
14 |
15 | export default (state = initialState, action) => {
16 | switch(action.type) {
17 | case LOGIN_SUCCESS:
18 | return { loggedIn: true, user: action.payload };
19 | case LOGIN_FAIL:
20 | return { loggedIn: false, error: action.payload };
21 | case LOGOUT:
22 | return initialState;
23 | case CREATE_USER_SUCCESS:
24 | return { loggedIn: true, user: action.payload };
25 | case CREATE_USER_FAIL:
26 | return { loggedIn: false, error: action.payload };
27 | default:
28 | return state;
29 | }
30 | }
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import { reducer as formReducer } from 'redux-form';
3 |
4 | import auth from './auth_reducer';
5 |
6 | export default combineReducers({
7 | auth,
8 | form: formReducer
9 | });
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | createStore,
3 | applyMiddleware,
4 | // compose
5 | } from 'redux';
6 | import thunk from 'redux-thunk';
7 | import reducers from '../reducers';
8 | import logger from 'redux-logger';
9 |
10 | const store = createStore(reducers, {}, applyMiddleware(thunk, logger));
11 |
12 | export default store;
13 |
14 |
--------------------------------------------------------------------------------
/src/styles/_base.scss:
--------------------------------------------------------------------------------
1 | a,
2 | a:visited,
3 | a:focus,
4 | a:hover {
5 | text-decoration: none;
6 | }
7 |
8 | ul {
9 | list-style: none;
10 | }
11 |
12 | .pullRight {
13 | float: right;
14 | }
--------------------------------------------------------------------------------
/src/styles/_colors.scss:
--------------------------------------------------------------------------------
1 | .greenBG {
2 | background: #8BC34A;
3 | }
4 |
5 | .orangeBG {
6 | background: orange;
7 | }
8 |
9 | .amberBG {
10 | background: #FFC107;
11 | }
12 |
13 | .tealBG {
14 | background: #1DE9B6;
15 | }
16 |
17 | .purpleBG {
18 | background: purple;
19 | }
20 |
21 | .cyanBG {
22 | background: #00BCD4;
23 | }
24 |
25 | .pinkBG {
26 | background: #F06292;
27 | }
28 |
29 | .text-light {
30 | color: #c6c6c6;
31 | }
32 |
33 | .green {
34 | color: #8BC34A;
35 | }
36 |
37 | .orange {
38 | color: orange;
39 | }
40 |
41 | .amber {
42 | color: #FFC107;
43 | }
44 |
45 | .teal {
46 | color: #1DE9B6;
47 | }
48 |
49 | .purple {
50 | color: purple;
51 | }
52 |
53 | .cyan {
54 | color: #00BCD4;
55 | }
56 |
57 | .pink {
58 | color: #F06292;
59 | }
60 |
61 | .white {
62 | color: #fff;
63 | }
--------------------------------------------------------------------------------
/src/styles/_fonts.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: .9em;
3 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
4 | color: #5b5c5d;
5 | }
6 |
7 | h1,
8 | h2,
9 | h3,
10 | h4,
11 | h5,
12 | h6 {
13 | font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif;
14 | }
15 |
16 | h1 {
17 | font-size: 1.2em;
18 | color: #F06292;
19 | }
20 |
21 | h2 {
22 | font-size: 1.2em;
23 | }
24 |
25 | .error {
26 | color: red;
27 | margin-top: .5rem;
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/src/styles/components/_authform.scss:
--------------------------------------------------------------------------------
1 | .authForm {
2 | max-width: 500px;
3 | margin: 1rem auto;
4 | display: block;
5 |
6 | h1 {
7 | text-align: center;
8 | color: transparent;
9 | background: linear-gradient(130deg,#fc00ff, #0097de);
10 | background-clip: text;
11 | -webkit-background-clip: text;
12 | }
13 |
14 | .card {
15 | width: 100%;
16 | padding: 2rem 0;
17 | }
18 |
19 | .form {
20 | padding: 1rem 2rem;
21 |
22 | input {
23 | width: 100%;
24 | height: 40px;
25 | border-radius: 4px;
26 | border: 1px solid #aeaeae;
27 | padding: 10px 15px;
28 |
29 | }
30 |
31 | button {
32 | margin: 2rem auto;
33 | display: block;
34 | width: 100%;
35 | }
36 |
37 | }
38 | }
--------------------------------------------------------------------------------
/src/styles/components/_buttons.scss:
--------------------------------------------------------------------------------
1 | .btnCommon,
2 | .ui .button {
3 | height: 44px;
4 | display: inline-block;
5 | line-height: 44px;
6 | padding: 0 25px;
7 | box-shadow: 0 4px 6px rgba(50,50,93,.11), 0 1px 3px rgba(0,0,0,.08);
8 | border-radius: 4px;
9 | font-size: 15px;
10 | letter-spacing: .15em;
11 | text-decoration: none;
12 | transition: all .15s ease;
13 | text-transform: uppercase;
14 | color: #5c63ce;
15 | border:none;
16 | margin-top: 1rem;
17 | }
18 |
19 | .btnWhite {
20 | background: #fff;
21 | }
22 |
23 | .btnOutline {
24 | border: 1px solid #0986c1;
25 | background: none;
26 | color: #0986c1;
27 | }
28 |
29 | .btnPrimary,
30 | .ui .button {
31 | color: #fff;
32 | background: linear-gradient(130deg,#fc00ff, #0097de);
33 | }
34 |
35 | .btnPrimary:hover,
36 | .ui .button:hover {
37 | color: #fff;
38 | background: linear-gradient(130deg, #b84eb9, #0986c1);
39 | }
--------------------------------------------------------------------------------
/src/styles/components/_card.scss:
--------------------------------------------------------------------------------
1 | .card {
2 | border: none;
3 | }
4 |
5 | .hCard {
6 | display: flex;
7 | flex-direction: row;
8 | height: 105px;
9 | width: 100%;
10 | margin: 1rem 0;
11 |
12 | .dataWrapper{
13 | width: 60%;
14 | display: flex;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | }
19 |
20 | .iconWrapper {
21 | width: 40%;
22 | display: flex;
23 | justify-content: center;
24 | align-items: center;
25 | color: #fff;
26 | border-top-left-radius: 5px;
27 | border-bottom-left-radius: 5px;
28 | }
29 |
30 | .number {
31 | font-size: 2.2em;
32 | line-height: 1;
33 | margin-bottom: .25rem;
34 | margin-top: .5rem;
35 | }
36 | }
37 |
38 | .vCard {
39 | padding: 1rem;
40 | }
--------------------------------------------------------------------------------
/src/styles/components/_container.scss:
--------------------------------------------------------------------------------
1 | .mainContainer {
2 | padding: 2rem;
3 | }
--------------------------------------------------------------------------------
/src/styles/components/_header.scss:
--------------------------------------------------------------------------------
1 | .header {
2 | padding: 1rem 2rem;
3 | display: flex;
4 | flex-direction: row;
5 | justify-content: space-between;
6 | box-shadow: 0px 0px 2px 0px #d2d1d1;
7 |
8 | h1 {
9 | color: #F06292;
10 | font-size: 2.2em;
11 | }
12 | }
13 |
14 | .headerNav {
15 | margin-right: 1rem;
16 | }
17 |
--------------------------------------------------------------------------------
/src/styles/components/_main.scss:
--------------------------------------------------------------------------------
1 | .main {
2 | padding: 0;
3 | background: #f6f6f6;
4 |
5 | .overview {
6 | padding: 0 2rem;
7 | width: 100%;
8 | box-shadow: 0px 0px 2px 0px #d2d1d1;
9 | }
10 |
11 | .graphSection,
12 | .latestSection {
13 | padding: 2rem;
14 | box-shadow: 0px 0px 2px 0px #d2d1d1;
15 | }
16 | }
--------------------------------------------------------------------------------
/src/styles/components/_menu.scss:
--------------------------------------------------------------------------------
1 | .sidebarMenu {
2 | background: #32343c;
3 | padding: 0;
4 | height: 100vh;
5 | overflow: auto;
6 |
7 | a {
8 | color: rgba(255,255,255,0.85);
9 | display: block;
10 | }
11 |
12 | ul {
13 | padding-left: 0;
14 | }
15 |
16 | ul li {
17 | width: 100%;
18 | }
19 |
20 | .brand {
21 | text-align: center;
22 | padding: 1rem 0;
23 | box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, .25);
24 |
25 | h2 {
26 | color: rgba(255,255,255,0.85);
27 | font-size: 2em;
28 | font-weight: normal;
29 | }
30 | }
31 | }
32 |
33 | .menuItem {
34 | font-size: 1em;
35 | font-weight: normal;
36 | width: 100%;
37 |
38 |
39 | :hover {
40 | background: #1b1c21;
41 | }
42 |
43 | a {
44 | color: rgba(255,255,255,0.85);
45 | padding: .75rem 0;
46 | }
47 |
48 | span {
49 | vertical-align: middle;
50 | }
51 |
52 | .fa {
53 | margin-left: 3rem;
54 | }
55 |
56 | .linkText {
57 | margin-left: 1rem;
58 | }
59 | }
60 |
61 | .accountMenu {
62 | button {
63 | margin-top: 0;
64 | padding: .5rem 1rem;
65 | height: initial;
66 | line-height: 1;
67 | font-size: .9em;
68 | }
69 | }
--------------------------------------------------------------------------------
/src/styles/components/_panel.scss:
--------------------------------------------------------------------------------
1 | .panel {
2 | display: flex;
3 | flex-direction: row;
4 |
5 | .panelImage,
6 | .panelContent {
7 | display: inline-block;
8 | padding: .5rem;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/styles/components/_welcome.scss:
--------------------------------------------------------------------------------
1 | .welcomeContainer {
2 | height: 100vh;
3 | width: 100%;
4 | // position: absolute;
5 | overflow: hidden;
6 | // transform: skewY(-10deg);
7 | transform-origin: 0;
8 | background: linear-gradient(130deg,#fc00ff, #00dbde);
9 |
10 |
11 | .mainContainer {
12 | // position: relative;
13 | }
14 |
15 | a.navbar-brand,
16 | a.navLink {
17 | color: #fff;
18 | }
19 |
20 | .navbar ul {
21 | display: flex;
22 | flex-direction: row;
23 | justify-content: space-between;
24 | align-items: baseline;
25 | }
26 |
27 | .navLink {
28 | margin: 0 1rem;
29 | }
30 |
31 | .content {
32 | padding: 5rem 5% 1rem 5%;
33 | }
34 |
35 | h1 {
36 | font-size: 3em;
37 | line-height: 1.4;
38 | margin-bottom: 2rem;
39 | }
40 |
41 | }
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | @import 'bootstrap';
2 | @import 'base';
3 | @import 'fonts';
4 | @import 'colors';
5 | @import 'components/header';
6 | @import 'components/menu';
7 | @import 'components/main';
8 | @import 'components/panel';
9 | @import 'components/card';
10 | @import 'components/welcome';
11 | @import 'components/buttons';
12 | @import 'components/authform';
13 | @import 'components/container';
--------------------------------------------------------------------------------
/src/utils/colors.js:
--------------------------------------------------------------------------------
1 | /** To be Refactored when switch to CSS in JS */
2 |
3 | export const Colors = {
4 | green: '#8BC34A',
5 | orange: 'orange',
6 | amber: '#FFC107',
7 | teal: '#1DE9B6',
8 | purple: 'purple',
9 | cyan: '#00BCD4',
10 | pink: '#F06292'
11 | }
--------------------------------------------------------------------------------
/src/utils/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | export default function register() {
12 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
13 | window.addEventListener('load', () => {
14 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
15 | navigator.serviceWorker
16 | .register(swUrl)
17 | .then(registration => {
18 | registration.onupdatefound = () => {
19 | const installingWorker = registration.installing;
20 | installingWorker.onstatechange = () => {
21 | if (installingWorker.state === 'installed') {
22 | if (navigator.serviceWorker.controller) {
23 | // At this point, the old content will have been purged and
24 | // the fresh content will have been added to the cache.
25 | // It's the perfect time to display a "New content is
26 | // available; please refresh." message in your web app.
27 | console.log('New content is available; please refresh.');
28 | } else {
29 | // At this point, everything has been precached.
30 | // It's the perfect time to display a
31 | // "Content is cached for offline use." message.
32 | console.log('Content is cached for offline use.');
33 | }
34 | }
35 | };
36 | };
37 | })
38 | .catch(error => {
39 | console.error('Error during service worker registration:', error);
40 | });
41 | });
42 | }
43 | }
44 |
45 | export function unregister() {
46 | if ('serviceWorker' in navigator) {
47 | navigator.serviceWorker.ready.then(registration => {
48 | registration.unregister();
49 | });
50 | }
51 | }
52 |
--------------------------------------------------------------------------------