amazon-clone

master
Kirelos Mickael 5 years ago
parent d3173e99ae
commit c75de564d7
  1. 16806
      package-lock.json
  2. 5
      package.json
  3. BIN
      public/img/ac.jpg
  4. BIN
      public/img/ad123.jpg
  5. BIN
      public/img/amazon_logo.png
  6. BIN
      public/img/banner1.jpg
  7. BIN
      public/img/gc1.jpg
  8. BIN
      public/img/gc2.jpg
  9. BIN
      public/img/gc3.jpg
  10. BIN
      public/img/rec.jpg
  11. BIN
      public/img/souqAmazon-logo-v2.png
  12. BIN
      public/img/strip.jpg
  13. BIN
      public/img/vr.jpg
  14. 39
      src/App.css
  15. 64
      src/App.js
  16. 22
      src/Checkout.css
  17. 48
      src/Checkout.js
  18. 36
      src/CheckoutProduct.css
  19. 40
      src/CheckoutProduct.js
  20. 71
      src/Header.css
  21. 66
      src/Header.js
  22. 24
      src/Home.css
  23. 62
      src/Home.js
  24. 69
      src/Login.css
  25. 56
      src/Login.js
  26. 45
      src/Product.css
  27. 42
      src/Product.js
  28. 8
      src/StateProvider.js
  29. 32
      src/Subtotal.css
  30. 35
      src/Subtotal.js
  31. 16
      src/firebase.js
  32. 1
      src/index.css
  33. 6
      src/index.js
  34. 35
      src/reducer.js

16806
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -3,11 +3,16 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"firebase": "^7.17.2",
"react": "^16.13.1",
"react-currency-format": "^1.0.0",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1"
},
"scripts": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

@ -1,38 +1,3 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
* {
margin: 0;
}

@ -1,25 +1,55 @@
import React from 'react';
import logo from './logo.svg';
import React, { useEffect } from 'react';
import './App.css';
import Header from "./Header";
import { BrowserRouter as Router, Switch, Route} from "react-router-dom";
import Home from './Home';
import Checkout from './Checkout';
import Login from './Login';
import { useStateValue } from "./StateProvider"
import { auth } from "./firebase"
function App() {
const [{ user }, dispatch] = useStateValue();
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((authUser) => {
if (authUser) {
dispatch({
type: "SET_USER",
user: authUser,
});
} else {
dispatch({
type: "SET_USER",
user: null
});
}
});
return () => {
unsubscribe();
}
}, [])
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<Router>
<div className="app">
<Switch>
<Route path="/checkout">
<Header />
<Checkout />
</Route>
<Route path="/login">
<Login />
</Route>
<Route path="/">
<Header />
<Home />
</Route>
</Switch>
</div>
</Router>
);
}

@ -0,0 +1,22 @@
.checkout {
display: flex;
padding: 20px;
background-color: white;
height: max-content;
}
.checkout__title {
margin-right: 10px;
padding: 10px;
border-bottom: 1px solid lightgray;
}
.checkout__ad {
width: 100%;
margin-bottom: 10px;
}
.checkout__empty {
direction: rtl;
margin: 10px;
}

@ -0,0 +1,48 @@
import React from 'react'
import { useStateValue } from './StateProvider'
import './Checkout.css'
import CheckoutProduct from "./CheckoutProduct"
import Subtotal from './Subtotal';
function Checkout() {
const [{basket}] = useStateValue();
return (
<div className="checkout">
{basket.length > 0 && (
<div className="checkout__left">
<Subtotal />
</div>
)}
<div className="checkout__right">
<img
className="checkout__ad"
src="./img/ad123.jpg"
alt=""
/>
{basket.length === 0 ? (
<div>
<h2 className="checkout__empty"> عــربــة التســـوق فارغة ({basket.length})</h2>
<p className="checkout__empty">عربة التسوق فارغة.
أضف سلع لعربة التسوق واستعرضهم قبل عملية الشراء. تكملة الشراء!</p>
</div>
) : (
<div>
<h2 className="checkout__empty">عــربــة التســـوق ({basket.length})</h2>
{basket.map(item => (
<CheckoutProduct
id={item.id}
title={item.title}
image={item.image}
price={item.price}
rating={item.rating}
/>
))}
</div>
)}
</div>
</div>
)
}
export default Checkout

@ -0,0 +1,36 @@
.checkoutProduct {
display: flex;
direction: rtl;
margin-top: 20px;
margin-bottom: 20px;
}
.checkoutProduct__image {
object-fit: contain;
width: 180px;
height: 180px;
}
.checkoutProduct__info {
padding-right: 20px;
direction: rtl;
}
.checkoutProduct__info > button {
background-color: #f0c14b;
border: 1px solid;
border-color: #a88734 #9c7e31 #846a29;
color: #111;
margin-top: 20px;
}
.checkoutProduct__rating {
display: flex;
margin-top: 20px;
}
.checkoutProduct__title {
font-size: 17px;
font-weight: 800;
margin-top: 20px;
}

@ -0,0 +1,40 @@
import React from 'react'
import './CheckoutProduct.css'
import { useStateValue } from "./StateProvider"
function CheckoutProduct({ id, title, image, price, rating }) {
const [{basket}, dispatch] = useStateValue();
const removeFromBasket = () => {
dispatch({
type: "REMOVE_FROM_BASKET",
id: id,
})
}
return (
<div className="checkoutProduct">
<img className="checkoutProduct__image" src={image} alt="" />
<div className="checkoutProduct__info">
<p className="checkoutProduct__title">{title}</p>
<p className="checkoutProduct__price">
<strong>{price}</strong>
<small> جنيه</small>
</p>
<div className="checkoutProduct__rating">
{Array(rating)
.fill()
.map((_) => (
<p></p>
))}
</div>
<button onClick={removeFromBasket}>مسح من السلة</button>
</div>
</div>
)
}
export default CheckoutProduct

@ -0,0 +1,71 @@
.header {
background-color: #131921;
display: flex;
align-items: center;
position: sticky;
top: 0;
z-index: 100;
}
.header__logo {
width: 100px;
object-fit: contain;
margin-left: 20px;
margin-right: 20px;
margin-top: 10px;
}
.header__optionBasket {
display: flex;
align-items: center;
}
.header__optionBasketCount {
margin-left: 10px;
margin-right: 10px;
}
.header__nav {
display: flex;
justify-content: space-evenly;
}
.header__option {
display: flex;
flex-direction: column;
margin-left: 10px;
margin-right: 10px;
}
.header__optionLineOne {
font-size: 10px;
}
.header__optionLineTwo {
font-size: 13px;
font-weight: 800;
}
.header__link {
color: white;
text-decoration: none;
}
.header__search {
display: flex;
flex: 1;
}
.header__searchInput {
height: 12px;
padding: 10px;
border: none;
width: 100%;
}
.header__searchIcon {
padding: 5px;
height: 22px !important;
background-color: #cd9042;
}

@ -0,0 +1,66 @@
import React from 'react'
import "./Header.css"
import { Link } from "react-router-dom";
import SearchIcon from '@material-ui/icons/Search';
import ShoppingBasketIcon from '@material-ui/icons/ShoppingBasket';
import { useStateValue } from "./StateProvider";
import { auth } from "firebase";
function Header() {
const [{ basket, user }] = useStateValue();
const login = () => {
if(user){
auth().signOut();
}
}
return (
<nav className="header">
<Link to="/">
<img className="header__logo" src="./img/amazon_logo.png" alt="amazon_logo"/>
</Link>
<div className="header__search">
<input type="text" className="header__searchInput"/>
<SearchIcon className="header__searchIcon"/>
</div>
<div className="header__nav">
<Link to={!user && "/login"} className="header__link">
<div onClick={login} className="header__option">
<span className="header__optionLineOne">Hello {user?.email}</span>
<span className="header__optionLineTwo">{user ? 'Sign Out' : 'Sign In'}</span>
</div>
</Link>
<Link to="/" className="header__link">
<div className="header__option">
<span className="header__optionLineOne">Returns</span>
<span className="header__optionLineTwo">& Orders</span>
</div>
</Link>
<Link to="/" className="header__link">
<div className="header__option">
<span className="header__optionLineOne">Your</span>
<span className="header__optionLineTwo">Prime</span>
</div>
</Link>
<Link to="/checkout" className="header__link">
<div className="header__optionBasket">
<ShoppingBasketIcon />
<span className="header__optionLineTwo header__optionBasketCount">{basket.length}</span>
</div>
</Link>
</div>
</nav>
)
}
export default Header

@ -0,0 +1,24 @@
.home {
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
.home__row {
display: flex;
z-index: 1;
margin-left: 5px;
margin-right: 5px;
}
.home__image {
width: 100%;
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
z-index: -1;
margin-bottom: -150px;
}
.home__strip {
width: 100%;
margin-top: 3px;
}

@ -0,0 +1,62 @@
import React from 'react'
import './Home.css'
import Product from "./Product"
function Home() {
return (
<div className="home">
<img className="home__image" src="./img/banner1.jpg" alt="banner" />
<div className="home__row">
<Product
id={111}
title="ريسيفر ميني اتش دي من سكاي لاين 222i - اسود"
price={215.00}
rating={5}
image="./img/rec.jpg"
/>
<Product
id={112}
title="نظارة 3D ثلاثية الابعاد المحاكية للواقع الإفتراضي متوافق مع كل الهواتف الذكيــة"
price={137.07}
rating={5}
image="./img/vr.jpg"
/>
</div>
<img className="home__strip" src="./img/strip.jpg" alt="banner" />
<div className="home__row">
<Product
id={113}
title="جيني كوليكشن 5573 للنساء 25 مل"
price={150.00}
rating={5}
image="./img/gc1.jpg"
/>
<Product
id={114}
title="جيني كوليكشين 5571 لل رجال 25 مل - او دى بارفان"
price={115.00}
rating={5}
image="./img/gc2.jpg"
/>
<Product
id={115}
title="جيني كوليكشين 8813 لل نساء 25 مل - او دى بارفان"
price={195.00}
rating={5}
image="./img/gc3.jpg"
/>
</div>
<div className="home__row">
<Product
id={116}
title="تكييف يونيون اير سبليت بارد وساخن ART1030HR-F – اسود، 4 حصان"
price={13280.00}
rating={5}
image="./img/ac.jpg"
/>
</div>
</div>
)
}
export default Home

@ -0,0 +1,69 @@
.login {
background-color: white;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
direction: rtl;
}
.login__container {
width: 300px;
display: flex;
flex-direction: column;
padding: 20px;
border: 1px solid lightgray;
}
.login__container > h1 {
font-weight: 500;
margin-bottom: 20px;
}
.login__container > p {
margin-bottom: 15px;
font-size: 12px;
}
.login__container > form > h5 {
margin-bottom: 5px;
}
.login__container > form > input {
height: 30px;
margin-bottom: 10px;
background-color: white;
width: 98%;
}
.login__logo {
margin-top: 20px;
margin-bottom: 20px;
width: 100px;
object-fit: contain;
}
.login__signInButton {
background: #f0c14b;
border-radius: 2px;
width: 100%;
height: 30px;
border: 1px solid;
margin-top: 10px;
border-color: #a88734 #9c7e31 #846a29;
}
.login__registerButton {
border-radius: 2px;
width: 100%;
height: 30px;
border: 1px solid;
border-color: darkgray;
}
.login__newUser {
margin-top: 20px;
margin-bottom: 5px;
text-align: center;
font-size: 15px;
}

@ -0,0 +1,56 @@
import React, { useState } from 'react'
import "./Login.css"
import { Link, useHistory } from "react-router-dom"
import { auth } from "./firebase"
function Login() {
const history = useHistory();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const login = event => {
event.preventDefault();
auth.signInWithEmailAndPassword(email,password)
.then((auth) => {
history.push('/');
})
.catch((e) => alert(e.message));
}
const register = event => {
event.preventDefault();
auth.createUserWithEmailAndPassword(email,password)
.then((auth) => {
history.push('/');
})
.catch((e) => alert(e.message));
}
return (
<div className="login">
<Link to="/">
<img
className="login__logo"
src="./img/souqAmazon-logo-v2.png"
alt=""
/>
</Link>
<div className="login__container">
<h1>تسجيل الدخول</h1>
<p>يمكنك الدخول إلى موقع سوق وأمازون باستخدام بيانات الدخول ذاتها!</p>
<p>قم بتسجيل الدخول باستخدام حسابك في سوق أو حسابك في أمازون</p>
<form>
<h5>البريد الالكتروني</h5>
<input value={email} onChange={event => setEmail(event.target.value)} type="email"/>
<h5>كلمة السر</h5>
<input value={password} onChange={event => setPassword(event.target.value)} type="password"/>
<button onClick={login} type="submit" className="login__signInButton">تسجيل الدخول</button>
</form>
<h6 className="login__newUser"> مستخدم جديد؟ </h6>
<button onClick={register} className="login__registerButton">انشئ حسابك</button>
</div>
</div>
)
}
export default Login

@ -0,0 +1,45 @@
.product {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
max-height: 400px;
min-width: 100px;
margin: 10px;
padding: 20px;
width: 100%;
background-color: white;
z-index: 1;
}
.product__info {
height: 100px;
margin-bottom: 15px;
}
.product__price {
margin-top: 5px;
direction: rtl;
}
.product__rating {
display: flex;
direction: rtl;
}
.product > img {
max-height: 200px;
width: 100%;
object-fit: contain;
margin-bottom: 15px;
}
.product > button {
background-color: #f0c14b;
border: 1px solid;
border-color: #a88734 #9c7e31 #846a29;
}
.product__title {
direction: rtl;
}

@ -0,0 +1,42 @@
import React from 'react'
import "./Product.css"
import { useStateValue } from './StateProvider'
function Product({ id, title, image, price, rating}) {
const [{basket}, dispatch] = useStateValue();
const addToBasket = () => {
dispatch({
type: 'ADD_TO_BASKET',
item: {
id: id,
title: title,
image: image,
price: price,
rating: rating,
}
})
}
return (
<div className="product">
<div className="product__info">
<p className="product__title">{title}</p>
<p className="product__price">
<strong>{price}</strong>
<small> جنيه</small>
</p>
<div className="product__rating">
{Array(rating)
.fill()
.map((_) => (
<p></p>
))}
</div>
</div>
<img src={image} />
<button onClick={addToBasket}>أضف الي السلة</button>
</div>
)
}
export default Product

@ -0,0 +1,8 @@
import React, { createContext, useContext, useReducer } from "react";
export const StateContext = createContext();
export const StateProvider = ({ reducer, initialState, children }) => (
<StateContext.Provider value={useReducer(reducer, initialState)}>
{children}
</StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);

@ -0,0 +1,32 @@
.subtotal {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 300px;
height: 100px;
padding: 20px;
background-color: #f3f3f3;
border: 1px solid #dddddd;
border-radius: 3px;
direction: rtl;
}
.subtotal__gift {
display: flex;
align-items: center;
}
.subtotal__gift > input {
margin-right: 5px;
}
.subtotal > button {
background: #f0c14b;
border-radius: 2px;
width: 100%;
height: 30px;
border: 1px solid;
margin-top: 10px;
border-color: #a88734 #9c7e31 #846a29;
color: #111;
}

@ -0,0 +1,35 @@
import React from 'react'
import './Subtotal.css'
import CurrencyFormat from "react-currency-format"
import { useStateValue } from "./StateProvider"
import { getBasketTotal } from "./reducer"
function Subtotal() {
const [{ basket }] = useStateValue();
return (
<div className="subtotal">
<CurrencyFormat
renderText={(value) => (
<>
<p>
الأجمالي ({basket.length} قطعة): <strong>{ value } جنيه</strong>
</p>
<small>
<input type="checkbox" /> هل الطلب يحتوي علي كارت هدايا
</small>
</>
)}
decimalScale={2}
value={getBasketTotal(basket)}
displayType={"text"}
thousandSeparator={true}
/>
<button>تابع عملية الشراء</button>
</div>
)
}
export default Subtotal

@ -0,0 +1,16 @@
import firebase from 'firebase'
const firebaseApp = firebase.initializeApp({
apiKey: YOUR_API_KEY,
authDomain: YOUR_AUTH_DOMAIN,
databaseURL: YOUR_DATABASE_URL,
projectId: YOUR_PROJECT_ID,
storageBucket: '',
messagingSenderId: YOUR_MESSAGING_SENDER_ID,
appId: YOUR_APP_ID,
measurementId: YOURS
});
const auth = firebase.auth();
export { auth };

@ -1,4 +1,5 @@
body {
background-color: rgb(234, 237, 237);
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',

@ -3,10 +3,14 @@ import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { StateProvider } from './StateProvider';
import reducer, { initialState } from './reducer';
ReactDOM.render(
<React.StrictMode>
<App />
<StateProvider initialState={initialState} reducer={reducer}>
<App />
</StateProvider>
</React.StrictMode>,
document.getElementById('root')
);

@ -0,0 +1,35 @@
export const initialState = {
basket: [],
user: null,
};
export const getBasketTotal = (basket) =>
basket.reduce((amount, item) => item.price + amount, 0);
const reducer = (state, action) => {
switch(action.type) {
case 'SET_USER':
return {
...state,
user: action.user,
};
case 'ADD_TO_BASKET':
return {
...state,
basket: [...state.basket, action.item]
};
case 'REMOVE_FROM_BASKET':
let newBasket = [...state.basket];
const index = state.basket.findIndex((basketItem) => basketItem.id === action.id);
if (index >= 0) {
newBasket.splice(index, 1);
};
return { ...state, basket: newBasket };
default:
return state;
}
}
export default reducer;
Loading…
Cancel
Save