Commit 832b9296 authored by Pavel Mishakov's avatar Pavel Mishakov

62 done

parent d8283adb
This diff is collapsed.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"axios": "^1.9.0",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-router": "^7.6.1", "react-router": "^7.6.1",
......
import axios from "axios";
export const axiosOrder = axios.create({
baseURL: 'https://burger-project-ajs-22-default-rtdb.firebaseio.com/'
})
\ No newline at end of file
import { useRef } from "react"; import { useEffect, useRef, useState } from "react";
import { TIngredients } from "../../types/TIngredients"; import { TIngredients } from "../../types/TIngredients";
import { CheckoutSummary } from "../CheckoutSummary/CheckoutSummary"; import { CheckoutSummary } from "../CheckoutSummary/CheckoutSummary";
import { useNavigate, useSearchParams } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { getTotalPrice } from "../../utils/getTotalPrice";
...@@ -9,18 +10,30 @@ import { useNavigate, useSearchParams } from "react-router-dom"; ...@@ -9,18 +10,30 @@ import { useNavigate, useSearchParams } from "react-router-dom";
export function Checkout() { export function Checkout() {
const [searchParams] = useSearchParams() const [searchParams] = useSearchParams()
const ingredients = useRef(Object.fromEntries(searchParams) as unknown as TIngredients) const ingredients = useRef(Object.fromEntries(searchParams) as unknown as TIngredients)
const [price, setPrice] = useState<number>(0)
const navigate = useNavigate(); const navigate = useNavigate();
const checkoutCancelledHandler = () => { const checkoutCancelledHandler = () => {
navigate('/'); navigate('/');
}; };
useEffect(() => {
const tempPrice = getTotalPrice({...ingredients.current})
setPrice(tempPrice)
}, [ingredients.current])
const checkoutContinuedHandler = () => { const checkoutContinuedHandler = () => {
navigate('contact-data'); navigate({
pathname: 'contact-data',
search: searchParams.toString()
}, {state: {
ingredients: ingredients.current,
price
}});
}; };
return <CheckoutSummary return <CheckoutSummary
price={price}
ingredients={ingredients.current} ingredients={ingredients.current}
checkoutContinued={checkoutContinuedHandler} checkoutContinued={checkoutContinuedHandler}
checkoutCancelled={checkoutCancelledHandler} checkoutCancelled={checkoutCancelledHandler}
......
...@@ -6,15 +6,17 @@ import { MouseEventHandler } from "react"; ...@@ -6,15 +6,17 @@ import { MouseEventHandler } from "react";
import { Outlet } from "react-router-dom"; import { Outlet } from "react-router-dom";
interface Props { interface Props {
price: number
ingredients: TIngredients; ingredients: TIngredients;
checkoutContinued: MouseEventHandler<HTMLButtonElement> checkoutContinued: MouseEventHandler<HTMLButtonElement>
checkoutCancelled: MouseEventHandler<HTMLButtonElement> checkoutCancelled: MouseEventHandler<HTMLButtonElement>
} }
export function CheckoutSummary({ ingredients, checkoutContinued, checkoutCancelled }: Props) { export function CheckoutSummary({ price, ingredients, checkoutContinued, checkoutCancelled }: Props) {
return ( return (
<div className={styles.CheckoutSummary}> <div className={styles.CheckoutSummary}>
<h1>We hope it tastes well!</h1> <h1>We hope it tastes well!</h1>
<h2>Price: {price}</h2>
<div className={styles.CheckoutSummaryBurger}> <div className={styles.CheckoutSummaryBurger}>
<Burger ingredients={ingredients} /> <Burger ingredients={ingredients} />
</div> </div>
......
import { ChangeEvent, FormEvent, useState } from 'react';
import Button from '../UI/Button/Button'; import Button from '../UI/Button/Button';
import styles from './ContactData.module.css'; import styles from './ContactData.module.css';
import { axiosOrder } from '../../axios/axiosOrder';
import { TCustomerData } from '../../types/TCustomerData';
import { useLocation, useNavigate } from 'react-router';
import Spinner from '../UI/Spinner/Spinner';
export function ContactData() { export function ContactData() {
const location = useLocation()
const navigate = useNavigate()
const [isLoading, setIsLoading] = useState<boolean>(false)
const [isSubmited, setIsSubmited] = useState<boolean>(false)
const [customerData, setCustomerData] = useState<TCustomerData>({
name: '',
email: '',
street: '',
postal: ''
})
const inputHandler = (e: ChangeEvent<HTMLInputElement>) => {
setCustomerData(prevState => ({ ...prevState, [e.target.name]: e.target.value }))
}
const submit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
if (isSubmited) return
try {
setIsLoading(true)
const { ingredients, price } = location.state
const response = await axiosOrder.post('orders.json', {
customer: { ...customerData },
ingredients,
price
})
console.log(response.data)
setIsSubmited(true)
} catch (err) {
console.log(err)
setIsSubmited(false)
} finally {
setIsLoading(false)
}
}
const goBack = () => {
navigate('/')
}
return ( return (
<div className={styles.ContactData}> <div className={styles.ContactData}>
{isLoading ?
<Spinner />
:
isSubmited ?
<>
<h1>
Your order is successful
</h1>
<Button btnType='Success' onClick={goBack}>Go back</Button>
</>
:
<>
<h4>Enter your Contact Data</h4> <h4>Enter your Contact Data</h4>
<form> <form onSubmit={submit}>
<input className={styles.Input} type="text" name="name" placeholder="Your Name" /> <input onChange={inputHandler} value={customerData.name} className={styles.Input} type="text" name="name" placeholder="Your Name" />
<input className={styles.Input} type="email" name="email" placeholder="Your Mail" /> <input onChange={inputHandler} value={customerData.email} className={styles.Input} type="email" name="email" placeholder="Your Mail" />
<input className={styles.Input} type="text" name="street" placeholder="Street" /> <input onChange={inputHandler} value={customerData.street} className={styles.Input} type="text" name="street" placeholder="Street" />
<input className={styles.Input} type="text" name="postal" placeholder="Postal Code" /> <input onChange={inputHandler} value={customerData.postal} className={styles.Input} type="text" name="postal" placeholder="Postal Code" />
<Button onClick={() => {}} btnType="Success"> <Button btnType="Success">
ORDER ORDER
</Button> </Button>
</form> </form>
</>
}
</div> </div>
); );
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ import { TIngredients } from "../../types/TIngredients" ...@@ -2,7 +2,7 @@ import { TIngredients } from "../../types/TIngredients"
import styles from './OrderSummary.module.css' import styles from './OrderSummary.module.css'
import Button from "../UI/Button/Button" import Button from "../UI/Button/Button"
import { FormEvent } from "react" import { FormEvent } from "react"
import { useNavigate, createSearchParams, URLSearchParamsInit } from "react-router-dom" import { useNavigate, useSearchParams } from "react-router-dom"
type Props = { type Props = {
ingredients: TIngredients ingredients: TIngredients
...@@ -10,7 +10,7 @@ type Props = { ...@@ -10,7 +10,7 @@ type Props = {
} }
const OrderSummary = ({ ingredients, price }: Props) => { const OrderSummary = ({ ingredients, price }: Props) => {
const [searchParams, setSearchParams] = useSearchParams()
const navigate = useNavigate() const navigate = useNavigate()
const ingredientSummary = Object.keys(ingredients).map((igKey) => { const ingredientSummary = Object.keys(ingredients).map((igKey) => {
return ( return (
...@@ -23,15 +23,16 @@ const OrderSummary = ({ ingredients, price }: Props) => { ...@@ -23,15 +23,16 @@ const OrderSummary = ({ ingredients, price }: Props) => {
const submit = (e: FormEvent) => { const submit = (e: FormEvent) => {
e.preventDefault() e.preventDefault()
// {meat: 1, salad: 2 ...}
// .../chackout?uim=wefwef123
// .../chackout?meat=1&salad=2& ...
// meat=1&salad=2& ... setSearchParams((searchParams) => {
const params = createSearchParams(ingredients as unknown as URLSearchParamsInit); Object.keys(ingredients).forEach(key => {
searchParams.set(key, ingredients[key as keyof typeof ingredients] + '');
})
return searchParams;
});
navigate({ navigate({
pathname: '/checkout', pathname: '/checkout',
search: `?${params.toString()}` search: `${searchParams.toString()}`
}) })
} }
......
.Spinner,
.Spinner:before,
.Spinner:after {
border-radius: 50%;
}
.Spinner {
color: #521751;
font-size: 11px;
text-indent: -99999em;
margin: 55px auto;
position: relative;
width: 10em;
height: 10em;
box-shadow: inset 0 0 0 1em;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
}
.Spinner:before,
.Spinner:after {
position: absolute;
content: '';
}
.Spinner:before {
width: 5.2em;
height: 10.2em;
background: #fff;
border-radius: 10.2em 0 0 10.2em;
top: -0.1em;
left: -0.1em;
-webkit-transform-origin: 5.2em 5.1em;
transform-origin: 5.2em 5.1em;
-webkit-animation: load2 2s infinite ease 1.5s;
animation: load2 2s infinite ease 1.5s;
}
.Spinner:after {
width: 5.2em;
height: 10.2em;
background: #fff;
border-radius: 0 10.2em 10.2em 0;
top: -0.1em;
left: 5.1em;
-webkit-transform-origin: 0px 5.1em;
transform-origin: 0px 5.1em;
-webkit-animation: load2 2s infinite ease;
animation: load2 2s infinite ease;
}
@-webkit-keyframes load2 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes load2 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
import styles from './Spinner.module.css'
const Spinner = () => <div className={styles.Spinner}>Loading...</div>
export default Spinner;
\ No newline at end of file
export type TCustomerData = {
name: string
email: string
street: string
postal: string
}
\ No newline at end of file
import { EIngredientPrices } from "../enums/EIngredientPrices";
import { TIngredientNames } from "../types/TIngredientNames";
export const getTotalPrice = (searchParms: object): number => {
return Object.keys(searchParms).reduce((acc: number, key) => {
if (!EIngredientPrices[key as keyof typeof searchParms]) {
return acc
}
const total = acc + EIngredientPrices[key as TIngredientNames] * searchParms[key as keyof typeof searchParms]
return total
}, EIngredientPrices.bread)
}
\ No newline at end of file
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
"strict": true, "strict": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"erasableSyntaxOnly": true, "erasableSyntaxOnly": false,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true "noUncheckedSideEffectImports": true
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment