diff --git a/src/front/component/App.jsx b/src/front/component/App.jsx
index ac741af..bcc1ec2 100644
--- a/src/front/component/App.jsx
+++ b/src/front/component/App.jsx
@@ -1,52 +1,188 @@
+/* eslint-disable react/forbid-prop-types */
import * as React from 'react';
-import { BrowserRouter as Router } from "react-router-dom";
-
+import { withRouter } from "react-router-dom";
+import PropTypes from 'prop-types'; // ES6
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
+import ButtonGroup from '@material-ui/core/ButtonGroup';
+import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
+import ClickAwayListener from '@material-ui/core/ClickAwayListener';
+import Grow from '@material-ui/core/Grow';
+import Paper from '@material-ui/core/Paper';
+import Popper from '@material-ui/core/Popper';
+import MenuItem from '@material-ui/core/MenuItem';
+import MenuList from '@material-ui/core/MenuList';
+
+import IconButton from '@material-ui/core/IconButton';
+import ArrowBack from '@material-ui/icons/ArrowBack';
+
import { logout, connectedState } from '../services/auth';
import Routes from "./Router";
+const options = ['Documentation','My Profile'];
+
class App extends React.PureComponent {
constructor() {
super();
- this.state = {userConnected : false};
+ this.state = {
+ canBack: false,
+ userConnected : false,
+ anchorRef: {current: null},
+ selectedIndex: 0,
+ open: false
+ };
}
componentDidMount() {
+ const { history } = this.props;
+ if (history.location.pathname !== '/home' && history.location.pathname !== '/') {
+ this.setState({canBack: true});
+ }
+ history.listen((location) => {
+ if (location.pathname !== '/home' && location.pathname !== '/') {
+ this.setState({canBack: true});
+ } else {
+ this.setState({canBack: false});
+ }
+ });
+
+
connectedState.subscribe((userConnected) => {
+ if(!userConnected) {
+ history.push('/');
+ }
this.setState({userConnected});
+ });
+
+ }
+
+ async handleMenuItemClick(event, index) {
+ const { history } = this.props;
+ if (index === 1) {
+ history.push('/profile')
+ }
+
+ this.handleToggle()
+
+ }
+
+ handleToggle() {
+ const { open } = this.state;
+ this.setState({
+ open: !open
})
}
+ handleClose(event) {
+ const { anchorRef } = this.state;
+ if (anchorRef.current && anchorRef.current.contains(event.target)) {
+ return;
+ }
+
+ this.setState({
+ open: false
+ })
+ }
+
+ goBack() {
+ const { history } = this.props;
+ history.goBack();
+ }
+
+
render() {
- const { userConnected } = this.state;
+ const { userConnected, anchorRef, selectedIndex, open, canBack } = this.state;
return (
+ {canBack && (
+ {this.goBack()}}
+ >
+
+
+ )}
+
Connect
- {userConnected && }
-
+ {userConnected &&
+ (
+ <>
+
+
+
+
+
+ {({ TransitionProps, placement }) => (
+
+
+
+ )}
+
+ >
+ )
+ }
-
-
-
+
);
}
}
-export default App;
+App.propTypes = {
+ history: PropTypes.instanceOf(Object).isRequired,
+};
+
+
+
+export default withRouter(App);
diff --git a/src/front/component/Router.jsx b/src/front/component/Router.jsx
index 2a94226..e20d4d9 100644
--- a/src/front/component/Router.jsx
+++ b/src/front/component/Router.jsx
@@ -5,6 +5,7 @@ import LoginPage from '../pages/login/login';
import Github from '../pages/login/github';
import HomePage from '../pages/home/home';
import DetailsPage from '../pages/details/details';
+import ProfilePage from '../pages/profile/profile';
export const ROUTES = {
HOME: '/',
@@ -28,6 +29,12 @@ class Routes extends React.PureComponent {
component={DetailsPage}
/>
+
+
-
-
>
);
}
diff --git a/src/front/index.jsx b/src/front/index.jsx
index b217674..f715198 100644
--- a/src/front/index.jsx
+++ b/src/front/index.jsx
@@ -1,8 +1,10 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
+import { BrowserRouter } from "react-router-dom";
+
import App from './component/App';
import './index.css';
import registerServiceWorker from './registerServiceWorker';
-ReactDOM.render(, document.getElementById('root'));
+ReactDOM.render(, document.getElementById('root'));
registerServiceWorker();
diff --git a/src/front/pages/details/details.jsx b/src/front/pages/details/details.jsx
index 88dc339..de6bc72 100644
--- a/src/front/pages/details/details.jsx
+++ b/src/front/pages/details/details.jsx
@@ -1,13 +1,19 @@
-/* eslint-disable react/forbid-prop-types */
+/* eslint-disable no-underscore-dangle */
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
import CircularProgress from '@material-ui/core/CircularProgress';
-
+import Button from '@material-ui/core/Button';
+import { green } from '@material-ui/core/colors';
+import InputAdornment from '@material-ui/core/InputAdornment';
+import IconButton from '@material-ui/core/IconButton';
+import FileCopy from '@material-ui/icons/FileCopy';
import PropTypes from 'prop-types'; // ES6
+import Snackbar from '@material-ui/core/Snackbar';
-import { getApplication } from '../../services/api';
+import { getApplication, updateApplication } from '../../services/api';
+import { validateFormField, checkValid } from '../../services/formValidator';
const styles = {
@@ -17,6 +23,7 @@ const styles = {
margin: "0 auto",
display: 'flex',
flexWrap: 'wrap',
+ "margin-top": 16
},
progress: {
margin: "0 auto",
@@ -27,7 +34,30 @@ const styles = {
},
textField: {
margin: 16
- }
+ },
+ button: {
+ margin: 8,
+ width: 120
+ },
+ buttonContainer: {
+ display: "flex",
+ width: "100%",
+ "justify-content": "flex-end",
+ },
+ buttonProgress: {
+ color: green[500],
+ position: 'absolute',
+ top: '50%',
+ left: '50%',
+ marginTop: -12,
+ marginLeft: -12,
+ },
+ wrapper: {
+ margin: 0,
+ position: 'relative',
+ },
+
+
};
@@ -36,15 +66,14 @@ class DetailsPage extends React.PureComponent {
super();
this.state = {
loading: true,
- application: {
- name: "Name",
- description: "Description",
- token: "token",
- token_sandbox: "token sandbox",
- apple_store_link: "http://apple",
- google_market_link: "http://google",
- create_at: new Date(),
- updated_at: new Date(),
+ updateLoading: false,
+ application: {},
+ snackBarOpen: false,
+ errors: {
+ name: false,
+ description: false,
+ apple_store_link: false,
+ google_market_link: false,
}
}
}
@@ -52,26 +81,80 @@ class DetailsPage extends React.PureComponent {
componentDidMount() {
const { match } = this.props;
getApplication(match.params.appId).then((res) => {
- this.setState({
- loading: false,
- application: res
+ this.setState((prevState) => {
+ return {
+ ...prevState,
+ loading: false,
+ application: res
+ }
});
});
}
handleChange(name, event) {
- const { application } = this.state;
+ const { application, errors } = this.state;
+ const { value } = event.target;
+
+ const validated = validateFormField(value, name);
this.setState({
application: {
...application,
- [name]: event.target.value
- }
+ [name]: value
+ },
+ errors: {
+ ...errors,
+ [name]: !validated
+ }
+ });
+ }
+
+ handleClick() {
+ this.setState({
+ snackBarOpen: true
+ });
+ }
+
+ handleClose(event, reason) {
+ if (reason === 'clickaway') {
+ return;
+ }
+
+ this.setState({
+ snackBarOpen: false
+ });
+ }
+
+
+ goBack() {
+ const { history } = this.props;
+ history.goBack();
+ }
+
+ async clickUpdateApplication() {
+ const { application } = this.state;
+ this.setState({
+ updateLoading: true
+ })
+ const response = await updateApplication(application._id, application);
+ this.setState({
+ updateLoading: false,
+ application: response
+ })
+ }
+
+ copyToClipboard(key) {
+ const { application } = this.state;
+ navigator.permissions.query({name: "clipboard-write"}).then(result => {
+ if (result.state === "granted" || result.state === "prompt") {
+ navigator.clipboard.writeText(application[key]);
+ this.setState({snackBarOpen: true});
+ }
});
}
render() {
const { classes } = this.props;
- const { application, loading } = this.state;
+ const { application, errors, loading, updateLoading, snackBarOpen } = this.state;
return (
<>
@@ -89,6 +172,7 @@ class DetailsPage extends React.PureComponent {
onChange={(event) => this.handleChange('name', event)}
margin="normal"
variant="outlined"
+ error={errors.name}
/>
@@ -102,55 +186,99 @@ class DetailsPage extends React.PureComponent {
margin="normal"
variant="outlined"
multiline
- rows="4"
+ rows="4"
+ error={errors.name}
/>
this.handleChange('token', event)}
+ value={application.apple_store_link || ''}
+ onChange={(event) => this.handleChange('apple_store_link', event)}
margin="normal"
variant="outlined"
+ error={errors.apple_store_link}
/>
-
this.handleChange('token_sandbox', event)}
+ value={application.google_market_link || ''}
+ onChange={(event) => this.handleChange('google_market_link', event)}
margin="normal"
variant="outlined"
+ error={errors.google_market_link}
/>
+
+
+
+ {updateLoading && }
+
+
+
this.handleChange('apple_store_link', event)}
+ value={application.token}
margin="normal"
variant="outlined"
+ InputProps={{
+ endAdornment: (
+
+ {this.copyToClipboard('token')}}>
+
+
+
+ )
+ }}
/>
this.handleChange('google_market_link', event)}
+ value={application.token_sandbox}
margin="normal"
variant="outlined"
+ InputProps={{
+ endAdornment: (
+
+ {this.copyToClipboard('token_sandbox')}}>
+
+
+
+ )
+ }}
+ />
+
+ {this.handleClose()}}
+ message={Copied!}
/>
>
@@ -164,9 +292,9 @@ class DetailsPage extends React.PureComponent {
}
DetailsPage.propTypes = {
- classes: PropTypes.object.isRequired,
- // history: PropTypes.object.isRequired,
- match: PropTypes.object.isRequired
+ classes: PropTypes.instanceOf(Object).isRequired,
+ history: PropTypes.instanceOf(Object).isRequired,
+ match: PropTypes.instanceOf(Object).isRequired
};
diff --git a/src/front/pages/home/home.jsx b/src/front/pages/home/home.jsx
index ae6804e..242f914 100644
--- a/src/front/pages/home/home.jsx
+++ b/src/front/pages/home/home.jsx
@@ -1,5 +1,4 @@
/* eslint-disable no-underscore-dangle */
-/* eslint-disable react/forbid-prop-types */
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import { withStyles } from '@material-ui/core/styles';
@@ -10,8 +9,8 @@ import ListItemText from '@material-ui/core/ListItemText';
import Typography from '@material-ui/core/Typography';
import CircularProgress from '@material-ui/core/CircularProgress';
import Fab from '@material-ui/core/Fab';
-import IconButton from '@material-ui/core/IconButton';
import AddIcon from '@material-ui/icons/Add';
+import DeveloperModeIcon from '@material-ui/icons/DeveloperMode';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
@@ -20,12 +19,16 @@ import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
+import Card from '@material-ui/core/Card';
+import CardActions from '@material-ui/core/CardActions';
+import CardContent from '@material-ui/core/CardContent';
import Moment from 'react-moment';
import PropTypes from 'prop-types'; // ES6
import { listOfApplications, createApplication } from '../../services/api';
+import { validateFormField, checkValid } from '../../services/formValidator';
const styles = {
@@ -55,6 +58,12 @@ const styles = {
marginRight: 16,
},
+ card: {
+ maxWidth: 720,
+ margin: "0 auto",
+ marginTop: 120
+ }
+
};
@@ -70,6 +79,12 @@ class HomePage extends React.PureComponent {
description: '',
apple_store_link: '',
google_market_link: ''
+ },
+ errors: {
+ name: false,
+ description: false,
+ apple_store_link: false,
+ google_market_link: false,
}
}
}
@@ -102,17 +117,32 @@ class HomePage extends React.PureComponent {
description: '',
apple_store_link: '',
google_market_link: ''
+ },
+ errors: {
+ name: false,
+ description: false,
+ apple_store_link: false,
+ google_market_link: false,
}
});
}
+
+
handleChange(name, event) {
- const { newApplication } = this.state;
+ const { newApplication, errors } = this.state;
+ const { value } = event.target;
+
+ const validated = validateFormField(value, name);
this.setState({
newApplication: {
...newApplication,
- [name]: event.target.value
- }
+ [name]: value
+ },
+ errors: {
+ ...errors,
+ [name]: !validated
+ }
});
}
@@ -127,7 +157,7 @@ class HomePage extends React.PureComponent {
render() {
const { classes } = this.props;
- const { developerApplications, loading, dialogNewApplicationOpen, newApplication } = this.state;
+ const { developerApplications, loading, dialogNewApplicationOpen, newApplication, errors } = this.state;
return (
<>
@@ -166,6 +196,27 @@ class HomePage extends React.PureComponent {
}
+ {
+ developerApplications.length === 0 && !loading &&
+ (
+
+
+
+
+ {" "} Welcome
+
+
+ Add your first application with the bottom right button.
+
+
+
+
+
+
+
+ )
+ }
+
this.handleChange('name', event)}
margin="normal"
variant="outlined"
+ error={errors.name}
/>
@@ -210,7 +262,8 @@ class HomePage extends React.PureComponent {
margin="normal"
variant="outlined"
multiline
- rows="4"
+ rows="4"
+ error={errors.description}
/>
this.handleChange('apple_store_link', event)}
margin="normal"
variant="outlined"
+ error={errors.apple_store_link}
/>
@@ -234,6 +288,7 @@ class HomePage extends React.PureComponent {
onChange={(event) => this.handleChange('google_market_link', event)}
margin="normal"
variant="outlined"
+ error={errors.google_market_link}
/>
@@ -241,7 +296,7 @@ class HomePage extends React.PureComponent {
-