From feab4bfc003fda727676d804ab4ba73d1d750bcb Mon Sep 17 00:00:00 2001 From: samilabud Date: Thu, 20 May 2021 16:31:46 -0400 Subject: [PATCH] All shop data from firebase db --- src/App.js | 9 +- .../cart-item/cart-item-component.jsx | 4 +- .../cart-item/cart-item-component.styles.jsx | 8 +- .../custom-button/custom-button.component.jsx | 6 +- .../custom-button/custom-button.styles.jsx | 89 ++++--- .../with-spinner/with-spinner.component.jsx | 17 ++ .../with-spinner/with-spinner.styles.jsx | 30 +++ src/fireabase/firebase.utils.js | 31 +++ src/pages/shop/shop.component.jsx | 49 +++- src/redux/shop/shop.actions.js | 6 + src/redux/shop/shop.data.js | 249 ------------------ src/redux/shop/shop.reducer.js | 9 +- src/redux/shop/shop.selector.js | 4 +- src/redux/shop/shop.type.js | 5 + 14 files changed, 195 insertions(+), 321 deletions(-) create mode 100644 src/components/with-spinner/with-spinner.component.jsx create mode 100644 src/components/with-spinner/with-spinner.styles.jsx create mode 100644 src/redux/shop/shop.actions.js delete mode 100644 src/redux/shop/shop.data.js create mode 100644 src/redux/shop/shop.type.js diff --git a/src/App.js b/src/App.js index 79c0707..ebbc101 100644 --- a/src/App.js +++ b/src/App.js @@ -13,12 +13,10 @@ import ShopPage from './pages/shop/shop.component'; import CheckoutPage from './pages/checkout/checkout.component'; import SignInAndSignUp from './pages/signin-and-singup/signin-and-singup.component'; import { auth,createUserProfileDocument } from './fireabase/firebase.utils'; + import { setCurrentUser } from './redux/user/user.actions'; import { selectCurrentUser } from './redux/user/user.selectors'; - - - class App extends React.Component { unsubscribeFromAuth = null; componentWillUnmount(){ @@ -37,10 +35,9 @@ class App extends React.Component { ...snapShot.data() }); }); - }else{ - setCurrentUser(userAuth); } - + setCurrentUser(userAuth); + // to add data, was deleted addCollectionAndItems('collections',collectionsArray.map(({title, items})=>({title, items}))); }) } diff --git a/src/components/cart-item/cart-item-component.jsx b/src/components/cart-item/cart-item-component.jsx index 380a66f..9c1de32 100644 --- a/src/components/cart-item/cart-item-component.jsx +++ b/src/components/cart-item/cart-item-component.jsx @@ -1,11 +1,11 @@ import React from 'react'; -import {CartItemContainer, ItemDetailsContainer} from './cart-item-component.styles' +import {CartItemContainer, ItemDetailsContainer, CartItemImage} from './cart-item-component.styles' const CartItem = ({item: {imageUrl, price, name, quantity}}) => ( - item + {name} diff --git a/src/components/cart-item/cart-item-component.styles.jsx b/src/components/cart-item/cart-item-component.styles.jsx index a321475..2882d55 100644 --- a/src/components/cart-item/cart-item-component.styles.jsx +++ b/src/components/cart-item/cart-item-component.styles.jsx @@ -5,12 +5,10 @@ export const CartItemContainer = styled.div` display: flex; height: 80px; margin-bottom: 15px; - - img { - width: 30%; - } `; - +export const CartItemImage = styled.img` + width: 30%; +`; export const ItemDetailsContainer = styled.div` .item-details { width: 70%; diff --git a/src/components/custom-button/custom-button.component.jsx b/src/components/custom-button/custom-button.component.jsx index 7556bf5..e507a18 100644 --- a/src/components/custom-button/custom-button.component.jsx +++ b/src/components/custom-button/custom-button.component.jsx @@ -2,8 +2,8 @@ import React from 'react'; import { CustomButtonContainer } from './custom-button.styles'; -const CustomButton = ({children, ...props}) => ( - {children} +const CustomButton = ({ children, ...props }) => ( + {children} ); -export default CustomButton; +export default CustomButton; \ No newline at end of file diff --git a/src/components/custom-button/custom-button.styles.jsx b/src/components/custom-button/custom-button.styles.jsx index 4a4fe88..0ccee5a 100644 --- a/src/components/custom-button/custom-button.styles.jsx +++ b/src/components/custom-button/custom-button.styles.jsx @@ -1,58 +1,57 @@ -import styled, {css} from 'styled-components'; +import styled, { css } from 'styled-components'; const buttonStyles = css` - background-color: black; - color: white; - border: none; - &:hover { - background-color: white; - color: black; - border: 1px solid black; - } -`; - -const invertedButtonStyles = css` + background-color: black; + color: white; + border: none; + &:hover { background-color: white; color: black; border: 1px solid black; - - &:hover { - background-color: black; - color: white; - border: none; - } + } `; -const googleSignInStyles = css` - background-color: #4285f4; + +const invertedButtonStyles = css` + background-color: white; + color: black; + border: 1px solid black; + &:hover { + background-color: black; color: white; + border: none; + } +`; - &:hover { - background-color: #357ae8; - border: none; - } +const googleSignInStyles = css` + background-color: #4285f4; + color: white; + &:hover { + background-color: #357ae8; + border: none; + } `; -const getButtonStyles = props =>{ - if(props.isGoogleSignIn){ - return googleSignInStyles - } - return props.inverted ? invertedButtonStyles: buttonStyles; -} +const getButtonStyles = props => { + if (props.isGoogleSignIn) { + return googleSignInStyles; + } -export const CustomButtonContainer = styled.button` - min-width: 165px; - width: auto; - height: 50px; - letter-spacing: 0.5px; - line-height: 50px; - padding: 0 35px 0 35px; - font-size: 15px; - text-transform: uppercase; - font-family: 'Open Sans Condensed'; - font-weight: bolder; - cursor: pointer; - display: flex; - justify-content: center; + return props.inverted ? invertedButtonStyles : buttonStyles; +}; - ${getButtonStyles} +export const CustomButtonContainer = styled.button` + min-width: 165px; + width: auto; + height: 50px; + letter-spacing: 0.5px; + line-height: 50px; + padding: 0 35px 0 35px; + font-size: 15px; + text-transform: uppercase; + font-family: 'Open Sans Condensed'; + font-weight: bolder; + cursor: pointer; + display: flex; + justify-content: center; + ${getButtonStyles} `; \ No newline at end of file diff --git a/src/components/with-spinner/with-spinner.component.jsx b/src/components/with-spinner/with-spinner.component.jsx new file mode 100644 index 0000000..ce73ed1 --- /dev/null +++ b/src/components/with-spinner/with-spinner.component.jsx @@ -0,0 +1,17 @@ +import React from 'react'; + +import {SpinnerContainer, SpinnerOverlay} from './with-spinner.styles'; + +const WithSpinner = WrappedDocument => { + const Spinner = ({isLoading, ...otherProps}) => { + return isLoading ? ( + + + + ) : ( + + ) + } + return Spinner; +} +export default WithSpinner; \ No newline at end of file diff --git a/src/components/with-spinner/with-spinner.styles.jsx b/src/components/with-spinner/with-spinner.styles.jsx new file mode 100644 index 0000000..5675eba --- /dev/null +++ b/src/components/with-spinner/with-spinner.styles.jsx @@ -0,0 +1,30 @@ +import styled from 'styled-components'; + +export const SpinnerOverlay = styled.div` + height: 60vh; + width: 100%; + display: flex; + justify-content: center; + align-items: center; +`; + +export const SpinnerContainer = styled.div` + display: inline-block; + width: 50px; + height: 50px; + border: 3px solid rgba(195, 195, 195, 0.6); + border-radius: 50%; + border-top-color: #636767; + animation: spin 1s ease-in-out infinite; + -webkit-animation: spin 1s ease-in-out infinite; + @keyframes spin { + to { + -webkit-transform: rotate(360deg); + } + } + @-webkit-keyframes spin { + to { + -webkit-transform: rotate(360deg); + } + } +`; diff --git a/src/fireabase/firebase.utils.js b/src/fireabase/firebase.utils.js index efc64ef..1046db8 100644 --- a/src/fireabase/firebase.utils.js +++ b/src/fireabase/firebase.utils.js @@ -7,6 +7,7 @@ const config = { authDomain: "ecommerceztom.firebaseapp.com", databaseURL: "https://ecommerceztom.firebaseio.com", projectId: "ecommerceztom", + name: "EcommerceZtoM", storageBucket: "ecommerceztom.appspot.com", messagingSenderId: "745149943574", appId: "1:745149943574:web:5e4d9e56554d82c35f8a37" @@ -38,6 +39,36 @@ const config = { return userRef; } + export const addCollectionAndItems = async (collectionKey, objectsToAdd) => { + const collectionRef = firestore.collection(collectionKey); + + const batch = firestore.batch() + objectsToAdd.forEach(object=>{ + const newDocRef = collectionRef.doc(); + batch.set(newDocRef, object); + + }); + return await batch.commit(); + } + +export const convertCollectionsSnapshotToMap = (collections) => { + const transformedCollection = collections.docs.map( + doc => { + const {title, items} = doc.data(); + return{ + routeName: encodeURI(title.toLowerCase()), + id: doc.id, + title, + items + } + } + ); + return transformedCollection.reduce((accumulator,collection)=>{ + accumulator[collection.title.toLowerCase()] = collection; + return accumulator; + },{}); + } + export const auth = firebase.auth(); export const firestore = firebase.firestore(); diff --git a/src/pages/shop/shop.component.jsx b/src/pages/shop/shop.component.jsx index b3b8202..d19c949 100644 --- a/src/pages/shop/shop.component.jsx +++ b/src/pages/shop/shop.component.jsx @@ -1,16 +1,51 @@ import React from 'react'; import { Route } from 'react-router-dom'; +import {connect} from 'react-redux'; import CollectionOverview from '../../components/collections-overview/collections-overview.component'; import CollectionPage from '../collection/collection.component'; -const ShopPage = ({ match }) => ( -
- - +import {firestore, convertCollectionsSnapshotToMap} from '../../fireabase/firebase.utils'; +import { updateCollections } from '../../redux/shop/shop.actions'; +import WithSpinner from '../../components/with-spinner/with-spinner.component'; + +const CollectionsOverviewWithSpinner = WithSpinner(CollectionOverview); +const CollectionPageWithSpinner = WithSpinner(CollectionPage); + +class ShopPage extends React.Component { + state = { + loading: true + } + unsubscribeFromSnapshot = null; + + componentDidMount() { + const {updateCollections} = this.props; + const collectionRef = firestore.collection('collections'); + + //this.unsubscribeFromSnapshot = + + collectionRef.get().then( snapshot=>{ + const collectionsMap = convertCollectionsSnapshotToMap(snapshot); + updateCollections(collectionsMap); + this.setState({loading:false}); + } + ); + } + + render() { + const { match } = this.props; + const { loading } = this.state; + return(
+ } /> + } /> -
-) +
+ ); + } +} +const mapDispatchToProps = dispatch => ({ + updateCollections: collectionsMap => dispatch(updateCollections(collectionsMap)) +}) -export default ShopPage; \ No newline at end of file +export default connect(null, mapDispatchToProps)(ShopPage); \ No newline at end of file diff --git a/src/redux/shop/shop.actions.js b/src/redux/shop/shop.actions.js new file mode 100644 index 0000000..878115b --- /dev/null +++ b/src/redux/shop/shop.actions.js @@ -0,0 +1,6 @@ +import ShopActionTypes from './shop.type'; + +export const updateCollections = collectionsMap => ({ + type: ShopActionTypes.UPDATE_COLLECTIONS, + payload: collectionsMap +}); \ No newline at end of file diff --git a/src/redux/shop/shop.data.js b/src/redux/shop/shop.data.js deleted file mode 100644 index d4aa96e..0000000 --- a/src/redux/shop/shop.data.js +++ /dev/null @@ -1,249 +0,0 @@ -const SHOP_DATA = { - hats: { - id: 1, - title: 'Hats', - routeName: 'hats', - items: [ - { - id: 1, - name: 'Brown Brim', - imageUrl: 'https://i.ibb.co/ZYW3VTp/brown-brim.png', - price: 25 - }, - { - id: 2, - name: 'Blue Beanie', - imageUrl: 'https://i.ibb.co/ypkgK0X/blue-beanie.png', - price: 18 - }, - { - id: 3, - name: 'Brown Cowboy', - imageUrl: 'https://i.ibb.co/QdJwgmp/brown-cowboy.png', - price: 35 - }, - { - id: 4, - name: 'Grey Brim', - imageUrl: 'https://i.ibb.co/RjBLWxB/grey-brim.png', - price: 25 - }, - { - id: 5, - name: 'Green Beanie', - imageUrl: 'https://i.ibb.co/YTjW3vF/green-beanie.png', - price: 18 - }, - { - id: 6, - name: 'Palm Tree Cap', - imageUrl: 'https://i.ibb.co/rKBDvJX/palm-tree-cap.png', - price: 14 - }, - { - id: 7, - name: 'Red Beanie', - imageUrl: 'https://i.ibb.co/bLB646Z/red-beanie.png', - price: 18 - }, - { - id: 8, - name: 'Wolf Cap', - imageUrl: 'https://i.ibb.co/1f2nWMM/wolf-cap.png', - price: 14 - }, - { - id: 9, - name: 'Blue Snapback', - imageUrl: 'https://i.ibb.co/X2VJP2W/blue-snapback.png', - price: 16 - } - ] - }, - sneakers: { - id: 2, - title: 'Sneakers', - routeName: 'sneakers', - items: [ - { - id: 10, - name: 'Adidas NMD', - imageUrl: 'https://i.ibb.co/0s3pdnc/adidas-nmd.png', - price: 220 - }, - { - id: 11, - name: 'Adidas Yeezy', - imageUrl: 'https://i.ibb.co/dJbG1cT/yeezy.png', - price: 280 - }, - { - id: 12, - name: 'Black Converse', - imageUrl: 'https://i.ibb.co/bPmVXyP/black-converse.png', - price: 110 - }, - { - id: 13, - name: 'Nike White AirForce', - imageUrl: 'https://i.ibb.co/1RcFPk0/white-nike-high-tops.png', - price: 160 - }, - { - id: 14, - name: 'Nike Red High Tops', - imageUrl: 'https://i.ibb.co/QcvzydB/nikes-red.png', - price: 160 - }, - { - id: 15, - name: 'Nike Brown High Tops', - imageUrl: 'https://i.ibb.co/fMTV342/nike-brown.png', - price: 160 - }, - { - id: 16, - name: 'Air Jordan Limited', - imageUrl: 'https://i.ibb.co/w4k6Ws9/nike-funky.png', - price: 190 - }, - { - id: 17, - name: 'Timberlands', - imageUrl: 'https://i.ibb.co/Mhh6wBg/timberlands.png', - price: 200 - } - ] - }, - jackets: { - id: 3, - title: 'Jackets', - routeName: 'jackets', - items: [ - { - id: 18, - name: 'Black Jean Shearling', - imageUrl: 'https://i.ibb.co/XzcwL5s/black-shearling.png', - price: 125 - }, - { - id: 19, - name: 'Blue Jean Jacket', - imageUrl: 'https://i.ibb.co/mJS6vz0/blue-jean-jacket.png', - price: 90 - }, - { - id: 20, - name: 'Grey Jean Jacket', - imageUrl: 'https://i.ibb.co/N71k1ML/grey-jean-jacket.png', - price: 90 - }, - { - id: 21, - name: 'Brown Shearling', - imageUrl: 'https://i.ibb.co/s96FpdP/brown-shearling.png', - price: 165 - }, - { - id: 22, - name: 'Tan Trench', - imageUrl: 'https://i.ibb.co/M6hHc3F/brown-trench.png', - price: 185 - } - ] - }, - womens:{ - id: 4, - title: 'Womens', - routeName: 'womens', - items: [ - { - id: 23, - name: 'Blue Tanktop', - imageUrl: 'https://i.ibb.co/7CQVJNm/blue-tank.png', - price: 25 - }, - { - id: 24, - name: 'Floral Blouse', - imageUrl: 'https://i.ibb.co/4W2DGKm/floral-blouse.png', - price: 20 - }, - { - id: 25, - name: 'Floral Dress', - imageUrl: 'https://i.ibb.co/KV18Ysr/floral-skirt.png', - price: 80 - }, - { - id: 26, - name: 'Red Dots Dress', - imageUrl: 'https://i.ibb.co/N3BN1bh/red-polka-dot-dress.png', - price: 80 - }, - { - id: 27, - name: 'Striped Sweater', - imageUrl: 'https://i.ibb.co/KmSkMbH/striped-sweater.png', - price: 45 - }, - { - id: 28, - name: 'Yellow Track Suit', - imageUrl: 'https://i.ibb.co/v1cvwNf/yellow-track-suit.png', - price: 135 - }, - { - id: 29, - name: 'White Blouse', - imageUrl: 'https://i.ibb.co/qBcrsJg/white-vest.png', - price: 20 - } - ] - }, - mens:{ - id: 5, - title: 'Mens', - routeName: 'mens', - items: [ - { - id: 30, - name: 'Camo Down Vest', - imageUrl: 'https://i.ibb.co/xJS0T3Y/camo-vest.png', - price: 325 - }, - { - id: 31, - name: 'Floral T-shirt', - imageUrl: 'https://i.ibb.co/qMQ75QZ/floral-shirt.png', - price: 20 - }, - { - id: 32, - name: 'Black & White Longsleeve', - imageUrl: 'https://i.ibb.co/55z32tw/long-sleeve.png', - price: 25 - }, - { - id: 33, - name: 'Pink T-shirt', - imageUrl: 'https://i.ibb.co/RvwnBL8/pink-shirt.png', - price: 25 - }, - { - id: 34, - name: 'Jean Long Sleeve', - imageUrl: 'https://i.ibb.co/VpW4x5t/roll-up-jean-shirt.png', - price: 40 - }, - { - id: 35, - name: 'Burgundy T-shirt', - imageUrl: 'https://i.ibb.co/mh3VM1f/polka-dot-shirt.png', - price: 25 - } - ] - } -}; - -export default SHOP_DATA; diff --git a/src/redux/shop/shop.reducer.js b/src/redux/shop/shop.reducer.js index d095b6b..266d989 100644 --- a/src/redux/shop/shop.reducer.js +++ b/src/redux/shop/shop.reducer.js @@ -1,11 +1,16 @@ -import ShopData from './shop.data' +import ShopActionTypes from './shop.type'; const INITIAL_STATE = { - collections: ShopData + collections: null } export const shopReducer = (state=INITIAL_STATE, action) => { switch(action.type){ + case ShopActionTypes.UPDATE_COLLECTIONS: + return { + ...state, + collections: action.payload + } default: return state; } diff --git a/src/redux/shop/shop.selector.js b/src/redux/shop/shop.selector.js index bff6680..b4e00fa 100644 --- a/src/redux/shop/shop.selector.js +++ b/src/redux/shop/shop.selector.js @@ -16,11 +16,11 @@ export const selectShopCollectionWMemoize = createSelector( export const selectShopCollection = memoize((collectionUrlParam) => createSelector( [selectShopCollections], - collections=> collections[collectionUrlParam] + collections=> collections ? collections[collectionUrlParam] : null ) ) export const selectCollectionForPreview = createSelector( [selectShopCollectionWMemoize], - collections=>Object.keys(collections).map(key=>collections[key]) + collections=> collections ? Object.keys(collections).map(key=>collections[key]) : [] ) \ No newline at end of file diff --git a/src/redux/shop/shop.type.js b/src/redux/shop/shop.type.js new file mode 100644 index 0000000..47dee69 --- /dev/null +++ b/src/redux/shop/shop.type.js @@ -0,0 +1,5 @@ +const ShopActionTypes = { + UPDATE_COLLECTIONS: 'UPDATE_COLLECTIONS' +} + +export default ShopActionTypes; \ No newline at end of file