├── conf ├── authnginx │ └── htpasswd └── default.conf ├── .gitignore ├── public ├── favicon.ico ├── manifest.json └── index.html ├── screenshot-cards.png ├── screenshot-signup.png ├── screenshot-wizard.png ├── screenshot-dashboard.png ├── src ├── App.test.js ├── index.css ├── components │ ├── ScrollTop.js │ ├── Menu.js │ ├── common │ │ ├── Months.js │ │ ├── Loading.js │ │ └── Back.js │ ├── SimpleLineChart.js │ ├── typo │ │ └── SectionHeader.js │ ├── buttons │ │ └── ButtonBar.js │ ├── dialogs │ │ ├── BaseDialog.js │ │ ├── InstructionDialog.js │ │ └── SwipeDialog.js │ ├── Cards.js │ ├── cards │ │ └── CardItem.js │ ├── Topbar.js │ ├── Main.js │ ├── Signup.js │ ├── Dashboard.js │ └── Wizard.js ├── index.js ├── App.css ├── images │ ├── shape.svg │ ├── back-arrow.svg │ └── logo.svg ├── routes.js ├── App.js └── serviceWorker.js ├── Dockerfile ├── .github └── FUNDING.yml ├── LICENSE ├── package.json └── README.md /conf/authnginx/htpasswd: -------------------------------------------------------------------------------- 1 | dbprototest:saHJ36Omlhks2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | build/ 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanmtz/material-sense/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /screenshot-cards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanmtz/material-sense/HEAD/screenshot-cards.png -------------------------------------------------------------------------------- /screenshot-signup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanmtz/material-sense/HEAD/screenshot-signup.png -------------------------------------------------------------------------------- /screenshot-wizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanmtz/material-sense/HEAD/screenshot-wizard.png -------------------------------------------------------------------------------- /screenshot-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanmtz/material-sense/HEAD/screenshot-dashboard.png -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /src/components/ScrollTop.js: -------------------------------------------------------------------------------- 1 | import { Component } from 'react' 2 | import { withRouter } from 'react-router-dom' 3 | 4 | class ScrollToTop extends Component { 5 | componentDidUpdate(prevProps) { 6 | if (this.props.location.pathname !== prevProps.location.pathname) { 7 | window.scrollTo(0, 0); 8 | } 9 | } 10 | 11 | render() { 12 | return this.props.children; 13 | } 14 | } 15 | 16 | export default withRouter(ScrollToTop); 17 | -------------------------------------------------------------------------------- /conf/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | 5 | location / { 6 | root /usr/share/nginx/html; 7 | index index.html index.htm; 8 | try_files $uri /index.html; 9 | } 10 | 11 | auth_basic "auth required to access this website"; 12 | auth_basic_user_file authnginx/htpasswd; 13 | 14 | error_page 500 502 503 504 /50x.html; 15 | location = /50x.html { 16 | root /usr/share/nginx/html; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # stage: 1 2 | FROM node:latest as react-build 3 | 4 | # Create app directory 5 | WORKDIR /app 6 | 7 | COPY . ./ 8 | 9 | RUN yarn install 10 | RUN yarn build 11 | 12 | # stage: 2 — the production environment 13 | FROM nginx:alpine 14 | COPY --from=react-build /app/build /usr/share/nginx/html 15 | 16 | # To provide a http authentication comment out the next two lines 17 | #COPY conf/default.conf /etc/nginx/conf.d/default.conf 18 | #COPY conf/authnginx/htpasswd /etc/nginx/authnginx/htpasswd 19 | EXPOSE 80 2222 20 | CMD ["nginx", "-g", "daemon off;"] 21 | -------------------------------------------------------------------------------- /src/components/Menu.js: -------------------------------------------------------------------------------- 1 | const Menu = [ 2 | { 3 | label: "Home", 4 | pathname: "/" 5 | }, 6 | { 7 | label: "Dashboard", 8 | pathname: "/dashboard" 9 | }, 10 | { 11 | label: "Signup", 12 | pathname: "/signup" 13 | }, 14 | { 15 | label: "Wizard", 16 | pathname: "/wizard" 17 | }, 18 | { 19 | label: "Cards", 20 | pathname: "/cards" 21 | }, 22 | { 23 | label: "Github", 24 | pathname: "https://github.com/alexanmtz/material-sense", 25 | external: true 26 | } 27 | 28 | ]; 29 | 30 | export default Menu; -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [alexanmtz] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: alexanmtz 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with a single custom sponsorship URL 13 | -------------------------------------------------------------------------------- /src/images/shape.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/common/Months.js: -------------------------------------------------------------------------------- 1 | const Months = [ 2 | '01 December 2018', 3 | '01 January 2019', 4 | '01 February 2019', 5 | '01 March 2019', 6 | '01 April 2019', 7 | '01 May 2019', 8 | '01 June 2019', 9 | '01 July 2019', 10 | '01 August 2019', 11 | '01 September 2019', 12 | '01 October 2019', 13 | '01 November 2019', 14 | '01 December 2019', 15 | '01 January 2020', 16 | '01 March 2020', 17 | '01 April 2020', 18 | '01 May 2020', 19 | '01 June 2020', 20 | '01 July 2020', 21 | '01 August 2020', 22 | '01 September 2020', 23 | '01 October 2020', 24 | '01 November 2020', 25 | '01 December 2020', 26 | '01 January 2020', 27 | '01 February 2020', 28 | '01 March 2020', 29 | '01 April 2020', 30 | ]; 31 | 32 | export default Months; -------------------------------------------------------------------------------- /src/components/common/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Typography from '@material-ui/core/Typography'; 3 | import withStyles from '@material-ui/styles/withStyles'; 4 | 5 | const styles = theme => ({ 6 | loadingMessage: { 7 | position: 'absolute', 8 | top: '40%', 9 | left: '40%' 10 | } 11 | }); 12 | 13 | function Loading(props) { 14 | const { classes, loading } = props; 15 | return ( 16 |
17 | 👋 18 | 19 | Waiting for input 20 | 21 |
22 | ); 23 | } 24 | 25 | export default withStyles(styles)(Loading); -------------------------------------------------------------------------------- /src/routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Route, HashRouter, Switch } from 'react-router-dom' 3 | import Dashboard from './components/Dashboard' 4 | import Wizard from './components/Wizard' 5 | import Cards from './components/Cards' 6 | import Main from './components/Main' 7 | import Signup from './components/Signup' 8 | import ScrollToTop from './components/ScrollTop' 9 | 10 | export default props => ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ) -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { ThemeProvider } from '@material-ui/styles'; 3 | import { createMuiTheme } from '@material-ui/core/styles' 4 | import './App.css'; 5 | import Routes from './routes' 6 | import { blue, indigo } from '@material-ui/core/colors' 7 | 8 | const theme = createMuiTheme({ 9 | palette: { 10 | secondary: { 11 | main: blue[900] 12 | }, 13 | primary: { 14 | main: indigo[700] 15 | } 16 | }, 17 | typography: { 18 | // Use the system font instead of the default Roboto font. 19 | fontFamily: [ 20 | '"Lato"', 21 | 'sans-serif' 22 | ].join(',') 23 | } 24 | }); 25 | 26 | 27 | class App extends Component { 28 | render() { 29 | return ( 30 |
31 | 32 | 33 | 34 |
35 | ); 36 | } 37 | } 38 | 39 | export default App; 40 | -------------------------------------------------------------------------------- /src/components/SimpleLineChart.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ResponsiveContainer from 'recharts/lib/component/ResponsiveContainer'; 3 | import BarChart from 'recharts/lib/chart/BarChart'; 4 | import Bar from 'recharts/lib/cartesian/Bar'; 5 | import XAxis from 'recharts/lib/cartesian/XAxis'; 6 | import Tooltip from 'recharts/lib/component/Tooltip'; 7 | import { withTheme } from '@material-ui/styles'; 8 | 9 | function SimpleLineChart(props) { 10 | const { theme, data } = props; 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | } 22 | 23 | export default withTheme(SimpleLineChart); -------------------------------------------------------------------------------- /src/components/typo/SectionHeader.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import withStyles from '@material-ui/styles/withStyles'; 3 | import Typography from '@material-ui/core/Typography'; 4 | import { withRouter } from 'react-router-dom'; 5 | 6 | const styles = theme => ({ 7 | sectionContainer: { 8 | marginTop: theme.spacing(4), 9 | marginBottom: theme.spacing(4) 10 | }, 11 | title: { 12 | fontWeight: 'bold' 13 | } 14 | }); 15 | 16 | class SectionHeader extends Component { 17 | render() { 18 | const { classes, title, subtitle} = this.props; 19 | return ( 20 |
21 | 22 | {title} 23 | 24 | 25 | {subtitle} 26 | 27 |
28 | ) 29 | } 30 | } 31 | 32 | export default withRouter(withStyles(styles)(SectionHeader)); 33 | -------------------------------------------------------------------------------- /src/components/buttons/ButtonBar.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import withStyles from '@material-ui/styles/withStyles'; 3 | import Button from '@material-ui/core/Button'; 4 | 5 | const styles = theme => ({ 6 | primary: { 7 | marginRight: theme.spacing(2) 8 | }, 9 | secondary: { 10 | background: theme.palette.secondary['100'], 11 | color: 'white' 12 | }, 13 | spaceTop: { 14 | marginTop: 20 15 | } 16 | }) 17 | 18 | class ButtonBar extends Component { 19 | 20 | render() { 21 | const { classes } = this.props; 22 | 23 | return ( 24 |
25 | 30 | 37 |
38 | ) 39 | } 40 | } 41 | 42 | export default withStyles(styles)(ButtonBar); -------------------------------------------------------------------------------- /src/components/common/Back.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import withStyles from '@material-ui/styles/withStyles'; 3 | import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft'; 4 | import Typography from '@material-ui/core/Typography'; 5 | import { Link, withRouter } from 'react-router-dom'; 6 | 7 | const styles = theme => ({ 8 | link: { 9 | textDecoration: 'none', 10 | color: 'inherit' 11 | }, 12 | text: { 13 | display: 'inline-block', 14 | verticalAlign: 'text-bottom' 15 | } 16 | }); 17 | 18 | class Back extends Component { 19 | render() { 20 | const { classes } = this.props; 21 | return ( 22 |
23 | 24 | 25 | 26 | Back to Dashboard 27 | 28 | 29 |
30 | ) 31 | } 32 | } 33 | 34 | export default withRouter(withStyles(styles)(Back)); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Alexandre Magno Teles Zimerer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/images/back-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "material-sense", 3 | "version": "0.1.0", 4 | "private": true, 5 | "homepage": "https://alexanmtz.github.io/material-sense", 6 | "dependencies": { 7 | "@material-ui/core": "^4.1.1", 8 | "@material-ui/icons": "^4.2.0", 9 | "@material-ui/lab": "^4.0.0-alpha.16", 10 | "@material-ui/styles": "^4.0.0", 11 | "gh-pages": "^2.0.1", 12 | "numeral": "^2.0.6", 13 | "opencollective-postinstall": "^2.0.2", 14 | "query-string": "^6.2.0", 15 | "react": "^16.8.6", 16 | "react-dom": "^16.8.6", 17 | "react-router-dom": "^5.0.1", 18 | "react-scripts": "3.0.1", 19 | "react-swipeable-views": "^0.13.0", 20 | "react-swipeable-views-utils": "^0.13.0", 21 | "recharts": "^1.3.5" 22 | }, 23 | "scripts": { 24 | "start": "react-scripts start", 25 | "build": "react-scripts build", 26 | "test": "react-scripts test", 27 | "eject": "react-scripts eject", 28 | "predeploy": "npm run build", 29 | "deploy": "gh-pages -d build", 30 | "postinstall": "opencollective-postinstall || true" 31 | }, 32 | "eslintConfig": { 33 | "extends": "react-app" 34 | }, 35 | "browserslist": [ 36 | ">0.2%", 37 | "not dead", 38 | "not ie <= 11", 39 | "not op_mini all" 40 | ], 41 | "collective": { 42 | "type": "opencollective", 43 | "url": "https://opencollective.com/material-sense" 44 | } 45 | } -------------------------------------------------------------------------------- /src/components/dialogs/BaseDialog.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import withStyles from '@material-ui/styles/withStyles'; 3 | import Dialog from '@material-ui/core/Dialog'; 4 | import DialogContent from '@material-ui/core/DialogContent'; 5 | import DialogContentText from '@material-ui/core/DialogContentText'; 6 | import DialogTitle from '@material-ui/core/DialogTitle'; 7 | 8 | const styles = theme => ({ 9 | container: { 10 | maxWidth: 600, 11 | flexGrow: 1, 12 | textAlign: 'center', 13 | display: 'flex', 14 | flexDirection: 'column', 15 | justifyContent: 'center' 16 | }, 17 | bottomMargin: { 18 | marginBottom: theme.spacing(2) 19 | } 20 | }); 21 | 22 | class BaseDialog extends Component { 23 | render() { 24 | const { classes, open, onClose } = this.props; 25 | return ( 26 | 33 | 34 | 35 | 36 |
37 | {this.props.children} 38 |
39 |
40 |
41 |
42 | ) 43 | } 44 | } 45 | 46 | export default withStyles(styles)(BaseDialog); -------------------------------------------------------------------------------- /src/components/dialogs/InstructionDialog.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Link, withRouter } from 'react-router-dom'; 3 | import withStyles from '@material-ui/styles/withStyles'; 4 | import Typography from '@material-ui/core/Typography'; 5 | import Button from '@material-ui/core/Button'; 6 | import BaseDialog from './BaseDialog'; 7 | 8 | const styles = theme => ({ 9 | container: { 10 | maxWidth: 600, 11 | flexGrow: 1, 12 | textAlign: 'center', 13 | display: 'flex', 14 | flexDirection: 'column', 15 | justifyContent: 'center' 16 | }, 17 | bottomMargin: { 18 | marginBottom: theme.spacing(2) 19 | } 20 | }); 21 | 22 | class InstructionDialog extends Component { 23 | render() { 24 | const { classes } = this.props; 25 | return ( 26 | 27 |
28 | 29 | This is a sample introduction 30 | 31 |
32 | 35 | 38 |
39 | ) 40 | } 41 | } 42 | 43 | export default withRouter(withStyles(styles)(InstructionDialog)); 44 | -------------------------------------------------------------------------------- /src/components/Cards.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import withStyles from "@material-ui/styles/withStyles"; 3 | import CssBaseline from "@material-ui/core/CssBaseline"; 4 | import Grid from "@material-ui/core/Grid"; 5 | import CardItem from "./cards/CardItem"; 6 | import Topbar from "./Topbar"; 7 | import SectionHeader from "./typo/SectionHeader"; 8 | const backgroundShape = require("../images/shape.svg"); 9 | 10 | const styles = theme => ({ 11 | root: { 12 | flexGrow: 1, 13 | backgroundColor: theme.palette.grey["A500"], 14 | overflow: "hidden", 15 | background: `url(${backgroundShape}) no-repeat`, 16 | backgroundSize: "cover", 17 | backgroundPosition: "0 400px", 18 | marginTop: 20, 19 | padding: 20, 20 | paddingBottom: 200 21 | }, 22 | grid: { 23 | width: 1000 24 | } 25 | }); 26 | 27 | class Cards extends Component { 28 | render() { 29 | const { classes } = this.props; 30 | const currentPath = this.props.location.pathname; 31 | 32 | return ( 33 | 34 | 35 | 36 |
37 | 38 | 45 | 46 | 50 | 51 | 52 | 53 | 54 |
55 |
56 | ); 57 | } 58 | } 59 | 60 | export default withStyles(styles)(Cards); 61 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | Material Sense 26 | 27 | 28 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/cards/CardItem.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import withStyles from '@material-ui/styles/withStyles'; 3 | import Typography from '@material-ui/core/Typography'; 4 | import Paper from '@material-ui/core/Paper'; 5 | import Avatar from '@material-ui/core/Avatar'; 6 | import DescriptionIcon from '@material-ui/icons/Description'; 7 | import ButtonBar from '../buttons/ButtonBar'; 8 | 9 | const styles = theme => ({ 10 | paper: { 11 | padding: theme.spacing(3), 12 | textAlign: 'left', 13 | color: theme.palette.text.secondary 14 | }, 15 | avatar: { 16 | margin: 10, 17 | backgroundColor: theme.palette.grey['200'], 18 | color: theme.palette.text.primary, 19 | }, 20 | avatarContainer: { 21 | [theme.breakpoints.down('sm')]: { 22 | marginLeft: 0, 23 | marginBottom: theme.spacing(4) 24 | } 25 | }, 26 | itemContainer: { 27 | display: 'flex', 28 | alignItems: 'center', 29 | justifyContent: 'flex-start', 30 | [theme.breakpoints.down('sm')]: { 31 | display: 'flex', 32 | flexDirection: 'column', 33 | justifyContent: 'center' 34 | } 35 | }, 36 | baseline: { 37 | alignSelf: 'baseline', 38 | marginLeft: theme.spacing(4), 39 | [theme.breakpoints.down('sm')]: { 40 | display: 'flex', 41 | flexDirection: 'column', 42 | textAlign: 'center', 43 | alignItems: 'center', 44 | width: '100%', 45 | marginTop: theme.spacing(2), 46 | marginBottom: theme.spacing(2), 47 | marginLeft: 0 48 | } 49 | }, 50 | inline: { 51 | display: 'inline-block', 52 | marginLeft: theme.spacing(4), 53 | [theme.breakpoints.down('sm')]: { 54 | marginLeft: 0 55 | } 56 | }, 57 | inlineRight: { 58 | width: '30%', 59 | textAlign: 'right', 60 | marginLeft: 50, 61 | alignSelf: 'flex-end', 62 | [theme.breakpoints.down('sm')]: { 63 | width: '100%', 64 | margin: 0, 65 | textAlign: 'center' 66 | } 67 | }, 68 | backButton: { 69 | marginRight: theme.spacing(2) 70 | } 71 | }) 72 | 73 | class CardItem extends Component { 74 | 75 | render() { 76 | const { classes } = this.props; 77 | 78 | return ( 79 |
80 | 81 |
82 |
83 | 84 | 85 | 86 |
87 |
88 |
89 | 90 | Months 91 | 92 | 93 | 4 month(s) 94 | 95 |
96 |
97 | 98 | Creation date 99 | 100 | 101 | 01 February 2019 102 | 103 |
104 |
105 | 106 | Amount 107 | 108 | 109 | 6,600 USD 110 | 111 |
112 |
113 |
114 | 115 | Other Amount 116 | 117 | 118 | Once a month 119 | 120 | 121 |
122 |
123 |
124 |
125 | ) 126 | } 127 | } 128 | 129 | export default withStyles(styles)(CardItem); 130 | -------------------------------------------------------------------------------- /src/components/dialogs/SwipeDialog.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Link, withRouter } from 'react-router-dom'; 3 | import withStyles from '@material-ui/styles/withStyles'; 4 | import Typography from '@material-ui/core/Typography'; 5 | import Button from '@material-ui/core/Button'; 6 | import BaseDialog from './BaseDialog'; 7 | import SwipeableViews from 'react-swipeable-views'; 8 | import MobileStepper from '@material-ui/core/MobileStepper'; 9 | import { autoPlay } from 'react-swipeable-views-utils'; 10 | 11 | const logo = require('../../images/logo.svg'); 12 | 13 | const AutoPlaySwipeableViews = autoPlay(SwipeableViews); 14 | 15 | const tutorialSteps = [ 16 | { 17 | label: 'A first label', 18 | description: 'This is the first item on the label', 19 | imgPath: 20 | 'https://images.unsplash.com/photo-1537944434965-cf4679d1a598?auto=format&fit=crop&w=400&h=250&q=60', 21 | }, 22 | { 23 | label: 'A second label', 24 | description: 'This is the second item on the label', 25 | imgPath: 26 | 'https://images.unsplash.com/photo-1538032746644-0212e812a9e7?auto=format&fit=crop&w=400&h=250&q=60', 27 | }, 28 | { 29 | label: 'A third label', 30 | description: 'This is the third item on the label', 31 | imgPath: 32 | 'https://images.unsplash.com/photo-1537996194471-e657df975ab4?auto=format&fit=crop&w=400&h=250&q=80', 33 | }, 34 | { 35 | label: 'A fifth label', 36 | description: 'This is the fifth item on the label', 37 | imgPath: 38 | 'https://images.unsplash.com/photo-1518732714860-b62714ce0c59?auto=format&fit=crop&w=400&h=250&q=60', 39 | }, 40 | { 41 | label: 'Other label', 42 | description: 'This is other label', 43 | imgPath: 44 | 'https://images.unsplash.com/photo-1512341689857-198e7e2f3ca8?auto=format&fit=crop&w=400&h=250&q=60', 45 | }, 46 | ]; 47 | 48 | const styles = theme => ({ 49 | container: { 50 | maxWidth: 600, 51 | flexGrow: 1, 52 | textAlign: 'center', 53 | display: 'flex', 54 | flexDirection: 'column', 55 | justifyContent: 'center' 56 | }, 57 | stepsContainer: { 58 | marginLeft: 72, 59 | textAlign: 'left', 60 | marginTop: 20, 61 | height: 65 62 | }, 63 | bottomMargin: { 64 | marginBottom: theme.spacing(2) 65 | } 66 | }); 67 | 68 | class SwipeDialog extends Component { 69 | 70 | state = { 71 | activeStep: 0 72 | } 73 | 74 | handleNext = () => { 75 | this.setState(prevState => ({ 76 | activeStep: prevState.activeStep + 1, 77 | })); 78 | }; 79 | 80 | handleBack = () => { 81 | this.setState(prevState => ({ 82 | activeStep: prevState.activeStep - 1, 83 | })); 84 | }; 85 | 86 | handleStepChange = activeStep => { 87 | this.setState({ activeStep }); 88 | }; 89 | 90 | render() { 91 | const { classes } = this.props; 92 | const maxSteps = tutorialSteps.length; 93 | const { activeStep } = this.state; 94 | return ( 95 | 96 |
97 |
98 | 99 |
100 |
101 | 107 | {tutorialSteps.map((step, index) => ( 108 |
109 | {Math.abs(activeStep - index) <= 2 ? ( 110 | {step.label} 111 | ) : null} 112 |
113 | ))} 114 |
115 | 122 | Next 123 | 124 | } 125 | backButton={ 126 | 129 | } 130 | /> 131 |
132 |
133 | 134 | {tutorialSteps[activeStep].label} 135 | 136 | 137 | {tutorialSteps[activeStep].description} 138 | 139 |
140 |
141 | 144 |
145 |
146 |
147 | ) 148 | } 149 | } 150 | 151 | export default withRouter(withStyles(styles)(SwipeDialog)); 152 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### If you're using this template, please add below your project and send a PR: 2 | - Alexandre Magno (http://ahorta.io) 3 | - Victoria Botelho Martins (https://contech-cbs.web.app/) 4 | 5 | ### Help to fund this project 6 | https://opencollective.com/material-sense 7 | 8 | #### Projects using this template: 9 | - Ahorta Client: https://github.com/worknenjoy/ahorta-client 10 | 11 | 12 | # React Material UI template - Material Sense 13 | A full simple application for react [material ui](https://material-ui.com/) 14 | 15 | ## Features 16 | - Responsive 17 | - Include a Graph using [recharts](https://github.com/recharts/recharts) 18 | - With [Router](https://github.com/ReactTraining/react-router) included 19 | - A docker container for production build 20 | - Created with [Create react app](https://github.com/facebook/create-react-app) 21 | 22 | ![Dashboard](screenshot-dashboard.png) 23 | 24 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 25 | 26 | ## Available Scripts 27 | 28 | In the project directory, you can run: 29 | 30 | ### `yarn start` 31 | 32 | Runs the app in the development mode.
33 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 34 | 35 | The page will reload if you make edits.
36 | You will also see any lint errors in the console. 37 | 38 | ### `npm test` 39 | 40 | Launches the test runner in the interactive watch mode.
41 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 42 | 43 | ### `npm run build` 44 | 45 | Builds the app for production to the `build` folder.
46 | It correctly bundles React in production mode and optimizes the build for the best performance. 47 | 48 | The build is minified and the filenames include the hashes.
49 | Your app is ready to be deployed! 50 | 51 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 52 | 53 | ### `npm run eject` 54 | 55 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 56 | 57 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 58 | 59 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 60 | 61 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 62 | 63 | ## Learn More 64 | 65 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 66 | 67 | To learn React, check out the [React documentation](https://reactjs.org/). 68 | 69 | ### Docker 70 | 71 | This project works in a docker container as well 72 | 73 | First run: 74 | `docker build . -t material-sense` 75 | 76 | Then: 77 | `docker run -p 2222:2222 material-sense` 78 | 79 | _the 2222 port intend to make work on Azure websites as container for default, cause is the port they use to expose the server_ 80 | 81 | ### Publish at Github pages 82 | `yarn deploy` 83 | 84 | ## Screenshots 85 | ![Dashboard](screenshot-dashboard.png) 86 | ![Signup](screenshot-signup.png) 87 | ![Wizard](screenshot-wizard.png) 88 | ![Cards](screenshot-cards.png) 89 | 90 | ## Contributors 91 | 92 | ### Code Contributors 93 | 94 | This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. 95 | 96 | 97 | ### Financial Contributors 98 | 99 | Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/material-sense/contribute)] 100 | 101 | #### Individuals 102 | 103 | 104 | 105 | #### Organizations 106 | 107 | Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/material-sense/contribute)] 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/components/Topbar.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import withStyles from "@material-ui/styles/withStyles"; 3 | import { Link, withRouter } from "react-router-dom"; 4 | import Grid from "@material-ui/core/Grid"; 5 | import Typography from "@material-ui/core/Typography"; 6 | import Toolbar from "@material-ui/core/Toolbar"; 7 | import AppBar from "@material-ui/core/AppBar"; 8 | import Tabs from "@material-ui/core/Tabs"; 9 | import Tab from "@material-ui/core/Tab"; 10 | import MenuIcon from "@material-ui/icons/Menu"; 11 | import IconButton from "@material-ui/core/IconButton"; 12 | import List from "@material-ui/core/List"; 13 | import ListItem from "@material-ui/core/ListItem"; 14 | import ListItemText from "@material-ui/core/ListItemText"; 15 | import SwipeableDrawer from "@material-ui/core/SwipeableDrawer"; 16 | import { Link as MaterialLink } from "@material-ui/core"; 17 | import Menu from "./Menu"; 18 | 19 | const logo = require("../images/logo.svg"); 20 | 21 | const styles = theme => ({ 22 | appBar: { 23 | position: "relative", 24 | boxShadow: "none", 25 | borderBottom: `1px solid ${theme.palette.grey["100"]}`, 26 | backgroundColor: "white" 27 | }, 28 | inline: { 29 | display: "inline" 30 | }, 31 | flex: { 32 | display: "flex", 33 | [theme.breakpoints.down("sm")]: { 34 | display: "flex", 35 | justifyContent: "space-evenly", 36 | alignItems: "center" 37 | } 38 | }, 39 | link: { 40 | textDecoration: "none", 41 | color: "inherit" 42 | }, 43 | productLogo: { 44 | display: "inline-block", 45 | borderLeft: `1px solid ${theme.palette.grey["A100"]}`, 46 | marginLeft: 32, 47 | paddingLeft: 24, 48 | [theme.breakpoints.up("md")]: { 49 | paddingTop: "1.5em" 50 | } 51 | }, 52 | tagline: { 53 | display: "inline-block", 54 | marginLeft: 10, 55 | [theme.breakpoints.up("md")]: { 56 | paddingTop: "0.8em" 57 | } 58 | }, 59 | iconContainer: { 60 | display: "none", 61 | [theme.breakpoints.down("sm")]: { 62 | display: "flex", 63 | justifyContent: 'center', 64 | alignItems: 'center', 65 | } 66 | }, 67 | iconButton: { 68 | float: "right" 69 | }, 70 | tabContainer: { 71 | marginLeft: 32, 72 | [theme.breakpoints.down("sm")]: { 73 | display: "none" 74 | } 75 | }, 76 | tabItem: { 77 | paddingTop: 20, 78 | paddingBottom: 20, 79 | minWidth: "auto" 80 | } 81 | }); 82 | 83 | class Topbar extends Component { 84 | state = { 85 | value: 0, 86 | menuDrawer: false 87 | }; 88 | 89 | handleChange = (event, value) => { 90 | this.setState({ value }); 91 | }; 92 | 93 | mobileMenuOpen = event => { 94 | this.setState({ menuDrawer: true }); 95 | }; 96 | 97 | mobileMenuClose = event => { 98 | this.setState({ menuDrawer: false }); 99 | }; 100 | 101 | componentDidMount() { 102 | window.scrollTo(0, 0); 103 | } 104 | 105 | current = () => { 106 | if (this.props.currentPath === "/home") { 107 | return 0; 108 | } 109 | if (this.props.currentPath === "/dashboard") { 110 | return 1; 111 | } 112 | if (this.props.currentPath === "/signup") { 113 | return 2; 114 | } 115 | if (this.props.currentPath === "/wizard") { 116 | return 3; 117 | } 118 | if (this.props.currentPath === "/cards") { 119 | return 4; 120 | } 121 | }; 122 | 123 | render() { 124 | const { classes } = this.props; 125 | 126 | return ( 127 | 128 | 129 | 130 | 131 |
132 | 133 | 134 | 135 | Material Sense 136 | 137 | 138 |
139 | {!this.props.noTabs && ( 140 | 141 |
142 | A material UI Template 143 |
144 |
145 | 151 | 152 | 153 |
154 |
155 | 161 | 162 | 163 | {Menu.map((item, index) => ( 164 | 178 | 179 | 180 | ))} 181 | 182 | 183 | 189 | {Menu.map((item, index) => ( 190 | 205 | ))} 206 | 207 |
208 |
209 | )} 210 |
211 |
212 |
213 |
214 | ); 215 | } 216 | } 217 | 218 | export default withRouter(withStyles(styles)(Topbar)); 219 | -------------------------------------------------------------------------------- /src/components/Main.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import withStyles from "@material-ui/styles/withStyles"; 3 | import { withRouter } from "react-router-dom"; 4 | import CssBaseline from "@material-ui/core/CssBaseline"; 5 | import Paper from "@material-ui/core/Paper"; 6 | import Typography from "@material-ui/core/Typography"; 7 | import Grid from "@material-ui/core/Grid"; 8 | import Button from "@material-ui/core/Button"; 9 | import InstructionDialog from "./dialogs/InstructionDialog"; 10 | import SwipeDialog from "./dialogs/SwipeDialog"; 11 | 12 | import Topbar from "./Topbar"; 13 | 14 | const backgroundShape = require("../images/shape.svg"); 15 | 16 | const styles = theme => ({ 17 | root: { 18 | flexGrow: 1, 19 | backgroundColor: theme.palette.grey["100"], 20 | overflow: "hidden", 21 | background: `url(${backgroundShape}) no-repeat`, 22 | backgroundSize: "cover", 23 | backgroundPosition: "0 400px", 24 | paddingBottom: 200 25 | }, 26 | grid: { 27 | width: 1200, 28 | marginTop: 40, 29 | [theme.breakpoints.down("sm")]: { 30 | width: "calc(100% - 20px)" 31 | } 32 | }, 33 | paper: { 34 | padding: theme.spacing(3), 35 | textAlign: "left", 36 | color: theme.palette.text.secondary 37 | }, 38 | rangeLabel: { 39 | display: "flex", 40 | justifyContent: "space-between", 41 | paddingTop: theme.spacing(2) 42 | }, 43 | topBar: { 44 | display: "flex", 45 | justifyContent: "space-between", 46 | alignItems: "center", 47 | marginTop: 32 48 | }, 49 | outlinedButtom: { 50 | textTransform: "uppercase", 51 | margin: theme.spacing(1) 52 | }, 53 | actionButtom: { 54 | textTransform: "uppercase", 55 | margin: theme.spacing(1), 56 | width: 152 57 | }, 58 | blockCenter: { 59 | padding: theme.spacing(2), 60 | textAlign: "center" 61 | }, 62 | block: { 63 | padding: theme.spacing(2) 64 | }, 65 | box: { 66 | marginBottom: 40, 67 | height: 65 68 | }, 69 | inlining: { 70 | display: "inline-block", 71 | marginRight: 10 72 | }, 73 | buttonBar: { 74 | display: "flex" 75 | }, 76 | alignRight: { 77 | display: "flex", 78 | justifyContent: "flex-end" 79 | }, 80 | noBorder: { 81 | borderBottomStyle: "hidden" 82 | }, 83 | loadingState: { 84 | opacity: 0.05 85 | }, 86 | loadingMessage: { 87 | position: "absolute", 88 | top: "40%", 89 | left: "40%" 90 | } 91 | }); 92 | 93 | class Main extends Component { 94 | state = { 95 | learnMoredialog: false, 96 | getStartedDialog: false 97 | }; 98 | 99 | componentDidMount() {} 100 | 101 | openDialog = event => { 102 | this.setState({ learnMoredialog: true }); 103 | }; 104 | 105 | dialogClose = event => { 106 | this.setState({ learnMoredialog: false }); 107 | }; 108 | 109 | openGetStartedDialog = event => { 110 | this.setState({ getStartedDialog: true }); 111 | }; 112 | 113 | closeGetStartedDialog = event => { 114 | this.setState({ getStartedDialog: false }); 115 | }; 116 | 117 | render() { 118 | const { classes } = this.props; 119 | return ( 120 | 121 | 122 | 123 |
124 | 125 | 132 | 133 | 134 |
135 | 140 | First title 141 | 142 | 143 | A first title style
with two lines 144 |
145 |
146 |
147 | 154 |
155 |
156 |
157 | 158 | 159 |
160 | 165 | Another box 166 | 167 | 168 | A default box 169 | 170 |
171 |
172 | 179 |
180 |
181 |
182 | 183 | 184 |
185 | 190 | A box with a carousel 191 | 192 | 193 | If you click in Getting Started, you will see a nice 194 | carousel 195 | 196 |
197 |
198 | 205 | 213 |
214 |
215 |
216 | 217 | 218 | 219 |
220 |
221 | 222 | Full box 223 | 224 | 225 | This is an example of a full-width box 226 | 227 |
228 |
229 | 236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 | 247 | 251 |
252 |
253 | ); 254 | } 255 | } 256 | 257 | export default withRouter(withStyles(styles)(Main)); 258 | -------------------------------------------------------------------------------- /src/components/Signup.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import withStyles from "@material-ui/styles/withStyles"; 3 | import { withRouter } from "react-router-dom"; 4 | import CssBaseline from "@material-ui/core/CssBaseline"; 5 | import Typography from "@material-ui/core/Typography"; 6 | import Grid from "@material-ui/core/Grid"; 7 | import Paper from "@material-ui/core/Paper"; 8 | import Button from "@material-ui/core/Button"; 9 | import Stepper from "@material-ui/core/Stepper"; 10 | import Step from "@material-ui/core/Step"; 11 | import StepLabel from "@material-ui/core/StepLabel"; 12 | import OutlinedInput from "@material-ui/core/OutlinedInput"; 13 | import MenuItem from "@material-ui/core/MenuItem"; 14 | import FormControl from "@material-ui/core/FormControl"; 15 | import Select from "@material-ui/core/Select"; 16 | import List from "@material-ui/core/List"; 17 | import ListItem from "@material-ui/core/ListItem"; 18 | import ListItemIcon from "@material-ui/core/ListItemIcon"; 19 | import ListItemText from "@material-ui/core/ListItemText"; 20 | import DoneIcon from "@material-ui/icons/Done"; 21 | import CircularProgress from "@material-ui/core/CircularProgress"; 22 | import Fade from "@material-ui/core/Fade"; 23 | import Back from "./common/Back"; 24 | 25 | const backgroundShape = require("../images/shape.svg"); 26 | 27 | const logo = require("../images/logo.svg"); 28 | 29 | const numeral = require("numeral"); 30 | numeral.defaultFormat("0"); 31 | 32 | const styles = theme => ({ 33 | root: { 34 | flexGrow: 1, 35 | backgroundColor: theme.palette.secondary["A100"], 36 | overflow: "hidden", 37 | background: `url(${backgroundShape}) no-repeat`, 38 | backgroundSize: "cover", 39 | backgroundPosition: "0 400px", 40 | marginTop: 10, 41 | padding: 20, 42 | paddingBottom: 500 43 | }, 44 | grid: { 45 | margin: `0 ${theme.spacing(2)}px` 46 | }, 47 | smallContainer: { 48 | width: "60%" 49 | }, 50 | bigContainer: { 51 | width: "80%" 52 | }, 53 | logo: { 54 | marginBottom: 24, 55 | display: "flex", 56 | justifyContent: "center" 57 | }, 58 | stepContainer: { 59 | display: "flex", 60 | flexDirection: "column", 61 | alignItems: "center" 62 | }, 63 | stepGrid: { 64 | width: "80%" 65 | }, 66 | buttonBar: { 67 | marginTop: 32, 68 | display: "flex", 69 | justifyContent: "center" 70 | }, 71 | button: { 72 | backgroundColor: theme.palette.primary["A100"] 73 | }, 74 | backButton: { 75 | marginRight: theme.spacing(1) 76 | }, 77 | outlinedButtom: { 78 | textTransform: "uppercase", 79 | margin: theme.spacing(1) 80 | }, 81 | stepper: { 82 | backgroundColor: "transparent" 83 | }, 84 | paper: { 85 | padding: theme.spacing(3), 86 | textAlign: "left", 87 | color: theme.palette.text.secondary 88 | }, 89 | topInfo: { 90 | display: "flex", 91 | justifyContent: "space-between", 92 | alignItems: "center", 93 | marginBottom: 42 94 | }, 95 | formControl: { 96 | width: "100%" 97 | }, 98 | selectEmpty: { 99 | marginTop: theme.spacing(2) 100 | } 101 | }); 102 | 103 | const getSteps = () => { 104 | return ["User", "Signin", "Permission"]; 105 | }; 106 | 107 | class Signup extends Component { 108 | state = { 109 | activeStep: 0, 110 | receivingAccount: "", 111 | termsChecked: false, 112 | loading: true, 113 | labelWidth: 0 114 | }; 115 | 116 | handleNext = () => { 117 | this.setState(state => ({ 118 | activeStep: state.activeStep + 1 119 | })); 120 | if (this.state.activeStep === 2) { 121 | setTimeout(() => this.props.history.push("/dashboard"), 5000); 122 | } 123 | }; 124 | 125 | handleBack = () => { 126 | this.setState(state => ({ 127 | activeStep: state.activeStep - 1 128 | })); 129 | }; 130 | 131 | handleReset = () => { 132 | this.setState({ 133 | activeStep: 0 134 | }); 135 | }; 136 | 137 | handleChange = event => { 138 | this.setState({ [event.target.name]: event.target.value }); 139 | }; 140 | 141 | handleTerms = event => { 142 | this.setState({ termsChecked: event.target.checked }); 143 | }; 144 | 145 | stepActions() { 146 | if (this.state.activeStep === 0) { 147 | return "Sign in"; 148 | } 149 | if (this.state.activeStep === 1) { 150 | return "Next"; 151 | } 152 | if (this.state.activeStep === 2) { 153 | return "Accept"; 154 | } 155 | return "Next"; 156 | } 157 | 158 | render() { 159 | const { classes } = this.props; 160 | const steps = getSteps(); 161 | const { activeStep, loading } = this.state; 162 | 163 | return ( 164 | 165 | 166 |
167 | 168 | 169 | 176 | 177 |
178 | 179 |
180 |
181 |
182 | 187 | {steps.map(label => { 188 | return ( 189 | 190 | {label} 191 | 192 | ); 193 | })} 194 | 195 |
196 | {activeStep === 0 && ( 197 |
198 | 199 |
200 |
201 | 206 | Select 207 | 208 | 209 | A item to select 210 | 211 |
212 |
213 | 221 | First options 222 | 223 | 227 | 245 | 246 |
247 |
248 |
249 |
250 | )} 251 | {activeStep === 1 && ( 252 |
253 | 254 | 255 | 256 | 257 | Sign & confirm 258 | 259 | 260 | Sign and confirm loan agreement 261 | 262 | 263 | One text to explain that 264 | 265 | 266 | 267 | 268 |
269 | )} 270 | {activeStep === 2 && ( 271 |
272 | 273 |
274 |
275 | 276 | Permissions 277 | 278 | 279 | We need some permissions to proceed. 280 | 281 |
282 |
283 | 284 | Accounts 285 | 286 | 287 | 288 | 289 | 290 | 291 | 295 | 296 | 297 | 298 | 299 | 300 | 304 | 305 | 306 |
307 |
308 |
309 |
310 | )} 311 | {activeStep === 3 && ( 312 |
313 | 314 |
317 |
318 |
319 | 324 | Collecting your data 325 | 326 | 327 | We are processing your request 328 | 329 |
330 |
331 | 338 | 345 | 346 |
347 |
348 |
349 |
350 |
351 | )} 352 | {activeStep !== 3 && ( 353 |
354 | {activeStep !== 2 ? ( 355 | 363 | ) : ( 364 | 372 | )} 373 | 387 |
388 | )} 389 |
390 |
391 |
392 |
393 |
394 |
395 | ); 396 | } 397 | } 398 | 399 | export default withRouter(withStyles(styles)(Signup)); 400 | -------------------------------------------------------------------------------- /src/components/Dashboard.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import withStyles from "@material-ui/styles/withStyles"; 3 | import { withRouter, Link } from "react-router-dom"; 4 | import CssBaseline from "@material-ui/core/CssBaseline"; 5 | import Paper from "@material-ui/core/Paper"; 6 | import Typography from "@material-ui/core/Typography"; 7 | import Grid from "@material-ui/core/Grid"; 8 | import Slider from "@material-ui/core/Slider"; 9 | import Button from "@material-ui/core/Button"; 10 | import Avatar from "@material-ui/core/Avatar"; 11 | import SimpleLineChart from "./SimpleLineChart"; 12 | import Months from "./common/Months"; 13 | import VerifiedUserIcon from "@material-ui/icons/VerifiedUser"; 14 | import Loading from "./common/Loading"; 15 | 16 | import Topbar from "./Topbar"; 17 | 18 | const numeral = require("numeral"); 19 | numeral.defaultFormat("0,000"); 20 | 21 | const backgroundShape = require("../images/shape.svg"); 22 | 23 | const styles = theme => ({ 24 | root: { 25 | flexGrow: 1, 26 | backgroundColor: theme.palette.grey["100"], 27 | overflow: "hidden", 28 | background: `url(${backgroundShape}) no-repeat`, 29 | backgroundSize: "cover", 30 | backgroundPosition: "0 400px", 31 | paddingBottom: 200 32 | }, 33 | grid: { 34 | width: 1200, 35 | margin: `0 ${theme.spacing(2)}px`, 36 | [theme.breakpoints.down("sm")]: { 37 | width: "calc(100% - 20px)" 38 | } 39 | }, 40 | loadingState: { 41 | opacity: 0.05 42 | }, 43 | paper: { 44 | padding: theme.spacing(3), 45 | margin: theme.spacing(2), 46 | textAlign: "left", 47 | color: theme.palette.text.secondary 48 | }, 49 | rangeLabel: { 50 | display: "flex", 51 | justifyContent: "space-between", 52 | paddingTop: theme.spacing(2) 53 | }, 54 | topBar: { 55 | display: "flex", 56 | justifyContent: "space-between", 57 | alignItems: "center" 58 | }, 59 | outlinedButton: { 60 | textTransform: "uppercase", 61 | margin: theme.spacing(1) 62 | }, 63 | actionButton: { 64 | textTransform: "uppercase", 65 | margin: theme.spacing(1), 66 | width: 152, 67 | height: 36 68 | }, 69 | blockCenter: { 70 | padding: theme.spacing(2), 71 | textAlign: "center" 72 | }, 73 | block: { 74 | padding: theme.spacing(2) 75 | }, 76 | loanAvatar: { 77 | display: "inline-block", 78 | verticalAlign: "center", 79 | width: 16, 80 | height: 16, 81 | marginRight: 10, 82 | marginBottom: -2, 83 | color: theme.palette.primary.contrastText, 84 | backgroundColor: theme.palette.primary.main 85 | }, 86 | interestAvatar: { 87 | display: "inline-block", 88 | verticalAlign: "center", 89 | width: 16, 90 | height: 16, 91 | marginRight: 10, 92 | marginBottom: -2, 93 | color: theme.palette.primary.contrastText, 94 | backgroundColor: theme.palette.primary.light 95 | }, 96 | inlining: { 97 | display: "inline-block", 98 | marginRight: 10 99 | }, 100 | buttonBar: { 101 | display: "flex" 102 | }, 103 | noBorder: { 104 | borderBottomStyle: "hidden" 105 | }, 106 | mainBadge: { 107 | textAlign: "center", 108 | marginTop: theme.spacing(4), 109 | marginBottom: theme.spacing(4) 110 | } 111 | }); 112 | 113 | const monthRange = Months; 114 | 115 | class Dashboard extends Component { 116 | state = { 117 | loading: true, 118 | amount: 15000, 119 | period: 3, 120 | start: 0, 121 | monthlyInterest: 0, 122 | totalInterest: 0, 123 | monthlyPayment: 0, 124 | totalPayment: 0, 125 | data: [] 126 | }; 127 | 128 | updateValues() { 129 | const { amount, period, start } = this.state; 130 | const monthlyInterest = 131 | (amount * Math.pow(0.01 * 1.01, period)) / Math.pow(0.01, period - 1); 132 | const totalInterest = monthlyInterest * (period + start); 133 | const totalPayment = amount + totalInterest; 134 | const monthlyPayment = 135 | period > start ? totalPayment / (period - start) : totalPayment / period; 136 | 137 | const data = Array.from({ length: period + start }, (value, i) => { 138 | const delayed = i < start; 139 | return { 140 | name: monthRange[i], 141 | Type: delayed ? 0 : Math.ceil(monthlyPayment).toFixed(0), 142 | OtherType: Math.ceil(monthlyInterest).toFixed(0) 143 | }; 144 | }); 145 | 146 | this.setState({ 147 | monthlyInterest, 148 | totalInterest, 149 | totalPayment, 150 | monthlyPayment, 151 | data 152 | }); 153 | } 154 | 155 | componentDidMount() { 156 | this.updateValues(); 157 | } 158 | 159 | handleChangeAmount = (event, value) => { 160 | this.setState({ amount: value, loading: false }); 161 | this.updateValues(); 162 | }; 163 | 164 | handleChangePeriod = (event, value) => { 165 | this.setState({ period: value, loading: false }); 166 | this.updateValues(); 167 | }; 168 | 169 | handleChangeStart = (event, value) => { 170 | this.setState({ start: value, loading: false }); 171 | this.updateValues(); 172 | }; 173 | 174 | render() { 175 | const { classes } = this.props; 176 | const { 177 | amount, 178 | period, 179 | start, 180 | monthlyPayment, 181 | monthlyInterest, 182 | data, 183 | loading 184 | } = this.state; 185 | const currentPath = this.props.location.pathname; 186 | 187 | return ( 188 | 189 | 190 | 191 |
192 | 193 | 200 | 201 |
202 |
203 | 204 | Dashboard 205 | 206 | 207 | Adjust and play with our sliders. 208 | 209 |
210 |
211 | 217 |
218 |
219 |
220 | 221 | 222 |
223 | 224 | How much you want to transfer 225 | 226 | 227 | Use slider to set the amount you need. 228 | 229 |
230 | 231 | {numeral(amount).format()} USD 232 | 233 |
234 |
235 | 242 |
243 |
244 |
245 | 15,000 USD 246 |
247 |
248 | 150,000 USD 249 |
250 |
251 |
252 |
253 |
254 | 255 | 256 |
257 | 258 | Period 259 | 260 | A sample period 261 |
262 | 263 | {period} months 264 | 265 |
266 |
267 | 274 |
275 |
276 |
277 | 1 month 278 |
279 |
280 | 6 months 281 |
282 |
283 |
284 |
285 |
286 | 287 | 288 |
289 | 290 | Start date 291 | 292 | 293 | Set your preferred start date. 294 | 295 |
296 | 297 | {monthRange[start]} 298 | 299 |
300 |
301 | 308 |
309 |
310 |
311 | Dec 2018 312 |
313 |
314 | May 2019 315 |
316 |
317 |
318 |
319 |
320 | 321 | 322 | 326 | 327 |
328 | 329 | Some details 330 | 331 | 332 | Details about the graph 333 | 334 |
335 |
336 | 337 | 342 | Type 343 | 344 | 350 | {numeral(monthlyPayment).format()} units 351 | 352 |
353 |
354 | 355 | 360 | Othe type 361 | 362 | 368 | {numeral(monthlyInterest).format()} units 369 | 370 |
371 |
372 |
373 | 374 |
375 |
376 |
377 |
378 | 379 | 383 | 384 |
385 | 386 | State 387 | 388 |
389 | 394 | 399 | Verified 400 | 401 |
402 |
403 | 411 | 420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 | ); 430 | } 431 | } 432 | 433 | export default withRouter(withStyles(styles)(Dashboard)); 434 | -------------------------------------------------------------------------------- /src/components/Wizard.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import withStyles from "@material-ui/styles/withStyles"; 3 | import { withRouter } from "react-router-dom"; 4 | import CssBaseline from "@material-ui/core/CssBaseline"; 5 | import Typography from "@material-ui/core/Typography"; 6 | import Grid from "@material-ui/core/Grid"; 7 | import Paper from "@material-ui/core/Paper"; 8 | import Button from "@material-ui/core/Button"; 9 | import Stepper from "@material-ui/core/Stepper"; 10 | import Step from "@material-ui/core/Step"; 11 | import StepLabel from "@material-ui/core/StepLabel"; 12 | import OutlinedInput from "@material-ui/core/OutlinedInput"; 13 | import FormGroup from "@material-ui/core/FormGroup"; 14 | import FormControlLabel from "@material-ui/core/FormControlLabel"; 15 | import Checkbox from "@material-ui/core/Checkbox"; 16 | import MenuItem from "@material-ui/core/MenuItem"; 17 | import FormControl from "@material-ui/core/FormControl"; 18 | import Select from "@material-ui/core/Select"; 19 | import Back from "./common/Back"; 20 | 21 | const qs = require("query-string"); 22 | const backgroundShape = require("../images/shape.svg"); 23 | 24 | const numeral = require("numeral"); 25 | numeral.defaultFormat("0,000"); 26 | 27 | const styles = theme => ({ 28 | root: { 29 | flexGrow: 1, 30 | backgroundColor: theme.palette.primary["A100"], 31 | overflow: "hidden", 32 | background: `url(${backgroundShape}) no-repeat`, 33 | backgroundSize: "cover", 34 | backgroundPosition: "0 400px", 35 | marginTop: 10, 36 | padding: 20, 37 | paddingBottom: 200 38 | }, 39 | grid: { 40 | margin: `0 ${theme.spacing(2)}px` 41 | }, 42 | smallContainer: { 43 | width: "60%" 44 | }, 45 | bigContainer: { 46 | width: "80%" 47 | }, 48 | stepContainer: { 49 | display: "flex", 50 | flexDirection: "column", 51 | alignItems: "center" 52 | }, 53 | stepGrid: { 54 | width: "80%" 55 | }, 56 | backButton: { 57 | marginRight: theme.spacing(1) 58 | }, 59 | outlinedButtom: { 60 | textTransform: "uppercase", 61 | margin: theme.spacing(1) 62 | }, 63 | stepper: { 64 | backgroundColor: "transparent" 65 | }, 66 | paper: { 67 | padding: theme.spacing(3), 68 | textAlign: "left", 69 | color: theme.palette.text.secondary 70 | }, 71 | topInfo: { 72 | display: "flex", 73 | justifyContent: "space-between", 74 | alignItems: "center", 75 | marginBottom: 42 76 | }, 77 | formControl: { 78 | width: "100%" 79 | }, 80 | selectEmpty: { 81 | marginTop: theme.spacing(2) 82 | }, 83 | borderColumn: { 84 | borderBottom: `1px solid ${theme.palette.grey["100"]}`, 85 | paddingBottom: 24, 86 | marginBottom: 24 87 | }, 88 | flexBar: { 89 | marginTop: 32, 90 | display: "flex", 91 | justifyContent: "center" 92 | } 93 | }); 94 | 95 | const getSteps = () => { 96 | return ["Info", "Bank", "Loan details", "Terms", "Confirm", "Done"]; 97 | }; 98 | 99 | class Wizard extends Component { 100 | state = { 101 | activeStep: 0, 102 | receivingAccount: "Home Account", 103 | repaimentAccount: "Saving Account", 104 | termsChecked: false, 105 | labelWidth: 0 106 | }; 107 | 108 | componentDidMount() {} 109 | 110 | handleNext = () => { 111 | this.setState(state => ({ 112 | activeStep: state.activeStep + 1 113 | })); 114 | }; 115 | 116 | handleBack = () => { 117 | this.setState(state => ({ 118 | activeStep: state.activeStep - 1 119 | })); 120 | }; 121 | 122 | handleReset = () => { 123 | this.setState({ 124 | activeStep: 0 125 | }); 126 | }; 127 | 128 | handleChange = event => { 129 | this.setState({ [event.target.name]: event.target.value }); 130 | }; 131 | 132 | handleTerms = event => { 133 | this.setState({ termsChecked: event.target.checked }); 134 | }; 135 | 136 | stepActions() { 137 | if (this.state.activeStep === 3) { 138 | return "Accept"; 139 | } 140 | if (this.state.activeStep === 4) { 141 | return "Send"; 142 | } 143 | if (this.state.activeStep === 5) { 144 | return "Done"; 145 | } 146 | return "Next"; 147 | } 148 | 149 | goToDashboard = event => { 150 | const queryString = this.props.location.search; 151 | 152 | this.props.history.push({ 153 | pathname: "/dashboard", 154 | search: queryString 155 | }); 156 | }; 157 | 158 | render() { 159 | const { classes } = this.props; 160 | const queryString = this.props.location.search; 161 | const parsed = queryString ? qs.parse(queryString) : {}; 162 | const steps = getSteps(); 163 | const { activeStep } = this.state; 164 | 165 | return ( 166 | 167 | 168 |
169 | 170 | 177 | 178 | 179 |
180 |
181 | 186 | {steps.map(label => { 187 | return ( 188 | 189 | {label} 190 | 191 | ); 192 | })} 193 | 194 |
195 | {activeStep === 0 && ( 196 |
197 | 198 |
199 |
200 | 205 | Information 206 | 207 | 208 | General information about the service 209 | 210 |
211 |
212 | 219 |
220 |
221 | 222 | 223 | 228 | User 229 | 230 | 231 | John Doe 232 | 233 | 234 | 235 | 240 | City 241 | 242 | 243 | Tokyo 244 | 245 | 246 | 247 |
248 |
249 | )} 250 | {activeStep === 1 && ( 251 |
252 | 253 |
254 |
255 | 260 | Bank information 261 | 262 | 263 | Select account to receive the money 264 | 265 |
266 |
267 | 272 | Bank 273 | 274 | 275 | N26 276 | 277 |
278 |
279 | 287 | Receiving account 288 | 289 | 293 | 316 | 317 |
318 |
319 |
320 |
321 | )} 322 | {activeStep === 2 && ( 323 |
324 | 325 |
326 |
327 | 332 | Details 333 | 334 | 335 | We need some details about any information 336 | 337 |
338 |
339 | 346 |
347 |
348 |
349 | 355 | 356 | 361 | Amount 362 | 363 | 364 | {parsed 365 | ? numeral(parsed.amount).format() 366 | : "75,000"}{" "} 367 | DKK 368 | 369 | 370 | 371 | 376 | Total fees 377 | 378 | 379 | 0 DKK 380 | 381 | 382 | 383 | 384 | 385 | 390 | Total price 391 | 392 | 393 | {parsed 394 | ? numeral(parsed.interest).format() 395 | : "6,600"}{" "} 396 | USD 397 | 398 | 399 | 400 | 405 | Total cost 406 | 407 | 408 | {parsed 409 | ? numeral(parsed.cost).format() 410 | : "81,600"}{" "} 411 | USD 412 | 413 | 414 | 415 |
416 | 417 | 423 | 424 | 429 | How often 430 | 431 | 432 | Once a month 433 | 434 | 435 | 436 | 437 | 442 | When to start 443 | 444 | 445 | 01 February 2019 446 | 447 | 448 | 449 | 454 | When it ends? 455 | 456 | 457 | 01 May 2019 458 | 459 | 460 | 461 | 462 | 463 | 471 | Destination account 472 | 473 | 477 | 500 | 501 | 502 | 503 |
504 |
505 | )} 506 | {activeStep === 3 && ( 507 |
508 | 509 |
510 | 515 | Terms & Conditions 516 | 517 | 518 | Please read through and accept the terms & 519 | conditions 520 | 521 |
522 |
531 | 536 | 1. Your agreement 537 | 538 | 539 | By using this Site, you agree to be bound by, and to 540 | comply with, these Terms and Conditions. If you do 541 | not agree to these Terms and Conditions, please do 542 | not use this site. PLEASE NOTE: We reserve the 543 | right, at our sole discretion, to change, modify or 544 | otherwise alter these Terms and Conditions at any 545 | time. Unless otherwise indicated, amendments will 546 | become effective immediately. Please review these 547 | Terms and Conditions periodically. Your continued 548 | use of the Site following the posting of changes 549 | and/or modifications will constitute your acceptance 550 | of the revised Terms and Conditions and the 551 | reasonableness of these standards for notice of 552 | changes. For your information, this page was last 553 | updated as of the date at the top of these terms and 554 | conditions. 555 | 556 | 561 | 2. Privacy 562 | 563 | 564 | Please review our Privacy Policy, which also governs 565 | your visit to this Site, to understand our 566 | practices. By using this Site, you agree to be bound 567 | by, and to comply with, these Terms and Conditions. 568 | If you do not agree to these Terms and Conditions, 569 | please do not use this site. PLEASE NOTE: We reserve 570 | the right, at our sole discretion, to change, modify 571 | or otherwise alter these Terms and Conditions at any 572 | time. Unless otherwise indicated, amendments will 573 | become effective immediately. Please review these 574 | Terms and Conditions periodically. Your continued 575 | use of the Site following the posting of changes 576 | and/or modifications will constitute your acceptance 577 | of the revised Terms and Conditions and the 578 | reasonableness of these standards for notice of 579 | changes. For your information, this page was last 580 | updated as of the date at the top of these terms and 581 | conditions. 582 | 583 |
584 | 585 | 592 | } 593 | label="I have read and understood the terms & conditions" 594 | /> 595 | 596 |
597 |
598 | )} 599 | {activeStep === 4 && ( 600 |
601 | 602 | 603 | 604 | 609 | Sign & confirm 610 | 611 | 612 | Sign and confirm your agreement 613 | 614 | 615 | 616 | 617 |
618 | )} 619 | {(activeStep === 5 || activeStep === 6) && ( 620 |
621 | 622 | 623 | 624 | 625 | Congratulations{" "} 626 | 627 | 🎉 628 | 629 | 630 | 631 | We have now a positive response 632 | 633 | 636 | 637 | 638 | 639 |
640 | )} 641 |
642 | {activeStep !== 5 && ( 643 | 651 | )} 652 | 665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 | ); 673 | } 674 | } 675 | 676 | export default withRouter(withStyles(styles)(Wizard)); 677 | --------------------------------------------------------------------------------