diff --git a/package.json b/package.json index f93b7411aab4a105d80af145cd87f38973d3dcda..613b95cb61066c8c0bea2ddb16675c75a48f55be 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "firebase": "^9.21.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.11.2" diff --git a/src/App.js b/src/App.js index d5afe050643c4beab53ae39b5d73839a828471ae..9f514f2195e124698f866dcfd782f3b119cb7a28 100644 --- a/src/App.js +++ b/src/App.js @@ -1,65 +1,109 @@ -import React, { useState, useEffect } from 'react'; -import './assets/css/app.css'; -import { BrowserRouter, Routes, Route } from 'react-router-dom'; -import CheckoutPage from './Checkout'; -import Products from './Products'; -import Header from './Header'; -import ProductRegistrationPage from './RegisterProductPage'; +import React, { useState, useEffect } from "react"; +import "./assets/css/app.css"; +import CheckoutPage from "./Checkout"; +import Products from "./Products"; +import Header from "./Header"; +import RegisterPage from "./RegisterProductPage"; +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { collection, getDocs, addDoc } from "firebase/firestore"; +import { db } from "./firebase"; const App = (props) => { - const [cartItems, setCartItems] = useState([]); - const [formattedProducts, setFormattedProducts] = useState([]); + let [cartItems, setCartItems] = useState([]); + let [products, setProducts] = useState([]); + let [user, setUser] = useState(null); + + const fetchData = async () => { + /* firestore security rule change : + allow read : if request.auth != null; + allow write : if request != null; + */ + const querySnapshot = await getDocs(collection(db, "petshop")); + let products = []; + querySnapshot.forEach((doc) => { + products.push(doc.data()); + }); + setProducts([...products]); + console.log(products); + }; useEffect(() => { - /* wget https://raw.githubusercontent.com/gilbutITbook/007024/master/chapter-05/products.json */ - fetch('./products.json') - .then((r) => r.json()) - .then((data) => { - setFormattedProducts([...data.products]); - console.log(data.products); - }); + fetchData(); }, []); - const handleAddProduct = (product) => { - setFormattedProducts([...formattedProducts, product]); + const handleDeleteItem = (index) => { + const updatedCartItems = cartItems.filter((item, i) => i !== index); + setCartItems(updatedCartItems); }; - const clearCart = () => { + const DeleteAllItem = () => { setCartItems([]); }; - const updateInventory = (productId, quantity) => { - setFormattedProducts((prevProducts) => { - return prevProducts.map((product) => { - if (product.id === productId) { - return { - ...product, - availableInventory: product.availableInventory - quantity - }; - } - return product; + const updateInventory = () => { + cartItems.forEach((item) => { + console.log("item" + item); + products.forEach((product) => { + console.log("product" + product); + if (item.id === product.id) product.availableInventory -= 1; }); }); + setCartItems([]); + }; + + const addProduct = async (product) => { + const docRef = await addDoc(collection(db, "petshop"), product); + console.log(`document id : ${docRef.id}`); + setProducts([...products, product]); }; return ( <BrowserRouter> <header> - <Header name={props.sitename} nItems={cartItems.length} clearCart={clearCart} /> + <Header + name={props.sitename} + nItems={cartItems.length} + user={user} + onSignIn={setUser} + onSignOut={() => setUser(null)} + /> </header> <main> <Routes> <Route path="/" - element={<Products products={formattedProducts} cart={cartItems} onSetCart={setCartItems} />} - /> - <Route path="/checkout" element={<CheckoutPage products={formattedProducts} cartItems={cartItems} - onSetCartItems={setCartItems} onSetProducts={setFormattedProducts} />} /> - <Route path="/register-product" element={<ProductRegistrationPage addProduct={handleAddProduct} />} /> + element={ + <Products + products={products} + cart={cartItems} + onSetCart={setCartItems} + user={user} + /> + } + ></Route> + <Route + path="/checkout" + element={ + <CheckoutPage + cartItems={cartItems} + onDeleteItem={handleDeleteItem} + deleteAll={DeleteAllItem} + updateInventory={updateInventory} + /> + } + ></Route> + <Route + path="/register-product" + element={ + <RegisterPage + addProduct={addProduct} + /> + } + ></Route> </Routes> </main> </BrowserRouter> ); }; -export default App; \ No newline at end of file +export default App; diff --git a/src/Checkout.js b/src/Checkout.js index 2065a5f0649046bb8895e5d64c7a632c705f9c7a..22d81e39d7223881b73c487f171e78ac4982896a 100644 --- a/src/Checkout.js +++ b/src/Checkout.js @@ -38,15 +38,7 @@ const CheckoutPage = ({ products, cartItems, onSetCartItems, onSetProducts }) => cartItems.forEach((item) => { let product = products.find(p => p.id == item.id); product.availableInventory -= 1; - // const updatedProducts = products.map((product) => { - // if (product.id === item.id) { - // return { - // ...product, - // availableInventory: product.availableInventory - 1, - // }; - // } - // return product; - // }); + onSetProducts([...products]); }); onSetCartItems([]); @@ -144,4 +136,4 @@ const CheckoutPage = ({ products, cartItems, onSetCartItems, onSetProducts }) => ); }; -export default CheckoutPage; \ No newline at end of file +export default CheckoutPage; diff --git a/src/Header.js b/src/Header.js index 9fad7865ab66f26b50ad8e3d9b4a330145b8a977..4630084e1c444ea27e32fbf1e3571b3233816a1f 100644 --- a/src/Header.js +++ b/src/Header.js @@ -1,7 +1,18 @@ import React from 'react'; import { Link, useLocation } from 'react-router-dom'; -const Header = ({ name, nItems, products, setProducts, clearCart }) => { +import { + GoogleAuthProvider, signInWithPopup, + getAdditionalUserInfo, signOut +} from 'firebase/auth'; +import { auth, auth_provider } from './firebase'; + + + + + + +const Header = ({ name, nItems, user, onSignIn, onSignOut }) => { const location = useLocation(); const hasItemsInCart = nItems > 0; const isCheckoutPage = location.pathname.startsWith('/checkout'); @@ -9,9 +20,31 @@ const Header = ({ name, nItems, products, setProducts, clearCart }) => { const handleCheckoutClick = () => { if (isCheckoutPage && hasItemsInCart) { - + } }; + const handleSignIn = () => { + signInWithPopup(auth, auth_provider) + .then(res => { + const credential = GoogleAuthProvider.credentialFromResult(res); + const token = credential.accessToken; + const user = res.user; + const userInfo = getAdditionalUserInfo(res); + console.log(userInfo.profile); + onSignIn(userInfo.profile); + }).catch(error => { + console.log(`[${error.code}] ${error.message}`); + }) + } + const handleSignOut = () => { + signOut(auth).then(() => { + console.log(`Bye ${user.name}`); + onSignOut(); + }).catch(error => { + console.log(`[${error.code}] ${error.message}`); + }) + } + return ( <div className="navbar navbar-default"> @@ -19,23 +52,41 @@ const Header = ({ name, nItems, products, setProducts, clearCart }) => { <h1>{name}</h1> </div> <div className="nav navbar-nav navbar-right cart"> - {nItems > 0 && ( - <Link to={isCheckoutPage ? '/' : '/checkout'}> - <button - type="button" - className="btn btn-default btn-lg" - onClick={handleCheckoutClick} - > - <span className="glyphicon glyphicon-shopping-cart"> - {nItems || ''} - </span> - {checkoutButtonText} - </button> - </Link> - )} + + <Link to={isCheckoutPage ? '/' : '/checkout'}> + <button + type="button" + className="btn btn-default btn-lg" + onClick={handleCheckoutClick} + > + <span className="glyphicon glyphicon-shopping-cart"> + {nItems || ''} + </span> + {checkoutButtonText} + </button> + </Link> + {(user) ? + <button type="button" className="btn btn-default btn-lg" + style={{ margin: '5px' }} + onClick={handleSignOut} > + <span style={{ margin: '5px' }}> + <img className="rounded-circle" src={user.picture} + style={{ width: '20px', objectFit: 'cover' }} /> + </span> + {user.name} 로그아웃 + </button> + : + <button type="button" className="btn btn-default btn-lg" + onClick={handleSignIn} > + 로그인 + </button> + } + + + </div> </div> ); }; -export default Header; \ No newline at end of file +export default Header; diff --git a/src/Products.js b/src/Products.js index 3c857a4fee39196117ecdc390ea84414f6347db6..e26db91b14db11d81c8ad2783cbd685e88d1d00b 100644 --- a/src/Products.js +++ b/src/Products.js @@ -48,6 +48,7 @@ const Products = ({ products, cart, onSetCart }) => { return 0; } }; + return ( <> diff --git a/src/firebase.js b/src/firebase.js new file mode 100644 index 0000000000000000000000000000000000000000..707ac10356c93cf1431e8c288023e75478536cbc --- /dev/null +++ b/src/firebase.js @@ -0,0 +1,35 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from "firebase/app"; +import { getAnalytics } from "firebase/analytics"; + +// TODO: Add SDKs for Firebase products that you want to use +// https://firebase.google.com/docs/web/setup#available-libraries + +// Your web app's Firebase configuration +// For Firebase JS SDK v7.20.0 and later, measurementId is optional + +import { getFirestore } from 'firebase/firestore'; +import { getAuth ,GoogleAuthProvider } from 'firebase/auth'; + + + + +const firebaseConfig = { + apiKey: "AIzaSyAMGZojwvf5o32lokZ1SkF3JRFYcD2NQcQ", + authDomain: "petshop-f62e0.firebaseapp.com", + projectId: "petshop-f62e0", + storageBucket: "petshop-f62e0.appspot.com", + messagingSenderId: "305060990130", + appId: "1:305060990130:web:98797b3fbb420f080a8dab", + measurementId: "G-CCV33S1HTF" +}; + +// Initialize Firebase +const app = initializeApp(firebaseConfig); +const analytics = getAnalytics(app); +export const db = getFirestore(app); +export const auth = getAuth(); +export const auth_provider = new GoogleAuthProvider(); + + +