Skip to content

Commit

Permalink
added checkout form, validation, buttons..
Browse files Browse the repository at this point in the history
  • Loading branch information
LuisPinedaJR committed Sep 13, 2021
1 parent 3fa7346 commit 4a79c40
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 20 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
## How I worked on this project

- This is template for project for a paying client. I used existing ordering menu currently in place['https://qmenu.us/#/hibachi-express-valrico'] for inspiration.
- features and bugs have different branches.
-
- This is template for project for a paying client. I used existing ordering menu currently in place['https://qmenu.us/#/hibachi-express-valrico'] for inspiration.
- features and bugs have different branches.

## How to navigate this project

- if you'd like to fork this project, you are more then welcome to do so.
- after forking run `npm install` or `yarn install` which ever is your preference.
- the complete code can be found main.
- you'll have to create your own Database to get the project to work, you can create a database quick using Firebase by google.
- if you'd like to fork this project, you are more then welcome to do so.
- after forking run `npm install` or `yarn install` which ever is your preference.
- the complete code can be found main.
- you'll have to create your own Database to get the project to work, you can create a database quick using Firebase by google.

## Why I built the project this way

- I decided to build this project this way for quick reference and quickly copy and reusable code to speed up development in the future.
- I decided to build this project this way for quick reference and quickly copy and reusable code to speed up development in the future.

## If I had more time I would change this

- I work on styling better, however I really like the way it looks currently ex:[food-order-app-photo](https://res.cloudinary.com/luispineda/image/upload/v1631236923/Screen_Shot_2021-09-09_at_9.21.11_PM_sivc9u.png)
- I work on styling better, however, I really like the way it looks currently ex:
![food-order-app-photo](https://res.cloudinary.com/luispineda/image/upload/v1631236923/Screen_Shot_2021-09-09_at_9.21.11_PM_sivc9u.png)

- ## Available Scripts

Expand Down
67 changes: 62 additions & 5 deletions src/components/Cart/Cart.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import React, { useContext } from 'react'
import React, { useContext, useState } from 'react'

import Modal from '../UI/Modal'
import CartItem from './CartItem'
import CartContext from '../../store/cart-context'
import Checkout from './Checkout'

import classes from './Cart.module.css'

const Cart = props => {
const [isCheckout, setIsCheckout] = useState(false)
const [isSubmitting, setIsSubmitting] = useState(false)
const [didSubmit, setDidSubmit] = useState(false)

const cartCtx = useContext(CartContext)

const totalAmount = `$${cartCtx.totalAmount.toFixed(2)}`
Expand All @@ -18,6 +23,27 @@ const Cart = props => {
const cartItemRemoveHandler = id => {
cartCtx.removeItem(id)
}
const orderHandler = event => {
setIsCheckout(true)
}

const submitOrderHandler = async userData => {
setIsSubmitting(true)

await fetch(
'https://food-order-app-8d642-default-rtdb.firebaseio.com/orders.json',
{
method: 'POST',
body: JSON.stringify({
user: userData,
orderedItem: cartCtx.items,
}),
}
)
setIsSubmitting(false)
setDidSubmit(true)
cartCtx.clearCart()
}

const cartitems = (
<ul className={classes['cart-items']}>
Expand All @@ -34,20 +60,51 @@ const Cart = props => {
</ul>
)

return (
<Modal onClose={props.onClose}>
const modalActions = (
<div className={classes.actions}>
<button className={classes['button--alt']} onClick={props.onClose}>
Close
</button>
{hasItems && (
<button className={classes.button} onClick={orderHandler}>
Order
</button>
)}
</div>
)

const cartModalContent = (
<>
{cartitems}

<div className={classes.total}>
<span>Total Amount</span>
<span>{totalAmount}</span>
</div>
{isCheckout && (
<Checkout onConfirm={submitOrderHandler} onCancel={props.onClose} />
)}
{!isCheckout && modalActions}
</>
)

const isSubmittingModalContent = <p>Sending order data...</p>
const didSubmitModalContent = (
<>
<p>Successfully sent the order!</p>
<div className={classes.actions}>
<button className={classes['button--alt']} onClick={props.onClose}>
<button className={classes.button} onClick={props.onClose}>
Close
</button>
{hasItems && <button className={classes.button}>Order</button>}
</div>
</>
)

return (
<Modal onClose={props.onClose}>
{!isSubmitting && !didSubmit && cartModalContent}
{isSubmitting && isSubmittingModalContent}
{!isSubmitting && didSubmit && didSubmitModalContent}
</Modal>
)
}
Expand Down
104 changes: 98 additions & 6 deletions src/components/Cart/Checkout.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,104 @@
import React from 'react'
import { useRef, useState } from 'react'

import classes from './Checkout.module.css'

const Checkout = () => {
const isEmpty = value => value.trim() === ''
const isFiveChars = value => value.trim().length === 5

const Checkout = props => {
const [formInputsValidity, setFormInputsValidity] = useState({
name: true,
street: true,
city: true,
postalCode: true,
})

const nameInputRef = useRef()
const streetInputRef = useRef()
const postalInputRef = useRef()
const cityInputRef = useRef()

const confirmHandler = event => {
event.preventDefault()

const enteredName = nameInputRef.current.value
const enteredStreet = streetInputRef.current.value
const enteredPostal = postalInputRef.current.value
const enteredCity = cityInputRef.current.value

const enteredNameIsValid = !isEmpty(enteredName)
const enteredStreetIsValid = !isEmpty(enteredStreet)
const enteredCityIsValid = !isEmpty(enteredCity)
const enteredPostalIsValid = isFiveChars(enteredPostal)

setFormInputsValidity({
name: enteredNameIsValid,
street: enteredStreetIsValid,
city: enteredCityIsValid,
postalCode: enteredPostalIsValid,
})

const formIsValid =
enteredNameIsValid &&
enteredStreetIsValid &&
enteredCityIsValid &&
enteredPostalIsValid

if (!formIsValid) {
return
}

props.onConfirm({
name: enteredName,
street: enteredStreet,
city: enteredCity,
postalCode: enteredPostal,
})
}
const nameControlClasses = `${classes.control} ${
formInputsValidity.name ? '' : classes.invalid
}`
const streetControlClasses = `${classes.control} ${
formInputsValidity.street ? '' : classes.invalid
}`
const cityControlClasses = `${classes.control} ${
formInputsValidity.city ? '' : classes.invalid
}`
const postalCodeControlClasses = `${classes.control} ${
formInputsValidity.postalCode ? '' : classes.invalid
}`

return (
<div classes={classes.control}>
<label htmlFor="name">Your name</label>
<input type="text" />
</div>
<form className={classes.form} onSubmit={confirmHandler}>
<div className={nameControlClasses}>
<label htmlFor="name">Your Name</label>
<input type="text" id="name" ref={nameInputRef} />
{!formInputsValidity.name && <p>Please enter a valid name</p>}
</div>
<div className={streetControlClasses}>
<label htmlFor="street">Street</label>
<input type="text" id="street" ref={streetInputRef} />
{!formInputsValidity.street && <p>Please enter a valid street</p>}
</div>
<div className={postalCodeControlClasses}>
<label htmlFor="postal">Postal Code</label>
<input type="text" id="postal" ref={postalInputRef} />
{!formInputsValidity.postalCode && (
<p>Please enter a valid postal code (5 characters long)</p>
)}
</div>
<div className={cityControlClasses}>
<label htmlFor="city">City</label>
<input type="text" id="city" ref={cityInputRef} />
{!formInputsValidity.city && <p>Please enter a valid city</p>}
</div>
<div className={classes.actions}>
<button type="button" onClick={props.onCancel}>
Cancel
</button>
<button className={classes.submit}>Confirm</button>
</div>
</form>
)
}

Expand Down
64 changes: 64 additions & 0 deletions src/components/Cart/Checkout.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.form {
margin: 1rem 0;
height: 19rem;
overflow: auto;
}

.control {
margin-bottom: 0.5rem;
}

.control label {
font-weight: bold;
margin-bottom: 0.25rem;
display: block;
}

.control input {
font: inherit;
border: 1px solid #ccc;
border-radius: 4px;
width: 20rem;
max-width: 100%;
}

.actions {
display: flex;
justify-content: flex-end;
gap: 1rem;
}

.actions button {
font: inherit;
color: #5a1a01;
cursor: pointer;
background-color: transparent;
border: none;
border-radius: 25px;
padding: 0.5rem 2rem;
}

.actions button:hover,
.actions button:active {
background-color: #ffe6dc;
}

.actions .submit {
border: 1px solid #5a1a01;
background-color: #5a1a01;
color: white;
}

.actions .submit:hover,
.actions .submit:active {
background-color: #7a2706;
}

.invalid label {
color: #ca3e51;
}

.invalid input {
border-color: #aa0b20;
background-color: #ffeff1;
}
9 changes: 9 additions & 0 deletions src/store/CartProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ const cartReducer = (state, action) => {
}
}

if (action.type === 'CLEAR') {
return defaultCartState
}

return defaultCartState
}

Expand All @@ -76,11 +80,16 @@ const CartProvider = props => {
})
}

const clearCartHandler = () => {
dispatchCartAction({ type: 'CLEAR' })
}

const cartContext = {
items: cartState.items,
totalAmount: cartState.totalAmount,
addItem: addItemToCartHandler,
removeItem: removeItemFromCartHandler,
clearCart: clearCartHandler,
}

return (
Expand Down
1 change: 1 addition & 0 deletions src/store/cart-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ const CartContext = React.createContext({
totalAmount: 0,
addItem: item => {},
removeItem: id => {},
clearCart: () => {},
})
export default CartContext

0 comments on commit 4a79c40

Please sign in to comment.