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

62 done

parent d8283adb
This diff is collapsed.
......@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.9.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"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 { CheckoutSummary } from "../CheckoutSummary/CheckoutSummary";
import { useNavigate, useSearchParams } from "react-router-dom";
import { getTotalPrice } from "../../utils/getTotalPrice";
......@@ -9,18 +10,30 @@ import { useNavigate, useSearchParams } from "react-router-dom";
export function Checkout() {
const [searchParams] = useSearchParams()
const ingredients = useRef(Object.fromEntries(searchParams) as unknown as TIngredients)
const [price, setPrice] = useState<number>(0)
const navigate = useNavigate();
const checkoutCancelledHandler = () => {
navigate('/');
};
useEffect(() => {
const tempPrice = getTotalPrice({...ingredients.current})
setPrice(tempPrice)
}, [ingredients.current])
const checkoutContinuedHandler = () => {
navigate('contact-data');
navigate({
pathname: 'contact-data',
search: searchParams.toString()
}, {state: {
ingredients: ingredients.current,
price
}});
};
return <CheckoutSummary
price={price}
ingredients={ingredients.current}
checkoutContinued={checkoutContinuedHandler}
checkoutCancelled={checkoutCancelledHandler}
......
......@@ -6,15 +6,17 @@ import { MouseEventHandler } from "react";
import { Outlet } from "react-router-dom";
interface Props {
price: number
ingredients: TIngredients;
checkoutContinued: MouseEventHandler<HTMLButtonElement>
checkoutCancelled: MouseEventHandler<HTMLButtonElement>
}
export function CheckoutSummary({ ingredients, checkoutContinued, checkoutCancelled }: Props) {
export function CheckoutSummary({ price, ingredients, checkoutContinued, checkoutCancelled }: Props) {
return (
<div className={styles.CheckoutSummary}>
<h1>We hope it tastes well!</h1>
<h2>Price: {price}</h2>
<div className={styles.CheckoutSummaryBurger}>
<Burger ingredients={ingredients} />
</div>
......
import { ChangeEvent, FormEvent, useState } from 'react';
import Button from '../UI/Button/Button';
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() {
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 (
<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>
<form>
<input className={styles.Input} type="text" name="name" placeholder="Your Name" />
<input className={styles.Input} type="email" name="email" placeholder="Your Mail" />
<input className={styles.Input} type="text" name="street" placeholder="Street" />
<input className={styles.Input} type="text" name="postal" placeholder="Postal Code" />
<Button onClick={() => {}} btnType="Success">
<form onSubmit={submit}>
<input onChange={inputHandler} value={customerData.name} className={styles.Input} type="text" name="name" placeholder="Your Name" />
<input onChange={inputHandler} value={customerData.email} className={styles.Input} type="email" name="email" placeholder="Your Mail" />
<input onChange={inputHandler} value={customerData.street} className={styles.Input} type="text" name="street" placeholder="Street" />
<input onChange={inputHandler} value={customerData.postal} className={styles.Input} type="text" name="postal" placeholder="Postal Code" />
<Button btnType="Success">
ORDER
</Button>
</form>
</>
}
</div>
);
}
\ No newline at end of file
......@@ -2,7 +2,7 @@ import { TIngredients } from "../../types/TIngredients"
import styles from './OrderSummary.module.css'
import Button from "../UI/Button/Button"
import { FormEvent } from "react"
import { useNavigate, createSearchParams, URLSearchParamsInit } from "react-router-dom"
import { useNavigate, useSearchParams } from "react-router-dom"
type Props = {
ingredients: TIngredients
......@@ -10,7 +10,7 @@ type Props = {
}
const OrderSummary = ({ ingredients, price }: Props) => {
const [searchParams, setSearchParams] = useSearchParams()
const navigate = useNavigate()
const ingredientSummary = Object.keys(ingredients).map((igKey) => {
return (
......@@ -23,15 +23,16 @@ const OrderSummary = ({ ingredients, price }: Props) => {
const submit = (e: FormEvent) => {
e.preventDefault()
// {meat: 1, salad: 2 ...}
// .../chackout?uim=wefwef123
// .../chackout?meat=1&salad=2& ...
// meat=1&salad=2& ...
const params = createSearchParams(ingredients as unknown as URLSearchParamsInit);
setSearchParams((searchParams) => {
Object.keys(ingredients).forEach(key => {
searchParams.set(key, ingredients[key as keyof typeof ingredients] + '');
})
return searchParams;
});
navigate({
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 @@
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"erasableSyntaxOnly": false,
"noFallthroughCasesInSwitch": 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