User:HKhan619/sandbox

Links to refer

https://www.w3schools.com/

https://angularjs.org/

https://thinkster.io/

https://docs.oracle.com

https://www.javatpoint.com

https://www.google.lk

https://www.mongodb.com/

https://spring.io/

http://projects.spring.io

http://mongoosejs.com/

https://www.npmjs.com/

https://registry.npmjs.org/

https://repo.maven.apache.org/maven2/

https://repo1.maven.org/maven2/

MERN Stack App

Package.json - server

npm init

node modules for server

npm i express body-parser mongoose concurrently

Nodemon for server

npm i -D nodemon

Run server

npm run server

To create client App (Inside a new client folder)

npm i -g create-react-app => Initial time(Globally)

create-react-app => After install

npm i bootstrap reactstrap uuid react-transition-group

npm i redux react-redux redux-thunk

npm i axios => for dbs

server.js const express = require('express'), bodyparser = require('body-parser'), mongoose = require('mongoose'), books = require('./routes/api/books'),

authors = require('./routes/api/authors');

const app = express;

//BodyParser Middleware

app.use(bodyparser.json);

//URI MongoDB

const url = 'mongodb://localhost/Library';

//Connect to MongoDB

mongoose.connect(url, function (err, con) {

if (err) {

console.log ('ERROR connecting to: ' + url + '. ' + err);

} else {

console.log ('Succeeded connected to: ' + url);

}

});

//Use routes

app.use('/api/books', books);

app.use('/api/authors', authors);

app.listen(3001, function {

console.log('App listening on port 3001!!!')

});

package.json => server

{

"name": "libraryapp",

"version": "1.0.0",

"description": "Books and Authors",

"main": "server.js",

"scripts": {

"client-install": "npm install --prefix client",

"start": "node server.js",

"server": "nodemon server.js",

"client": "npm start --prefix client",

"dev": "concurrently \"npm run server\" \"npm run client\""

},

"author": "Hashan Kavinda",

"license": "MIT",

"devDependencies": {

"nodemon": "^1.18.8"

} }

Create a new routes folder => api folder => books.js

books.js

const express = require('express');

const router = express.Router;

//Book Model

const Book = require('../../models/Book');

// @route GET api/books

// @desc Get all books

// @access Public

router.get('/', (req, res) => {

Book.find.then(books => res.json(books));

});

// @route POST api/books

// @desc Create a Book

// @access Public

router.post('/', (req, res) => {

const newBook = new Book({

name: req.body.name,

isbn: req.body.isbn,

author: req.body.author,

price: req.body.price,

year: req.body.year,

publisher: req.body.publisher

});

newBook.save.then(book => res.json(book));

});

// @route DELETE api/books/:id

// @desc Remove a Book

// @access Public

router.delete('/:id', function(req, res, next) {

Book.findByIdAndRemove(req.params.id, req.body, function (err, post) {

if (err) return next(err);

res.json(post);

});

});

// @route GET api/books/:author

// @desc Get all books of the particular author.

// @access Public

router.get('/:author', (req, res) => {

Book.find({author: req.params.author}).then(books => res.json(books));

}); module.exports = router;

Create a new models Folder => Book.js

Book.js

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const BookSchema = new Schema({

name: String,

isbn: String,

author: String,

price: Number,

year: String,

publisher: String

});

const Book = mongoose.model('book', BookSchema);

//Data can be accessed from is if only we export this. module.exports = Book;

Client side

client folder => public => index.html (edit title)

Create 3 folders in src folder (actions,components,reducers)

create a store.js file in the src folder.

store.js import { createStore, applyMiddleware, compose } from 'redux';

import thunk from 'redux-thunk';

import rootReducer from './reducers';

//const initialState = {};

const middleware = [thunk];

/*const store = createStore(rootReducer, initialState, compose(

applyMiddleware(...middleware),

window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__

));*/

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(rootReducer,

composeEnhancers(

applyMiddleware(...middleware)

)

);

export default store; Edit the App.css file

App.css .remove-btn {

margin-right: 0.5rem;

}

.fade-enter{

opacity: 0.01;

}

.fade-enter-active{

opacity: 1;

transition: opacity 1000ms ease-in;

}

.fade-exit{

opacity: 1;

}

.fade-exit-active{

opacity: 0.01;

transition: opacity 1000ms ease-in;

} Edit App.js as you wish (Main Interface)

App.js

import React, { Component } from 'react';

import AppNavBar from './components/AppNavBar';

import BookList from './components/BookList';

import BookModal from './components/BookModal';

import BookTable from './components/BookTable';

import SearchModal from './components/SearchModal';

import { Container } from 'reactstrap';

import { Provider } from 'react-redux';

import store from './store';

import 'bootstrap/dist/css/bootstrap.min.css';

import './App.css';

class App extends Component {

render {

return (









 {/**/}







);

}

}

export default App; Edit package.json in client side

package.json {

"name": "client",

"version": "0.1.0",

"private": true,

"dependencies": {

"axios": "^0.18.0",

"bootstrap": "^4.1.3",

"react": "^16.6.3",

"react-dom": "^16.6.3",

"react-redux": "^6.0.0",

"react-scripts": "2.1.1",

"react-transition-group": "^2.5.1",

"reactstrap": "^6.5.0",

"redux": "^4.0.1",

"redux-thunk": "^2.3.0",

"uuid": "^3.3.2"

},

"scripts": {

"start": "react-scripts start",

"build": "react-scripts build",

"test": "react-scripts test",

"eject": "react-scripts eject"

},

"proxy": " http://localhost:3001 ",

"eslintConfig": {

"extends": "react-app"

},

"browserslist": [

">0.2%",

"not dead",

"not ie <= 11",

"not op_mini all"

]

} Inside actions folder => types.js

types.js //Book Types

export const GET_BOOKS = 'GET_BOOKS';

export const ADD_BOOK = 'ADD_BOOK';

export const DELETE_BOOK = 'DELETE_BOOK';

export const SEARCH_BOOKS = 'SEARCH_BOOKS';

export const BOOKS_LOADING = 'BOOKS_LOADING';

//Author Types

export const GET_AUTHORS = 'GET_AUTHORS';

export const AUTHORS_LOADING = 'AUTHORS_LOADING'; Inside actions folder bookactions.js

bookactions.js import axios from 'axios';

import { GET_BOOKS, ADD_BOOK, DELETE_BOOK, SEARCH_BOOKS, BOOKS_LOADING} from "./types";

export const getBooks = => dispatch => {

dispatch(setBooksLoading);

axios

.get('/api/books')

.then(res => dispatch({

type: GET_BOOKS,

payload: res.data

}));

};

export const addBook = (book) => dispatch => {

axios

.post('/api/books', book)

.then(res => dispatch({

type: ADD_BOOK,

payload: res.data

}));

};

export const deleteBook = (id) => dispatch => {

axios

.delete('/api/books/'+id)

.then(res => dispatch({

type: DELETE_BOOK,

payload: id

}));

};

export const searchBooks = (author) => dispatch => {

axios

.get('/api/books'+author)

.then(res => dispatch({

type: SEARCH_BOOKS,

payload: author

}));

};

export const setBooksLoading = => {

return {

type: BOOKS_LOADING

}; };

Inside components folder => AppNavBar.js

AppNavBar.js import React, { Component } from 'react';

import {

Collapse,

Navbar,

NavbarToggler,

NavbarBrand,

Nav,

NavItem,

NavLink,

Container

} from 'reactstrap';

class AppNavBar extends Component{

state = {

isOpen: false

}

toggle = => {

this.setState({

isOpen: !this.state.isOpen

});

}

render{

return(





Library App







<NavItem>

<NavLink href=" https://github.com/HashanKhan ">Github</NavLink>

</NavItem>

</Nav>

</Collapse>

</Container>

</Navbar>

);

}

} export default AppNavBar;

Inside components Booklist.js

Booklist.js

import React, { Component } from 'react';

import { Container, ListGroup, ListGroupItem, Button, InputGroup, Input } from 'reactstrap';

import { CSSTransition, TransitionGroup } from 'react-transition-group';

import { connect } from 'react-redux';

import { getBooks, deleteBook, searchBooks } from "../actions/bookActions";

import { getAuthors } from "../actions/authorActions";

import PropTypes from 'prop-types';

class BookList extends Component{ componentDidMount{

this.props.getBooks;

this.props.getAuthors;

}

onDeleteClick = (id) => {

this.props.deleteBook(id);

};

onSearchClick = (author) => {

this.props.searchBooks(author);

};

render{

const { books } = this.props.book;

const { authors } = this.props.author;

return(

<Container>

<ListGroup style= >

<TransitionGroup className="book-list">

{books.map(({ _id, name }) => (

<CSSTransition key={_id} timeout={500} classNames="fade">

<ListGroupItem> <Button className="remove-btn"                                           color="danger"                                            size="sm"                                            onClick={this.onDeleteClick.bind(this, _id)}                                    > &#xD7; </Button> {name}

</ListGroupItem>

</CSSTransition>

))}

</TransitionGroup>

</ListGroup>

<InputGroup>

<Input type="select" name="author" id="bookauthor" onChange={this.onChange}>

Select Author-

{authors.map(({ _id, fname, lname }) => (

<option key={_id} value={fname.lname}>{fname} {lname}

))}

</Input>

</InputGroup> <Button                   color="dark"                    style=                     onClick={this.onSearchClick}                    block> SEARCH </Button> </Container>

);

} }

BookList.propTypes = { getBooks: PropTypes.func.isRequired,

book: PropTypes.object.isRequired,

getAuthors: PropTypes.func.isRequired,

author: PropTypes.object.isRequired }

const mapStateToProps = (state) => ({   book: state.book,

author: state.author });

export default connect(mapStateToProps, { getBooks, deleteBook, searchBooks, getAuthors })(BookList);

Inside components BookModal.js

BookModal.js import React, { Component } from 'react';

import {

Button,

Modal,

ModalHeader,

ModalBody,

Form,

FormGroup,

Label,

Input

} from 'reactstrap';

import { connect } from 'react-redux';

import { addBook } from '../actions/bookActions';

import { getAuthors } from "../actions/authorActions";

import PropTypes from 'prop-types';

class BookModal extends Component{

componentDidMount{

this.props.getAuthors;

}

state = {

modal: false,

name: '' ,

isbn: '' ,

author: '' ,

price: '' ,

year: '' ,

publisher: ''

};

toggle = => {

this.setState({

modal: !this.state.modal

});

};

onChange = (e) => {

this.setState({

[e.target.name]: e.target.value,

[e.target.isbn]: e.target.value,

[e.target.author]: e.target.value,

[e.target.price]: e.target.value,

[e.target.year]: e.target.value,

[e.target.publisher]: e.target.value

});

};

onSubmit = (e) => {

e.preventDefault;

const newBook = {

name: this.state.name,

isbn: this.state.isbn,

author: this.state.author,

price: this.state.price,

year: this.state.year,

publisher: this.state.publisher

}

//Add Book via addBook action

this.props.addBook(newBook);

//Close modal

this.toggle;

};

render{

const { authors } = this.props.author;

return (

<Modal isOpen={this.state.modal}

toggle={this.toggle}

>

<ModalHeader toggle={this.toggle}>Add Book Items</ModalHeader>

<ModalBody>

<Form onSubmit={this.onSubmit}>

<FormGroup>

<Label for="book">Book Title</Label>

<Input

type="text"

name="name"

id="book"

placeholder="Add book title"

onChange={this.onChange}

/>

<Label for="bookid">Book ID</Label>

<Input

type="text"

name="isbn"

id="bookid"

placeholder="Add book id"

onChange={this.onChange}

/>

<Label for="bookauthor">Author</Label>

<Input

type="select"

name="author"

id="bookauthor"

onChange={this.onChange}>

Select Author-

{authors.map(({ _id, fname, lname }) => (

<option key={_id} value={fname.lname}>{fname} {lname}

))}

</Input>

<Label for="bookprice">Price</Label>

<Input

type="text"

name="price"

id="bookprice"

placeholder="Add Price"

onChange={this.onChange}

/>

<Label for="bookyear">Year</Label>

<Input

type="text"

name="year"

id="bookyear"

placeholder="Add Year"

onChange={this.onChange}

/>

<Label for="bookpublisher">Publisher</Label>

<Input

type="text"

name="publisher"

id="bookpublisher"

placeholder="Add Publisher"

onChange={this.onChange}

/>

<Button

color="dark"

style=

block>

ADD

</Button>

</FormGroup>

</Form>

</ModalBody>

</Modal>

<Button

color="dark"

style=

onClick={this.toggle}

>Add Book</Button>

);

}

}

BookModal.propTypes = {

getAuthors: PropTypes.func.isRequired,

author: PropTypes.object.isRequired

}

const mapStateToProps = (state) => ({

book: state.book,

author: state.author

});

export default connect(mapStateToProps, { addBook, getAuthors })(BookModal); Inside components => BookTable.js

BookTable.js

import React, { Component } from 'react';

import { Table, Input, Form } from 'reactstrap';

import { connect } from 'react-redux';

import { getBooks } from "../actions/bookActions";

import PropTypes from 'prop-types';

class BookTable extends Component{ componentDidMount{

this.props.getBooks;

}

render {

const { books } = this.props.book;

return (                                              {books.map(({ _id, name, isbn, author, price, year, publisher}) => )}        );

} }

BookTable.propTypes = { getBooks: PropTypes.func.isRequired,

book: PropTypes.object.isRequired }

const mapStateToProps = (state) => ({   book: state.book });

export default connect(mapStateToProps, { getBooks })(BookTable);

Inside reducers folder => index.js (register reducers)

index.js import { combineReducers } from 'redux';

import bookReducer from './bookReducer';

import authorReducer from "./authorReducer";

export default combineReducers({

book: bookReducer,

author: authorReducer

}); bookReducer.js import { GET_BOOKS, ADD_BOOK, DELETE_BOOK, SEARCH_BOOKS, BOOKS_LOADING } from "../actions/types";

const initialState = {

books:[],

loading: false

};

export default function (state = initialState, action) {

switch (action.type){

case GET_BOOKS:

return {

...state,

books: action.payload,

loading: false

};

case DELETE_BOOK:

return {

...state,

books: state.books.filter(book => book._id !== action.payload)

};

case ADD_BOOK:

return {

...state,

books: [action.payload, ...state.books]

};

case SEARCH_BOOKS:

return {

...state,

books: state.books.filter(book => book._author)

};

case BOOKS_LOADING:

return {

...state,

loading: true

};

default:

return state;

}

}

Angular App