From 7ac59f7e9660f7b692ff8eab55a468f70fa7d766 Mon Sep 17 00:00:00 2001 From: vinodh tankasala Date: Mon, 19 Nov 2018 10:39:32 -0500 Subject: [PATCH] added_notification_serivice_and_data_service --- src/App/App.js | 48 +++++++++++---- src/product-condensed/product-condensed.css | 3 + src/product-condensed/product-condensed.js | 15 +++++ src/product/product.css | 4 +- src/product/product.js | 26 ++++++-- src/services/data-service.js | 56 +++++++++++++++++ src/services/http-service.js | 8 +-- src/services/notification-service.js | 66 +++++++++++++++++++++ src/wishlist/wishlist.css | 0 src/wishlist/wishlist.js | 61 +++++++++++++++++++ 10 files changed, 267 insertions(+), 20 deletions(-) create mode 100644 src/product-condensed/product-condensed.css create mode 100644 src/product-condensed/product-condensed.js create mode 100644 src/services/data-service.js create mode 100644 src/services/notification-service.js create mode 100644 src/wishlist/wishlist.css create mode 100644 src/wishlist/wishlist.js diff --git a/src/App/App.js b/src/App/App.js index 08d7334..416587c 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -1,10 +1,13 @@ import React, { Component } from 'react'; -import logo from './logo.svg'; +// import logo from './logo.svg'; import './App.css'; + +// components import Product from '../product/product'; +import WishList from '../wishlist/wishlist'; +// services import HttpService from '../services/http-service'; - const http = new HttpService(); class App extends Component { @@ -13,9 +16,9 @@ class App extends Component { this.state = {products:[]}; //Bind funictions - this.loadData = this.loadData.bind(this);//the loaddata is bound to here thus referring to this scope rather than refering it to global scope + this.loadData = this.loadData.bind(this);//the loaddata is bound here, thus referring to this scope rather than refering it to global scope this.productList = this.productList.bind(this); - + this.loadData(); //this is where the function is passed which is inside the loaddata variable. } @@ -27,12 +30,12 @@ class App extends Component { self.setState({products:data}) // we are inside of a promise here and // "then" here is screwing up our "this" hence a reference is created - // before the promise is loaded. self is referring to the component + // before th e promise is loaded. self is referring to the component // here. But if self is not used and this is placed along with the // setState then this referes to the promise and no longer to the // component because it is asynchronous. - // everytime setState is called, it will render that component again and - // all the components inside of it but not outside of it + // everytime setState is called, it will render that component and + // all the components inside of it but not outside of it again },err => { }); @@ -41,7 +44,8 @@ class App extends Component { productList = () => { const list = this.state.products.map((product) =>
- + + {/* the whole product is passed as props */}
); return (list); @@ -53,9 +57,19 @@ class App extends Component {

welcome suckers, find your best deals

-
+
+
+
{this.productList()} + +
+
+ {/* a row is taken first which contains two columns, products + and wishlist.Then within the products column productsList is inserted */} +
+ +
@@ -65,4 +79,18 @@ class App extends Component { } export default App; - \ No newline at end of file +// the complete description +/* we load the data and when the data is loaded we set the state, refresh the Ui with data. +when you see .then we can no longer use this unless we grab a reference to it +such as self setstate Here. in this example products is refreshed +which we get from the server goes into the products array and the render +function is called again. this.productlist function is called which uses +javascript mapping array .we prettymuch use map function whenever we have a list +in react. map goes to every item in the list that we have in the +products array in this state, frop that product into the "product" parameter +and grab the element out of it, put it into our component, we pass the elements +into different properties and then we return the list which is rendered + to the screen. Now in the product.js, we access the list by saying this.props.imgUrl + which is coming from the parent. when the setstate is called, product.js is also + rendered +*/ \ No newline at end of file diff --git a/src/product-condensed/product-condensed.css b/src/product-condensed/product-condensed.css new file mode 100644 index 0000000..26fd5f7 --- /dev/null +++ b/src/product-condensed/product-condensed.css @@ -0,0 +1,3 @@ +.pc-condensed a{ + margin-right:25px; +} \ No newline at end of file diff --git a/src/product-condensed/product-condensed.js b/src/product-condensed/product-condensed.js new file mode 100644 index 0000000..17ee923 --- /dev/null +++ b/src/product-condensed/product-condensed.js @@ -0,0 +1,15 @@ +import React, { Component } from 'react'//we are grabbing one specific thing 'component' from react,hence curly braces +import './product-condensed.css'; + +class ProductCondensed extends Component{ + render(){ + return ( +
  • + X +

    {this.props.product.title} | ${this.props.product.price}

    +
  • + ) + } +} + +export default ProductCondensed; \ No newline at end of file diff --git a/src/product/product.css b/src/product/product.css index 1b14fc1..6528dd8 100644 --- a/src/product/product.css +++ b/src/product/product.css @@ -1,7 +1,7 @@ .Product { - width:20rem; + max-width:15rem; } .Product img { - max-height:15rem; + max-height:10rem; } diff --git a/src/product/product.js b/src/product/product.js index ea1bfb7..bfa16df 100644 --- a/src/product/product.js +++ b/src/product/product.js @@ -1,16 +1,34 @@ import React, { Component } from 'react'//we are grabbing one specific thing 'component' from react,hence curly braces import './product.css'; +import DataService from '../services/data-service'; + +let ds = new DataService(); class Product extends Component{ + + constructor(props){ + super(props); + this.onButtonClicked = this.onButtonClicked.bind(this); + } + onButtonClicked = () =>{ + ds.addWishListItem(this.props.product); +// when we add whishlist item, then we enter the dataservice, it added the item, +// and the notification is posted which is passing the brand new wishlist with +// all the items. Now, since wishlist.js file is listening, it is going to pass +// in as a newWishlist and then we set the state for the new items in the wishlist. + + } + render(){ + return (
    - + {/* curly braces is a special syntax to insert javascript */}
    -

    {this.props.title}

    -

    Price: ${this.props.price}

    - Add to wishlist +

    {this.props.product.title}

    +

    Price: ${this.props.product.price}

    + this.onButtonClicked()}className="btn btn-primary">Add to wishlist
    diff --git a/src/services/data-service.js b/src/services/data-service.js new file mode 100644 index 0000000..274229a --- /dev/null +++ b/src/services/data-service.js @@ -0,0 +1,56 @@ +import NotificationService, {NOTIF_WISHLIST_CHANGED} from './notification-service'; + +let ns = new NotificationService(); +// no matter how many times a new object of type notificationservice is created, +// it will still reference to the same one in memory +let instance = null; +var wishList = []; + +class DataService{ + constructor(){ + if(!instance){ + instance = this; + // if instance is created for the very first time, we are + // making it not null and create once in memory at "this" point in time + // and we store in the instance permanently + // now next time an object of the class is created, it checks that + // the object is not null and thus returns the same instance + + } + return instance; + } + addWishListItem = item => { + wishList.push(item); + ns.postNotification(NOTIF_WISHLIST_CHANGED,wishList); + // posts notification with the new item in the wish list + } + removeWishListItem = item => { + for(var x=0; x{ @@ -7,14 +7,14 @@ class HttpService { // 2 fetch('http://localhost:3002/product') .then(res => { -// 4 + //then is chained to whatever fetch is returning + // 4 resolve(res.json()); - //josn takes the response and converts to json + //json takes the response and converts to json }) }); // 3 return promise; - //then is chained to whatever fetch is returning } } diff --git a/src/services/notification-service.js b/src/services/notification-service.js new file mode 100644 index 0000000..ab03257 --- /dev/null +++ b/src/services/notification-service.js @@ -0,0 +1,66 @@ +// we could also make our http service a singleton which is not needed here. +// If there is app that has multipe components and those components needs to access the +// HTTP service we would want to make it a singleton. +export const NOTIF_WISHLIST_CHANGED = "notif_wishlist_changed"; +// in our data-service, we need to start posting notifications, but before posting +// notifications, we need to have a central place where we can store them +var observers = {}; +let instance = null; +class NotificationService { + constructor(){ + if (!instance){ + instance = this; + } + + return instance; + } + + postNotification = (notifName, data) => { + let obs = observers[notifName]; + for (var x = 0; x < obs.length; x++){ + var obj = obs[x]; + obj.callBack(data); + } + } + removeObserver = (observer,notifName) => { + var obs = observers[notifName]; + if(obs) { + for (var x=0; x { + let obs = observers[notifName]; + + if(!obs){ + observers[notifName] = []; + //if there is no array in there, + // that means we have never registered for that notification + // before. So we are creating an + // empty array at tha slot for that specific notification + // name that is passed to this function + } + let obj = {observer: observer, callBack: callBack}; + observers[notifName].push(obj); + // notification name is used as a special key on our observers list + // and pushed to that array + } +} + +export default NotificationService; +// we store a list of observers. An observer is a class or a component. An observer is a class or a component that says hello, I would like to listen +// (kind of like register to vote, here class registers to observe) and when it is time to be notified. Obbserver will register and the system will send +// back notifications when it is time to be notified. \ No newline at end of file diff --git a/src/wishlist/wishlist.css b/src/wishlist/wishlist.css new file mode 100644 index 0000000..e69de29 diff --git a/src/wishlist/wishlist.js b/src/wishlist/wishlist.js new file mode 100644 index 0000000..9e41290 --- /dev/null +++ b/src/wishlist/wishlist.js @@ -0,0 +1,61 @@ +import React, { Component } from 'react'//we are grabbing one specific thing 'component' from react,hence curly braces +import './wishlist.css'; +import ProductCondensed from '../product-condensed/product-condensed' +import DataService from '../services/data-service'; +import NotificationService,{NOTIF_WISHLIST_CHANGED} from '../services/notification-service' + +let ns = new NotificationService(); +class WishList extends Component{ + + constructor(props){ + super(props); + + this.state = {wishList:[]}; + // bind functions + this.createWishList = this.createWishList.bind(this); + this.onWishListChanged = this.onWishListChanged.bind(this); + } + +// when the component is mounting or it is about to load or if it did just load on +// the screen we can do something, same goes with unmount, we can do something when +// it goes out of memory + componentDidMount() { + ns.addObserver(NOTIF_WISHLIST_CHANGED, this, this.onWishListChanged) + // we can add ourselves an observer here + } + + componentWillUnmount(){ + ns.removeObserver(this, NOTIF_WISHLIST_CHANGED); + // we can remove ourelves an observer here. If we dont remove ourselves + // an observer here, we could have a memory leak on our app. The notification + // service will still hold on to this entire component even though it is not + // on the screen anymore. + } + + onWishListChanged(newWishList){ + this.setState({wishList: newWishList}) + } + + createWishList = () => { + const list = this.state.wishList.map((product) => + + + ) + return (list); + } + + render(){ + return ( +
    +
    +

    wish List

    +
      + {this.createWishList()} +
    +
    +
    + ); + } +} + +export default WishList; \ No newline at end of file