diff --git a/frontend/src/App.js b/frontend/src/App.js index ad122e1a0ac6267270627a506d2a88c5cb47f059..0e3278bf44ca9939f38a5ca24417822a49331048 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -6,6 +6,7 @@ import Users from './containers/Users.container'; import SignUp from './containers/SignUp.container'; import Login from './containers/Login.container'; import Profile from './containers/Profile.container'; +import Bank from './containers/Bank.container'; import { Navbar, Nav } from 'react-bootstrap'; import {userService} from "./services/authentication.service"; import * as loginActions from './actions/Login.actions'; @@ -54,6 +55,11 @@ class App extends Component { Profile </Nav.Link> } + { this.props.loginState.loggedIn && + <Nav.Link as={Link} to="/bank/"> + Bank + </Nav.Link> + } { this.props.loginState.loggedIn && <Nav.Link as={Link} to="/" onClick={(e) => {e.preventDefault(); this.props.logoutRequest()}} > Log out @@ -74,6 +80,7 @@ class App extends Component { <Route path="/signup/" component={SignUp} /> <Route path="/login/" component={Login} /> <PrivateRoute path="/profile/" component={Profile} /> + <PrivateRoute path="/bank/" component={Bank} /> </div> </Router> ); diff --git a/frontend/src/actions/Bank.actions.js b/frontend/src/actions/Bank.actions.js new file mode 100644 index 0000000000000000000000000000000000000000..f33ffc44b9489e134ec9a0b971743bc9dc4eedb0 --- /dev/null +++ b/frontend/src/actions/Bank.actions.js @@ -0,0 +1,83 @@ +import {userService} from "../services/authentication.service"; + +export const profileDataFetchSuccess = (data) => { + return { + type:'PROFILE_DATA_REQ_SUCCESS', + data + } +} + +export const profileDataFetchFailure = () => { + return { + type:'PROFILE_DATA_REQ_FAILURE' + } +} + +export const updateUserSuccess = () => { + return { + type:'UPDATE_USER_SUCCESS', + } +} + +export const updateUserFailure = (error) => { + return { + type:'UPDATE_USER_FAILURE', + message:error, + } +} + +export const fetchUserData = () => { + return async (dispatch) => { + const response = await fetch( "/api/me", { + method: 'GET', + headers: { + 'Authorization': userService.getToken() + } + }) + + if(response.ok){ + response.json().then(data => { + console.log(data); + dispatch(profileDataFetchSuccess(data)); + }).catch(err => dispatch(profileDataFetchFailure(err))); + } + else{ + response.json().then(error => { + dispatch(profileDataFetchFailure(error)); + }).catch(err => dispatch(profileDataFetchFailure(err))); + } + + return response; + } +} + +export const changeUserData = (data) => { + return async (dispatch) => { + const response = await fetch( "/api/me/update", { + method: 'POST', + headers: { + 'Authorization': userService.getToken(), + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data), + }) + + if(response.ok){ + dispatch(updateUserSuccess()); + } + else{ + response.json().then(error => { + dispatch(updateUserFailure(error)); + }).catch(err => dispatch(updateUserFailure(err))); + } + + return response; + } +} + +export const reinitializeState = () => { + return { + type:'REINITIALIZE_STATE' + } +} diff --git a/frontend/src/containers/Bank.container.js b/frontend/src/containers/Bank.container.js new file mode 100644 index 0000000000000000000000000000000000000000..778d36e66301f6f52fb20dcecace1515413bcbf9 --- /dev/null +++ b/frontend/src/containers/Bank.container.js @@ -0,0 +1,108 @@ +import { connect } from 'react-redux'; +import React from 'react'; +import logo from '../icons/transaction.png'; +import { withRouter } from 'react-router-dom' +import { Table, Accordion, Button, Card, Image, Container, Row, Col } from "react-bootstrap"; +import * as bankActions from "../actions/Bank.actions"; + +export class Bank extends React.Component { + + constructor(props) { + super(props); + + this.state = { + readOnly: true + }; + + this.switchToEditionMode = this.switchToEditionMode.bind(this); + } + + componentWillMount(){ + this.props.fetchUserData(); + this.props.reinitializeState(); + } + + componentDidUpdate(prevProps) { + if (prevProps.state !== this.props.state) { + this.setState({ + readOnly: this.props.state.updateUserSuccess + }); + } + } + + handleChange = event => { + this.setState({ + [event.target.id]: event.target.value, + }); + } + + switchToEditionMode() { + this.setState({ + readOnly: false + }); + } + + changeUserData() { + this.props.changeUserData(this.state); + } + + + render() { + return ( + <Row style={{ width: '95%', margin: '0 auto', marginTop:'30px' }}> + <Col xs lg="4"> + <Card style={{ width: '100%', margin: '0 auto', marginTop:'30px' }}> + <Card.Body> + <Card.Title>Balance</Card.Title> + </Card.Body> + </Card> + </Col> + <Col> + <Card style={{ width: '100%', margin: '0 auto', marginTop:'30px' }}> + <Card.Body> + <Card.Title>Transactions</Card.Title> + <Table hover> + <tbody> + <tr> + <td><Image src={logo} width={30} height={30} /></td> + <td colSpan="2">29/09/2021</td> + <td>-8€</td> + </tr> + <tr> + <td><Image src={logo} width={30} height={30} /></td> + <td colSpan="2">29/09/2021</td> + <td>-8€</td> + </tr> + <tr> + <td><Image src={logo} width={30} height={30} /></td> + <td colSpan="2">29/09/2021</td> + <td>-8€</td> + </tr> + </tbody> + </Table> + </Card.Body> + </Card> + </Col> + {this.props.state.updateUserError && <div><br/>{JSON.stringify(this.props.state.updateUserErrorMessage.message)}</div>} + {this.props.state.updateUserSuccess && <div><br/>Success! You can now use your new password.</div>} + </Row> + ); + } +} + +// map state from store to props +const mapStateToProps = (state) => { + return { + state: state.profile + } +} +// map actions to props +const mapDispatchToProps = (dispatch) => { + return { + fetchUserData: () => dispatch(bankActions.fetchUserData()), + changeUserData: (data) => dispatch(bankActions.changeUserData(data)), + reinitializeState: () => dispatch(bankActions.reinitializeState()), + } +} + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Bank)) diff --git a/frontend/src/containers/Profile.container.js b/frontend/src/containers/Profile.container.js index 4a2dcd2e079f155173118939b5d754dd51f2960e..22cd54001c79de6818c1fc87308a71cccde2d4a4 100644 --- a/frontend/src/containers/Profile.container.js +++ b/frontend/src/containers/Profile.container.js @@ -13,7 +13,7 @@ export class Profile extends React.Component { readOnly: true }; - this.switchEditionMode = this.switchEditionMode.bind(this); + this.switchToEditionMode = this.switchToEditionMode.bind(this); } componentWillMount(){ @@ -21,25 +21,28 @@ export class Profile extends React.Component { this.props.reinitializeState(); } + componentDidUpdate(prevProps) { + if (prevProps.state !== this.props.state) { + this.setState({ + readOnly: this.props.state.updateUserSuccess + }); + } + } + handleChange = event => { this.setState({ [event.target.id]: event.target.value, }); } - switchEditionMode() { - this.setState(prevState => ({ - readOnly: !prevState.readOnly - })); + switchToEditionMode() { + this.setState({ + readOnly: false + }); } changeUserData() { this.props.changeUserData(this.state); - if(this.props.state.updateUserSuccess){ - this.setState({ - readOnly: true - }); - } } @@ -152,10 +155,10 @@ export class Profile extends React.Component { Save </Button> } - { this.state.readOnly && + { this.state.readOnly && <Button block - onClick={this.switchEditionMode} + onClick={this.switchToEditionMode} variant="primary" > Edit @@ -163,7 +166,7 @@ export class Profile extends React.Component { } </Form> {this.props.state.updateUserError && <div><br/>{JSON.stringify(this.props.state.updateUserErrorMessage.message)}</div>} - {this.props.state.updateUserSuccess && <div><br/>Success! You can now use your new password.</div>} + {this.props.state.updateUserSuccess && <div><br/>Profile changed with success.</div>} </Card.Body> </Card> ); diff --git a/frontend/src/containers/Users.container.js b/frontend/src/containers/Users.container.js index e9a68d7463193a9ed3ee370e6474371752482acb..1785e18413592ea24585c7aa1eaba31f802d9602 100644 --- a/frontend/src/containers/Users.container.js +++ b/frontend/src/containers/Users.container.js @@ -23,8 +23,6 @@ export class Users extends React.Component { <thead> <tr> <td>Username</td> - <td># likes</td> - { this.props.loginState.loggedIn && <td></td> } </tr> </thead> <tbody> diff --git a/frontend/src/icons/transaction.png b/frontend/src/icons/transaction.png new file mode 100644 index 0000000000000000000000000000000000000000..7782275daf26875be6d85341f96eb12fcd7e0699 Binary files /dev/null and b/frontend/src/icons/transaction.png differ diff --git a/frontend/src/reducers/Bank.reducer.js b/frontend/src/reducers/Bank.reducer.js new file mode 100644 index 0000000000000000000000000000000000000000..b3f1b31c9ce96ed3936715b6f3e51609c81e15a0 --- /dev/null +++ b/frontend/src/reducers/Bank.reducer.js @@ -0,0 +1,27 @@ +const INITIAL_STATE = { + me: {}, + updateUserError: false, + updateUserErrorMessage: {}, + updateUserSuccess: false, + loading: false, + profileDataError: false, +} + +const forgotpasswordReducer = (currentState = INITIAL_STATE, action) => { + switch (action.type) { + case 'REINITIALIZE_STATE': + return {...currentState, updateUserError: false, updateUserErrorMessage: {}, loading:false, updateUserSuccess:false}; + case 'PROFILE_DATA_REQ_SUCCESS': + return {...currentState, me:action.data}; + case 'PROFILE_DATA_REQ_FAILURE': + return {...currentState, profileDataError: true}; + case 'UPDATE_USER_FAILURE': + return {...currentState, updateUserError:true, updateUserErrorMessage:action.message, loading: false, updateUserSuccess:false}; + case 'UPDATE_USER_SUCCESS': + return {...currentState, updateUserError:false, updateUserErrorMessage:{}, updateUserSuccess: true, loading: false}; + default: + return currentState; + } +} + +export default forgotpasswordReducer;