created checkout section on checkout page
This commit is contained in:
parent
7279157625
commit
0b6516e19d
6 changed files with 109 additions and 42 deletions
|
@ -1,16 +1,39 @@
|
|||
"use client"
|
||||
import React, { useContext } from 'react'
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { CartContext, productTotal } from '../../components/AppContext'
|
||||
import Image from 'next/image';
|
||||
import { IoMdCloseCircleOutline } from "react-icons/io";
|
||||
import AddressInfo from '../../components/layout/AddressInfo';
|
||||
import useProfile from '../../components/UseProfile';
|
||||
|
||||
const CartPage = () => {
|
||||
const {cartProducts, removeCartProduct} = useContext(CartContext);
|
||||
const [address, setAddress] = useState({})
|
||||
const {data:profileCheckoutData} = useProfile()
|
||||
|
||||
useEffect(() => {
|
||||
if(profileCheckoutData?.city){
|
||||
const {phoneNumber, streetAddress, city, stateProvince, zipCode, country} = profileCheckoutData;
|
||||
const addressFormProfile = {phoneNumber, streetAddress, city, stateProvince, zipCode, country}
|
||||
setAddress(addressFormProfile)
|
||||
}
|
||||
}, [profileCheckoutData])
|
||||
|
||||
function handleAddresschange(propName, value){
|
||||
setAddress(prevAddress => ({...prevAddress, [propName]:value}));
|
||||
}
|
||||
|
||||
//checkout to Stripe
|
||||
function handleCheckout(ev){
|
||||
fetch('/api/checkout', {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
//cart total
|
||||
let total = 0
|
||||
let subtotal = 0
|
||||
for(const p of cartProducts){
|
||||
total += productTotal(p)
|
||||
subtotal += productTotal(p)
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +41,7 @@ const CartPage = () => {
|
|||
<div className='pb-20 md:pb-40'>
|
||||
<div className='px-5 md:px-10 py-5 sm:py-10'>
|
||||
<p className='text-center text-2xl sm:text-3xl md:text-4xl text-pink-500 uppercase font-bold drop-shadow-[0_2px_2px_rgba(105,105,105,1)]'>My cart</p>
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-5 lg:gap-10 xl:gap-20 mt-5 md:mt-10'>
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-10 mt-5 md:mt-10'>
|
||||
<div className='border-t'>
|
||||
{cartProducts?.length === 0 && (
|
||||
<div>Your cart is empty</div>
|
||||
|
@ -50,12 +73,33 @@ const CartPage = () => {
|
|||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className='hidden md:flex justify-end items-end mt-5 md:mt-10'>
|
||||
<p className='uppercase font-semibold text-sm'>Sub-total <span className='ml-5'>${total}</span></p>
|
||||
<div className='flex justify-end'>
|
||||
<div className='flex flex-col gap-1 mt-5 md:mt-10 text-xs sm:text-sm'>
|
||||
<div className='flex gap-10 justify-between font-semibold'>
|
||||
<p className='uppercase'>subtotal</p>
|
||||
<p className='ml-5 text-end'>${subtotal}</p>
|
||||
</div>
|
||||
<div className='flex gap-10 justify-between font-semibold'>
|
||||
<p className='uppercase'>Delivery Fees</p>
|
||||
<p className='ml-5 text-end'>$4.99</p>
|
||||
</div>
|
||||
<div className='flex gap-10 justify-between font-semibold'>
|
||||
<p className='uppercase'>Order total</p>
|
||||
<p className='ml-5 text-end'>${subtotal + 5}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<p className='uppercase text-gray-700 font-semibold'>Summary</p>
|
||||
<div>
|
||||
<div className='w-full md:max-w-lg mx-auto px-5 py-10 border rounded-md shadow-lg'>
|
||||
<div className='flex flex-col w-full md:max-w-md mx-auto capitalize text-sm sm:text-base'>
|
||||
<p className='uppercase font-semibold mb-5 text-center'>Shipping Address</p>
|
||||
<form onSubmit={handleCheckout} className='border-t py-5'>
|
||||
<AddressInfo addressProps={address} setAddressProps={handleAddresschange}/>
|
||||
<button type='button' className='w-full rounded-md bg-pink-500 text-white hover:opacity-80 duration-300 p-2 block'>Process to pay</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
"use client"
|
||||
import { useSession } from 'next-auth/react'
|
||||
import Image from 'next/image';
|
||||
import { redirect } from 'next/navigation';
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast';
|
||||
import UserTabs from "../../components/layout/UserTab"
|
||||
import EditImage from "../../components/layout/EditImage"
|
||||
import UserForm from "../../components/layout/UserForm"
|
||||
|
||||
const ProfilePage = () => {
|
||||
|
@ -14,7 +12,7 @@ const ProfilePage = () => {
|
|||
const {status} = session;
|
||||
const [user, setUser] = useState(null);
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const [profileFetchd, setProfileFetched] = useState(false);
|
||||
const [profileFetched, setProfileFetched] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -37,7 +35,7 @@ const ProfilePage = () => {
|
|||
const response = await fetch('/api/profile', {
|
||||
method: 'PUT',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({data}),
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if(response.ok)
|
||||
resolve()
|
||||
|
@ -52,7 +50,7 @@ const ProfilePage = () => {
|
|||
}
|
||||
|
||||
|
||||
if(status === 'loading' || !profileFetchd){
|
||||
if(status === 'loading' || !profileFetched){
|
||||
return <p className='flex justify-center items-center'>Loading...</p>
|
||||
}
|
||||
if(status === 'unauthenticated'){
|
||||
|
|
|
@ -7,13 +7,13 @@ import Link from 'next/link';
|
|||
|
||||
const Userspage = () => {
|
||||
const {data, loading} = useProfile();
|
||||
const [users, setUser] = useState([]);
|
||||
const [users, setUsers] = useState([]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
fetch('api/users').then(response => {
|
||||
fetch('/api/users').then(response => {
|
||||
response.json().then(users => {
|
||||
setUser(users)
|
||||
setUsers(users)
|
||||
})
|
||||
})
|
||||
}, [])
|
||||
|
|
38
donutshop_ecommerce/src/components/layout/AddressInfo.js
Normal file
38
donutshop_ecommerce/src/components/layout/AddressInfo.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import React from 'react'
|
||||
|
||||
const AddressInfo = ({addressProps, setAddressProps}) => {
|
||||
const {phoneNumber, streetAddress, city, stateProvince, zipCode, country} = addressProps;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>Phone number</label>
|
||||
<input type='tel' placeholder='Phone number' value={phoneNumber} onChange={ev => setAddressProps('phoneNumber', ev.target.value)}/>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>Street Address</label>
|
||||
<input type='text' placeholder='Address' value={streetAddress} onChange={ev => setAddressProps('streetAddress', ev.target.value)}/>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>City</label>
|
||||
<input type='text' placeholder='City' value={city} onChange={ev => setAddressProps('city', ev.target.value)}/>
|
||||
</div>
|
||||
<div className='flex flex-col sm:flex-row gap-0 sm:gap-2'>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>State/Province</label>
|
||||
<input type='text' placeholder='State/Province' value={stateProvince} onChange={ev => setAddressProps('stateProvince', ev.target.value)}/>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>Zip/Postal code</label>
|
||||
<input type='text' placeholder='Zip/Postal code' value={zipCode} onChange={ev => setAddressProps('zipCode', ev.target.value)}/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>Country</label>
|
||||
<input type='text' placeholder='Country' value={country} onChange={ev => setAddressProps('country', ev.target.value)}/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AddressInfo
|
|
@ -65,6 +65,7 @@ const Header = () => {
|
|||
)}
|
||||
{status === 'unauthenticated' && (
|
||||
<>
|
||||
<Link href='/cart' className="flex gap-1 items-center"><BsBox2Heart/>({cartProducts.length})</Link>
|
||||
<Link href='/login' className="">Login</Link>
|
||||
<Link href='/register' className="px-4 py-2 border border-[#DCA0AE] rounded-full hover:bg-[#DCA0AE] hover:text-white duration-300">Register</Link>
|
||||
</>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import React, { useState } from 'react'
|
||||
import EditImage from '../../components/layout/EditImage'
|
||||
import useProfile from '../UseProfile';
|
||||
import AddressInfo from '../layout/AddressInfo';
|
||||
|
||||
const UserForm = ({user, onSave}) => {
|
||||
const [userName, setUserName] = useState(user?.name || '');
|
||||
|
@ -16,6 +17,16 @@ const UserForm = ({user, onSave}) => {
|
|||
const {data:loginAsUser} = useProfile();
|
||||
|
||||
|
||||
function handleAddressChange(propName, value){
|
||||
if(propName === 'phoneNumber') setPhoneNumber(value);
|
||||
if(propName === 'streetAddress') setStreetAddress(value);
|
||||
if(propName === 'city') setCity(value);
|
||||
if(propName === 'stateProvince') setStateProvince(value);
|
||||
if(propName === 'zipCode') setZipCode(value);
|
||||
if(propName === 'country') setCountry(value);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className='max-w-md mx-auto mt-10'>
|
||||
<div className='flex flex-col gap-2 justify-center items-center max-w-[100px] mx-auto'>
|
||||
|
@ -30,32 +41,7 @@ const UserForm = ({user, onSave}) => {
|
|||
<label className='text-gray-700 text-sm font-semibold'>Email</label>
|
||||
<input type='text' value={user.email} disabled={true} className='disabled:bg-gray-200 disabled:text-gray-400'/>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>Phone number</label>
|
||||
<input type='tel' placeholder='Phone number' value={phoneNumber} onChange={ev => setPhoneNumber(ev.target.value)}/>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>Street Address</label>
|
||||
<input type='text' placeholder='Address' value={streetAddress} onChange={ev => setStreetAddress(ev.target.value)}/>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>City</label>
|
||||
<input type='text' placeholder='City' value={city} onChange={ev => setCity(ev.target.value)}/>
|
||||
</div>
|
||||
<div className='flex flex-col sm:flex-row gap-0 sm:gap-2'>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>State/Province</label>
|
||||
<input type='text' placeholder='State/Province' value={stateProvince} onChange={ev => setStateProvince(ev.target.value)}/>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>Zip/Postal code</label>
|
||||
<input type='text' placeholder='Zip/Postal code' value={zipCode} onChange={ev => setZipCode(ev.target.value)}/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className='text-gray-700 text-sm font-semibold'>Country</label>
|
||||
<input type='text' placeholder='Country' value={country} onChange={ev => setCountry(ev.target.value)}/>
|
||||
</div>
|
||||
<AddressInfo addressProps={{phoneNumber, streetAddress, city, stateProvince, zipCode, country}} setAddressProps={handleAddressChange}/>
|
||||
{loginAsUser.admin && (
|
||||
<div className='flex gap-2 items-center mb-5'>
|
||||
<label htmlFor='admin' className='text-gray-700 text-sm font-semibold'>Admin:</label>
|
||||
|
|
Loading…
Add table
Reference in a new issue