From 3d6774108020e8527e923b46b38777daff1b5f66 Mon Sep 17 00:00:00 2001 From: Steven Ding Date: Tue, 16 Oct 2018 00:20:04 +1100 Subject: [PATCH 01/10] Enable multi-lines description and cover url when add a book --- client/src/Admin/BookManage.jsx | 49 +++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/client/src/Admin/BookManage.jsx b/client/src/Admin/BookManage.jsx index 787a954..a7b23aa 100644 --- a/client/src/Admin/BookManage.jsx +++ b/client/src/Admin/BookManage.jsx @@ -239,7 +239,8 @@ class BookManage extends React.Component { newTitle: "YOU ARE IN DEBUG MODE", newAuthors: ["name"], newDescription: "New Description", - newPublishDate: "7 21 2018" + newPublishDate: "7 21 2018", + newCoverURL: 'https://images-na.ssl-images-amazon.com/images/I/41iYksBR8BL._SX358_BO1,204,203,200_.jpg' }); } this.setState({ open: true }); @@ -425,9 +426,8 @@ class BookManage extends React.Component { - - this.setState({newDescription: e.target.value}) } - error={newBookError.hasOwnProperty('description')} - helperText={newBookError.hasOwnProperty('description') ? newBookError.description : ""} - /> - + + this.setState({newDescription: e.target.value}) } + error={newBookError.hasOwnProperty('description')} + helperText={newBookError.hasOwnProperty('description') ? newBookError.description : ""} + /> + + + + + this.setState({newCoverURL: e.target.value}) } + error={newBookError.hasOwnProperty('description')} + helperText={newBookError.hasOwnProperty('coverUrl') ? newBookError.description : ""} + /> + From 1eee141f8257dc4d3b03fe3182149d4ec0f461a0 Mon Sep 17 00:00:00 2001 From: "jennyhu19900914@gmail.com" Date: Thu, 18 Oct 2018 20:54:35 +1100 Subject: [PATCH 02/10] Fix html code style of HTML Account , login and register page --- .../account/containers/Account/AccountTab.jsx | 9 +- .../containers/Account/MyBookLists.jsx | 84 ++++++++++++------- .../src/account/containers/Account/index.jsx | 26 ++++-- .../containers/AvatarUploader/index.jsx | 28 ++++--- .../account/containers/EmailSent/index.jsx | 15 +++- .../account/containers/LoginForm/index.jsx | 47 ++++++----- .../src/account/containers/Register/index.jsx | 50 +++++------ 7 files changed, 158 insertions(+), 101 deletions(-) diff --git a/client/src/account/containers/Account/AccountTab.jsx b/client/src/account/containers/Account/AccountTab.jsx index 33759af..f743666 100644 --- a/client/src/account/containers/Account/AccountTab.jsx +++ b/client/src/account/containers/Account/AccountTab.jsx @@ -28,7 +28,10 @@ const styles = theme => ({ function TabContainer(props) { return ( - + {props.children} ); @@ -56,13 +59,9 @@ class AccountTab extends React.Component { - {/**/} - {/**/} - {/**/} {value === 0 && } - {/*{value === 1 && }*/} ); } diff --git a/client/src/account/containers/Account/MyBookLists.jsx b/client/src/account/containers/Account/MyBookLists.jsx index 2665674..76d66c3 100644 --- a/client/src/account/containers/Account/MyBookLists.jsx +++ b/client/src/account/containers/Account/MyBookLists.jsx @@ -17,6 +17,7 @@ const styles = theme => ({ buttonWrapper: { position: 'relative', marginBottom: theme.spacing.unit * 4, + paddingTop:'20px' }, checked: {}, @@ -25,6 +26,8 @@ const styles = theme => ({ }, card: { minWidth: 275, + marginTop:'10px', + backgroundColor:'#FAFAFA', }, title: { marginBottom: 16, @@ -47,12 +50,26 @@ const styles = theme => ({ }, paper: { position: 'absolute', - width: theme.spacing.unit * 50, backgroundColor: theme.palette.background.paper, boxShadow: theme.shadows[5], padding: theme.spacing.unit * 4, + top:'26%', + left:'30%', + width:'44%', + height:'31%', + }, + addButton: { + outline:'none', + backgroundColor:'#3D5AFE', + color:'#fff', + width:'170px', + height:'40px', + }, + titleStyle: { + display:'inline', + fontSize:'18px', + paddingBottom:'0', }, - }); @@ -111,67 +128,70 @@ class MyBookLists extends React.Component { const { classes } = this.props; return ( -
- - +
+ + -
- +
+ Create a new book list - +
this.title = title} + className={classes.textField} id="BookListTitle" + required label="Title" multiline - className={classes.textField} - inputRef={title => this.title = title} - required /> this.description = description} error={this.state.isDescriptionWrong} helperText={this.state.descriptionError} - required - style={{width:'270px'}} - onKeyDown={this.onKeyDown} + type="text" />
-
@@ -183,15 +203,19 @@ class MyBookLists extends React.Component { { this.props.bookLists.map( (bookList)=>{ - return + return - + {bookList.title} - - {bookList.updateDate.substring(0,10)} + + Update Date: {bookList.updateDate.substring(0,10)} diff --git a/client/src/account/containers/Account/index.jsx b/client/src/account/containers/Account/index.jsx index 269b152..0d17629 100644 --- a/client/src/account/containers/Account/index.jsx +++ b/client/src/account/containers/Account/index.jsx @@ -26,17 +26,22 @@ const styles = { bigAvatar: { width: 160, height: 160, + backgroundColor: '#E0E0E0', }, avatarModal: { - marginTop: '150px' + marginTop: '150px', + }, + usernameStyle: { + fontSize: '24px', + fontWeight:'bold', } }; function AccountInfo(props) { - const {username} = props; + const {username, usernameStyle} = props; return (
-

{username}

+

{username}

); } @@ -78,11 +83,20 @@ class Account extends React.Component {
{avatarType === 'letter' ? : - } + }
-
diff --git a/client/src/account/containers/AvatarUploader/index.jsx b/client/src/account/containers/AvatarUploader/index.jsx index f122dfe..6fbd821 100644 --- a/client/src/account/containers/AvatarUploader/index.jsx +++ b/client/src/account/containers/AvatarUploader/index.jsx @@ -52,17 +52,25 @@ class AvatarUploader extends PureComponent {

My Avatar

- - + +
- +
) } diff --git a/client/src/account/containers/EmailSent/index.jsx b/client/src/account/containers/EmailSent/index.jsx index 1f0242d..de66087 100644 --- a/client/src/account/containers/EmailSent/index.jsx +++ b/client/src/account/containers/EmailSent/index.jsx @@ -43,10 +43,17 @@ class EmailSent extends Component { return (

Thank you for signing up!

-

We have sent an email with an activation link to your email address. In order to complete the sign-up process, please click the activation link. - If you didn't receive the activation email, click on the button below to resend it.

-
-
+

+ We have sent an email with an activation link to your email address. In order to complete the sign-up process, please click the activation link. + If you didn't receive the activation email, click on the button below to resend it. +

+
+ +
+
+ +
); } diff --git a/client/src/account/containers/LoginForm/index.jsx b/client/src/account/containers/LoginForm/index.jsx index 5a88249..2f2b800 100644 --- a/client/src/account/containers/LoginForm/index.jsx +++ b/client/src/account/containers/LoginForm/index.jsx @@ -37,7 +37,7 @@ const styles = theme => ({ fontWeight: 'normal', color: '#424242', marginTop: '40px' -}, + }, loginBtn: { width: '200px', height: '44px', @@ -131,34 +131,37 @@ class LoginForm extends Component {

Log in

-
New here?
+ +
New here?
+
) } diff --git a/client/src/account/containers/Register/index.jsx b/client/src/account/containers/Register/index.jsx index 742ed23..0cf366e 100644 --- a/client/src/account/containers/Register/index.jsx +++ b/client/src/account/containers/Register/index.jsx @@ -1,4 +1,4 @@ -import React, {Component} from 'react'; + import React, {Component} from 'react'; import {connect} from "react-redux"; import {compose} from "redux"; import {registerUser} from "../../common/actions/authActions"; @@ -86,54 +86,56 @@ class RegisterForm extends Component {

Sign up

- -
+ Create your new account + From d64ef859e6c6e3ef674ddfcc49f1cfd9140b5205 Mon Sep 17 00:00:00 2001 From: Steven Ding Date: Thu, 18 Oct 2018 21:18:38 +1100 Subject: [PATCH 03/10] Fix slug bug in book list --- client/src/BookList/BookListEditorModal.js | 74 ++++++++++++---------- client/src/BookList/actions.js | 30 ++++----- client/src/BookList/index.js | 4 +- 3 files changed, 58 insertions(+), 50 deletions(-) diff --git a/client/src/BookList/BookListEditorModal.js b/client/src/BookList/BookListEditorModal.js index ae8928f..a6a7ff2 100644 --- a/client/src/BookList/BookListEditorModal.js +++ b/client/src/BookList/BookListEditorModal.js @@ -4,8 +4,8 @@ import { withStyles } from '@material-ui/core/styles'; import Modal from '@material-ui/core/Modal'; import Button from '@material-ui/core/Button'; import TextField from '@material-ui/core/TextField'; -import swal from "sweetalert2"; -import {updateBookList} from "./actions"; +import swal from 'sweetalert2'; +import { updateBookList } from './actions'; const styles = theme => ({ @@ -22,11 +22,12 @@ class BookListEditorModal extends React.Component { constructor(props) { super(props); this.state = { - errorMsg:'', + errorMsg: '', isError: false, title: props.title, description: props.description }; + this.slug = props.slug; this.onSubmitHandle = this.onSubmitHandle.bind(this); } @@ -34,31 +35,33 @@ class BookListEditorModal extends React.Component { if (description.length < 10) { this.setState({ errorMsg: 'Too short!', - isError: true + isError: true }) } else { - this.setState({ - isError: false - }); - this.confirmUpdate(title, description, this.props.bookListId); - this.props.handleClose(); + this.setState({ + isError: false + }); + + const { bookListId: id } = this.props; + this.confirmUpdate(title, description, id, this.slug); + this.props.handleClose(); } } - confirmUpdate(title, description, id) { - swal({ - title: 'Update?', - showCancelButton: true, - confirmButtonColor: '#f50057', - cancelButtonColor: '#3f51b5', - confirmButtonText: 'Yes', - }) - .then((result) => { - if (result.value) { - updateBookList(title, description, id); - } - }) - } + confirmUpdate(title, description, id, slug) { + swal({ + title: 'Update?', + showCancelButton: true, + confirmButtonColor: '#f50057', + cancelButtonColor: '#3f51b5', + confirmButtonText: 'Yes', + }) + .then((result) => { + if (result.value) { + updateBookList(title, description, id, slug); + } + }) + } render() { const { classes } = this.props; @@ -71,7 +74,8 @@ class BookListEditorModal extends React.Component { open={!!this.props.openModal} onClose={this.props.handleClose} > -
+

Edit the book list

this.setState({title: event.target.value})} + onChange={event => this.setState({ title: event.target.value })} // inputRef={title => this.setState({title: title.value})} /> - this.setState({description: e.target.value})} - // inputRef={description => this.description = description} + onChange={e => this.setState({ description: e.target.value })} + // inputRef={description => this.description = description} helperText={this.state.errorMsg} error={this.state.isError} - /> + />
diff --git a/client/src/BookList/actions.js b/client/src/BookList/actions.js index 7202ace..2722669 100644 --- a/client/src/BookList/actions.js +++ b/client/src/BookList/actions.js @@ -1,20 +1,20 @@ -import Axios from "axios"; -import {showErrorMsgFromObject, alertDeleted, showSuccess} from '../common/utils/sweetAlert'; +import axios from "axios"; +import { showErrorMsgFromObject, alertDeleted, showSuccess } from '../common/utils/sweetAlert'; export function deleteBookList(id) { - Axios.delete(`/booklists/${id}`) - .then(() => { - alertDeleted(); - window.location = '/account'; - }) - .catch(err => showErrorMsgFromObject(err.response.data)); + axios.delete(`/booklists/${id}`) + .then(() => { + alertDeleted(); + window.location = '/account'; + }) + .catch(err => showErrorMsgFromObject(err.response.data)); } -export function updateBookList(title, description, id) { - Axios.post(`/booklists/${id}`, {title, description}) - .then((res) => { - showSuccess(); - window.location = `/booklist/${res.data.slug}`; - }) - .catch(err => showErrorMsgFromObject(err.response.data)); +export function updateBookList(title, description, id, slug) { + axios.post(`/booklists/${id}`, { title, description }) + .then(() => { + showSuccess(); + window.location = `/booklist/${slug}`; + }) + .catch(err => showErrorMsgFromObject(err.response.data)); } diff --git a/client/src/BookList/index.js b/client/src/BookList/index.js index 38f5569..fa5a0e6 100644 --- a/client/src/BookList/index.js +++ b/client/src/BookList/index.js @@ -49,13 +49,14 @@ class BookList extends React.PureComponent { bookListId: 0, openBookListEditorModal: false, }; + this.slug = this.props.match.params.slug; this.confirmDelete = this.confirmDelete.bind(this); this.handleBookListEditorModalClose = this.handleBookListEditorModalClose.bind(this); this.operationButtons = this.operationButtons.bind(this); } componentDidMount() { - this.getBooksInBookList(this.props.match.params.slug); + this.getBooksInBookList(this.slug); } getBooksInBookList(slug) { @@ -174,6 +175,7 @@ class BookList extends React.PureComponent { bookListId={bookListId} handleClose={this.handleBookListEditorModalClose} openModal={openBookListEditorModal} + slug={this.slug} />

{bookListTitle}

From b8c2428bdd6b123aeb0e0362b23945ddb1cc814c Mon Sep 17 00:00:00 2001 From: Steven Ding Date: Thu, 18 Oct 2018 21:49:10 +1100 Subject: [PATCH 04/10] Fix showing of email existed and user not found. --- client/src/account/common/reducers/errorReducer.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/account/common/reducers/errorReducer.js b/client/src/account/common/reducers/errorReducer.js index 11997fb..9b171a2 100644 --- a/client/src/account/common/reducers/errorReducer.js +++ b/client/src/account/common/reducers/errorReducer.js @@ -5,7 +5,12 @@ const initialState = {}; export default function (state = initialState, action) { switch (action.type) { case GET_ERRORS: - // use the key value in the payload directly + if(action.payload.hasOwnProperty('emailexist')) { + return { email: 'This email address is already singed up.' }; + } + if(action.payload.hasOwnProperty('usernotfound')) { + return { email: 'The email address is not signed up.' }; + } return action.payload; default: return state; From 5975c62e724bb1aaecef5fbdf13f968779d659cf Mon Sep 17 00:00:00 2001 From: "jennyhu19900914@gmail.com" Date: Thu, 18 Oct 2018 21:58:40 +1100 Subject: [PATCH 05/10] Fix html code style of HTML Admin --- client/src/Admin/AdminHome.jsx | 10 ++ client/src/Admin/BookManage.jsx | 138 ++++++++++++++++------------ client/src/Admin/CustomerManage.jsx | 24 +++-- 3 files changed, 106 insertions(+), 66 deletions(-) diff --git a/client/src/Admin/AdminHome.jsx b/client/src/Admin/AdminHome.jsx index 67ea2c7..c898a56 100644 --- a/client/src/Admin/AdminHome.jsx +++ b/client/src/Admin/AdminHome.jsx @@ -2,6 +2,16 @@ import React from 'react'; import Button from '@material-ui/core/Button'; import {Link} from 'react-router-dom'; +//wait for Ding +// const style ={ +// welcomeContent: { +// color: '#00B0FF', +// fontSize: '100px', +// marginLeft: '100px', +// marginTop: '100px' +// } +// }; + class AdminHome extends React.Component { render() { return ( diff --git a/client/src/Admin/BookManage.jsx b/client/src/Admin/BookManage.jsx index 787a954..3f2ab3b 100644 --- a/client/src/Admin/BookManage.jsx +++ b/client/src/Admin/BookManage.jsx @@ -47,8 +47,9 @@ const styles = theme => ({ display: 'none', }, root: { - width: '100%', + width: '95%', marginTop: theme.spacing.unit * 3, + marginLeft: theme.spacing.unit * 3, }, table: { minWidth: 500, @@ -67,10 +68,13 @@ const styles = theme => ({ }, paper: { position: 'absolute', - width: theme.spacing.unit * 50, backgroundColor: theme.palette.background.paper, boxShadow: theme.shadows[5], padding: theme.spacing.unit * 4, + top:'17%', + left:'23%', + width:'60%', + height:'60%', }, textField: { marginLeft: theme.spacing.unit, @@ -88,6 +92,19 @@ const styles = theme => ({ card: { minWidth: 275, }, + headerStyle: { + backgroundColor:'#C5CAE9', + color:'#1A237E', + fontSize:16, + textAlign:'Center', + }, + headerLeft: { + textAlign:'left', + backgroundColor:'#C5CAE9', + color:'#1A237E', + fontSize:16, + }, + }); // Control of the table page @@ -171,7 +188,6 @@ class BookManage extends React.Component { isbn:0 }], page: 0, - newTitle: "", newAuthors: [""], newISBN: "", @@ -182,9 +198,7 @@ class BookManage extends React.Component { newPrice: 0, newCategory: "", newBookError:{}, - rowsPerPage: 15, - open: false, deleteDialogOpen: false, expanded: null, @@ -313,34 +327,35 @@ class BookManage extends React.Component { const { classes } = this.props; const { rows, rowsPerPage, page, newBookError } = this.state; const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage); - return ( -
+ //add a new book +
-
- + +
+ New book -
+ this.setState({newStock: e.target.value}) } + error={newBookError.hasOwnProperty('stock')} + helperText={newBookError.hasOwnProperty('stock') ? newBookError.stock : ""} + value={this.state.newStock} + className={classes.textField} id="Stock" label="In stock" - className={classes.textField} type="text" required - value={this.state.newStock} - onChange={e => this.setState({newStock: e.target.value}) } - error={newBookError.hasOwnProperty('stock')} - helperText={newBookError.hasOwnProperty('stock') ? newBookError.stock : ""} /> this.setState({newISBN: e.target.value}) } + error={newBookError.hasOwnProperty('isbn')} + helperText={newBookError.hasOwnProperty('isbn') ? newBookError.isbn : ""} + value={this.state.newISBN} + className={classes.textField} id="ISBN" label="ISBN" - className={classes.textField} - placeholder="13 digits" type="ISBN" + placeholder="13 digits" required - value={this.state.newISBN} - onChange={e => this.setState({newISBN: e.target.value}) } - error={newBookError.hasOwnProperty('isbn')} - helperText={newBookError.hasOwnProperty('isbn') ? newBookError.isbn : ""} />
this.setState({newPrice: e.target.value}) } + error={newBookError.hasOwnProperty('price')} + helperText={newBookError.hasOwnProperty('price') ? newBookError.price : ""} + value={this.state.newPrice} + className={classes.textField} id="Price" label="Price" - className={classes.textField} type="text" required - value={this.state.newPrice} - onChange={e => this.setState({newPrice: e.target.value}) } - error={newBookError.hasOwnProperty('price')} - helperText={newBookError.hasOwnProperty('price') ? newBookError.price : ""} /> this.setState({newPublishDate: e.target.value}) } + error={newBookError.hasOwnProperty('publishDate')} + helperText={newBookError.hasOwnProperty('publishDate') ? newBookError.publishDate : ""} + value={this.state.newPublishDate} + className={classes.textField} id="PublishDate" label="PublishDate" - className={classes.textField} placeholder="sample: 7 21 2018" required - value={this.state.newPublishDate} - onChange={e => this.setState({newPublishDate: e.target.value}) } - error={newBookError.hasOwnProperty('publishDate')} - helperText={newBookError.hasOwnProperty('publishDate') ? newBookError.publishDate : ""} />
this.setState({newDescription: e.target.value}) } + error={newBookError.hasOwnProperty('description')} + helperText={newBookError.hasOwnProperty('description') ? newBookError.description : ""} + value={this.state.newDescription} + className={classes.textField} id="Description" label="Description" - className={classes.textField} type="Description" placeholder="10 to 1000 characters" required - value={this.state.newDescription} - onChange={e => this.setState({newDescription: e.target.value}) } - error={newBookError.hasOwnProperty('description')} - helperText={newBookError.hasOwnProperty('description') ? newBookError.description : ""} + />
- + variant="contained" + onClick={this.handleCancelAddNewBook} + style={{margin:'2%', outline:'none'}}> + Cancel + +
+ open={this.state.deleteDialogOpen} + onClose={this.handleDeleteDialogClose} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > {"Delete this book?"} @@ -490,10 +512,10 @@ class BookManage extends React.Component { - Book Name - Author - ISBN - Action + Book Name + Author + ISBN + Action @@ -511,7 +533,7 @@ class BookManage extends React.Component { {/**/}
- - E-mail - User Name - Activated + + E-mail + User Name + Activated @@ -191,13 +199,13 @@ class CustomerManage extends React.Component { From 9040d7cf8c184c1f2df774bb551667d6354c55db Mon Sep 17 00:00:00 2001 From: Steven Ding Date: Thu, 18 Oct 2018 22:07:35 +1100 Subject: [PATCH 06/10] Merge from Style and Master --- client/src/Admin/AdminHome.jsx | 10 ++ client/src/Admin/BookManage.jsx | 121 ++++++++++-------- client/src/Admin/CustomerManage.jsx | 24 ++-- .../account/containers/Account/AccountTab.jsx | 9 +- .../containers/Account/MyBookLists.jsx | 84 +++++++----- .../src/account/containers/Account/index.jsx | 26 +++- .../containers/AvatarUploader/index.jsx | 28 ++-- .../account/containers/EmailSent/index.jsx | 15 ++- .../account/containers/LoginForm/index.jsx | 47 +++---- .../src/account/containers/Register/index.jsx | 50 ++++---- 10 files changed, 253 insertions(+), 161 deletions(-) diff --git a/client/src/Admin/AdminHome.jsx b/client/src/Admin/AdminHome.jsx index 67ea2c7..c898a56 100644 --- a/client/src/Admin/AdminHome.jsx +++ b/client/src/Admin/AdminHome.jsx @@ -2,6 +2,16 @@ import React from 'react'; import Button from '@material-ui/core/Button'; import {Link} from 'react-router-dom'; +//wait for Ding +// const style ={ +// welcomeContent: { +// color: '#00B0FF', +// fontSize: '100px', +// marginLeft: '100px', +// marginTop: '100px' +// } +// }; + class AdminHome extends React.Component { render() { return ( diff --git a/client/src/Admin/BookManage.jsx b/client/src/Admin/BookManage.jsx index a7b23aa..0e7d4cd 100644 --- a/client/src/Admin/BookManage.jsx +++ b/client/src/Admin/BookManage.jsx @@ -47,8 +47,9 @@ const styles = theme => ({ display: 'none', }, root: { - width: '100%', + width: '95%', marginTop: theme.spacing.unit * 3, + marginLeft: theme.spacing.unit * 3, }, table: { minWidth: 500, @@ -67,10 +68,13 @@ const styles = theme => ({ }, paper: { position: 'absolute', - width: theme.spacing.unit * 50, backgroundColor: theme.palette.background.paper, boxShadow: theme.shadows[5], padding: theme.spacing.unit * 4, + top:'17%', + left:'23%', + width:'60%', + height:'60%', }, textField: { marginLeft: theme.spacing.unit, @@ -88,6 +92,19 @@ const styles = theme => ({ card: { minWidth: 275, }, + headerStyle: { + backgroundColor:'#C5CAE9', + color:'#1A237E', + fontSize:16, + textAlign:'Center', + }, + headerLeft: { + textAlign:'left', + backgroundColor:'#C5CAE9', + color:'#1A237E', + fontSize:16, + }, + }); // Control of the table page @@ -171,7 +188,6 @@ class BookManage extends React.Component { isbn:0 }], page: 0, - newTitle: "", newAuthors: [""], newISBN: "", @@ -182,9 +198,7 @@ class BookManage extends React.Component { newPrice: 0, newCategory: "", newBookError:{}, - rowsPerPage: 15, - open: false, deleteDialogOpen: false, expanded: null, @@ -314,34 +328,35 @@ class BookManage extends React.Component { const { classes } = this.props; const { rows, rowsPerPage, page, newBookError } = this.state; const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage); - return ( -
+ //add a new book +
-
- + +
+ New book
- @@ -471,20 +482,26 @@ class BookManage extends React.Component {
+ this.setState({newStock: e.target.value}) } + error={newBookError.hasOwnProperty('stock')} + helperText={newBookError.hasOwnProperty('stock') ? newBookError.stock : ""} + value={this.state.newStock} + className={classes.textField} id="Stock" label="In stock" - className={classes.textField} type="text" required - value={this.state.newStock} - onChange={e => this.setState({newStock: e.target.value}) } - error={newBookError.hasOwnProperty('stock')} - helperText={newBookError.hasOwnProperty('stock') ? newBookError.stock : ""} /> this.setState({newISBN: e.target.value}) } + error={newBookError.hasOwnProperty('isbn')} + helperText={newBookError.hasOwnProperty('isbn') ? newBookError.isbn : ""} + value={this.state.newISBN} + className={classes.textField} id="ISBN" label="ISBN" - className={classes.textField} - placeholder="13 digits" type="ISBN" + placeholder="13 digits" required - value={this.state.newISBN} - onChange={e => this.setState({newISBN: e.target.value}) } - error={newBookError.hasOwnProperty('isbn')} - helperText={newBookError.hasOwnProperty('isbn') ? newBookError.isbn : ""} />
this.setState({newPrice: e.target.value}) } + error={newBookError.hasOwnProperty('price')} + helperText={newBookError.hasOwnProperty('price') ? newBookError.price : ""} + value={this.state.newPrice} + className={classes.textField} id="Price" label="Price" - className={classes.textField} type="text" required - value={this.state.newPrice} - onChange={e => this.setState({newPrice: e.target.value}) } - error={newBookError.hasOwnProperty('price')} - helperText={newBookError.hasOwnProperty('price') ? newBookError.price : ""} /> @@ -430,10 +445,6 @@ class BookManage extends React.Component { label="PublishDate" placeholder="sample: 7 21 2018" required - value={this.state.newPublishDate} - onChange={e => this.setState({newPublishDate: e.target.value}) } - error={newBookError.hasOwnProperty('publishDate')} - helperText={newBookError.hasOwnProperty('publishDate') ? newBookError.publishDate : ""} />
- + variant="contained" + onClick={this.handleCancelAddNewBook} + style={{margin:'2%', outline:'none'}}> + Cancel + +
+ open={this.state.deleteDialogOpen} + onClose={this.handleDeleteDialogClose} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > {"Delete this book?"} @@ -505,10 +522,10 @@ class BookManage extends React.Component { - Book Name - Author - ISBN - Action + Book Name + Author + ISBN + Action @@ -526,7 +543,7 @@ class BookManage extends React.Component { {/**/}
- - E-mail - User Name - Activated + + E-mail + User Name + Activated @@ -191,13 +199,13 @@ class CustomerManage extends React.Component { diff --git a/client/src/account/containers/Account/AccountTab.jsx b/client/src/account/containers/Account/AccountTab.jsx index 33759af..f743666 100644 --- a/client/src/account/containers/Account/AccountTab.jsx +++ b/client/src/account/containers/Account/AccountTab.jsx @@ -28,7 +28,10 @@ const styles = theme => ({ function TabContainer(props) { return ( - + {props.children} ); @@ -56,13 +59,9 @@ class AccountTab extends React.Component { - {/**/} - {/**/} - {/**/} {value === 0 && } - {/*{value === 1 && }*/} ); } diff --git a/client/src/account/containers/Account/MyBookLists.jsx b/client/src/account/containers/Account/MyBookLists.jsx index 2665674..76d66c3 100644 --- a/client/src/account/containers/Account/MyBookLists.jsx +++ b/client/src/account/containers/Account/MyBookLists.jsx @@ -17,6 +17,7 @@ const styles = theme => ({ buttonWrapper: { position: 'relative', marginBottom: theme.spacing.unit * 4, + paddingTop:'20px' }, checked: {}, @@ -25,6 +26,8 @@ const styles = theme => ({ }, card: { minWidth: 275, + marginTop:'10px', + backgroundColor:'#FAFAFA', }, title: { marginBottom: 16, @@ -47,12 +50,26 @@ const styles = theme => ({ }, paper: { position: 'absolute', - width: theme.spacing.unit * 50, backgroundColor: theme.palette.background.paper, boxShadow: theme.shadows[5], padding: theme.spacing.unit * 4, + top:'26%', + left:'30%', + width:'44%', + height:'31%', + }, + addButton: { + outline:'none', + backgroundColor:'#3D5AFE', + color:'#fff', + width:'170px', + height:'40px', + }, + titleStyle: { + display:'inline', + fontSize:'18px', + paddingBottom:'0', }, - }); @@ -111,67 +128,70 @@ class MyBookLists extends React.Component { const { classes } = this.props; return ( -
- - +
+ + -
- +
+ Create a new book list - +
this.title = title} + className={classes.textField} id="BookListTitle" + required label="Title" multiline - className={classes.textField} - inputRef={title => this.title = title} - required /> this.description = description} error={this.state.isDescriptionWrong} helperText={this.state.descriptionError} - required - style={{width:'270px'}} - onKeyDown={this.onKeyDown} + type="text" />
- @@ -183,15 +203,19 @@ class MyBookLists extends React.Component { { this.props.bookLists.map( (bookList)=>{ - return + return - + {bookList.title} - - {bookList.updateDate.substring(0,10)} + + Update Date: {bookList.updateDate.substring(0,10)} diff --git a/client/src/account/containers/Account/index.jsx b/client/src/account/containers/Account/index.jsx index 269b152..0d17629 100644 --- a/client/src/account/containers/Account/index.jsx +++ b/client/src/account/containers/Account/index.jsx @@ -26,17 +26,22 @@ const styles = { bigAvatar: { width: 160, height: 160, + backgroundColor: '#E0E0E0', }, avatarModal: { - marginTop: '150px' + marginTop: '150px', + }, + usernameStyle: { + fontSize: '24px', + fontWeight:'bold', } }; function AccountInfo(props) { - const {username} = props; + const {username, usernameStyle} = props; return (
-

{username}

+

{username}

); } @@ -78,11 +83,20 @@ class Account extends React.Component {
{avatarType === 'letter' ? : - } + }
-
diff --git a/client/src/account/containers/AvatarUploader/index.jsx b/client/src/account/containers/AvatarUploader/index.jsx index f122dfe..6fbd821 100644 --- a/client/src/account/containers/AvatarUploader/index.jsx +++ b/client/src/account/containers/AvatarUploader/index.jsx @@ -52,17 +52,25 @@ class AvatarUploader extends PureComponent {

My Avatar

- - + +
- +
) } diff --git a/client/src/account/containers/EmailSent/index.jsx b/client/src/account/containers/EmailSent/index.jsx index 1f0242d..de66087 100644 --- a/client/src/account/containers/EmailSent/index.jsx +++ b/client/src/account/containers/EmailSent/index.jsx @@ -43,10 +43,17 @@ class EmailSent extends Component { return (

Thank you for signing up!

-

We have sent an email with an activation link to your email address. In order to complete the sign-up process, please click the activation link. - If you didn't receive the activation email, click on the button below to resend it.

-
-
+

+ We have sent an email with an activation link to your email address. In order to complete the sign-up process, please click the activation link. + If you didn't receive the activation email, click on the button below to resend it. +

+
+ +
+
+ +
); } diff --git a/client/src/account/containers/LoginForm/index.jsx b/client/src/account/containers/LoginForm/index.jsx index 5a88249..2f2b800 100644 --- a/client/src/account/containers/LoginForm/index.jsx +++ b/client/src/account/containers/LoginForm/index.jsx @@ -37,7 +37,7 @@ const styles = theme => ({ fontWeight: 'normal', color: '#424242', marginTop: '40px' -}, + }, loginBtn: { width: '200px', height: '44px', @@ -131,34 +131,37 @@ class LoginForm extends Component {

Log in

-
New here?
+ +
New here?
+
) } diff --git a/client/src/account/containers/Register/index.jsx b/client/src/account/containers/Register/index.jsx index 742ed23..0cf366e 100644 --- a/client/src/account/containers/Register/index.jsx +++ b/client/src/account/containers/Register/index.jsx @@ -1,4 +1,4 @@ -import React, {Component} from 'react'; + import React, {Component} from 'react'; import {connect} from "react-redux"; import {compose} from "redux"; import {registerUser} from "../../common/actions/authActions"; @@ -86,54 +86,56 @@ class RegisterForm extends Component {

Sign up

- -
+ Create your new account + From 4d6dfd9adfe3f9827842f2f7070715db61a82407 Mon Sep 17 00:00:00 2001 From: "jennyhu19900914@gmail.com" Date: Thu, 18 Oct 2018 22:39:15 +1100 Subject: [PATCH 07/10] Fix html code style of HTML Detail of Booklist, header --- client/src/BookList/index.js | 110 +++++++++++++++++++---------- client/src/Header/headerPageCss.js | 6 ++ client/src/Header/index.jsx | 11 ++- 3 files changed, 87 insertions(+), 40 deletions(-) diff --git a/client/src/BookList/index.js b/client/src/BookList/index.js index 38f5569..e3e6872 100644 --- a/client/src/BookList/index.js +++ b/client/src/BookList/index.js @@ -23,6 +23,8 @@ const styles = theme => ({ }, table: { minWidth: 700, + minHeight:100, + textAlign: 'center', }, button: { margin: theme.spacing.unit, @@ -34,11 +36,44 @@ const styles = theme => ({ fontWeight: 'bold', fontSize: '15px', }, + addNewbook: { + outline: 'none', + width: '170px', + backgroundColor: '#3D5AFE', + color: '#fff', + marginRight: '10px' + }, + editBooklist: { + outline: 'none', + width: '80px', + marginRight: '10px', + }, + deleteBookListStyle: { + outline: 'none', + width: '120px', + marginRight: '10px', + }, + bookTitleStyle: { + fontSize: '14px', + fontFamily: '"Lato", "Helvetica Neue", Helvetica, Arial, sans-serif', + }, + cardBorder: { + height: '220px', + borderBottom: '8px #E0E0E0 solid', + }, + tableBook: { + width: '20%', + paddingLeft: '20px' + }, + tableTitle: { + width: '50%', + textAlign:'left' + }, container: KFStyles.container, }); class BookList extends React.PureComponent { - constructor(props) { + constructor(props) { super(props); this.state = { userID: '', @@ -54,7 +89,7 @@ class BookList extends React.PureComponent { this.operationButtons = this.operationButtons.bind(this); } - componentDidMount() { + componentDidMount() { this.getBooksInBookList(this.props.match.params.slug); } @@ -105,41 +140,39 @@ class BookList extends React.PureComponent { operationButtons(bookListOwnerId, userId, isAdmin, bookListId) { const deletable = userId === bookListOwnerId || isAdmin; const editable = userId === bookListOwnerId; + const {classes} = this.props; return (
- {editable && } - {editable && } - {deletable && } @@ -151,6 +184,7 @@ class BookList extends React.PureComponent { const { root, table, container, } = this.props.classes; + const {classes} = this.props; const { bookListTitle, books, totalBooks, @@ -169,43 +203,45 @@ class BookList extends React.PureComponent { return (

{bookListTitle}

-

{description}

+

{description}

{this.operationButtons(this.props.userID, this.state.userID, this.props.isAdmin, bookListId)} {/* Show books in list */} {books.length ? books.map(book => ( - - + - - )) : - + }
+
- {book.title} + {book.title} -
{`by ${book.authors.map(author => author.name).join(', ')}`}
- +

{`by ${book.authors.map(author => author.name).join(', ')}`}

- {book.reviewContent ? book.reviewContent : ''} + +

+ {book.reviewContent ? book.reviewContent : 'No reviews yet'} +

+
No books yet.No books yet.
diff --git a/client/src/Header/headerPageCss.js b/client/src/Header/headerPageCss.js index d606362..278bdb3 100644 --- a/client/src/Header/headerPageCss.js +++ b/client/src/Header/headerPageCss.js @@ -85,3 +85,9 @@ export const navSpan = { display: 'table-cell', verticalAlign: 'middle', }; + +export const dashboardStyle = { + marginBottom:'3px', + cursor: 'pointer', + marginLeft: '15px' +}; diff --git a/client/src/Header/index.jsx b/client/src/Header/index.jsx index 4bb85ea..f9363b5 100644 --- a/client/src/Header/index.jsx +++ b/client/src/Header/index.jsx @@ -75,6 +75,7 @@ class headerPageIndex extends Component { iconLogo, searchIcon, rightIcon, + dashboardStyle } = style; return ( @@ -121,12 +122,16 @@ class headerPageIndex extends Component { isAuthenticated={this.props.auth.isAuthenticated} logoutUser={this.props.logoutUser} /> - + {this.props.isAdmin &&
{this.props.history.push('/admin')}} - style={{ cursor: 'pointer', marginLeft: '15px' }}> - + style={dashboardStyle} + > +
}
From 908a64aeef108ca66b00189c2c760352052a6818 Mon Sep 17 00:00:00 2001 From: Steven Ding Date: Thu, 18 Oct 2018 23:26:33 +1100 Subject: [PATCH 08/10] Reformat and clean the code --- client/src/Admin/AdminHome.jsx | 60 +- client/src/Admin/BookManage.jsx | 999 +++++++++--------- client/src/Admin/CustomerManage.jsx | 364 +++---- client/src/Admin/index.jsx | 91 +- .../AllCategoriesPage/childComponent/aBook.js | 6 +- client/src/account/common/AccountStyles.js | 5 +- .../src/account/common/actions/authActions.js | 21 +- .../account/common/reducers/authReducer.js | 19 +- .../account/common/reducers/errorReducer.js | 4 +- .../src/account/common/utils/dataURLtoFile.js | 24 +- client/src/account/common/utils/isEmpty.js | 6 +- .../account/containers/Account/AccountTab.jsx | 88 +- .../containers/Account/MyBookLists.jsx | 424 ++++---- .../src/account/containers/Account/actions.js | 10 +- .../src/account/containers/Account/index.jsx | 196 ++-- .../account/containers/Account/index.test.js | 4 +- .../account/containers/Account/reducers.js | 5 +- .../containers/AvatarUploader/Avatars.jsx | 6 - .../AvatarUploader/avatarReducers.js | 19 - .../containers/AvatarUploader/index.jsx | 146 +-- .../account/containers/EmailSent/index.jsx | 22 +- .../containers/EmailVerification/index.jsx | 73 +- .../src/account/containers/KFAccountInput.jsx | 5 +- .../account/containers/LoginForm/index.jsx | 305 +++--- .../src/account/containers/Register/index.jsx | 283 +++-- .../account/containers/Register/index.test.js | 22 +- client/src/config.js | 3 +- 27 files changed, 1571 insertions(+), 1639 deletions(-) delete mode 100644 client/src/account/containers/AvatarUploader/avatarReducers.js diff --git a/client/src/Admin/AdminHome.jsx b/client/src/Admin/AdminHome.jsx index c898a56..729f1f1 100644 --- a/client/src/Admin/AdminHome.jsx +++ b/client/src/Admin/AdminHome.jsx @@ -1,35 +1,41 @@ import React from 'react'; import Button from '@material-ui/core/Button'; -import {Link} from 'react-router-dom'; +import { Link } from 'react-router-dom'; -//wait for Ding -// const style ={ -// welcomeContent: { -// color: '#00B0FF', -// fontSize: '100px', -// marginLeft: '100px', -// marginTop: '100px' -// } -// }; + +const style = { + welcomeContent: { + color: '#00B0FF', + fontSize: '100px', + marginLeft: '100px', + marginTop: '100px' + }, + exitButton: { + display: 'flex', + width: '120px', + marginLeft: '100px', + backgroundColor: '#1E88E5' + } +}; class AdminHome extends React.Component { - render() { - return ( -
-

- Welcome Admin
^~^ -

- -
) - } + render() { + return ( +
+

+ Welcome Admin
^~^ +

+ +
) + } } export default AdminHome; diff --git a/client/src/Admin/BookManage.jsx b/client/src/Admin/BookManage.jsx index 0e7d4cd..240fda0 100644 --- a/client/src/Admin/BookManage.jsx +++ b/client/src/Admin/BookManage.jsx @@ -28,560 +28,529 @@ import DialogTitle from '@material-ui/core/DialogTitle'; // Styles const actionsStyles = theme => ({ - root: { - flexShrink: 0, - color: theme.palette.text.secondary, - marginLeft: theme.spacing.unit * 2.5, - }, - head: { - backgroundColor: theme.palette.common.black, - color: theme.palette.common.white, - }, + root: { + flexShrink: 0, + color: theme.palette.text.secondary, + marginLeft: theme.spacing.unit * 2.5, + }, + head: { + backgroundColor: theme.palette.common.black, + color: theme.palette.common.white, + }, }); const styles = theme => ({ - button: { - margin: theme.spacing.unit, - }, - input: { - display: 'none', - }, - root: { - width: '95%', - marginTop: theme.spacing.unit * 3, - marginLeft: theme.spacing.unit * 3, - }, - table: { - minWidth: 500, - }, - tableWrapper: { - overflowX: 'auto', - }, - leftIcon: { - marginRight: theme.spacing.unit, - }, - rightIcon: { - marginLeft: theme.spacing.unit, - }, - iconSmall: { - fontSize: 20, - }, - paper: { - position: 'absolute', - backgroundColor: theme.palette.background.paper, - boxShadow: theme.shadows[5], - padding: theme.spacing.unit * 4, - top:'17%', - left:'23%', - width:'60%', - height:'60%', - }, - textField: { - marginLeft: theme.spacing.unit, - marginRight: theme.spacing.unit, - minWidth: '90%', - }, - selectEmpty: { - marginTop: theme.spacing.unit * 2, - minWidth:200, - }, - formControl: { - margin: theme.spacing.unit, - minWidth: 100, - }, - card: { - minWidth: 275, - }, - headerStyle: { - backgroundColor:'#C5CAE9', - color:'#1A237E', - fontSize:16, - textAlign:'Center', - }, - headerLeft: { - textAlign:'left', - backgroundColor:'#C5CAE9', - color:'#1A237E', - fontSize:16, - }, + button: { + margin: theme.spacing.unit, + }, + input: { + display: 'none', + }, + root: { + width: '95%', + marginTop: theme.spacing.unit * 3, + marginLeft: theme.spacing.unit * 3, + }, + table: { + minWidth: 500, + }, + tableWrapper: { + overflowX: 'auto', + }, + leftIcon: { + marginRight: theme.spacing.unit, + }, + rightIcon: { + marginLeft: theme.spacing.unit, + }, + iconSmall: { + fontSize: 20, + }, + paper: { + position: 'absolute', + backgroundColor: theme.palette.background.paper, + boxShadow: theme.shadows[5], + padding: theme.spacing.unit * 4, + top: '17%', + left: '23%', + width: '60%', + height: '60%', + }, + textField: { + marginLeft: theme.spacing.unit, + marginRight: theme.spacing.unit, + minWidth: '90%', + }, + selectEmpty: { + marginTop: theme.spacing.unit * 2, + minWidth: 200, + }, + formControl: { + margin: theme.spacing.unit, + minWidth: 100, + }, + card: { + minWidth: 275, + }, + headerStyle: { + backgroundColor: '#C5CAE9', + color: '#1A237E', + fontSize: 16, + textAlign: 'Center', + }, + headerLeft: { + textAlign: 'left', + backgroundColor: '#C5CAE9', + color: '#1A237E', + fontSize: 16, + }, }); // Control of the table page class TablePaginationActions extends React.Component { - handleFirstPageButtonClick = event => { - this.props.onChangePage(event, 0); - }; + handleFirstPageButtonClick = event => { + this.props.onChangePage(event, 0); + }; - handleBackButtonClick = event => { - this.props.onChangePage(event, this.props.page - 1); - }; + handleBackButtonClick = event => { + this.props.onChangePage(event, this.props.page - 1); + }; - handleNextButtonClick = event => { - this.props.onChangePage(event, this.props.page + 1); - }; + handleNextButtonClick = event => { + this.props.onChangePage(event, this.props.page + 1); + }; - handleLastPageButtonClick = event => { - this.props.onChangePage( - event, - Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1), - ); - }; + handleLastPageButtonClick = event => { + this.props.onChangePage( + event, + Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1), + ); + }; - render() { - const { classes, count, page, rowsPerPage, theme } = this.props; + render() { + const { classes, count, page, rowsPerPage, theme } = this.props; - return ( -
- - {theme.direction === 'rtl' ? : } - - - {theme.direction === 'rtl' ? : } - - = Math.ceil(count / rowsPerPage) - 1} - aria-label="Next Page" - > - {theme.direction === 'rtl' ? : } - - = Math.ceil(count / rowsPerPage) - 1} - aria-label="Last Page" - > - {theme.direction === 'rtl' ? : } - -
- ); - } + return ( +
+ + {theme.direction === 'rtl' ? : } + + + {theme.direction === 'rtl' ? : } + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="Next Page" + > + {theme.direction === 'rtl' ? : } + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="Last Page" + > + {theme.direction === 'rtl' ? : } + +
+ ); + } } TablePaginationActions.propTypes = { - classes: PropTypes.object.isRequired, - count: PropTypes.number.isRequired, - onChangePage: PropTypes.func.isRequired, - page: PropTypes.number.isRequired, - rowsPerPage: PropTypes.number.isRequired, - theme: PropTypes.object.isRequired, + classes: PropTypes.object.isRequired, + count: PropTypes.number.isRequired, + onChangePage: PropTypes.func.isRequired, + page: PropTypes.number.isRequired, + rowsPerPage: PropTypes.number.isRequired, + theme: PropTypes.object.isRequired, }; const TablePaginationActionsWrapped = withStyles(actionsStyles, { withTheme: true })( - TablePaginationActions, + TablePaginationActions, ); class BookManage extends React.Component { - state = { - rows: [{ - _id:0, - title:"", - authors:[{name:""}], - isbn:0 - }], - page: 0, - newTitle: "", - newAuthors: [""], - newISBN: "", - newDescription: "", - newPublishDate: "", - newCoverURL: "", - newStock: 0, - newPrice: 0, - newCategory: "", - newBookError:{}, - rowsPerPage: 15, - open: false, - deleteDialogOpen: false, - expanded: null, - selectedBookID: null, - selectedBookTitle: "" - }; + state = { + rows: [{ + _id: 0, + title: "", + authors: [{ name: "" }], + isbn: 0 + }], + page: 0, + newTitle: "", + newAuthors: [""], + newISBN: "", + newDescription: "", + newPublishDate: "", + newCoverURL: "", + newStock: 0, + newPrice: 0, + newCategory: "", + newBookError: {}, + rowsPerPage: 15, + open: false, + deleteDialogOpen: false, + expanded: null, + selectedBookID: null, + selectedBookTitle: "" + }; - componentDidMount() { - this.getAllBooks(); - } + componentDidMount() { + this.getAllBooks(); + } - getAllBooks () { - Axios.get('/books') - .then(res => { - this.setState({ - rows: res.data - }) - }) - } + getAllBooks() { + Axios.get('/books') + .then(res => { + this.setState({ + rows: res.data + }) + }) + } - handleDeleteDialogOpen = (bookID, title) => { - this.setState({ - deleteDialogOpen: true, - selectedBookID: bookID, - selectedBookTitle: title }); - }; + handleDeleteDialogOpen = (bookID, title) => { + this.setState({ + deleteDialogOpen: true, + selectedBookID: bookID, + selectedBookTitle: title + }); + }; - handleDeleteDialogClose = () => { - this.setState({ deleteDialogOpen: false }); - }; + handleDeleteDialogClose = () => { + this.setState({ deleteDialogOpen: false }); + }; - handleAddNewBookOpen = () => { - if(process.env.NODE_ENV === 'production'){ - this.setState({ - newTitle: "", - newAuthors: [""], - newISBN: "", - newDescription: "", - newPublishDate: "", - newCoverURL: "", - newStock: 0, - newPrice: 0, - // TODO: Add a drop down for category - // newCategory: "5b65103ac55fe361685262bf", - }) - } else { - // TEST - this.setState({ - newISBN: "9780312426781", - newStock: 1, - newPrice: 1, - newTitle: "YOU ARE IN DEBUG MODE", - newAuthors: ["name"], - newDescription: "New Description", - newPublishDate: "7 21 2018", - newCoverURL: 'https://images-na.ssl-images-amazon.com/images/I/41iYksBR8BL._SX358_BO1,204,203,200_.jpg' - }); - } - this.setState({ open: true }); - }; + handleAddNewBookOpen = () => { + this.setState({ + newTitle: "", + newAuthors: [""], + newISBN: "", + newDescription: "", + newPublishDate: "", + newCoverURL: "", + newStock: 0, + newPrice: 0, + }); + this.setState({ open: true }); + }; - handleAddNewBookClose = () => { - this.setState({ open: false }); - }; + handleAddNewBookClose = () => { + this.setState({ open: false }); + }; - handleChangePage = (event, page) => { - this.setState({ page }); - }; + handleChangePage = (event, page) => { + this.setState({ page }); + }; - handleChangeRowsPerPage = event => { - this.setState({ rowsPerPage: event.target.value }); - }; + handleChangeRowsPerPage = event => { + this.setState({ rowsPerPage: event.target.value }); + }; - handleCancelAddNewBook = () => { - this.setState(state => ({ - open: !state.open, - })); - }; + handleCancelAddNewBook = () => { + this.setState(state => ({ + open: !state.open, + })); + }; - addABook = () => { - const { - newISBN: isbn, - newTitle: title, - newAuthors: authors, - newDescription: description, - // newCategory: category, - newStock: stock, - newPrice: price, - newCoverURL: coverUrl, - newPublishDate: publishDate } = this.state; + addABook = () => { + const { + newISBN: isbn, + newTitle: title, + newAuthors: authors, + newDescription: description, + newStock: stock, + newPrice: price, + newCoverURL: coverUrl, + newPublishDate: publishDate + } = this.state; - Axios.post('/books', { - title, - authors, - isbn, - description, - publishDate, - coverUrl, - stock, - price, - // category - }) - .then(() => { - this.setState(state => ({ - open: !state.open, - })); - // refresh - this.getAllBooks(); - this.setState({newBookError:{}}) - }) - .catch(err => { - let errorBody = err.response.data; - if (errorBody.hasOwnProperty('bookexisted')) { - errorBody.isbn = 'This book is duplicate.'; - } - this.setState({newBookError: errorBody}); - }) - }; + Axios.post('/books', { + title, + authors, + isbn, + description, + publishDate, + coverUrl, + stock, + price, + }) + .then(() => { + this.setState(state => ({ + open: !state.open, + })); + // refresh + this.getAllBooks(); + this.setState({ newBookError: {} }) + }) + .catch(err => { + let errorBody = err.response.data; + if (errorBody.hasOwnProperty('bookexisted')) { + errorBody.isbn = 'This book is duplicate.'; + } + this.setState({ newBookError: errorBody }); + }) + }; - confirmDelete () { - Axios.delete('/books/'+ this.state.selectedBookID) - .then(() => this.getAllBooks()); - this.handleDeleteDialogClose(); - } + confirmDelete() { + Axios.delete('/books/' + this.state.selectedBookID) + .then(() => this.getAllBooks()); + this.handleDeleteDialogClose(); + } - render() { - const { classes } = this.props; - const { rows, rowsPerPage, page, newBookError } = this.state; - const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage); - return ( - //add a new book -
- - + render() { + const { classes } = this.props; + const { rows, rowsPerPage, page, newBookError } = this.state; + const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage); + return ( + // add a new book +
+ + -
- - New book - - - - - - - - - {/* - TODO: make a dropdown list for category - - */} - - - - - - - - - - - - - - - -
- this.setState({newTitle: e.target.value}) } - required - error={newBookError.hasOwnProperty('title')} - helperText={newBookError.hasOwnProperty('title') ? newBookError.title : ""} - /> - - this.setState({newAuthors: [e.target.value]})} - required - error={newBookError.hasOwnProperty('authors')} - helperText={newBookError.hasOwnProperty('authors') ? newBookError.authors : ""} - /> -
- this.setState({newCategory: e.target.value}) } - /> -
- this.setState({newStock: e.target.value}) } - error={newBookError.hasOwnProperty('stock')} - helperText={newBookError.hasOwnProperty('stock') ? newBookError.stock : ""} - value={this.state.newStock} - className={classes.textField} - id="Stock" - label="In stock" - type="text" - required - /> - - this.setState({newISBN: e.target.value}) } - error={newBookError.hasOwnProperty('isbn')} - helperText={newBookError.hasOwnProperty('isbn') ? newBookError.isbn : ""} - value={this.state.newISBN} - className={classes.textField} - id="ISBN" - label="ISBN" - type="ISBN" - placeholder="13 digits" - required - /> -
- this.setState({newPrice: e.target.value}) } - error={newBookError.hasOwnProperty('price')} - helperText={newBookError.hasOwnProperty('price') ? newBookError.price : ""} - value={this.state.newPrice} - className={classes.textField} - id="Price" - label="Price" - type="text" - required - /> - - -
- this.setState({newDescription: e.target.value}) } - error={newBookError.hasOwnProperty('description')} - helperText={newBookError.hasOwnProperty('description') ? newBookError.description : ""} - /> -
- this.setState({newCoverURL: e.target.value}) } - error={newBookError.hasOwnProperty('description')} - helperText={newBookError.hasOwnProperty('coverUrl') ? newBookError.description : ""} - /> -
- - -
-
-
- - {"Delete this book?"} - - - {this.state.selectedBookTitle} - - - - - - - - -
- - - - Book Name - Author - ISBN - Action - - - - {rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(row => { - return ( - - - {row.title} - - {row.authors.length > 0 ? row.authors[0].name : ""} - {row.isbn} - - {/**/} - - - - ); - })} - {emptyRows > 0 && ( - - - - )} - - - - - - -
-
-
-
- ); - } +
+ + New book + + + + + + + + + + + + + + + + + + + + + + + +
+ this.setState({ newTitle: e.target.value })} + required + error={newBookError.hasOwnProperty('title')} + helperText={newBookError.hasOwnProperty('title') ? newBookError.title : ""} + /> + + this.setState({ newAuthors: [e.target.value] })} + required + error={newBookError.hasOwnProperty('authors')} + helperText={newBookError.hasOwnProperty('authors') ? newBookError.authors : ""} + /> +
+ this.setState({ newStock: e.target.value })} + error={newBookError.hasOwnProperty('stock')} + helperText={newBookError.hasOwnProperty('stock') ? newBookError.stock : ""} + value={this.state.newStock} + className={classes.textField} + id="Stock" + label="In stock" + type="text" + required + /> + + this.setState({ newISBN: e.target.value })} + error={newBookError.hasOwnProperty('isbn')} + helperText={newBookError.hasOwnProperty('isbn') ? newBookError.isbn : ""} + value={this.state.newISBN} + className={classes.textField} + id="ISBN" + label="ISBN" + type="ISBN" + placeholder="13 digits" + required + /> +
+ this.setState({ newPrice: e.target.value })} + error={newBookError.hasOwnProperty('price')} + helperText={newBookError.hasOwnProperty('price') ? newBookError.price : ""} + value={this.state.newPrice} + className={classes.textField} + id="Price" + label="Price" + type="text" + required + /> + + +
+ this.setState({ newDescription: e.target.value })} + error={newBookError.hasOwnProperty('description')} + helperText={newBookError.hasOwnProperty('description') ? newBookError.description : ""} + /> +
+ this.setState({ newCoverURL: e.target.value })} + error={newBookError.hasOwnProperty('description')} + helperText={newBookError.hasOwnProperty('coverUrl') ? newBookError.description : ""} + /> +
+ + +
+
+
+ + {"Delete this book?"} + + + {this.state.selectedBookTitle} + + + + + + + + +
+ + + + Book Name + Author + ISBN + Action + + + + {rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(row => { + return ( + + + {row.title} + + {row.authors.length > 0 ? row.authors[0].name : ""} + {row.isbn} + + + + + ); + })} + {emptyRows > 0 && ( + + + + )} + + + + + + +
+
+
+
+ ); + } } BookManage.propTypes = { - classes: PropTypes.object.isRequired, + classes: PropTypes.object.isRequired, }; export default withStyles(styles)(BookManage); diff --git a/client/src/Admin/CustomerManage.jsx b/client/src/Admin/CustomerManage.jsx index 3eae709..8565d39 100644 --- a/client/src/Admin/CustomerManage.jsx +++ b/client/src/Admin/CustomerManage.jsx @@ -17,207 +17,207 @@ import LastPageIcon from '@material-ui/icons/LastPage'; import Axios from 'axios'; const actionsStyles = theme => ({ - root: { - flexShrink: 0, - color: theme.palette.text.secondary, - marginLeft: theme.spacing.unit * 2.5, - }, - head: { - backgroundColor: theme.palette.common.black, - color: theme.palette.common.white, - }, + root: { + flexShrink: 0, + color: theme.palette.text.secondary, + marginLeft: theme.spacing.unit * 2.5, + }, + head: { + backgroundColor: theme.palette.common.black, + color: theme.palette.common.white, + }, }); const styles = theme => ({ - button: { - margin: theme.spacing.unit, - }, - input: { - display: 'none', - }, - root: { - width: '95%', - marginTop: theme.spacing.unit * 3, - marginLeft: theme.spacing.unit * 3, - - }, - table: { - minWidth: 500, - }, - tableWrapper: { - overflowX: 'auto', - }, - leftIcon: { - marginRight: theme.spacing.unit, - }, - rightIcon: { - marginLeft: theme.spacing.unit, - }, - iconSmall: { - fontSize: 20, - }, - headerStyle: { - backgroundColor:'#C5CAE9', - color:'#1A237E', - fontSize:16, - textAlign: 'left', - } + button: { + margin: theme.spacing.unit, + }, + input: { + display: 'none', + }, + root: { + width: '95%', + marginTop: theme.spacing.unit * 3, + marginLeft: theme.spacing.unit * 3, + + }, + table: { + minWidth: 500, + }, + tableWrapper: { + overflowX: 'auto', + }, + leftIcon: { + marginRight: theme.spacing.unit, + }, + rightIcon: { + marginLeft: theme.spacing.unit, + }, + iconSmall: { + fontSize: 20, + }, + headerStyle: { + backgroundColor: '#C5CAE9', + color: '#1A237E', + fontSize: 16, + textAlign: 'left', + } }); -//page +// age class TablePaginationActions extends React.Component { - handleFirstPageButtonClick = event => { - this.props.onChangePage(event, 0); - }; - - handleBackButtonClick = event => { - this.props.onChangePage(event, this.props.page - 1); - }; - - handleNextButtonClick = event => { - this.props.onChangePage(event, this.props.page + 1); - }; - - handleLastPageButtonClick = event => { - this.props.onChangePage( - event, - Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1), - ); - }; - - render() { - const { classes, count, page, rowsPerPage, theme } = this.props; - - return ( -
- - {theme.direction === 'rtl' ? : } - - - {theme.direction === 'rtl' ? : } - - = Math.ceil(count / rowsPerPage) - 1} - aria-label="Next Page" - > - {theme.direction === 'rtl' ? : } - - = Math.ceil(count / rowsPerPage) - 1} - aria-label="Last Page" - > - {theme.direction === 'rtl' ? : } - -
- ); - } + handleFirstPageButtonClick = event => { + this.props.onChangePage(event, 0); + }; + + handleBackButtonClick = event => { + this.props.onChangePage(event, this.props.page - 1); + }; + + handleNextButtonClick = event => { + this.props.onChangePage(event, this.props.page + 1); + }; + + handleLastPageButtonClick = event => { + this.props.onChangePage( + event, + Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1), + ); + }; + + render() { + const { classes, count, page, rowsPerPage, theme } = this.props; + + return ( +
+ + {theme.direction === 'rtl' ? : } + + + {theme.direction === 'rtl' ? : } + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="Next Page" + > + {theme.direction === 'rtl' ? : } + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="Last Page" + > + {theme.direction === 'rtl' ? : } + +
+ ); + } } TablePaginationActions.propTypes = { - classes: PropTypes.object.isRequired, - count: PropTypes.number.isRequired, - onChangePage: PropTypes.func.isRequired, - page: PropTypes.number.isRequired, - rowsPerPage: PropTypes.number.isRequired, - theme: PropTypes.object.isRequired, + classes: PropTypes.object.isRequired, + count: PropTypes.number.isRequired, + onChangePage: PropTypes.func.isRequired, + page: PropTypes.number.isRequired, + rowsPerPage: PropTypes.number.isRequired, + theme: PropTypes.object.isRequired, }; const TablePaginationActionsWrapped = withStyles(actionsStyles, { withTheme: true })( - TablePaginationActions, + TablePaginationActions, ); class CustomerManage extends React.Component { - state = { - rows: [{_id:1, email:'', name:'', active:''}], - page: 0, - rowsPerPage: 15, - }; - - componentDidMount() { - Axios.get('/users') - .then(res => { - this.setState({ - rows: res.data - }) - }) - } - - handleChangePage = (event, page) => { - this.setState({ page }); - }; - - handleChangeRowsPerPage = event => { - this.setState({ rowsPerPage: event.target.value }); - }; - - render() { - const { classes } = this.props; - const { rows, rowsPerPage, page } = this.state; - const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage); - - return ( - -
- - - - E-mail - User Name - Activated - - - - {rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(row => { - return ( - - - {row.email} - - {row.name} - {row.active ? "Yes" : "No"} - - ); - - })} - {emptyRows > 0 && ( - - - - )} - - - - - - -
-
-
- ); - } + state = { + rows: [{ _id: 1, email: '', name: '', active: '' }], + page: 0, + rowsPerPage: 15, + }; + + componentDidMount() { + Axios.get('/users') + .then(res => { + this.setState({ + rows: res.data + }) + }) + } + + handleChangePage = (event, page) => { + this.setState({ page }); + }; + + handleChangeRowsPerPage = event => { + this.setState({ rowsPerPage: event.target.value }); + }; + + render() { + const { classes } = this.props; + const { rows, rowsPerPage, page } = this.state; + const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage); + + return ( + +
+ + + + E-mail + User Name + Activated + + + + {rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(row => { + return ( + + + {row.email} + + {row.name} + {row.active ? "Yes" : "No"} + + ); + + })} + {emptyRows > 0 && ( + + + + )} + + + + + + +
+
+
+ ); + } } CustomerManage.propTypes = { - classes: PropTypes.object.isRequired, + classes: PropTypes.object.isRequired, }; export default withStyles(styles)(CustomerManage); diff --git a/client/src/Admin/index.jsx b/client/src/Admin/index.jsx index 7cb2f5c..38a11ac 100644 --- a/client/src/Admin/index.jsx +++ b/client/src/Admin/index.jsx @@ -12,69 +12,68 @@ import AdminHome from './AdminHome' const styles = theme => ({ - root: { - flexGrow: 1, - backgroundColor: theme.palette.background.paper, - }, + root: { + flexGrow: 1, + backgroundColor: theme.palette.background.paper, + }, - buttonStyle: { - flex: 1,// extend as much as it can - alignSelf: 'stretch', - backgroundColor: '#fff', - borderRadius: 5, - borderWidth: 1, - borderColor: '#007aff', - marginLeft: 5, - marginRight: 5 - }, + buttonStyle: { + flex: 1,// extend as much as it can + alignSelf: 'stretch', + backgroundColor: '#fff', + borderRadius: 5, + borderWidth: 1, + borderColor: '#007aff', + marginLeft: 5, + marginRight: 5 + }, }); function TabContainer(props) { - return ( - - {props.children} - - ); + return ( + + {props.children} + + ); } - TabContainer.propTypes = { - children: PropTypes.node.isRequired, + children: PropTypes.node.isRequired, }; class Admin extends React.Component { - state = { - value: 0, - }; + state = { + value: 0, + }; - handleChange = (event, value) => { - this.setState({ value }); - }; + handleChange = (event, value) => { + this.setState({ value }); + }; - render() { - const { classes } = this.props; - const { value } = this.state; + render() { + const { classes } = this.props; + const { value } = this.state; - return ( -
- - - }/> - - - - - {value === 0 && } - {value === 1 && } - {value === 2 && } -
- ); - } + return ( +
+ + + }/> + + + + + {value === 0 && } + {value === 1 && } + {value === 2 && } +
+ ); + } } Admin.propTypes = { - classes: PropTypes.object.isRequired, + classes: PropTypes.object.isRequired, }; export default withStyles(styles)(Admin); diff --git a/client/src/AllCategoriesPage/childComponent/aBook.js b/client/src/AllCategoriesPage/childComponent/aBook.js index fa8370f..5ea325b 100644 --- a/client/src/AllCategoriesPage/childComponent/aBook.js +++ b/client/src/AllCategoriesPage/childComponent/aBook.js @@ -34,7 +34,8 @@ const styles = { function SimpleMediaCard(props) { const { classes } = props; return ( - + {props.bookAuthor} -

{props.bookReviews}

+

{props.bookReviews}

{props.bookPrice ? `$${props.bookPrice}` : null} diff --git a/client/src/account/common/AccountStyles.js b/client/src/account/common/AccountStyles.js index 3df8c84..80aa3df 100644 --- a/client/src/account/common/AccountStyles.js +++ b/client/src/account/common/AccountStyles.js @@ -1,4 +1,3 @@ -// separate this into each page folder export const styles = { container: { display: 'flex', @@ -6,10 +5,10 @@ export const styles = { flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'center', - padding: '5% 15%' + padding: '5% 15%' }, emailVerificationHint: { - padding: '10%', + padding: '10%', fontSize: '25px' }, verticalCenter: { diff --git a/client/src/account/common/actions/authActions.js b/client/src/account/common/actions/authActions.js index 602dffd..19e3c0d 100644 --- a/client/src/account/common/actions/authActions.js +++ b/client/src/account/common/actions/authActions.js @@ -4,7 +4,6 @@ import { GET_ERRORS, SET_CURRENT_USER } from './types'; import setAuthTokenInHeader from '../utils/setAuthTokenInHeader'; /** - * @todo use Redux for the validation * @param data - User data * @returns boolean is validated */ @@ -97,19 +96,18 @@ export const setCurrentUser = decoded => ({ payload: decoded, }); -// TODO: split it to the right page folder // Login and get the token export const loginUser = userData => (dispatch) => { axios.post('/users/login', userData) - .then((res) => { - const { token } = res.data; - // Save to localStorage - localStorage.setItem('jwtToken', token); - // Set to Axios global header - setAuthTokenInHeader(token); - const decoded = jwt_decode(token); - dispatch(setCurrentUser(decoded)); - }) + .then((res) => { + const { token } = res.data; + // Save to localStorage + localStorage.setItem('jwtToken', token); + // Set to Axios global header + setAuthTokenInHeader(token); + const decoded = jwt_decode(token); + dispatch(setCurrentUser(decoded)); + }) .catch(err => dispatch({ type: GET_ERRORS, payload: err.response.data, @@ -125,7 +123,6 @@ export const logoutUser = () => (dispatch) => { dispatch(setCurrentUser({})); }; -// TODO: move this to account folder export const getCurrentUserInfo = () => (dispatch) => { axios.get('/users/current') .then((res) => { diff --git a/client/src/account/common/reducers/authReducer.js b/client/src/account/common/reducers/authReducer.js index cb86185..a5538e8 100644 --- a/client/src/account/common/reducers/authReducer.js +++ b/client/src/account/common/reducers/authReducer.js @@ -8,23 +8,22 @@ const initialState = { }; export default function (state = initialState, action) { - // TODO: redux-actions switch (action.type) { - case SET_CURRENT_USER: - return { - ...state, - isAuthenticated: !isEmpty(action.payload), - user: action.payload, - }; + case SET_CURRENT_USER: + return { + ...state, + isAuthenticated: !isEmpty(action.payload), + user: action.payload, + }; case SET_AVATAR: - // TODO: refine this const newUser = state.user; + // update the avatar URL in the user newUser.avatar = action.imgURL; return { ...state, user: newUser }; - default: - return state; + default: + return state; } } diff --git a/client/src/account/common/reducers/errorReducer.js b/client/src/account/common/reducers/errorReducer.js index 9b171a2..4e2026c 100644 --- a/client/src/account/common/reducers/errorReducer.js +++ b/client/src/account/common/reducers/errorReducer.js @@ -5,10 +5,10 @@ const initialState = {}; export default function (state = initialState, action) { switch (action.type) { case GET_ERRORS: - if(action.payload.hasOwnProperty('emailexist')) { + if (Object.prototype.hasOwnProperty.call(action.payload, 'emailexist')) { return { email: 'This email address is already singed up.' }; } - if(action.payload.hasOwnProperty('usernotfound')) { + if (Object.prototype.hasOwnProperty.call(action.payload, 'usernotfound')) { return { email: 'The email address is not signed up.' }; } return action.payload; diff --git a/client/src/account/common/utils/dataURLtoFile.js b/client/src/account/common/utils/dataURLtoFile.js index 752d3f0..5771e3e 100644 --- a/client/src/account/common/utils/dataURLtoFile.js +++ b/client/src/account/common/utils/dataURLtoFile.js @@ -1,13 +1,13 @@ export default function dataURLtoFile(dataURL, filename) { - var arr = dataURL.split(','), - mime = arr[0].match(/:(.*?);/)[1], - // remove the header of URL and covert to byte - bstr = atob(arr[1]), - n = bstr.length, - u8arr = new Uint8Array(n); - // handle exceptions. convert <0 to >0 in ascii - while(n--){ - u8arr[n] = bstr.charCodeAt(n); - } - return new File([u8arr], filename, {type:mime}); - } \ No newline at end of file + var arr = dataURL.split(','), + mime = arr[0].match(/:(.*?);/)[1], + // remove the header of URL and covert to byte + bstr = atob(arr[1]), + n = bstr.length, + u8arr = new Uint8Array(n); + // handle exceptions. convert <0 to >0 in ascii + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new File([u8arr], filename, { type: mime }); +} \ No newline at end of file diff --git a/client/src/account/common/utils/isEmpty.js b/client/src/account/common/utils/isEmpty.js index a8567e9..b5ec24e 100644 --- a/client/src/account/common/utils/isEmpty.js +++ b/client/src/account/common/utils/isEmpty.js @@ -1,7 +1,7 @@ // TODO: add to prototype const isEmpty = value => value === undefined - || value === null - || (typeof value === 'object' && Object.keys(value).length === 0) - || (typeof value === 'string' && value.trim().length === 0); + || value === null + || (typeof value === 'object' && Object.keys(value).length === 0) + || (typeof value === 'string' && value.trim().length === 0); export default isEmpty; diff --git a/client/src/account/containers/Account/AccountTab.jsx b/client/src/account/containers/Account/AccountTab.jsx index f743666..5924f4c 100644 --- a/client/src/account/containers/Account/AccountTab.jsx +++ b/client/src/account/containers/Account/AccountTab.jsx @@ -9,66 +9,66 @@ import MyBookLists from './MyBookLists' const styles = theme => ({ - root: { - flexGrow: 1, - backgroundColor: theme.palette.background.paper, - }, + root: { + flexGrow: 1, + backgroundColor: theme.palette.background.paper, + }, - buttonStyle: { - flex: 1,// extend as much as it can - alignSelf: 'stretch', - backgroundColor: '#fff', - borderRadius: 5, - borderWidth: 1, - borderColor: '#007aff', - marginLeft: 5, - marginRight: 5 - }, + buttonStyle: { + flex: 1,// extend as much as it can + alignSelf: 'stretch', + backgroundColor: '#fff', + borderRadius: 5, + borderWidth: 1, + borderColor: '#007aff', + marginLeft: 5, + marginRight: 5 + }, }); function TabContainer(props) { - return ( - - {props.children} - - ); + return ( + + {props.children} + + ); } TabContainer.propTypes = { - children: PropTypes.node.isRequired, + children: PropTypes.node.isRequired, }; class AccountTab extends React.Component { - state = { - value: 0, - }; + state = { + value: 0, + }; - handleChange = (event, value) => { - this.setState({ value }); - }; + handleChange = (event, value) => { + this.setState({ value }); + }; - render() { - const { classes } = this.props; - const { value } = this.state; + render() { + const { classes } = this.props; + const { value } = this.state; - return ( -
- - - - - - {value === 0 && } -
- ); - } + return ( +
+ + + + + + {value === 0 && } +
+ ); + } } AccountTab.propTypes = { - classes: PropTypes.object.isRequired, + classes: PropTypes.object.isRequired, }; export default withStyles(styles)(AccountTab); diff --git a/client/src/account/containers/Account/MyBookLists.jsx b/client/src/account/containers/Account/MyBookLists.jsx index 76d66c3..9a506dd 100644 --- a/client/src/account/containers/Account/MyBookLists.jsx +++ b/client/src/account/containers/Account/MyBookLists.jsx @@ -14,226 +14,226 @@ import { connect } from 'react-redux'; const styles = theme => ({ - buttonWrapper: { - position: 'relative', - marginBottom: theme.spacing.unit * 4, - paddingTop:'20px' - }, - - checked: {}, - typography: { - margin: theme.spacing.unit * 2, - }, - card: { - minWidth: 275, - marginTop:'10px', - backgroundColor:'#FAFAFA', - }, - title: { - marginBottom: 16, - fontSize: 14, - }, - pos: { - marginBottom: 12, - }, - container: { - display: 'flex', - flexWrap: 'wrap', - }, - textField: { - marginLeft: theme.spacing.unit, - marginRight: theme.spacing.unit, - width: 200, - }, - menu: { - width: 200, - }, - paper: { - position: 'absolute', - backgroundColor: theme.palette.background.paper, - boxShadow: theme.shadows[5], - padding: theme.spacing.unit * 4, - top:'26%', - left:'30%', - width:'44%', - height:'31%', - }, - addButton: { - outline:'none', - backgroundColor:'#3D5AFE', - color:'#fff', - width:'170px', - height:'40px', - }, - titleStyle: { - display:'inline', - fontSize:'18px', - paddingBottom:'0', - }, + buttonWrapper: { + position: 'relative', + marginBottom: theme.spacing.unit * 4, + paddingTop: '20px' + }, + + checked: {}, + typography: { + margin: theme.spacing.unit * 2, + }, + card: { + minWidth: 275, + marginTop: '10px', + backgroundColor: '#FAFAFA', + }, + title: { + marginBottom: 16, + fontSize: 14, + }, + pos: { + marginBottom: 12, + }, + container: { + display: 'flex', + flexWrap: 'wrap', + }, + textField: { + marginLeft: theme.spacing.unit, + marginRight: theme.spacing.unit, + width: 200, + }, + menu: { + width: 200, + }, + paper: { + position: 'absolute', + backgroundColor: theme.palette.background.paper, + boxShadow: theme.shadows[5], + padding: theme.spacing.unit * 4, + top: '26%', + left: '30%', + width: '44%', + height: '31%', + }, + addButton: { + outline: 'none', + backgroundColor: '#3D5AFE', + color: '#fff', + width: '170px', + height: '40px', + }, + titleStyle: { + display: 'inline', + fontSize: '18px', + paddingBottom: '0', + }, }); class MyBookLists extends React.Component { - descriptionMinLength = 10; - - state = { - open: false, - isDescriptionWrong: false, - descriptionError: null - }; - - handleCancelButton = () => { - // init error msg - this.setState({ - isDescriptionWrong: false, - descriptionError: null - }); - - this.handleClose(); - }; - - handleClose = () => { - this.setState({ - open: false, - }); - }; - - handleOpen = () => { - this.setState({ - open: true, - }); - }; - - handleConfirmButton = () => { - const { description, title } = this; - if (description.value.length > this.descriptionMinLength) { - // post - this.props.createBookList(title.value, description.value); - this.handleClose(); - } else { - this.setState({ - isDescriptionWrong: true, - descriptionError: 'Too short!' - }) - } - }; - - onKeyDown = e => { - if (e.keyCode === 13 ) { - this.handleConfirmButton() - } - }; - - render() { - const { classes } = this.props; - - return ( -
- - - - -
- - Create a new book list - - - - - - - - - -
- this.title = title} - className={classes.textField} - id="BookListTitle" - required - label="Title" - multiline - /> - - this.description = description} - error={this.state.isDescriptionWrong} - helperText={this.state.descriptionError} - type="text" - /> -
- - -
-
-
-
-
-
- { - this.props.bookLists.map( - (bookList)=>{ - return - - - - {bookList.title} - - - - Update Date: {bookList.updateDate.substring(0,10)} - - - - } - ) - } -
-
- ); - } + descriptionMinLength = 10; + + state = { + open: false, + isDescriptionWrong: false, + descriptionError: null + }; + + handleCancelButton = () => { + // init error msg + this.setState({ + isDescriptionWrong: false, + descriptionError: null + }); + + this.handleClose(); + }; + + handleClose = () => { + this.setState({ + open: false, + }); + }; + + handleOpen = () => { + this.setState({ + open: true, + }); + }; + + handleConfirmButton = () => { + const { description, title } = this; + if (description.value.length > this.descriptionMinLength) { + // post + this.props.createBookList(title.value, description.value); + this.handleClose(); + } else { + this.setState({ + isDescriptionWrong: true, + descriptionError: 'Too short!' + }) + } + }; + + onKeyDown = e => { + if (e.keyCode === 13) { + this.handleConfirmButton() + } + }; + + render() { + const { classes } = this.props; + + return ( +
+ + + + +
+ + Create a new book list + + + + + + + + + +
+ this.title = title} + className={classes.textField} + id="BookListTitle" + required + label="Title" + multiline + /> + + this.description = description} + error={this.state.isDescriptionWrong} + helperText={this.state.descriptionError} + type="text" + /> +
+ + +
+
+
+
+
+
+ { + this.props.bookLists.map( + (bookList) => { + return + + + + {bookList.title} + + + + Update Date: {bookList.updateDate.substring(0, 10)} + + + + } + ) + } +
+
+ ); + } } MyBookLists.propTypes = { - bookLists: PropTypes.array.isRequired, - classes: PropTypes.object.isRequired, + bookLists: PropTypes.array.isRequired, + classes: PropTypes.object.isRequired, }; export default compose( - withStyles(styles), - connect( state => ({bookLists: state.user.bookLists}), { createBookList }) + withStyles(styles), + connect(state => ({ bookLists: state.user.bookLists }), { createBookList }) )(MyBookLists); diff --git a/client/src/account/containers/Account/actions.js b/client/src/account/containers/Account/actions.js index 6f5f27f..1c03393 100644 --- a/client/src/account/containers/Account/actions.js +++ b/client/src/account/containers/Account/actions.js @@ -1,12 +1,12 @@ -import Axios from 'axios'; -import {createAction} from 'redux-actions'; +import axios from 'axios'; +import { createAction } from 'redux-actions'; import swal from 'sweetalert2'; -import {showErrorMsgFromErrorObject} from '../../../common/utils/sweetAlert'; +import { showErrorMsgFromErrorObject } from '../../../common/utils/sweetAlert'; export const setCurrentUserBookLists = createAction('SET_CURRENT_USER_BOOKLISTS'); export const getCurrentUserBookLists = () => (dispatch) => { - Axios.get('/users/current/booklist') + axios.get('/users/current/booklist') .then((res) => { dispatch(setCurrentUserBookLists(res.data)); }) @@ -14,7 +14,7 @@ export const getCurrentUserBookLists = () => (dispatch) => { }; export const createBookList = (title, description) => (dispatch) => { - Axios.post('/booklists', {title, description}) + axios.post('/booklists', { title, description }) .then(() => { // refresh getCurrentUserBookLists()(dispatch); diff --git a/client/src/account/containers/Account/index.jsx b/client/src/account/containers/Account/index.jsx index 0d17629..96da5d8 100644 --- a/client/src/account/containers/Account/index.jsx +++ b/client/src/account/containers/Account/index.jsx @@ -1,142 +1,142 @@ import React from 'react'; -import {withStyles} from '@material-ui/core/styles'; +import { withStyles } from '@material-ui/core/styles'; import Modal from 'react-responsive-modal'; import AccountTab from './AccountTab' -import {styles as accountStyles} from '../../common/AccountStyles'; +import { styles as accountStyles } from '../../common/AccountStyles'; import AvatarUploader from "../AvatarUploader"; -import {connect} from 'react-redux'; -import {compose} from "redux"; -import {getCurrentUserInfo} from '../../common/actions/authActions'; +import { connect } from 'react-redux'; +import { compose } from "redux"; +import { getCurrentUserInfo } from '../../common/actions/authActions'; import isEmpty from '../../common/utils/isEmpty' -import {UPLOAD_BASE_URL} from '../../../config'; -import {ImageAvatar, LetterAvatar} from "../AvatarUploader/Avatars"; +import { UPLOAD_BASE_URL } from '../../../config'; +import { ImageAvatar, LetterAvatar } from "../AvatarUploader/Avatars"; import './avatar-uploader.css'; -import {getCurrentUserBookLists} from './actions'; +import { getCurrentUserBookLists } from './actions'; import Button from '@material-ui/core/Button'; const styles = { - row: { - display: 'flex', - justifyContent: 'center', - }, - avatar: { - margin: 10, - }, - bigAvatar: { - width: 160, - height: 160, - backgroundColor: '#E0E0E0', - }, - avatarModal: { - marginTop: '150px', - }, - usernameStyle: { - fontSize: '24px', - fontWeight:'bold', - } + row: { + display: 'flex', + justifyContent: 'center', + }, + avatar: { + margin: 10, + }, + bigAvatar: { + width: 160, + height: 160, + backgroundColor: '#E0E0E0', + }, + avatarModal: { + marginTop: '150px', + }, + usernameStyle: { + fontSize: '24px', + fontWeight: 'bold', + } }; function AccountInfo(props) { - const {username, usernameStyle} = props; - return ( -
-

{username}

-
); + const { username, usernameStyle } = props; + return ( +
+

{username}

+
); } class Account extends React.Component { - constructor(props) { - super(props); - this.state = { - avatarPageOpened: false, - bookLists: null - }; - } + constructor(props) { + super(props); + this.state = { + avatarPageOpened: false, + bookLists: null + }; + } - componentDidMount() { - this.props.getCurrentUserInfo(); - this.props.getCurrentUserBookLists(); - }; + componentDidMount() { + this.props.getCurrentUserInfo(); + this.props.getCurrentUserBookLists(); + }; - onOpenModal = () => { - this.setState({avatarPageOpened: true}); - }; + onOpenModal = () => { + this.setState({ avatarPageOpened: true }); + }; - onCloseModal = () => { - this.setState({avatarPageOpened: false}); - }; + onCloseModal = () => { + this.setState({ avatarPageOpened: false }); + }; - render() { - const {avatarPageOpened} = this.state; - const {container, verticalCenter} = accountStyles; + render() { + const { avatarPageOpened } = this.state; + const { container, verticalCenter } = accountStyles; - const { - classes, - avatarURL, - username, - avatarType - } = this.props; + const { + classes, + avatarURL, + username, + avatarType + } = this.props; - return
+ return
{avatarType === 'letter' ? : - } + }
- +
- {/*Avatar uploader*/} - - - -
; - } + {/*Avatar uploader*/} + + + +
; + } } const mapStateToProps = state => { - // Map user info - if (!isEmpty(state.auth.user)) { - const {id: userId, name: username, email, avatar: avatarURL} = state.auth.user; - let props = { - userId, - username, - email, - }; - if (avatarURL) { - props.avatarType = 'image'; - props.avatarURL = UPLOAD_BASE_URL + '/' + avatarURL; - } else { - props.avatarType = 'letter'; - } - return props; - } - return {} + // Map user info + if (!isEmpty(state.auth.user)) { + const { id: userId, name: username, email, avatar: avatarURL } = state.auth.user; + let props = { + userId, + username, + email, + }; + if (avatarURL) { + props.avatarType = 'image'; + props.avatarURL = UPLOAD_BASE_URL + '/' + avatarURL; + } else { + props.avatarType = 'letter'; + } + return props; + } + return {} }; export default compose( - withStyles(styles), - connect(mapStateToProps, {getCurrentUserInfo, getCurrentUserBookLists}), + withStyles(styles), + connect(mapStateToProps, { getCurrentUserInfo, getCurrentUserBookLists }), )(Account); diff --git a/client/src/account/containers/Account/index.test.js b/client/src/account/containers/Account/index.test.js index 027575c..5df1cfb 100644 --- a/client/src/account/containers/Account/index.test.js +++ b/client/src/account/containers/Account/index.test.js @@ -37,14 +37,12 @@ describe('Test account page', () => { const inputElement = await page.$('input[type=submit]'); await inputElement.click(); await page.waitFor(1000); - // _sleep(5); - // await page.goto(url+'/account'); // a new tab const accountButton = await page.$('a[href$=account]'); await accountButton.click(); await page.waitFor(3000); const url = page.url(); - expect(url).toBe(url+'login'); + expect(url).toBe(url + 'login'); await page.screenshot({ path: '/Users/anluoridge/Downloads/TEMP/KnightFrankAccount.png', diff --git a/client/src/account/containers/Account/reducers.js b/client/src/account/containers/Account/reducers.js index 4e899e4..76779ad 100644 --- a/client/src/account/containers/Account/reducers.js +++ b/client/src/account/containers/Account/reducers.js @@ -2,7 +2,7 @@ import { handleActions } from 'redux-actions'; import { setCurrentUserBookLists } from './actions'; const initialState = { - bookLists: [] + bookLists: [] }; const accountReducer = handleActions({ @@ -12,9 +12,6 @@ const accountReducer = handleActions({ bookLists: payload, }; }, - // [decrementCounter](state) { - // return state - 1; - // }, }, initialState); export default accountReducer; diff --git a/client/src/account/containers/AvatarUploader/Avatars.jsx b/client/src/account/containers/AvatarUploader/Avatars.jsx index 635dbf3..492200a 100644 --- a/client/src/account/containers/AvatarUploader/Avatars.jsx +++ b/client/src/account/containers/AvatarUploader/Avatars.jsx @@ -5,12 +5,6 @@ import PropTypes from 'prop-types'; // Image avatar and letter avatar component. -/** - * - * @param props - * @returns {*} - * @constructor - */ export function ImageAvatar(props) { const { classes, avatarURL, alt } = props; return ( diff --git a/client/src/account/containers/AvatarUploader/avatarReducers.js b/client/src/account/containers/AvatarUploader/avatarReducers.js deleted file mode 100644 index 86d5f9b..0000000 --- a/client/src/account/containers/AvatarUploader/avatarReducers.js +++ /dev/null @@ -1,19 +0,0 @@ -import { SET_AVATAR } from './types'; - -// TODO: -const initialState = { - imgURL: null - // avatarURL: 'Axios' -}; - -export default function (state = initialState, action) { - switch (action.type) { - case SET_AVATAR: - return { - ...state, - imgURL: action.imgURL - }; - default: - return state; - } -} diff --git a/client/src/account/containers/AvatarUploader/index.jsx b/client/src/account/containers/AvatarUploader/index.jsx index 6fbd821..a0dd767 100644 --- a/client/src/account/containers/AvatarUploader/index.jsx +++ b/client/src/account/containers/AvatarUploader/index.jsx @@ -1,79 +1,81 @@ import React, { PureComponent } from 'react'; import Axios from 'axios'; import Button from '@material-ui/core/Button'; -import { default as AvatarEdit }from 'react-avatar-edit'; -import dataURLtoFile from "../../common/utils/dataURLtoFile"; -import { styles } from "../../common/AccountStyles"; +import { default as AvatarEdit } from 'react-avatar-edit'; +import dataURLtoFile from '../../common/utils/dataURLtoFile'; +import { styles } from '../../common/AccountStyles'; import { withRouter } from 'react-router-dom'; import PropTypes from 'prop-types'; -import { setAvatar } from "./actions"; +import { setAvatar } from './actions'; import { connect } from 'react-redux'; -import { compose } from "redux"; +import { compose } from 'redux'; +import { showErrorMsgFromErrorObject, showSuccess } from "../../../common/utils/sweetAlert"; class AvatarUploader extends PureComponent { - constructor(props) { - super(props); - this.state = { - preview: null, - src: null, - }; -} + constructor(props) { + super(props); + this.state = { + preview: null, + src: null, + }; + } + + uploadHandler = () => { + const previewInFile = dataURLtoFile(this.state.preview, "avatar.png"); + const formData = new FormData(); + formData.append('image', previewInFile, previewInFile.name); + Axios({ + method: 'POST', + data: formData, + url: '/upload/avatar', + }) + .then(res => { + this.props.setAvatar(res.data.avatar); + showSuccess(); + window.location.reload(); + }) + .catch(err => showErrorMsgFromErrorObject(err)); + this.props.handleCompletion(); + }; - uploadHandler = () => { - const previewInFile = dataURLtoFile(this.state.preview, "avatar.png"); - const formData = new FormData(); - formData.append('image', previewInFile, previewInFile.name); - Axios({ - method: 'POST', - data: formData, - url: '/upload/avatar', - }) - .then(res =>{ - console.log('upload', res.data.avatar); - this.props.setAvatar(res.data.avatar); - this.props.history.push('account'); - }); - this.props.handleCompletion(); - }; + onClose = () => { + this.setState({ preview: null }) + }; - onClose = () => { - this.setState({preview: null}) - }; + onCrop = (preview) => { + this.setState({ preview }) + }; - onCrop = (preview) => { - this.setState({preview}) - }; + render() { + const { preview, src } = this.state; - render() { - const { preview, src } = this.state; - - return( -
-

My Avatar

-
- - -
- -
- ) - } + return ( +
+

My Avatar

+
+ + +
+ +
+ ) + } } // show the preview of the cropped avatar @@ -81,23 +83,21 @@ class AvatarUploader extends PureComponent { * * @param srcDataURL * base64 url - * @returns {*} - * @constructor */ const Preview = (props) => { - return (props.srcDataURL === null ?
: Preview); - }; + return (props.srcDataURL === null ?
: + Preview); +}; Preview.propTypes = { - srcDataURL: PropTypes.string, + srcDataURL: PropTypes.string, }; AvatarUploader.propTypes = { - handleCompletion: PropTypes.func + handleCompletion: PropTypes.func }; -// export default withRouter(Avatar) export default compose( - withRouter, - connect(null, { setAvatar }), - )(AvatarUploader); + withRouter, + connect(null, { setAvatar }), +)(AvatarUploader); diff --git a/client/src/account/containers/EmailSent/index.jsx b/client/src/account/containers/EmailSent/index.jsx index de66087..20c673d 100644 --- a/client/src/account/containers/EmailSent/index.jsx +++ b/client/src/account/containers/EmailSent/index.jsx @@ -10,9 +10,6 @@ import axios from 'axios'; * If success, the page will show a success message for 2s and direct to the login page. * If failed, the page will show a failure message and go to the home page. * - * @todo use Button property for onClick - * @todo countDown() - * @todo jumpToUsersMailbox() should support various mailbox * @author AnLuoRidge */ @@ -25,17 +22,17 @@ class EmailSent extends Component { axios({ method: 'post', url: '/users/active/', - data: {email: sessionStorage.getItem('unactivatedEmail')} + data: { email: sessionStorage.getItem('unactivatedEmail') } }) .then(this.countDown) .catch(() => { - alert('Fail to send email.'); + alert('Fail to send email.'); }) }; - countDown = () => { - this.setState({timer:'(60s)'}) - }; + countDown = () => { + this.setState({ timer: '(60s)' }) + }; render() { const { container } = styles; @@ -44,15 +41,16 @@ class EmailSent extends Component {

Thank you for signing up!

- We have sent an email with an activation link to your email address. In order to complete the sign-up process, please click the activation link. + We have sent an email with an activation link to your email address. In order to complete the + sign-up process, please click the activation link. If you didn't receive the activation email, click on the button below to resend it.

- +
+ Resend the verification email {this.state.timer.toString()}
); @@ -60,7 +58,7 @@ class EmailSent extends Component { } function jumpToUsersMailbox() { - window.open('http://mail.google.com', '_blank'); + window.open('http://mail.google.com', '_blank'); } export default EmailSent; \ No newline at end of file diff --git a/client/src/account/containers/EmailVerification/index.jsx b/client/src/account/containers/EmailVerification/index.jsx index 476c676..d8d5f9d 100644 --- a/client/src/account/containers/EmailVerification/index.jsx +++ b/client/src/account/containers/EmailVerification/index.jsx @@ -1,46 +1,49 @@ import React from 'react'; import axios from 'axios'; -import {styles} from '../../common/AccountStyles' +import { styles } from '../../common/AccountStyles' class EmailVerification extends React.Component { - state = { - status: '' - }; + state = { + status: '' + }; - verify = token => { - axios.get('/users/active/' + token) - .then(() => { - this.setState({status: "You have been successfully activated!"}); - // back to login page - setTimeout( - () => {window.location = '/login'}, - 1000); - }) - .catch(() => { - this.setState({status: 'Oops! Your activation link is invalid.'}); - // back to home page - setTimeout(() => { - window.location = '/login'}, - 3000); - }); - }; + verify = token => { + axios.get('/users/active/' + token) + .then(() => { + this.setState({ status: "You have been successfully activated!" }); + // back to login page + setTimeout( + () => { + window.location = '/login' + }, + 1000); + }) + .catch(() => { + this.setState({ status: 'Oops! Your activation link is invalid.' }); + // back to home page + setTimeout(() => { + window.location = '/login' + }, + 3000); + }); + }; - componentDidMount() { - const token = this.props.match.params.token; - this.verify(token); - } + componentDidMount() { + const token = this.props.match.params.token; + this.verify(token); + } - render() { - const {emailVerificationHint: hint, container} = styles; + render() { + const { emailVerificationHint: hint, container } = styles; - return ( -
-

- {this.state.status} -

-
- ) - } + return ( +
+

+ {this.state.status} +

+
+ ) + } } export default EmailVerification; diff --git a/client/src/account/containers/KFAccountInput.jsx b/client/src/account/containers/KFAccountInput.jsx index 115a18e..a0948cd 100644 --- a/client/src/account/containers/KFAccountInput.jsx +++ b/client/src/account/containers/KFAccountInput.jsx @@ -11,9 +11,10 @@ export default function KFAccountInput(props) { } = props; return ( + style={{ width: '330px' }}> {name} - + {error && {error}} ); diff --git a/client/src/account/containers/LoginForm/index.jsx b/client/src/account/containers/LoginForm/index.jsx index 2f2b800..8a9e3c0 100644 --- a/client/src/account/containers/LoginForm/index.jsx +++ b/client/src/account/containers/LoginForm/index.jsx @@ -5,52 +5,54 @@ import Button from '@material-ui/core/Button'; import KFAccountInput from '../KFAccountInput'; import { loginUser } from '../../common/actions/authActions'; import { connect } from 'react-redux'; -import { compose } from "redux"; +import { compose } from 'redux'; +import { swal } from 'sweetalert2'; + const styles = theme => ({ - container: { - display: 'flex', - flexDirection: 'column', - flexWrap: 'wrap', - justifyContent: 'space-between', - alignItems: 'center', - }, - formControl: { - margin: theme.spacing.unit, - }, - underlineStyle: { - color: 'gray', - textDecoration: 'underline' - }, - buttonStyle: { - flex: 1,// extend as much as it can - alignSelf: 'stretch', - backgroundColor: '#fff', - borderRadius: 5, - borderWidth: 1, - borderColor: '#007aff', - marginLeft: 5, - marginRight: 5 - }, - loginTitle: { - fontSize: '42px', - fontWeight: 'normal', - color: '#424242', - marginTop: '40px' - }, - loginBtn: { - width: '200px', - height: '44px', - fontSize: '15px', - fontWeight: 'normal', - marginTop: '20px', - letterSpacing: '1px' - }, - newHere: { - color: 'gray', - textDecoration: 'underline', - marginTop: '10px' - } + container: { + display: 'flex', + flexDirection: 'column', + flexWrap: 'wrap', + justifyContent: 'space-between', + alignItems: 'center', + }, + formControl: { + margin: theme.spacing.unit, + }, + underlineStyle: { + color: 'gray', + textDecoration: 'underline' + }, + buttonStyle: { + flex: 1,// extend as much as it can + alignSelf: 'stretch', + backgroundColor: '#fff', + borderRadius: 5, + borderWidth: 1, + borderColor: '#007aff', + marginLeft: 5, + marginRight: 5 + }, + loginTitle: { + fontSize: '42px', + fontWeight: 'normal', + color: '#424242', + marginTop: '40px' + }, + loginBtn: { + width: '200px', + height: '44px', + fontSize: '15px', + fontWeight: 'normal', + marginTop: '20px', + letterSpacing: '1px' + }, + newHere: { + color: 'gray', + textDecoration: 'underline', + marginTop: '10px' + } }); /** @@ -58,128 +60,119 @@ const styles = theme => ({ * Support ENTER key in password box. */ class LoginForm extends Component { - constructor(props) { - super(props); - this.state = { - email: '', - password: '', - errors: {} - }; - this.handleChange = this.handleChange.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); - this.handleEnter = this.handleEnter.bind(this); - } - /** - if the user has already logged in, redirect to home page. - */ - componentDidMount() { - if (this.props.auth.isAuthenticated) { - this.props.history.push('/'); - } - // TODO: HUD hint - } - - /** - * @todo: how to use 'this' in getDerivedStateFromProps - // static getDerivedStateFromProps(nextProps, prevState) { - // if (nextProps.auth.isAuthenticated) { - // props.history.push('/welcome'); - // } - - // if (nextProps.errors) { - // return{ errors: nextProps.errors }; - // } - // } - * @param nextProps - * @param nextState - */ - componentWillReceiveProps(nextProps, nextState) { - if (nextProps.auth.isAuthenticated) { - this.props.history.push('/'); - } - - if (nextProps.errors) { - this.setState({ errors: nextProps.errors }); - } - } - - handleChange(e) { - this.setState({ [e.target.id]: e.target.value }); - }; - - handleSubmit(e) { - e.preventDefault(); - const userData = { + constructor(props) { + super(props); + this.state = { + email: '', + password: '', + errors: {} + }; + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.handleEnter = this.handleEnter.bind(this); + } + + /** + if the user has already logged in, redirect to home page. + */ + componentDidMount() { + if (this.props.auth.isAuthenticated) { + swal({ + title: 'You are already logged in!', + }) + .then(() => { + this.props.history.push('/'); + }) + } + } + + UNSAFE_componentWillReceiveProps(nextProps, nextState) { + if (nextProps.auth.isAuthenticated) { + this.props.history.push('/'); + } + + if (nextProps.errors) { + this.setState({ errors: nextProps.errors }); + } + } + + handleChange(e) { + this.setState({ [e.target.id]: e.target.value }); + }; + + handleSubmit(e) { + e.preventDefault(); + const userData = { email: this.state.email, password: this.state.password, }; - this.props.loginUser(userData); - }; - - handleEnter(e) { - if(e.keyCode === 13) { - this.handleSubmit(e) - } - }; - - render() { - const { email, password, errors } = this.state; - const { classes } = this.props; - - return ( -
-

Log in

- - - - - - - -
New here?
-
-
- ) - } + this.props.loginUser(userData); + }; + + handleEnter(e) { + if (e.keyCode === 13) { + this.handleSubmit(e) + } + }; + + render() { + const { email, password, errors } = this.state; + const { classes } = this.props; + + return ( +
+

Log in

+ + + + + + + +
New here?
+
+
+ ) + } } LoginForm.propTypes = { - classes: PropTypes.object.isRequired, - loginUser: PropTypes.func.isRequired, - auth: PropTypes.object.isRequired, - errors: PropTypes.object.isRequired, + classes: PropTypes.object.isRequired, + loginUser: PropTypes.func.isRequired, + auth: PropTypes.object.isRequired, + errors: PropTypes.object.isRequired, }; const mapStateToProps = state => ({ - auth: state.auth, - errors: state.errors, + auth: state.auth, + errors: state.errors, }); export default compose( - withStyles(styles), - connect(mapStateToProps, { loginUser }), + withStyles(styles), + connect(mapStateToProps, { loginUser }), )(LoginForm); diff --git a/client/src/account/containers/Register/index.jsx b/client/src/account/containers/Register/index.jsx index 0cf366e..0e0d03e 100644 --- a/client/src/account/containers/Register/index.jsx +++ b/client/src/account/containers/Register/index.jsx @@ -1,161 +1,158 @@ - import React, {Component} from 'react'; -import {connect} from "react-redux"; -import {compose} from "redux"; -import {registerUser} from "../../common/actions/authActions"; -import {PropTypes} from "prop-types"; -import {withRouter} from "react-router-dom"; -import {withStyles} from '@material-ui/core/styles'; +import React, { Component } from 'react'; +import { connect } from "react-redux"; +import { compose } from "redux"; +import { registerUser } from "../../common/actions/authActions"; +import { PropTypes } from "prop-types"; +import { withRouter } from "react-router-dom"; +import { withStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; import KFAccountInput from '../KFAccountInput'; const styles = theme => ({ - container: { - display: 'flex', - flexDirection: 'column', - flexWrap: 'wrap', - justifyContent: 'space-between', - alignItems: 'center', - }, - formControl: { - margin: theme.spacing.unit, - }, - underlineStyle: { - color: 'gray', - textDecoration: 'underline' - }, - loginTitle: { - fontSize: '42px', - fontWeight: 'normal', - color: '#424242', - marginTop: '40px', - }, - registerBtn: { - marginTop: '20px', - outline: 'none' - } + container: { + display: 'flex', + flexDirection: 'column', + flexWrap: 'wrap', + justifyContent: 'space-between', + alignItems: 'center', + }, + formControl: { + margin: theme.spacing.unit, + }, + underlineStyle: { + color: 'gray', + textDecoration: 'underline' + }, + loginTitle: { + fontSize: '42px', + fontWeight: 'normal', + color: '#424242', + marginTop: '40px', + }, + registerBtn: { + marginTop: '20px', + outline: 'none' + } }); class RegisterForm extends Component { - constructor(props) { - super(props); - this.state = { - email: '', - name: '', - password: '', - password2: '', - errors: {}, - } - }; - - static getDerivedStateFromProps(nextProps, prevState) { - // Store prevId in state so we can compare when props change. - if (nextProps.errors) { - return { - errors: nextProps.errors, - }; - } - } - - handleChange = e => { - this.setState({[e.target.id]: e.target.value}); - }; - - handleSubmit = e => { - e.preventDefault(); // prevent resetting the inputs - const {name, email, password, password2} = this.state; - const newUser = { - name, - email, - password, - password2 - }; - - this.props.registerUser(newUser, this.props.history); - }; - - // TODO: !!!! validation action. State of error cannot be changed in the component. - // TODO: move validation out, return errors not boolean. -// TODO: implement better validation approach - render() { - const {underlineStyle} = styles; - const {email, name, password, password2, errors} = this.state; - const {classes} = this.props; - - return
-

Sign up

- - - - - - - - - - - -
- } + constructor(props) { + super(props); + this.state = { + email: '', + name: '', + password: '', + password2: '', + errors: {}, + } + }; + + static getDerivedStateFromProps(nextProps, prevState) { + // Store prevId in state so we can compare when props change. + if (nextProps.errors) { + return { + errors: nextProps.errors, + }; + } + } + + handleChange = e => { + this.setState({ [e.target.id]: e.target.value }); + }; + + handleSubmit = e => { + e.preventDefault(); // prevent resetting the inputs + const { name, email, password, password2 } = this.state; + const newUser = { + name, + email, + password, + password2 + }; + + this.props.registerUser(newUser, this.props.history); + }; + + render() { + const { underlineStyle } = styles; + const { email, name, password, password2, errors } = this.state; + const { classes } = this.props; + + return
+

Sign up

+ + + + + + + + + + + +
+ } } RegisterForm.propTypes = { - registerUser: PropTypes.func.isRequired, - auth: PropTypes.object.isRequired, - errors: PropTypes.object.isRequired, - classes: PropTypes.object.isRequired + registerUser: PropTypes.func.isRequired, + auth: PropTypes.object.isRequired, + errors: PropTypes.object.isRequired, + classes: PropTypes.object.isRequired }; const mapStateToProps = (state) => ({ - auth: state.auth, - errors: state.errors + auth: state.auth, + errors: state.errors }); export default compose( - withStyles(styles), - connect(mapStateToProps, {registerUser}), + withStyles(styles), + connect(mapStateToProps, { registerUser }), )(withRouter(RegisterForm)); diff --git a/client/src/account/containers/Register/index.test.js b/client/src/account/containers/Register/index.test.js index df2578c..b158395 100644 --- a/client/src/account/containers/Register/index.test.js +++ b/client/src/account/containers/Register/index.test.js @@ -25,17 +25,17 @@ describe('Test sign up', () => { browser.close(); }); - it('Success: update the page after the account created', async () => { - const fakeEmail = `${Math.floor((Math.random() * 1000) + 1).toString()}@mail.com`; - await page.type('#email', fakeEmail); - await page.type('#name', 'username'); - await page.type('#password', 'rightPassword'); - await page.type('#password2', 'rightPassword'); - await page.click('Button[id="submit"]'); - await page.waitFor(1000); - const submitButton = await page.$('Button[id="submit"]'); - expect(submitButton).toBe(null); - }); + it('Success: update the page after the account created', async () => { + const fakeEmail = `${Math.floor((Math.random() * 1000) + 1).toString()}@mail.com`; + await page.type('#email', fakeEmail); + await page.type('#name', 'username'); + await page.type('#password', 'rightPassword'); + await page.type('#password2', 'rightPassword'); + await page.click('Button[id="submit"]'); + await page.waitFor(1000); + const submitButton = await page.$('Button[id="submit"]'); + expect(submitButton).toBe(null); + }); it('Validation: Length of password > 5 error hint', async () => { await page.type('#email', 'test@mail.com'); diff --git a/client/src/config.js b/client/src/config.js index 776628a..3c5ba5f 100644 --- a/client/src/config.js +++ b/client/src/config.js @@ -1,3 +1,2 @@ export const UPLOAD_BASE_URL = process.env.NODE_ENV === 'production' ? 'https://lovely-aip.herokuapp.com' : 'http://localhost:5000'; -export const API_BASE_URL = process.env.NODE_ENV === 'production' ? 'https://lovely-aip.herokuapp.com/api' : 'http://localhost:5000/api'; -export const HOME_URL = process.env.NODE_ENV === 'production' ? 'http://knight-frank-web.s3-website-ap-southeast-2.amazonaws.com/' : 'http://localhost:3000'; +export const API_BASE_URL = process.env.NODE_ENV === 'production' ? 'https://lovely-aip.herokuapp.com/api' : 'http://localhost:5000/api'; \ No newline at end of file From 59393d9b28ec0463e9f97c8e3dcd3fa253d3bf85 Mon Sep 17 00:00:00 2001 From: "jennyhu19900914@gmail.com" Date: Thu, 18 Oct 2018 23:31:06 +1100 Subject: [PATCH 09/10] Delete console.log and useless commits --- client/src/AllCategoriesPage/actions.js | 5 +++-- client/src/AllCategoriesPage/categoriesPageCss.js | 4 ---- .../AllCategoriesPage/childComponent/childCategories.js | 1 - client/src/BookList/BookListEditorModal.js | 2 -- client/src/Cart/cartTableRow/component.js | 2 +- client/src/Cart/cartTableRow/index.js | 8 ++++---- client/src/Header/actions.js | 8 ++++---- 7 files changed, 12 insertions(+), 18 deletions(-) diff --git a/client/src/AllCategoriesPage/actions.js b/client/src/AllCategoriesPage/actions.js index 89cabd5..bad8e1d 100644 --- a/client/src/AllCategoriesPage/actions.js +++ b/client/src/AllCategoriesPage/actions.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import { showErrorMsgFromErrorObject } from "../common/utils/sweetAlert"; export const showBooksinCategoryAction = str => ({ type: 'SELECT_CATEGORY', name: str }); export const initialAllCateories = data => ({ type: 'INITIAL_ALL_CATEGORIES', allCategories: data }); @@ -14,7 +15,7 @@ export const getAllCategories = () => (dispatch) => { dispatch(initialAllCateories(response.data)); }) .catch((error) => { - console.log(error); + showErrorMsgFromErrorObject(error); }); }; @@ -34,6 +35,6 @@ export const getBooksInCategories = (id, name) => (dispatch) => { } dispatch(setBooksInCategories(response.data)); }).catch((error) => { - console.log(error); + showErrorMsgFromErrorObject(error); }); }; diff --git a/client/src/AllCategoriesPage/categoriesPageCss.js b/client/src/AllCategoriesPage/categoriesPageCss.js index 7e7c55f..ddc2ecb 100644 --- a/client/src/AllCategoriesPage/categoriesPageCss.js +++ b/client/src/AllCategoriesPage/categoriesPageCss.js @@ -26,11 +26,7 @@ export const booksContainer = { }; export const bookRow = { - // display: 'flex', - // flexDirection: 'row', - // justifyContent: 'space-around', marginTop: '35px', - // marginBottom: '35px', boxSizing: 'border-box', borderLeftStyle: 'solid', borderLeftWidth: '20px', diff --git a/client/src/AllCategoriesPage/childComponent/childCategories.js b/client/src/AllCategoriesPage/childComponent/childCategories.js index 318e7d6..780f14e 100644 --- a/client/src/AllCategoriesPage/childComponent/childCategories.js +++ b/client/src/AllCategoriesPage/childComponent/childCategories.js @@ -33,7 +33,6 @@ class childList extends React.Component { render() { return (
- {console.log(this.props)} {this.props.subcategoriesName.length === 0 ? ( { this.props.getBooksInCategories(this.props.categoryID, this.props.categoriesName); diff --git a/client/src/BookList/BookListEditorModal.js b/client/src/BookList/BookListEditorModal.js index ae8928f..1ae0055 100644 --- a/client/src/BookList/BookListEditorModal.js +++ b/client/src/BookList/BookListEditorModal.js @@ -80,7 +80,6 @@ class BookListEditorModal extends React.Component { margin="dense" value={this.state.title} onChange={event => this.setState({title: event.target.value})} - // inputRef={title => this.setState({title: title.value})} /> this.setState({description: e.target.value})} - // inputRef={description => this.description = description} helperText={this.state.errorMsg} error={this.state.isError} /> diff --git a/client/src/Cart/cartTableRow/component.js b/client/src/Cart/cartTableRow/component.js index 3920a3c..74fa4e4 100644 --- a/client/src/Cart/cartTableRow/component.js +++ b/client/src/Cart/cartTableRow/component.js @@ -20,7 +20,7 @@ const rowComponent = props => ( {props.author} - + ${props.price} diff --git a/client/src/Cart/cartTableRow/index.js b/client/src/Cart/cartTableRow/index.js index b585b5d..653da9c 100644 --- a/client/src/Cart/cartTableRow/index.js +++ b/client/src/Cart/cartTableRow/index.js @@ -11,7 +11,7 @@ class cartTableRow extends Component { number: this.props.number, }; this.handleChange = this.handleChange.bind(this); - this.deleateRow = this.deleateRow.bind(this); + this.deleteRow = this.deleteRow.bind(this); this.props.setEachProductsPriceAction(this.props.totalPrice + this.props.number * this.props.price); } @@ -24,12 +24,12 @@ class cartTableRow extends Component { } } - deleateRow(id) { + deleteRow(id) { axios({ method: 'delete', url: `/cart/${id}`, }) - .then((res) => { + .then(_ => { window.location.reload(true); }) .catch((err) => { @@ -47,7 +47,7 @@ class cartTableRow extends Component { price={this.props.price} number={this.state.number} handleChange={this.handleChange} - deleateRow={this.deleateRow} + deleteRow={this.deleteRow} /> ); } diff --git a/client/src/Header/actions.js b/client/src/Header/actions.js index a46f2ac..b41eaca 100644 --- a/client/src/Header/actions.js +++ b/client/src/Header/actions.js @@ -1,9 +1,9 @@ import axios from 'axios'; -import { showSuccess } from "../common/utils/sweetAlert"; +import { showSuccess,showErrorMsgFromErrorObject } from "../common/utils/sweetAlert"; + export const setCartNumberAction = number => ({ type: 'SET_CART_NUMBER', cartNumber: number }); export const addBookToCart = { type: 'ADD_CART_NUMBER' }; -// export const initialCartContent = data => ({ type: 'SET_ini_CART', cartContent: data }); export const getUsersCart = () => (dispatch) => { axios({ @@ -14,7 +14,7 @@ export const getUsersCart = () => (dispatch) => { dispatch(setCartNumberAction(res.data.length)); }) .catch((err) => { - console.log(err); + showErrorMsgFromErrorObject(err); }); }; @@ -32,6 +32,6 @@ export const addBookToCartData = (bookid, count) => (dispatch) => { showSuccess(); }) .catch((error) => { - console.log(error); + showErrorMsgFromErrorObject(error); }); }; From 97e11f6368b970f9ee8f79e264311348d03c1eb7 Mon Sep 17 00:00:00 2001 From: Steven Ding Date: Fri, 19 Oct 2018 00:29:47 +1100 Subject: [PATCH 10/10] Reformat all the code --- client/src/AllCategoriesPage/actions.js | 16 +- .../childComponent/booksInCategory.js | 8 +- .../childComponent/categoriesBar.js | 12 +- .../childComponent/childCategories.js | 13 +- client/src/BookList/BookListEditorModal.js | 2 - client/src/BookList/index.js | 128 +++++----- client/src/BookPage/actions.js | 1 - client/src/BookPage/booksPageCss.js | 7 - .../src/BookPage/childComponent/addReview.js | 5 +- .../childComponent/bookInformation.js | 32 ++- .../src/BookPage/childComponent/dropDown.js | 23 +- client/src/BookPage/childComponent/moudel.js | 12 +- .../BookPage/childComponent/reviewOfBook.js | 4 +- client/src/BookPage/component.js | 6 +- client/src/BookPage/index.js | 17 +- client/src/Cart/CheckOutButton.js | 4 +- client/src/Cart/cartTable.js | 3 +- client/src/Cart/cartTableRow/actions.js | 1 - client/src/Cart/cartTableRow/component.js | 3 +- client/src/Cart/cartTableRow/index.js | 4 +- client/src/Cart/index.js | 5 +- client/src/Footer/index.jsx | 24 +- client/src/Header/actions.js | 5 +- client/src/Header/authPage.js | 6 +- client/src/Header/badgeIcon.js | 6 +- client/src/Header/index.jsx | 24 +- client/src/Header/navigationBar.js | 10 +- client/src/PageNotFound/index.jsx | 41 ++-- client/src/Payment/DeliveryInfo.jsx | 146 ------------ client/src/Payment/DetailConfirm.jsx | 72 ------ client/src/Payment/PaymentSelect.jsx | 111 --------- client/src/Payment/index.jsx | 218 ------------------ client/src/Payment/payment.css | 0 client/src/RSS/BookListFeed.js | 21 -- client/src/Recommendation/action.js | 5 +- client/src/Recommendation/index.jsx | 2 +- client/src/Search/index.js | 25 +- client/src/Search/showBook.js | 18 +- client/src/Search/showList.js | 5 +- client/src/Welcome/actions.js | 13 +- client/src/Welcome/carouselDIV.js | 11 +- client/src/Welcome/index.jsx | 4 +- client/src/Welcome/popularBooks.js | 2 +- client/src/Welcome/rowOfBookComponent.js | 56 ++--- client/src/Welcome/welcomePageCss.js | 25 -- client/src/common/utils/printObject.js | 12 +- client/src/common/utils/sweetAlert.js | 68 +++--- client/src/routers/mainRouter.jsx | 2 - 48 files changed, 336 insertions(+), 902 deletions(-) delete mode 100644 client/src/BookPage/actions.js delete mode 100644 client/src/Payment/DeliveryInfo.jsx delete mode 100644 client/src/Payment/DetailConfirm.jsx delete mode 100644 client/src/Payment/PaymentSelect.jsx delete mode 100644 client/src/Payment/index.jsx delete mode 100644 client/src/Payment/payment.css delete mode 100644 client/src/RSS/BookListFeed.js delete mode 100644 client/src/Welcome/welcomePageCss.js diff --git a/client/src/AllCategoriesPage/actions.js b/client/src/AllCategoriesPage/actions.js index bad8e1d..9b25b71 100644 --- a/client/src/AllCategoriesPage/actions.js +++ b/client/src/AllCategoriesPage/actions.js @@ -4,18 +4,18 @@ import { showErrorMsgFromErrorObject } from "../common/utils/sweetAlert"; export const showBooksinCategoryAction = str => ({ type: 'SELECT_CATEGORY', name: str }); export const initialAllCateories = data => ({ type: 'INITIAL_ALL_CATEGORIES', allCategories: data }); export const setBooksInCategories = data => ({ type: 'SET_BOOKS_IN_CATEGORIES', booksInCategories: data }); -export const clearBooksinCategoryAction = () => dispatch => dispatch({ type: 'SELECT_CATEGORY', name: { mainCategories: 'All', subCategories: '' } }); +export const clearBooksinCategoryAction = () => dispatch => dispatch({ + type: 'SELECT_CATEGORY', + name: { mainCategories: 'All', subCategories: '' } +}); export const getAllCategories = () => (dispatch) => { - axios({ - method: 'get', - url: '/categories', - }) + axios.get('/categories') .then((response) => { dispatch(initialAllCateories(response.data)); }) .catch((error) => { - showErrorMsgFromErrorObject(error); + showErrorMsgFromErrorObject(error); }); }; @@ -35,6 +35,6 @@ export const getBooksInCategories = (id, name) => (dispatch) => { } dispatch(setBooksInCategories(response.data)); }).catch((error) => { - showErrorMsgFromErrorObject(error); - }); + showErrorMsgFromErrorObject(error); + }); }; diff --git a/client/src/AllCategoriesPage/childComponent/booksInCategory.js b/client/src/AllCategoriesPage/childComponent/booksInCategory.js index d6308e9..20e82e1 100644 --- a/client/src/AllCategoriesPage/childComponent/booksInCategory.js +++ b/client/src/AllCategoriesPage/childComponent/booksInCategory.js @@ -11,12 +11,14 @@ export default class booksPage extends Component {
  • {this.props.categoryName}
  • {this.props.subCategoryName - ? (
  • ›
  • -
  • {this.props.subCategoryName}
  • ) : (null) + ? (
    +
  • ›
  • +
  • {this.props.subCategoryName}
  • +
    ) : (null) }
-
+
{this.props.booksInCategories.length !== 0 ? (
{this.props.booksInCategories.map( diff --git a/client/src/AllCategoriesPage/childComponent/categoriesBar.js b/client/src/AllCategoriesPage/childComponent/categoriesBar.js index bdc7955..21b0a8a 100644 --- a/client/src/AllCategoriesPage/childComponent/categoriesBar.js +++ b/client/src/AllCategoriesPage/childComponent/categoriesBar.js @@ -20,13 +20,19 @@ class NestedList extends React.Component { return (
All Categories} + subheader={All + Categories} > -
+
{ this.props.categoriesList.map( item => ( diff --git a/client/src/AllCategoriesPage/childComponent/childCategories.js b/client/src/AllCategoriesPage/childComponent/childCategories.js index 780f14e..dd6c099 100644 --- a/client/src/AllCategoriesPage/childComponent/childCategories.js +++ b/client/src/AllCategoriesPage/childComponent/childCategories.js @@ -38,12 +38,12 @@ class childList extends React.Component { this.props.getBooksInCategories(this.props.categoryID, this.props.categoriesName); this.handleClick(this.props.categoriesName); }} component={Link} to={`/categories/${this.props.categoryID}`}> - + ) : ( this.handleClick(this.props.categoriesName)}> - - {this.state.open ? : } + + {this.state.open ? : } )} @@ -55,13 +55,16 @@ class childList extends React.Component { key={subitems._id} button onClick={() => { - this.props.updateCategory({ mainCategories: this.props.categoriesName, subCategories: subitems.subname }); + this.props.updateCategory({ + mainCategories: this.props.categoriesName, + subCategories: subitems.subname + }); this.props.getBooksInCategories(subitems.subid, this.props.categoriesName); }} component={Link} to={`/categories/${subitems.subid}`} > - + ), ) } diff --git a/client/src/BookList/BookListEditorModal.js b/client/src/BookList/BookListEditorModal.js index a6a7ff2..b26a5ff 100644 --- a/client/src/BookList/BookListEditorModal.js +++ b/client/src/BookList/BookListEditorModal.js @@ -84,7 +84,6 @@ class BookListEditorModal extends React.Component { margin="dense" value={this.state.title} onChange={event => this.setState({ title: event.target.value })} - // inputRef={title => this.setState({title: title.value})} /> this.setState({ description: e.target.value })} - // inputRef={description => this.description = description} helperText={this.state.errorMsg} error={this.state.isError} /> diff --git a/client/src/BookList/index.js b/client/src/BookList/index.js index e3e6872..ff4e863 100644 --- a/client/src/BookList/index.js +++ b/client/src/BookList/index.js @@ -23,8 +23,8 @@ const styles = theme => ({ }, table: { minWidth: 700, - minHeight:100, - textAlign: 'center', + minHeight: 100, + textAlign: 'center', }, button: { margin: theme.spacing.unit, @@ -37,43 +37,43 @@ const styles = theme => ({ fontSize: '15px', }, addNewbook: { - outline: 'none', - width: '170px', - backgroundColor: '#3D5AFE', - color: '#fff', - marginRight: '10px' - }, - editBooklist: { - outline: 'none', - width: '80px', - marginRight: '10px', - }, - deleteBookListStyle: { - outline: 'none', - width: '120px', - marginRight: '10px', - }, - bookTitleStyle: { - fontSize: '14px', - fontFamily: '"Lato", "Helvetica Neue", Helvetica, Arial, sans-serif', - }, - cardBorder: { - height: '220px', - borderBottom: '8px #E0E0E0 solid', - }, - tableBook: { - width: '20%', - paddingLeft: '20px' - }, - tableTitle: { - width: '50%', - textAlign:'left' - }, + outline: 'none', + width: '170px', + backgroundColor: '#3D5AFE', + color: '#fff', + marginRight: '10px' + }, + editBooklist: { + outline: 'none', + width: '80px', + marginRight: '10px', + }, + deleteBookListStyle: { + outline: 'none', + width: '120px', + marginRight: '10px', + }, + bookTitleStyle: { + fontSize: '14px', + fontFamily: '"Lato", "Helvetica Neue", Helvetica, Arial, sans-serif', + }, + cardBorder: { + height: '220px', + borderBottom: '8px #E0E0E0 solid', + }, + tableBook: { + width: '20%', + paddingLeft: '20px' + }, + tableTitle: { + width: '50%', + textAlign: 'left' + }, container: KFStyles.container, }); class BookList extends React.PureComponent { - constructor(props) { + constructor(props) { super(props); this.state = { userID: '', @@ -89,7 +89,7 @@ class BookList extends React.PureComponent { this.operationButtons = this.operationButtons.bind(this); } - componentDidMount() { + componentDidMount() { this.getBooksInBookList(this.props.match.params.slug); } @@ -140,24 +140,24 @@ class BookList extends React.PureComponent { operationButtons(bookListOwnerId, userId, isAdmin, bookListId) { const deletable = userId === bookListOwnerId || isAdmin; const editable = userId === bookListOwnerId; - const {classes} = this.props; + const { classes } = this.props; return (
{editable && - } {editable && - } {deletable && ) : ( )}
diff --git a/client/src/BookPage/childComponent/bookInformation.js b/client/src/BookPage/childComponent/bookInformation.js index e25e825..f084b87 100644 --- a/client/src/BookPage/childComponent/bookInformation.js +++ b/client/src/BookPage/childComponent/bookInformation.js @@ -12,14 +12,20 @@ const isInstock = number => (number ? 'In Stock.' : 'Out of Stock'); const bookInformation = props => (
- {props.coverUrl &&
000
} + {props.coverUrl && +
000
}

{props.bookName}

{`by ${props.bookAuthor} (Author)`}
-
{props.bookReviews}customer reviews
-
-
{props.description}
+
{props.bookReviews}customer reviews
+
+
{props.description}
@@ -30,25 +36,31 @@ const bookInformation = props => (

{`Price: $${props.bookPrice}`}

Buy - props.onQuantityChange(value)} /> + props.onQuantityChange(value)}/>
{`Total: $${totalPrice(props.quantity, props.bookPrice)}`}

{isInstock(props.stockNumber)}

Deliver to Australia -
+
- } trigger={['click']} > + } + trigger={['click']}>
diff --git a/client/src/BookPage/childComponent/dropDown.js b/client/src/BookPage/childComponent/dropDown.js index e721269..d9080e3 100644 --- a/client/src/BookPage/childComponent/dropDown.js +++ b/client/src/BookPage/childComponent/dropDown.js @@ -12,7 +12,8 @@ const menu = (bookList, open, addBookIntoBooklist, bookid) => ( { bookList.map(item => ( - addBookIntoBooklist(item._id, bookid)}> + addBookIntoBooklist(item._id, bookid)}> {item.title} )) @@ -25,16 +26,16 @@ const menu = (bookList, open, addBookIntoBooklist, bookid) => ( ); const dropdown = props => (!props.isLogin ? ( -
- - - - You need to login - - - -
-) : menu(props.booklist, props.open, props.addBookIntoBooklist, props.bookid) +
+ + + + You need to login + + + +
+ ) : menu(props.booklist, props.open, props.addBookIntoBooklist, props.bookid) ); export default dropdown; diff --git a/client/src/BookPage/childComponent/moudel.js b/client/src/BookPage/childComponent/moudel.js index 6ad2cc9..a238f2c 100644 --- a/client/src/BookPage/childComponent/moudel.js +++ b/client/src/BookPage/childComponent/moudel.js @@ -40,7 +40,8 @@ class SimpleModal extends React.Component { open={!!this.props.openMoudal} onClose={this.props.handleClose} > -
+

Creat a new BookList

this.onChangeHandle(event.target.value) } + onChange={event => this.onChangeHandle(event.target.value)} /> - - + +
diff --git a/client/src/BookPage/childComponent/reviewOfBook.js b/client/src/BookPage/childComponent/reviewOfBook.js index fae4a56..fe513db 100644 --- a/client/src/BookPage/childComponent/reviewOfBook.js +++ b/client/src/BookPage/childComponent/reviewOfBook.js @@ -37,12 +37,12 @@ const reviewOfBook = props => ( {item.username}
- +
{new Date(item.createDate).toLocaleString()}

- [Verified Purchase]

+ [Verified Purchase]

{item.content}
diff --git a/client/src/BookPage/component.js b/client/src/BookPage/component.js index eadb833..d22735d 100644 --- a/client/src/BookPage/component.js +++ b/client/src/BookPage/component.js @@ -40,19 +40,19 @@ const BooksPageComponent = props => ( addBookIntoBooklist={props.addBookIntoBooklist} id={props.id} /> -
+
{(props.relatedBookList && props.relatedBookList.books.length > 1) ? () : null} -
+
{/* review */}

Reviews

-
+
{/* Review Editor */} { this.getUserBookList(); this.handleClose(); }) + .then(() => { + this.getUserBookList(); + this.handleClose(); + }) .catch((error => showErrorMsgFromErrorObject(error))); } addBookIntoBooklist(booklistId, bookId) { const url = `/booklists/book/${booklistId}/${bookId}`; axios.post(url) - .then(() => { showSuccess(); }) + .then(() => { + showSuccess(); + }) .catch((error => showErrorMsgFromErrorObject(error))); } getRelateBookList(category) { axios.get(`/categories/${category}`) - .then((response) => { this.setState({ relatedBookList: response.data }); }) + .then((response) => { + this.setState({ relatedBookList: response.data }); + }) .catch(error => showErrorMsgFromErrorObject(error)); } @@ -166,7 +173,9 @@ class BooksPage extends Component { description={description} bookPrice={price} quantity={quantity} - onQuantityChange={(quantity) => { this.setState({ quantity }); }} + onQuantityChange={(quantity) => { + this.setState({ quantity }); + }} stockNumber={stock} views={reviews} submittedReviewStar={submittedReviewStar} diff --git a/client/src/Cart/CheckOutButton.js b/client/src/Cart/CheckOutButton.js index d6e35c4..bd211fe 100644 --- a/client/src/Cart/CheckOutButton.js +++ b/client/src/Cart/CheckOutButton.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {withStyles} from '@material-ui/core/styles'; +import { withStyles } from '@material-ui/core/styles'; import Card from '@material-ui/core/Card'; import CardActions from '@material-ui/core/CardActions'; import CardContent from '@material-ui/core/CardContent'; @@ -39,7 +39,7 @@ function onClickCheckOut() { } function CheckOutButton(props) { - const {classes} = props; + const { classes } = props; return ( diff --git a/client/src/Cart/cartTable.js b/client/src/Cart/cartTable.js index 889fc6b..d3a76cc 100644 --- a/client/src/Cart/cartTable.js +++ b/client/src/Cart/cartTable.js @@ -37,7 +37,8 @@ function cartTable(props) { - {props.cartBooks.length === 0 ? (

Nothing Here

) : ( + {props.cartBooks.length === 0 ? ( +

Nothing Here

) : ( props.cartBooks.map(row => ( ({ type: 'SET_PRODUCTS_TOTALPRICE', totalPrice: number }); -// export const initialCartContent = data => ({ type: 'SET_ini_CART', cartContent: data }); diff --git a/client/src/Cart/cartTableRow/component.js b/client/src/Cart/cartTableRow/component.js index 74fa4e4..6539718 100644 --- a/client/src/Cart/cartTableRow/component.js +++ b/client/src/Cart/cartTableRow/component.js @@ -20,7 +20,8 @@ const rowComponent = props => ( {props.author} - +
${props.price} diff --git a/client/src/Cart/cartTableRow/index.js b/client/src/Cart/cartTableRow/index.js index 653da9c..0d4fa5b 100644 --- a/client/src/Cart/cartTableRow/index.js +++ b/client/src/Cart/cartTableRow/index.js @@ -61,7 +61,9 @@ function mapStateToProps(state) { function mapDispatchToProps(dispatch) { return { - setEachProductsPriceAction: (number) => { dispatch(setEachProductsPriceAction(number)); }, + setEachProductsPriceAction: (number) => { + dispatch(setEachProductsPriceAction(number)); + }, }; } diff --git a/client/src/Cart/index.js b/client/src/Cart/index.js index 1501b6f..4d93417 100644 --- a/client/src/Cart/index.js +++ b/client/src/Cart/index.js @@ -29,8 +29,9 @@ class CartTablePage extends Component {

Cart

-
-
+
+
); diff --git a/client/src/Footer/index.jsx b/client/src/Footer/index.jsx index bf26c08..71d298f 100644 --- a/client/src/Footer/index.jsx +++ b/client/src/Footer/index.jsx @@ -9,19 +9,19 @@ import { API_BASE_URL, UPLOAD_BASE_URL } from '../config'; const footerPageIndex = () => (
- logo + logo
Made by Lovely AIP
- +
diff --git a/client/src/Header/actions.js b/client/src/Header/actions.js index 7f489c5..01a2f2c 100644 --- a/client/src/Header/actions.js +++ b/client/src/Header/actions.js @@ -12,9 +12,6 @@ export const getUsersCart = () => (dispatch) => { }) .then((res) => { dispatch(setCartNumberAction(res.data.length)); - }) - .catch((err) => { - console.log(err.reponse.data); }); }; @@ -32,6 +29,6 @@ export const addBookToCartData = (bookid, count) => (dispatch) => { showSuccess(); }) .catch((error) => { - showErrorMsgFromErrorObject(error); + showErrorMsgFromErrorObject(error); }); }; diff --git a/client/src/Header/authPage.js b/client/src/Header/authPage.js index 954c65e..2250b9b 100644 --- a/client/src/Header/authPage.js +++ b/client/src/Header/authPage.js @@ -23,7 +23,7 @@ function MenuItems(props) { } return ( - + Log in @@ -61,8 +61,8 @@ class AuthIcon extends Component { return (
+ onClick={this.handleClick} + >
({ // The border color match the background color. border: `2px solid ${ theme.palette.type === 'light' ? theme.palette.grey[200] : theme.palette.grey[900] - }`, + }`, }, }); @@ -24,10 +24,10 @@ function CustomizedBadge(props) { { props.number === 0 || !props.number ? ( - + ) : ( - + ) } diff --git a/client/src/Header/index.jsx b/client/src/Header/index.jsx index f9363b5..9d73ff7 100644 --- a/client/src/Header/index.jsx +++ b/client/src/Header/index.jsx @@ -62,7 +62,7 @@ class headerPageIndex extends Component { onKeyDown(e) { // if ENTER pushed - if(e.keyCode === 13) { + if (e.keyCode === 13) { this.onSearchClick(); } } @@ -75,7 +75,7 @@ class headerPageIndex extends Component { iconLogo, searchIcon, rightIcon, - dashboardStyle + dashboardStyle } = style; return ( @@ -83,7 +83,7 @@ class headerPageIndex extends Component {
@@ -123,15 +123,17 @@ class headerPageIndex extends Component { logoutUser={this.props.logoutUser} /> + number={this.props.cartCount} + auth={this.props.auth.isAuthenticated} + /> {this.props.isAdmin &&
{this.props.history.push('/admin')}} - style={dashboardStyle} - > - + onClick={() => { + this.props.history.push('/admin') + }} + style={dashboardStyle} + > +
}
diff --git a/client/src/Header/navigationBar.js b/client/src/Header/navigationBar.js index 80bc76c..fc9b14d 100644 --- a/client/src/Header/navigationBar.js +++ b/client/src/Header/navigationBar.js @@ -58,16 +58,12 @@ class FullWidthTabs extends React.Component { value={this.state.value} onChange={this.handleChange} indicatorColor="primary" - // textColor="inherit" style={{ color: 'white' }} fullWidth - // scrollable - // scrollButtons="auto" > - - - - {/* */} + + +
diff --git a/client/src/PageNotFound/index.jsx b/client/src/PageNotFound/index.jsx index 91e65ed..0aebf29 100644 --- a/client/src/PageNotFound/index.jsx +++ b/client/src/PageNotFound/index.jsx @@ -2,27 +2,28 @@ import React from 'react'; import UFO from '../Img/ufo.png'; class PageNotFound extends React.Component { - render(){ - return( -
-

-

Oooops ^~^
The page can not be found.

- page not found -

- I wanna go Home -

-

-
+ render() { + return ( +
+

+

Oooops ^~^
The page can not be found.

+ page not found +

+ I wanna go Home +

+

+
- ); - } + ); + } } export default PageNotFound diff --git a/client/src/Payment/DeliveryInfo.jsx b/client/src/Payment/DeliveryInfo.jsx deleted file mode 100644 index 4fbcf96..0000000 --- a/client/src/Payment/DeliveryInfo.jsx +++ /dev/null @@ -1,146 +0,0 @@ -import React, {Component} from 'react'; -import PropTypes from 'prop-types'; -import { withStyles } from '@material-ui/core/styles'; -import MenuItem from '@material-ui/core/MenuItem'; -import TextField from '@material-ui/core/TextField'; -import Table from '@material-ui/core/Table'; -import TableCell from '@material-ui/core/TableCell'; -import TableHead from '@material-ui/core/TableHead'; -import TableRow from '@material-ui/core/TableRow'; -import Select from '@material-ui/core/Select'; -import FormControl from '@material-ui/core/FormControl'; -import InputLabel from '@material-ui/core/InputLabel'; - - - -const styles = theme => ({ - container: { - display: 'flex', - flexWrap: 'wrap', - }, - textField: { - marginLeft: theme.spacing.unit, - marginRight: theme.spacing.unit, - width: 200, - }, - table: { - minWidth: 700, - }, - menu: { - width: 200, - }, - selectEmpty: { - marginTop: theme.spacing.unit * 2, - }, - formControl: { - margin: theme.spacing.unit, - minWidth: 120, - }, -}); - - -class DeliveryInfo extends Component { - state = { - name: 'Jenny', - Email: '', - Phone: '04234234234', - State: 'UNS', - City: 'Sydney', - }; - handleChange = event => { - this.setState({ [event.target.name]: event.target.value }); - }; - - - render() { - const { classes } = this.props; - return ( -
- - - - - - - - - - - - - - - - - State - - - - - - - - - - - -
-
- ); - } -} - -DeliveryInfo.propTypes = { - classes: PropTypes.object.isRequired, -}; - -export default withStyles(styles)(DeliveryInfo); diff --git a/client/src/Payment/DetailConfirm.jsx b/client/src/Payment/DetailConfirm.jsx deleted file mode 100644 index 8a4c4a4..0000000 --- a/client/src/Payment/DetailConfirm.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { withStyles } from '@material-ui/core/styles'; -import Table from '@material-ui/core/Table'; -import TableBody from '@material-ui/core/TableBody'; -import TableCell from '@material-ui/core/TableCell'; -import TableHead from '@material-ui/core/TableHead'; -import TableRow from '@material-ui/core/TableRow'; - -const styles = theme => ({ - root: { - width: '80%', - marginTop: theme.spacing.unit * 3, - overflowX: 'auto', - }, - table: { - minWidth: 700, - }, -}); - -let id = 0; -function createData(BookName, Price, Amount, Cost ) { - id += 1; - return { id, BookName, Price,Amount, Cost}; -} - -const rows = [ - createData('Big Data', 32.1, 2, 64.2), - createData('Data Visulation', 29.1, 1, 29.1), - createData('Internet Programming', 10, 3, 30), -]; - - -class DetailConfirm extends Component{ - render(){ - const { classes } = this.props; - return( - - - - Book Name - Price(AU$) - Amount - Cost - - - - {rows.map(row => { - return ( - - - {row.BookName} - - {row.Price} - {row.Amount} - {row.Cost} - - ); - })} - -
- ); - - } - -} - -DetailConfirm.propTypes = { - classes: PropTypes.object.isRequired, -}; - -export default withStyles(styles)(DetailConfirm); \ No newline at end of file diff --git a/client/src/Payment/PaymentSelect.jsx b/client/src/Payment/PaymentSelect.jsx deleted file mode 100644 index 82c0285..0000000 --- a/client/src/Payment/PaymentSelect.jsx +++ /dev/null @@ -1,111 +0,0 @@ -import React, {Component} from 'react'; -import PropTypes from 'prop-types'; -import { withStyles } from '@material-ui/core/styles'; -import TextField from '@material-ui/core/TextField'; -import Table from '@material-ui/core/Table'; -import TableCell from '@material-ui/core/TableCell'; -import TableHead from '@material-ui/core/TableHead'; -import TableRow from '@material-ui/core/TableRow'; - -const styles = theme => ({ - container: { - display: 'flex', - flexWrap: 'wrap', - }, - textField: { - marginLeft: theme.spacing.unit, - marginRight: theme.spacing.unit, - width: 200, - }, - table: { - minWidth: 700, - }, - menu: { - width: 200, - }, - selectEmpty: { - marginTop: theme.spacing.unit * 2, - }, - formControl: { - margin: theme.spacing.unit, - minWidth: 120, - }, - -}); - - -class PaymentSelect extends Component { - state = { - holdername: ' ', - cardno: '', - expireDate: ' ', - CVV: ' ', - }; - handleChange = event => { - this.setState({ [event.target.name]: event.target.value }); - }; - - - render() { - const { classes } = this.props; - return ( -
- - - - - - - - - - - - - - - - - - - - - -
- - ); - } -} - -PaymentSelect.propTypes = { - classes: PropTypes.object.isRequired, -}; - -export default withStyles(styles)(PaymentSelect); diff --git a/client/src/Payment/index.jsx b/client/src/Payment/index.jsx deleted file mode 100644 index 52c4776..0000000 --- a/client/src/Payment/index.jsx +++ /dev/null @@ -1,218 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { withStyles } from '@material-ui/core/styles'; -import Stepper from '@material-ui/core/Stepper'; -import Step from '@material-ui/core/Step'; -import StepButton from '@material-ui/core/StepButton'; -import Button from '@material-ui/core/Button'; -import Typography from '@material-ui/core/Typography'; -import DetailConfirm from './DetailConfirm'; -import DeliveryInfo from './DeliveryInfo'; -import PaymentSelect from './PaymentSelect'; -import Card from '@material-ui/core/Card'; -import CardActions from '@material-ui/core/CardActions'; -import CardContent from '@material-ui/core/CardContent'; -import CardMedia from '@material-ui/core/CardMedia'; - - -const styles = theme => ({ - root: { - width: '90%', - }, - button: { - marginRight: theme.spacing.unit, - }, - completed: { - display: 'inline-block', - }, - instructions: { - marginTop: theme.spacing.unit, - marginBottom: theme.spacing.unit, - }, - card: { - maxWidth: 345, - }, - media: { - height: 140, - }, -}); - -function getSteps() { - return ['Product Confirm', 'Delivery Info', 'Payment Select']; -} - -function getStepContent(step) { - switch (step) { - case 0: - return (); - case 1: - return (); - case 2: - return (); - default: - return 'Unknown step'; - } -} - -class Payment extends React.Component { - state = { - activeStep: 0, - completed: {}, - }; - - totalSteps = () => { - return getSteps().length; - }; - - handleNext = () => { - let activeStep; - - if (this.isLastStep() && !this.allStepsCompleted()) { - // It's the last step, but not all steps have been completed, - // find the first step that has been completed - const steps = getSteps(); - activeStep = steps.findIndex((step, i) => !(i in this.state.completed)); - } else { - activeStep = this.state.activeStep + 1; - } - this.setState({ - activeStep, - }); - }; - - handleBack = () => { - const { activeStep } = this.state; - this.setState({ - activeStep: activeStep - 1, - }); - }; - - handleStep = step => () => { - this.setState({ - activeStep: step, - }); - }; - - handleComplete = () => { - const { completed } = this.state; - completed[this.state.activeStep] = true; - this.setState({ - completed, - }); - this.handleNext(); - }; - - handleReset = () => { - this.setState({ - activeStep: 0, - completed: {}, - }); - }; - - completedSteps() { - return Object.keys(this.state.completed).length; - } - - isLastStep() { - return this.state.activeStep === this.totalSteps() - 1; - } - - allStepsCompleted() { - return this.completedSteps() === this.totalSteps(); - } - - render() { - const { classes } = this.props; - const steps = getSteps(); - const { activeStep } = this.state; - - return ( -
- - {steps.map((label, index) => { - return ( - - - {label} - - - ); - })} - -
- {this.allStepsCompleted() ? ( -
- - - - - - Success!! - - - The E-mail has been sent to your E-mail. - - - - - - - - -
- ) : ( -
- {getStepContent(activeStep)} -
- - - {activeStep !== steps.length && - (this.state.completed[this.state.activeStep] ? ( - - Step {activeStep + 1} already completed - - ) : ( - - ))} -
-
- )} -
-
- ); - } -} - -Payment.propTypes = { - classes: PropTypes.object, -}; - -export default withStyles(styles)(Payment); diff --git a/client/src/Payment/payment.css b/client/src/Payment/payment.css deleted file mode 100644 index e69de29..0000000 diff --git a/client/src/RSS/BookListFeed.js b/client/src/RSS/BookListFeed.js deleted file mode 100644 index 04a4ad5..0000000 --- a/client/src/RSS/BookListFeed.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import Axios from 'axios'; -import ReactDOM from 'react-dom'; - -class BookListFeed extends React.PureComponent { - componentDidMount() { - Axios.get('/feed/booklists') - .then(res => { - ReactDOM.render( - res.data, - document.getElementById('root') - ); - }) - } - - render() { - return
- } -} - -export default BookListFeed; diff --git a/client/src/Recommendation/action.js b/client/src/Recommendation/action.js index 3336bf5..94158d4 100644 --- a/client/src/Recommendation/action.js +++ b/client/src/Recommendation/action.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import { showErrorMsgFromErrorObject } from "../common/utils/sweetAlert"; export const setBookListDataAction = data => ({ type: 'SET_BOOKLIST_DATA', recommendation: data }); @@ -7,5 +8,7 @@ export const getBookListDataAction = () => (dispatch) => { .then((response) => { dispatch(setBookListDataAction(response.data)); }) - .catch((error) => { console.log(error); }); + .catch((error) => { + showErrorMsgFromErrorObject(error) + }); }; diff --git a/client/src/Recommendation/index.jsx b/client/src/Recommendation/index.jsx index 8d2c3f8..e9fb1bf 100644 --- a/client/src/Recommendation/index.jsx +++ b/client/src/Recommendation/index.jsx @@ -13,7 +13,7 @@ class recommendation extends Component {
- +
); } diff --git a/client/src/Search/index.js b/client/src/Search/index.js index 5bf4391..a000bda 100644 --- a/client/src/Search/index.js +++ b/client/src/Search/index.js @@ -10,11 +10,12 @@ const ShowContent = (bookNotFound, type, content) => { ); } if (type === 'Book Lists') { - return (); - } if (type === 'Books') { - return (); + return (); } - return (); + if (type === 'Books') { + return (); + } + return (); }; class searchIndex extends Component { @@ -41,14 +42,14 @@ class searchIndex extends Component { let searchURL = ''; switch (type.replace('%20', ' ')) { - case 'Books': - searchURL = `/books/search/${parm}?page=1&pageSize=20`; - break; - case 'Book Lists': - searchURL = `/booklists/search/${parm}`; - break; - default: - break; + case 'Books': + searchURL = `/books/search/${parm}?page=1&pageSize=20`; + break; + case 'Book Lists': + searchURL = `/booklists/search/${parm}`; + break; + default: + break; } if (searchURL.length > 0) { diff --git a/client/src/Search/showBook.js b/client/src/Search/showBook.js index 47c4d70..03d64cf 100644 --- a/client/src/Search/showBook.js +++ b/client/src/Search/showBook.js @@ -10,15 +10,15 @@ class showBook extends Component { ? ( this.props.content.map(v => ( )) ) : ( diff --git a/client/src/Search/showList.js b/client/src/Search/showList.js index 0df8ab6..ff69f99 100644 --- a/client/src/Search/showList.js +++ b/client/src/Search/showList.js @@ -22,11 +22,10 @@ class showList extends Component { Books: {v.books.length} - Likes: {v.likes.length} - Create Date: {new Date(v.createDate).toLocaleDateString()} - Updata Date: {new Date(v.updateDate).toLocaleDateString()} + Created Date: {new Date(v.createDate).toLocaleDateString()} + Updated Date: {new Date(v.updateDate).toLocaleDateString()} )) diff --git a/client/src/Welcome/actions.js b/client/src/Welcome/actions.js index 221749b..6ef8965 100644 --- a/client/src/Welcome/actions.js +++ b/client/src/Welcome/actions.js @@ -1,22 +1,21 @@ import axios from 'axios'; +import { showErrorMsgFromErrorObject } from "../common/utils/sweetAlert"; export const setWelcomePageBooksDataAction = data => ({ type: 'SET_WELCOME_BOOKS_DATA', booksInHomePage: data }); -const booklistID = ['5b87b6da566163069154f729', '5b87b55f566163069154f705', '5b83eda73cf33874746df9b1']; +const bookListID = ['5b87b6da566163069154f729', '5b87b55f566163069154f705', '5b83eda73cf33874746df9b1']; export const getWelcomePageBooksDataAction = () => (dispatch) => { const result = []; - booklistID.forEach( + bookListID.forEach( (v) => { - axios({ - method: 'get', - url: `/booklists/${v}`, - }).then((response) => { + axios.get(`/booklists/${v}`) + .then((response) => { result.push(response.data); dispatch(setWelcomePageBooksDataAction(result)); }) .catch((error) => { - console.log(error); + showErrorMsgFromErrorObject(error) }); }, ); diff --git a/client/src/Welcome/carouselDIV.js b/client/src/Welcome/carouselDIV.js index ffab652..e443caa 100644 --- a/client/src/Welcome/carouselDIV.js +++ b/client/src/Welcome/carouselDIV.js @@ -82,8 +82,9 @@ class CarouselDIV extends Component { onExiting={this.onExiting} onExited={this.onExited} > - {item.altText}/ - + {item.altText}/ + )); @@ -94,10 +95,10 @@ class CarouselDIV extends Component { next={this.next} previous={this.previous} > - + {slides} - - + + ); } diff --git a/client/src/Welcome/index.jsx b/client/src/Welcome/index.jsx index 005a7ce..1a63bf1 100644 --- a/client/src/Welcome/index.jsx +++ b/client/src/Welcome/index.jsx @@ -17,10 +17,10 @@ class welcomePageIndex extends Component { height: 'auto', width: '80%', marginLeft: '10%', marginTop: '10px', }}> {/* Carousel */} - + {/* Render books from database */} {this.props.booksInHomePage ? : null}
); diff --git a/client/src/Welcome/popularBooks.js b/client/src/Welcome/popularBooks.js index 02402f0..41e23e5 100644 --- a/client/src/Welcome/popularBooks.js +++ b/client/src/Welcome/popularBooks.js @@ -10,7 +10,7 @@ export default class PopularBooks extends Component { {this.props.bookList.map(obj => (

{obj.title || obj.name}

-
+
))} diff --git a/client/src/Welcome/rowOfBookComponent.js b/client/src/Welcome/rowOfBookComponent.js index 6ea04bd..f4759c0 100644 --- a/client/src/Welcome/rowOfBookComponent.js +++ b/client/src/Welcome/rowOfBookComponent.js @@ -5,7 +5,7 @@ import ArrowLeft from '@material-ui/icons/ArrowLeft'; import Book from '../AllCategoriesPage/childComponent/aBook'; -// According to window's width, caculate the variables: +// According to window's width, calculate the variables: // numberOfCard: the length of books in row // bookMarginRight: the margin right of each book component // transformation: How many pixels will row component move when buttons clicked @@ -98,23 +98,23 @@ export default class rowOfBookComponent extends Component { onMouseOver={() => this.decreaseButtonOver()} onMouseLeave={() => this.decreaseButtonLeave()} onClick={() => this.decreaseTransform()} style={{ - zIndex: '11', - opacity: '0.4', - backgroundColor: 'gray', - height: '100%', - width: '15px', - position: 'absolute', - left: '0px', - top: '0px', - overflow: 'hidden', - paddingLeft: '0', - paddingRight: '0', - transition: 'transform 0.5s', - transform: `translateX(${this.state.decreaseButtonTransform}%)`, - }}> + zIndex: '11', + opacity: '0.4', + backgroundColor: 'gray', + height: '100%', + width: '15px', + position: 'absolute', + left: '0px', + top: '0px', + overflow: 'hidden', + paddingLeft: '0', + paddingRight: '0', + transition: 'transform 0.5s', + transform: `translateX(${this.state.decreaseButtonTransform}%)`, + }}>
); } @@ -164,7 +164,7 @@ export default class rowOfBookComponent extends Component { transition: 'transform 0.5s', transform: `translateX(${this.state.increaseButtonTransform}%)`, }}> + style={{ zIndex: '5', fontSize: '100px', color: 'white' }}/>
); } diff --git a/client/src/Welcome/welcomePageCss.js b/client/src/Welcome/welcomePageCss.js deleted file mode 100644 index 67f3237..0000000 --- a/client/src/Welcome/welcomePageCss.js +++ /dev/null @@ -1,25 +0,0 @@ -export const carouselDive = { - height: '150px', - width: '100%', - marginLeft: '20%', -}; - -export const eachBook = { - height: '270px', - width: '160px', - fontSize: '15px', - display: 'flex', - justifyContent: 'space-evenly', - flexDirection: 'column', -}; - -export const bookRow = { - display: 'flex', - flexDirection: 'row', - // justifyContent: 'space-around', - marginBottom: '35px', - boxSizing: 'border-box', - borderLeftStyle: 'solid', - borderLeftWidth: '2px', - borderColor: 'white', -}; diff --git a/client/src/common/utils/printObject.js b/client/src/common/utils/printObject.js index d3b5a88..363f2c0 100644 --- a/client/src/common/utils/printObject.js +++ b/client/src/common/utils/printObject.js @@ -1,8 +1,8 @@ export default function printObj(obj) { - let output = ''; - for (const key in obj) { - const value = obj[key]; - output += value + '\n'; - } - return output; + let output = ''; + for (const key in obj) { + const value = obj[key]; + output += value + '\n'; + } + return output; } diff --git a/client/src/common/utils/sweetAlert.js b/client/src/common/utils/sweetAlert.js index 0d3051e..7bb150c 100644 --- a/client/src/common/utils/sweetAlert.js +++ b/client/src/common/utils/sweetAlert.js @@ -2,50 +2,50 @@ import swal from 'sweetalert2'; import printObj from './printObject'; export function showErrorMsg(msg) { - swal({ - position: 'top', - title: 'Oops!', - text: msg, - showConfirmButton: false, - timer: 2000 - }) + swal({ + position: 'top', + title: 'Oops!', + text: msg, + showConfirmButton: false, + timer: 2000 + }) } export function showErrorMsgFromObject(obj) { - swal({ - position: 'top', - title: 'Oops!', - text: printObj(obj), - showConfirmButton: false, - timer: 2000 - }) + swal({ + position: 'top', + title: 'Oops!', + text: printObj(obj), + showConfirmButton: false, + timer: 2000 + }) } export function showErrorMsgFromErrorObject(obj) { - swal({ - position: 'top', - title: 'Oops!', - text: printObj(obj.response.data), - showConfirmButton: false, - timer: 2000 - }) + swal({ + position: 'top', + title: 'Oops!', + text: printObj(obj.response.data), + showConfirmButton: false, + timer: 2000 + }) } export function alertDeleted() { - swal({ - position: 'top', - title: 'Deleted!', - showConfirmButton: false, - timer: 2000 - }) + swal({ + position: 'top', + title: 'Deleted!', + showConfirmButton: false, + timer: 2000 + }) } export function showSuccess() { - swal({ - position: 'top', - type: 'success', - title: 'Success!', - showConfirmButton: false, - timer: 1500 - }); + swal({ + position: 'top', + type: 'success', + title: 'Success!', + showConfirmButton: false, + timer: 1500 + }); } diff --git a/client/src/routers/mainRouter.jsx b/client/src/routers/mainRouter.jsx index 39549bd..c1e7f06 100644 --- a/client/src/routers/mainRouter.jsx +++ b/client/src/routers/mainRouter.jsx @@ -14,7 +14,6 @@ import Cart from '../Cart'; import Admin from '../Admin'; import BookListDetail from '../BookList/index'; import Recommendation from '../Recommendation'; -import BookListFeed from '../RSS/BookListFeed'; import Search from '../Search'; import PageNotFound from '../PageNotFound'; @@ -36,7 +35,6 @@ const MainRoute = (props) => { -