|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
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; |
||||
} |
||||
@ -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 }; |
||||
@ -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; |
||||