diff --git a/package.json b/package.json
index 579d515885..36eb906e74 100644
--- a/package.json
+++ b/package.json
@@ -3,9 +3,11 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "bootstrap": "4.6.0",
"prop-types": "^15.6.2",
"react": "^16.6.3",
"react-dom": "^16.6.3",
+ "react-router-dom": "^5.3.0",
"react-scripts": "2.1.1"
},
"scripts": {
diff --git a/src/App.js b/src/App.js
index 785820d5df..eedc3fc3a2 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,206 +1,153 @@
-import React from 'react'
-// import * as BooksAPI from './BooksAPI'
-import './App.css'
+import React from "react";
+import * as BooksAPI from "./BooksAPI";
+import "./App.css";
+import ShelfsBooks from "./components/shelfBooksRender";
+import Search from "./components/search";
+import { Link, Route } from "react-router-dom";
+import BookDetails from "./components/bookDetails";
+
+
+/**
+ * top parent where defines router components and instantiate all component
+ * handing shelf selection in here and send aknowldgement to server
+ * rendering main pages
+ * components map: 1- BooksApp => Search => SearchBooks => Books => BookDetials
+ * 2- BooksApp => BooksShelfRender => Book =
+ */
class BooksApp extends React.Component {
+
state = {
- /**
- * TODO: Instead of using this state variable to keep track of which page
- * we're on, use the URL in the browser's address bar. This will ensure that
- * users can use the browser's back and forward buttons to navigate between
- * pages, as well as provide a good URL they can bookmark and share.
- */
- showSearchPage: false
- }
+ books: [],
+ shelfs: [],
+ showSearchPage: false,
+ isUpdated: false,
+ };
+
+ /**
+ * load when component inserted into DOM to fetch API and get books using API.getAll()
+ * function get result from API and then iterate over it to get important fields for book and shelf Components
+ */
+ componentDidMount = () => {
+ let [books, shelfs] = [[], []]; //initialize empty arrays for pushing data in it
+ BooksAPI.getAll().then((res) => {
+
+ res.forEach((cur) => {
+ if (!shelfs.includes(cur.shelf)) shelfs.push(cur.shelf); //only push shelf if not find in shelfs array
+
+ //initilzie category to if empty to avoid undefined values
+ const categories = cur.categories ? [...cur.categories] : [];
+
+ //get fields from books and push it into books array
+ books.push({
+ id: cur.id,
+ title: cur.title,
+ shelf: cur.shelf,
+ bookImage: cur.imageLinks.smallThumbnail,
+ categories: [...categories],
+ authors: [...cur.authors],
+ });
+ });
+ //set state with recived data from server
+ this.setState({ books, shelfs });
+ });
+ };
+
+ /**
+ *Update state of books and push not defined books into state and track book shefl
+ *
+ * @param {*} bookState: express about new selected shelf name
+ * @param {*} updatedBook : is book object that fired event
+ */
+ updateBookShelf = (bookState, updatedBook) => {
+
+ //fetch API to update
+ BooksAPI.update(updatedBook, bookState)
+ .then((res) => {
+ if (bookState !== "none") { //at shelf not none
+ this.setState((curState) => { //update state and remove book
+ const books = [...curState.books]; //cloning current books state
+ updatedBook.shelf = bookState;
+ const index = books.indexOf(updatedBook); //get target book
+ if (index === -1) books.push({ ...updatedBook }); //if index book not find then add it
+ else {
+ books[index].shelf = bookState; //else update book shelf
+ }
+ return { books }; //set state with new data
+ });
+ }
+ else { //if assign to none then remove book from shelfs
+ this.setState((curState) => {
+ const books = curState.books.filter( //filter and remove book
+ (book) => book.id !== updatedBook.id
+ );
+ return { books };
+ });
+ }
+
+ //cached updated books into localStorage to keep its ids at reloading
+ //this.cachedBooks();
+ })
+ .catch((er) => alert(`Error! can't update data `));
+ };
+ /**
+ * render two component search component and shelf component for rendering main page books using Link and Route
+ * @returns return mark up to inject into html index page as final result1
+ */
render() {
return (
- {this.state.showSearchPage ? (
-
-
-
-
- {/*
- NOTES: The search from BooksAPI is limited to a particular set of search terms.
- You can find these search terms here:
- https://github.com/udacity/reactnd-project-myreads-starter/blob/master/SEARCH_TERMS.md
+ (
+
+ )}
+ />
- However, remember that the BooksAPI.search method DOES search by title or author. So, don't worry if
- you don't find a specific author or title. Every search is limited by search terms.
- */}
-
-
-
-
-
-
-
-
- ) : (
-
-
-
MyReads
-
-
-
-
-
Currently Reading
-
-
-
-
-
-
-
-
-
-
-
To Kill a Mockingbird
-
Harper Lee
-
-
-
-
-
-
-
-
-
-
-
Ender's Game
-
Orson Scott Card
-
-
-
-
-
-
-
Want to Read
-
-
-
-
-
-
-
-
-
-
-
1776
-
David McCullough
-
-
-
-
-
-
-
-
-
-
-
Harry Potter and the Sorcerer's Stone
-
J.K. Rowling
-
-
-
-
-
-
-
Read
-
-
-
-
-
-
-
-
-
-
-
The Hobbit
-
J.R.R. Tolkien
-
-
-
-
-
-
-
-
-
-
-
Oh, the Places You'll Go!
-
Seuss
-
-
-
-
-
-
-
-
-
-
-
The Adventures of Tom Sawyer
-
Mark Twain
-
-
-
-
+ (
+
+
+
+
MyReads
+
+
+
+
-
-
-
-
- )}
+ )}
+ />
+
+ {
+ return(
+
+ )
+ }}
+ />
- )
+ );
}
}
-export default BooksApp
+export default BooksApp;
diff --git a/src/components/book.js b/src/components/book.js
new file mode 100644
index 0000000000..50baf8a7c2
--- /dev/null
+++ b/src/components/book.js
@@ -0,0 +1,43 @@
+import React from "react";
+import { Link } from "react-router-dom";
+
+/**
+ * functional component for rendering book details
+ *
+ * has function contains event firing at book sehlf selection change
+ *
+ * @param {*} props sending from component parent
+ * @returns final book rendering product
+ *
+ */
+const Book = (props) => {
+
+ //handel images if not define so return alt text or black book image
+ const {book, shelfName, bookSender } = {...props};
+ const imagePath = (book.bookImage !=='alt')? `${(book.bookImage)}`: '../icons/1021547.png';
+
+ return