(feat): car and checkout static texts
This commit is contained in:
parent
bfd3cb9f0a
commit
25da28f001
@ -35,8 +35,7 @@ const FeatherIcon : FC<IFeatherIcon> = (props : IFeatherIcon) => {
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={`feather feather-${icon} ${className}`}
|
||||
{...otherProps}
|
||||
>
|
||||
{...otherProps}>
|
||||
<IconInner icon={icon} />
|
||||
</svg>
|
||||
)
|
||||
|
||||
@ -29,20 +29,18 @@ const NavMenu : FC = () => {
|
||||
{content?.topMenu ? content.topMenu.map((item: MenuItemModel, index: number) => {
|
||||
return <NavItem key={index}>
|
||||
<NavLink tag={Link} className="text-dark" to={item.target}>
|
||||
{item.icon ? <FeatherIcon icon={item.icon}/> : ''}
|
||||
{item.title}
|
||||
{item.icon ? <><FeatherIcon icon={item.icon}/> </> : ''}{item.title}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
}) : ''}
|
||||
</ul>
|
||||
</Collapse>
|
||||
|
||||
<form className="d-flex">
|
||||
{/* <form className="d-flex">
|
||||
<button className="btn btn-outline-dark" type="submit">
|
||||
<FeatherIcon icon='shopping-cart' className="me-1"/>Cart
|
||||
<span className="badge bg-dark text-white ms-1 rounded-pill">0</span>
|
||||
<FeatherIcon icon='shopping-cart' className="me-1"/>Cart <span className="badge bg-dark text-white ms-1 rounded-pill">0</span>
|
||||
</button>
|
||||
</form>
|
||||
</form> */}
|
||||
</Navbar>
|
||||
</header>
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AuthorModel, ImageModel } from "./"
|
||||
import { AuthorModel, FormItemModel, ImageModel } from "./"
|
||||
|
||||
|
||||
export interface RequestModel {
|
||||
@ -17,6 +17,18 @@ export interface PageSectionModel {
|
||||
text?: string
|
||||
}
|
||||
|
||||
export interface AddressPageSectionModel extends PageSectionModel {
|
||||
firstName: FormItemModel,
|
||||
lastName: FormItemModel,
|
||||
address: FormItemModel,
|
||||
address2: FormItemModel,
|
||||
country: FormItemModel,
|
||||
state: FormItemModel,
|
||||
city: FormItemModel,
|
||||
zip: FormItemModel
|
||||
}
|
||||
|
||||
|
||||
export interface PersonModel {
|
||||
id: string,
|
||||
image?: ImageModel
|
||||
|
||||
@ -28,7 +28,8 @@ export interface FeatureModel {
|
||||
|
||||
export interface FormItemModel {
|
||||
title?: string,
|
||||
placeHolder?: string
|
||||
optional?: string,
|
||||
placeHolder?: string,
|
||||
}
|
||||
|
||||
export interface ImageModel {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { FeatureModel, FormItemModel, ImageModel, MenuItemModel, TestimonialModel } from "./"
|
||||
import { PageSectionModel } from "./abstractions"
|
||||
import { FeatureModel, FormItemModel, ImageModel, LinkModel, MenuItemModel, TestimonialModel } from "./"
|
||||
import { AddressPageSectionModel, PageSectionModel } from "./abstractions"
|
||||
|
||||
export interface BlogTitleSectionModel extends PageSectionModel {
|
||||
postedOnBy: string
|
||||
@ -41,7 +41,39 @@ export interface TitleSectionModel extends PageSectionModel {
|
||||
}
|
||||
|
||||
|
||||
|
||||
export interface CartProductsSectionModel extends PageSectionModel {
|
||||
product: string,
|
||||
price: string,
|
||||
quantity: string,
|
||||
subtotal: string,
|
||||
continueShopping: LinkModel,
|
||||
submit: FormItemModel
|
||||
}
|
||||
|
||||
export interface BillingAddressSectionModel extends AddressPageSectionModel { }
|
||||
|
||||
export interface ShippingAddressSectionModel extends AddressPageSectionModel { }
|
||||
|
||||
export interface CheckoutSummarySectionModel extends PageSectionModel {
|
||||
title: string,
|
||||
total: string,
|
||||
|
||||
promoCode: FormItemModel,
|
||||
submit: FormItemModel
|
||||
}
|
||||
|
||||
export interface CheckoutSettingsSectionModel extends PageSectionModel {
|
||||
shippingAddressSameAsBillingAddress: string,
|
||||
saveThisInformation: string
|
||||
}
|
||||
|
||||
export interface PaymentSectionModel extends PageSectionModel {
|
||||
title: string,
|
||||
nameOnCard: FormItemModel,
|
||||
cardNumber: FormItemModel,
|
||||
expiration: FormItemModel,
|
||||
cvv: FormItemModel
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,27 +1,27 @@
|
||||
import { FormItemModel, LinkModel } from "."
|
||||
import { PageModel } from "./abstractions"
|
||||
import { BlogTitleSectionModel, CallToActionSectionModel, CommentsSectionModel, FeaturedBlogSectionModel, FeaturedBlogsSectionModel, FeaturesSectionModel, ProductSectionModel, RelatedProductsSectionModel, TestimonialsSectionModel, TitleSectionModel } from "./pageSections"
|
||||
import * as PageSection from "./pageSections"
|
||||
|
||||
export interface BlogCatalogPageModel extends PageModel {
|
||||
titleSection: TitleSectionModel,
|
||||
featuredBlogSection: FeaturedBlogSectionModel
|
||||
titleSection: PageSection.TitleSectionModel,
|
||||
featuredBlogSection: PageSection.FeaturedBlogSectionModel
|
||||
}
|
||||
|
||||
export interface BlogItemPageModel extends PageModel {
|
||||
titleSection: BlogTitleSectionModel,
|
||||
commentsSection: CommentsSectionModel
|
||||
titleSection: PageSection.BlogTitleSectionModel,
|
||||
commentsSection: PageSection.CommentsSectionModel
|
||||
}
|
||||
|
||||
export interface HomePageModel extends PageModel {
|
||||
titleSection: TitleSectionModel,
|
||||
featuresSection: FeaturesSectionModel,
|
||||
testimonialsSection: TestimonialsSectionModel,
|
||||
featuredBlogsSection: FeaturedBlogsSectionModel,
|
||||
callToActionSection: CallToActionSectionModel
|
||||
titleSection: PageSection.TitleSectionModel,
|
||||
featuresSection: PageSection.FeaturesSectionModel,
|
||||
testimonialsSection: PageSection.TestimonialsSectionModel,
|
||||
featuredBlogsSection: PageSection.FeaturedBlogsSectionModel,
|
||||
callToActionSection: PageSection.CallToActionSectionModel
|
||||
}
|
||||
|
||||
export interface ShopCatalogPageModel extends PageModel {
|
||||
titleSection: TitleSectionModel
|
||||
titleSection: PageSection.TitleSectionModel
|
||||
}
|
||||
|
||||
export interface SignInPageModel extends PageModel {
|
||||
@ -45,6 +45,21 @@ export interface SignUpPageModel extends PageModel {
|
||||
}
|
||||
|
||||
export interface ShopItemPageModel extends PageModel {
|
||||
productSection: ProductSectionModel
|
||||
relatedProductsSection: RelatedProductsSectionModel
|
||||
productSection: PageSection.ProductSectionModel
|
||||
relatedProductsSection: PageSection.RelatedProductsSectionModel
|
||||
}
|
||||
|
||||
export interface CartPageModel extends PageModel {
|
||||
titleSection: PageSection.TitleSectionModel
|
||||
productsSection: PageSection.CartProductsSectionModel
|
||||
}
|
||||
|
||||
export interface CheckoutPageModel extends PageModel {
|
||||
titleSection: PageSection.TitleSectionModel,
|
||||
billingAddressSection: PageSection.BillingAddressSectionModel,
|
||||
shippingAddressSection: PageSection.ShippingAddressSectionModel,
|
||||
settingsSection: PageSection.CheckoutSettingsSectionModel,
|
||||
summarySection: PageSection.CheckoutSummarySectionModel,
|
||||
paymentSection: PageSection.PaymentSectionModel,
|
||||
submit: FormItemModel
|
||||
}
|
||||
@ -39,3 +39,5 @@ export interface GetShopItemRequestModel extends RequestModel {
|
||||
}
|
||||
|
||||
export interface GetShopRelatedRequestModel extends RequestModel { }
|
||||
|
||||
export interface GetShopCartRequestModel extends RequestModel {}
|
||||
|
||||
@ -7,9 +7,14 @@ import {
|
||||
ShopCatalogPageModel,
|
||||
ShopItemPageModel,
|
||||
SignInPageModel,
|
||||
SignUpPageModel
|
||||
SignUpPageModel,
|
||||
CartPageModel,
|
||||
CheckoutPageModel
|
||||
} from "./pages"
|
||||
|
||||
|
||||
|
||||
|
||||
// Shop response models
|
||||
export interface GetShopCatalogResponseModel extends PaginationModel<ShopItemModel>, ResponseModel {}
|
||||
|
||||
@ -29,6 +34,11 @@ export interface GetShopRelatedResponseModel extends ResponseModel {
|
||||
items: ShopItemModel []
|
||||
}
|
||||
|
||||
export interface GetShopCartResponseModel extends ResponseModel {
|
||||
quantity: number
|
||||
}
|
||||
|
||||
|
||||
// Static content response model
|
||||
export interface GetContentResponseModel extends ResponseModel {
|
||||
siteName: string,
|
||||
@ -44,6 +54,8 @@ export interface GetContentResponseModel extends ResponseModel {
|
||||
|
||||
shopCatalog: ShopCatalogPageModel,
|
||||
shopItem: ShopItemPageModel,
|
||||
cart: CartPageModel,
|
||||
checkout: CheckoutPageModel,
|
||||
|
||||
blogCatalog: BlogCatalogPageModel,
|
||||
blogItem: BlogItemPageModel,
|
||||
|
||||
@ -149,19 +149,19 @@ const BlogCatalog = () => {
|
||||
const path = findRoutes(content?.routes, 'BlogCatalog')[0]?.targets[0]
|
||||
|
||||
useEffect(() => {
|
||||
// dispatch(blogCatalogActionCreators.requestBlogCatalog({
|
||||
// currentPage: params?.page ? params.page : "1"
|
||||
// }))
|
||||
// dispatch(blogFeaturedActionCreators.requestBlogFeatured())
|
||||
dispatch(blogCatalogActionCreators.requestBlogCatalog({
|
||||
currentPage: params?.page ? params.page : "1"
|
||||
}))
|
||||
dispatch(blogFeaturedActionCreators.requestBlogFeatured())
|
||||
dispatch(blogCategoriesActionCreators.requestBlogCategories())
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// blogCatalog?.isLoading
|
||||
// ? dispatch(loaderActionCreators.show())
|
||||
// : setTimeout(() => {
|
||||
// dispatch(loaderActionCreators.hide())
|
||||
// }, 1000)
|
||||
blogCatalog?.isLoading
|
||||
? dispatch(loaderActionCreators.show())
|
||||
: setTimeout(() => {
|
||||
dispatch(loaderActionCreators.hide())
|
||||
}, 1000)
|
||||
}, [blogCatalog?.isLoading])
|
||||
|
||||
const blogItem = blogFeatured?.items[0]
|
||||
|
||||
@ -57,18 +57,18 @@ const BlogItem = () => {
|
||||
const page = content?.blogItem
|
||||
|
||||
useEffect(() => {
|
||||
// if(params?.slug)
|
||||
// dispatch(blogItemActionCreators.requestBlogItem({
|
||||
// slug: params.slug
|
||||
// }))
|
||||
if(params?.slug)
|
||||
dispatch(blogItemActionCreators.requestBlogItem({
|
||||
slug: params.slug
|
||||
}))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// blogItem?.isLoading
|
||||
// ? dispatch(loaderActionCreators.show())
|
||||
// : setTimeout(() => {
|
||||
// dispatch(loaderActionCreators.hide())
|
||||
// }, 1000)
|
||||
blogItem?.isLoading
|
||||
? dispatch(loaderActionCreators.show())
|
||||
: setTimeout(() => {
|
||||
dispatch(loaderActionCreators.hide())
|
||||
}, 1000)
|
||||
}, [blogItem?.isLoading])
|
||||
|
||||
const blogItemTitle: BlogItemTitle = {
|
||||
|
||||
5
webapi/ClientApp/src/pages/Profile/index.tsx
Normal file
5
webapi/ClientApp/src/pages/Profile/index.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
const Profile = () => {}
|
||||
|
||||
export {
|
||||
Profile
|
||||
}
|
||||
79
webapi/ClientApp/src/pages/Shop/Cart/index.tsx
Normal file
79
webapi/ClientApp/src/pages/Shop/Cart/index.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import React from 'react'
|
||||
import { Container } from 'reactstrap'
|
||||
import { FeatherIcon } from '../../../components/FeatherIcons'
|
||||
|
||||
import style from './scss/style.module.scss'
|
||||
|
||||
const Cart = () => {
|
||||
return <Container fluid>
|
||||
<section className="pt-5 pb-5">
|
||||
<div className="row w-100">
|
||||
<div className="col-lg-12 col-md-12 col-12">
|
||||
<h3 className="display-5 mb-2 text-center">Shopping Cart</h3>
|
||||
<p className="mb-5 text-center">
|
||||
<i className="text-info font-weight-bold">3</i> items in your cart</p>
|
||||
<table id="shoppingCart" className="table table-condensed table-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ width: "60%" }}>Product</th>
|
||||
<th style={{ width: "12%" }}>Price</th>
|
||||
<th style={{ width: "10%" }}>Quantity</th>
|
||||
<th style={{ width: "16%" }}></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
{[{}, {}, {}, {}].map((item, index) => <tr key={index}>
|
||||
<td data-th="Product">
|
||||
<div className="row">
|
||||
<div className="col-md-3 text-left">
|
||||
<img src="https://dummyimage.com/250x250/ced4da/6c757d.jpg" alt="" className="img-fluid d-none d-md-block rounded mb-2 shadow" />
|
||||
</div>
|
||||
<div className="col-md-9 text-left mt-sm-2">
|
||||
<h4>Product Name</h4>
|
||||
<p className="font-weight-light">Brand & Name</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td data-th="Price">$49.00</td>
|
||||
<td data-th="Quantity">
|
||||
<input type="number" className="form-control form-control-lg text-center" value="1" />
|
||||
</td>
|
||||
<td className="actions" data-th="">
|
||||
<div className="text-right">
|
||||
<button className="btn btn-white border-secondary bg-white btn-md mb-2">
|
||||
<FeatherIcon icon="refresh-cw" />
|
||||
</button>
|
||||
<button className="btn btn-white border-secondary bg-white btn-md mb-2">
|
||||
<FeatherIcon icon="trash-2" />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>)}
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="float-right text-right">
|
||||
<h4>Subtotal:</h4>
|
||||
<h1>$99.00</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row mt-4 d-flex align-items-center">
|
||||
<div className="col-sm-6 order-md-2 text-right">
|
||||
<a href="catalog.html" className="btn btn-primary mb-4 btn-lg pl-5 pr-5">Checkout</a>
|
||||
</div>
|
||||
<div className="col-sm-6 mb-3 mb-m-1 order-md-1 text-md-left">
|
||||
<a href="catalog.html">
|
||||
<i className="fas fa-arrow-left mr-2"></i> Continue Shopping</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Container>
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
Cart
|
||||
}
|
||||
@ -111,17 +111,17 @@ const ShopCatalog = () => {
|
||||
const path = findRoutes(content?.routes, 'ShopCatalog')[0]?.targets[0]
|
||||
|
||||
useEffect(() => {
|
||||
// dispatch(shopCatalogActionCreators.requestShopCatalog({
|
||||
// currentPage: params?.page ? params.page : "1"
|
||||
// }))
|
||||
dispatch(shopCatalogActionCreators.requestShopCatalog({
|
||||
currentPage: params?.page ? params.page : "1"
|
||||
}))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// shopCatalog?.isLoading
|
||||
// ? dispatch(loaderActionCreators.show())
|
||||
// : setTimeout(() => {
|
||||
// dispatch(loaderActionCreators.hide())
|
||||
// }, 1000)
|
||||
shopCatalog?.isLoading
|
||||
? dispatch(loaderActionCreators.show())
|
||||
: setTimeout(() => {
|
||||
dispatch(loaderActionCreators.hide())
|
||||
}, 1000)
|
||||
}, [shopCatalog?.isLoading])
|
||||
|
||||
const shopItems: ShopItems = {
|
||||
|
||||
221
webapi/ClientApp/src/pages/Shop/Checkout/index.tsx
Normal file
221
webapi/ClientApp/src/pages/Shop/Checkout/index.tsx
Normal file
@ -0,0 +1,221 @@
|
||||
import React from 'react'
|
||||
import { Container } from 'reactstrap'
|
||||
|
||||
// CSS Modules
|
||||
import style from './scss/style.module.scss'
|
||||
|
||||
const Checkout = () => {
|
||||
return <Container fluid className={style.container}>
|
||||
<main>
|
||||
<div className="py-5 text-center">
|
||||
<img className="d-block mx-auto mb-4" src="../assets/brand/bootstrap-logo.svg" alt="" width="72" height="57" />
|
||||
<h2>Checkout form</h2>
|
||||
<p className="lead">Below is an example form built entirely with Bootstrap’s form controls. Each required form group has a validation state that can be triggered by attempting to submit the form without completing it.</p>
|
||||
</div>
|
||||
|
||||
<div className="row g-5">
|
||||
<div className="col-md-5 col-lg-4 order-md-last">
|
||||
<h4 className="d-flex justify-content-between align-items-center mb-3">
|
||||
<span className="text-primary">Your cart</span>
|
||||
<span className="badge bg-primary rounded-pill">3</span>
|
||||
</h4>
|
||||
<ul className="list-group mb-3">
|
||||
<li className="list-group-item d-flex justify-content-between lh-sm">
|
||||
<div>
|
||||
<h6 className="my-0">Product name</h6>
|
||||
<small className="text-muted">Brief description</small>
|
||||
</div>
|
||||
<span className="text-muted">$12</span>
|
||||
</li>
|
||||
<li className="list-group-item d-flex justify-content-between lh-sm">
|
||||
<div>
|
||||
<h6 className="my-0">Second product</h6>
|
||||
<small className="text-muted">Brief description</small>
|
||||
</div>
|
||||
<span className="text-muted">$8</span>
|
||||
</li>
|
||||
<li className="list-group-item d-flex justify-content-between lh-sm">
|
||||
<div>
|
||||
<h6 className="my-0">Third item</h6>
|
||||
<small className="text-muted">Brief description</small>
|
||||
</div>
|
||||
<span className="text-muted">$5</span>
|
||||
</li>
|
||||
<li className="list-group-item d-flex justify-content-between bg-light">
|
||||
<div className="text-success">
|
||||
<h6 className="my-0">Promo code</h6>
|
||||
<small>EXAMPLECODE</small>
|
||||
</div>
|
||||
<span className="text-success">−$5</span>
|
||||
</li>
|
||||
<li className="list-group-item d-flex justify-content-between">
|
||||
<span>Total (USD)</span>
|
||||
<strong>$20</strong>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form className="card p-2">
|
||||
<div className="input-group">
|
||||
<input type="text" className="form-control" placeholder="Promo code" />
|
||||
<button type="submit" className="btn btn-secondary">Redeem</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div className="col-md-7 col-lg-8">
|
||||
<h4 className="mb-3">Billing address</h4>
|
||||
<form className="needs-validation" noValidate>
|
||||
<div className="row g-3">
|
||||
<div className="col-sm-6">
|
||||
<label htmlFor="firstName" className="form-label">First name</label>
|
||||
<input type="text" className="form-control" id="firstName" placeholder="" value="" required />
|
||||
<div className="invalid-feedback">
|
||||
Valid first name is required.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6">
|
||||
<label htmlFor="lastName" className="form-label">Last name</label>
|
||||
<input type="text" className="form-control" id="lastName" placeholder="" value="" required />
|
||||
<div className="invalid-feedback">
|
||||
Valid last name is required.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col-12">
|
||||
<label htmlFor="address" className="form-label">Address</label>
|
||||
<input type="text" className="form-control" id="address" placeholder="1234 Main St" required />
|
||||
<div className="invalid-feedback">
|
||||
Please enter your shipping address.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-12">
|
||||
<label htmlFor="address2" className="form-label">Address 2 <span className="text-muted">(Optional)</span></label>
|
||||
<input type="text" className="form-control" id="address2" placeholder="Apartment or suite" />
|
||||
</div>
|
||||
|
||||
<div className="col-md-3">
|
||||
<label htmlFor="country" className="form-label">Country</label>
|
||||
<select className="form-select" id="country" required>
|
||||
<option value="">Choose...</option>
|
||||
<option>United States</option>
|
||||
</select>
|
||||
<div className="invalid-feedback">
|
||||
Please select a valid country.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-md-3">
|
||||
<label htmlFor="state" className="form-label">State</label>
|
||||
<select className="form-select" id="state" required>
|
||||
<option value="">Choose...</option>
|
||||
<option>California</option>
|
||||
</select>
|
||||
<div className="invalid-feedback">
|
||||
Please provide a valid state.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-md-3">
|
||||
<label htmlFor="state" className="form-label">City</label>
|
||||
<select className="form-select" id="state" required>
|
||||
<option value="">Choose...</option>
|
||||
<option>California</option>
|
||||
</select>
|
||||
<div className="invalid-feedback">
|
||||
Please provide a valid city.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-md-3">
|
||||
<label htmlFor="zip" className="form-label">Zip</label>
|
||||
<input type="text" className="form-control" id="zip" placeholder="" required />
|
||||
<div className="invalid-feedback">
|
||||
Zip code required.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="my-4" />
|
||||
|
||||
<div className="form-check">
|
||||
<input type="checkbox" className="form-check-input" id="same-address" />
|
||||
<label className="form-check-label" htmlFor="same-address">Shipping address is the same as my billing address</label>
|
||||
</div>
|
||||
|
||||
<div className="form-check">
|
||||
<input type="checkbox" className="form-check-input" id="save-info" />
|
||||
<label className="form-check-label" htmlFor="save-info">Save this information for next time</label>
|
||||
</div>
|
||||
|
||||
<hr className="my-4" />
|
||||
|
||||
<h4 className="mb-3">Payment</h4>
|
||||
|
||||
<div className="my-3">
|
||||
<div className="form-check">
|
||||
<input id="credit" name="paymentMethod" type="radio" className="form-check-input" checked required />
|
||||
<label className="form-check-label" htmlFor="credit">Credit card</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input id="debit" name="paymentMethod" type="radio" className="form-check-input" required />
|
||||
<label className="form-check-label" htmlFor="debit">Debit card</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input id="paypal" name="paymentMethod" type="radio" className="form-check-input" required />
|
||||
<label className="form-check-label" htmlFor="paypal">PayPal</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row gy-3">
|
||||
<div className="col-md-6">
|
||||
<label htmlFor="cc-name" className="form-label">Name on card</label>
|
||||
<input type="text" className="form-control" id="cc-name" placeholder="" required />
|
||||
<small className="text-muted">Full name as displayed on card</small>
|
||||
<div className="invalid-feedback">
|
||||
Name on card is required
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-md-6">
|
||||
<label htmlFor="cc-number" className="form-label">Credit card number</label>
|
||||
<input type="text" className="form-control" id="cc-number" placeholder="" required />
|
||||
<div className="invalid-feedback">
|
||||
Credit card number is required
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-md-3">
|
||||
<label htmlFor="cc-expiration" className="form-label">Expiration</label>
|
||||
<input type="text" className="form-control" id="cc-expiration" placeholder="" required />
|
||||
<div className="invalid-feedback">
|
||||
Expiration date required
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-md-3">
|
||||
<label htmlFor="cc-cvv" className="form-label">CVV</label>
|
||||
<input type="text" className="form-control" id="cc-cvv" placeholder="" required />
|
||||
<div className="invalid-feedback">
|
||||
Security code required
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="my-4" />
|
||||
|
||||
<button className="w-100 btn btn-primary btn-lg" type="submit">Continue to checkout</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Container>
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
Checkout
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
.container {
|
||||
max-width: 960px;
|
||||
}
|
||||
@ -19,18 +19,18 @@ const ShopItem = () => {
|
||||
const page = content?.shopItem
|
||||
|
||||
useEffect(() => {
|
||||
// if(params?.slug)
|
||||
// dispatch(shopItemActionCreators.requestShopItem({
|
||||
// slug: params.slug
|
||||
// }))
|
||||
if(params?.slug)
|
||||
dispatch(shopItemActionCreators.requestShopItem({
|
||||
slug: params.slug
|
||||
}))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// shopItem?.isLoading
|
||||
// ? dispatch(loaderActionCreators.show())
|
||||
// : setTimeout(() => {
|
||||
// dispatch(loaderActionCreators.hide())
|
||||
// }, 1000)
|
||||
shopItem?.isLoading
|
||||
? dispatch(loaderActionCreators.show())
|
||||
: setTimeout(() => {
|
||||
dispatch(loaderActionCreators.hide())
|
||||
}, 1000)
|
||||
}, [shopItem?.isLoading])
|
||||
|
||||
return <>
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import { ShopCatalog } from './Catalog'
|
||||
import { ShopItem } from './Item'
|
||||
import { Cart } from './Cart'
|
||||
import { Checkout } from './Checkout'
|
||||
|
||||
export {
|
||||
ShopCatalog,
|
||||
ShopItem
|
||||
ShopItem,
|
||||
Cart,
|
||||
Checkout
|
||||
}
|
||||
@ -8,9 +8,11 @@ import { AdminHome } from './AdminHome'
|
||||
|
||||
import { Signin } from './Signin'
|
||||
import { Signup } from './Signup'
|
||||
import { ShopCatalog, ShopItem } from './Shop'
|
||||
import { ShopCatalog, ShopItem, Cart, Checkout } from './Shop'
|
||||
import { BlogCatalog, BlogItem } from './Blog'
|
||||
|
||||
|
||||
|
||||
interface IPages {
|
||||
[key: string]: FC<any>;
|
||||
}
|
||||
@ -20,6 +22,8 @@ const pages: IPages = {
|
||||
|
||||
ShopCatalog,
|
||||
ShopItem,
|
||||
Cart,
|
||||
Checkout,
|
||||
|
||||
BlogCatalog,
|
||||
BlogItem,
|
||||
|
||||
69
webapi/ClientApp/src/store/reducers/Cart.ts
Normal file
69
webapi/ClientApp/src/store/reducers/Cart.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Action, Reducer } from 'redux'
|
||||
import { AppThunkAction } from '..'
|
||||
import { GetShopCartRequestModel } from '../../models/requests'
|
||||
import { GetShopCartResponseModel } from '../../models/responses'
|
||||
|
||||
export interface CartState extends GetShopCartResponseModel {
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
export interface RequestAction extends GetShopCartRequestModel {
|
||||
type: 'REQUEST_CART'
|
||||
}
|
||||
|
||||
export interface ReceiveAction extends GetShopCartResponseModel {
|
||||
type: 'RECEIVE_CART'
|
||||
}
|
||||
|
||||
export type KnownAction = RequestAction | ReceiveAction
|
||||
|
||||
export const actionCreators = {
|
||||
requestCart: (): AppThunkAction<KnownAction> => (dispatch, getState) => {
|
||||
|
||||
},
|
||||
|
||||
addToCart: (): AppThunkAction<KnownAction> => (dispatch, getState) => {
|
||||
|
||||
// Get<Promise<GetBlogItemResponseModel>>('https://localhost:7151/api/BlogItem', props)
|
||||
// .then(response => response)
|
||||
// .then(data => {
|
||||
// if(data)
|
||||
// dispatch({ type: 'RECEIVE_BLOG_ITEM', ...data })
|
||||
// })
|
||||
|
||||
// dispatch({ type: 'REQUEST_BLOG_ITEM', slug: props.slug })
|
||||
},
|
||||
|
||||
remFromCart: (): AppThunkAction<KnownAction> => (dispatch, getState) => {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const unloadedState: CartState = {
|
||||
quantity: 0,
|
||||
|
||||
isLoading: false
|
||||
}
|
||||
|
||||
export const reducer: Reducer<CartState> = (state: CartState | undefined, incomingAction: Action): CartState => {
|
||||
if (state === undefined) {
|
||||
return unloadedState
|
||||
}
|
||||
|
||||
const action = incomingAction as KnownAction
|
||||
switch (action.type) {
|
||||
case 'REQUEST_CART':
|
||||
return {
|
||||
...state,
|
||||
isLoading: true
|
||||
}
|
||||
|
||||
case 'RECEIVE_CART':
|
||||
return {
|
||||
...action,
|
||||
isLoading: false
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
@ -44,6 +44,10 @@ const unloadedState: ContentState = {
|
||||
{ target: ":page", component: "ShopCatalog" },
|
||||
{ target: ":page" , childRoutes: [
|
||||
{ target: ":slug", component: "ShopItem" }
|
||||
]},
|
||||
{ target:"cart", childRoutes: [
|
||||
{ target: "", component: "Cart" },
|
||||
{ target: "checkout", component: "Checkout" }
|
||||
]}
|
||||
]},
|
||||
{ target: "/blog", childRoutes: [
|
||||
@ -66,7 +70,9 @@ const unloadedState: ContentState = {
|
||||
{ target: "/blog", title: "Blog" },
|
||||
|
||||
{ target: "/signin", title: "Sing in" },
|
||||
{ target: "/signup", title: "Sign up" }
|
||||
{ target: "/signup", title: "Sign up" },
|
||||
|
||||
{ target: "/shop/cart", icon: "shopping-cart", title: "Cart ({quantity})" }
|
||||
],
|
||||
sideMenu: [],
|
||||
|
||||
@ -144,6 +150,143 @@ const unloadedState: ContentState = {
|
||||
}
|
||||
},
|
||||
|
||||
cart: {
|
||||
titleSection: {
|
||||
title: "Shopping Cart"
|
||||
},
|
||||
productsSection: {
|
||||
title: "Shopping Cart",
|
||||
text: "{quantity} items in your cart",
|
||||
product: "Product",
|
||||
price: "Price",
|
||||
quantity: "Quantity",
|
||||
subtotal: "Subtotal",
|
||||
continueShopping: {
|
||||
target: "#",
|
||||
anchorText: "Continue shopping"
|
||||
},
|
||||
submit: {
|
||||
title: "Checkout"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
checkout: {
|
||||
titleSection: {
|
||||
title: "Checkout",
|
||||
text: "Below is an example form built entirely with Bootstrap’s form controls. Each required form group has a validation state that can be triggered by attempting to submit the form without completing it."
|
||||
},
|
||||
billingAddressSection: {
|
||||
title: "Billing address",
|
||||
firstName: {
|
||||
title: "First name",
|
||||
placeHolder: "First name..."
|
||||
},
|
||||
lastName: {
|
||||
title: "Last name",
|
||||
placeHolder: "Last name..."
|
||||
},
|
||||
address: {
|
||||
title: "Address",
|
||||
placeHolder: "1234 Main Str.."
|
||||
},
|
||||
address2: {
|
||||
title: "Address",
|
||||
optional: "(Optional)",
|
||||
placeHolder: "1234 Main Str.."
|
||||
},
|
||||
country: {
|
||||
title: "Country",
|
||||
placeHolder: "Country..."
|
||||
},
|
||||
state: {
|
||||
title: "State",
|
||||
placeHolder: "State..."
|
||||
},
|
||||
city: {
|
||||
title: "City",
|
||||
placeHolder: "City..."
|
||||
},
|
||||
zip: {
|
||||
title: "Zip",
|
||||
placeHolder: "Zip..."
|
||||
}
|
||||
},
|
||||
shippingAddressSection: {
|
||||
title: "Shipping address",
|
||||
firstName: {
|
||||
title: "First name",
|
||||
placeHolder: "First name..."
|
||||
},
|
||||
lastName: {
|
||||
title: "Last name",
|
||||
placeHolder: "Last name..."
|
||||
},
|
||||
address: {
|
||||
title: "Address",
|
||||
placeHolder: "1234 Main Str.."
|
||||
},
|
||||
address2: {
|
||||
title: "Address",
|
||||
optional: "(Optional)",
|
||||
placeHolder: "1234 Main Str.."
|
||||
},
|
||||
country: {
|
||||
title: "Country",
|
||||
placeHolder: "Country..."
|
||||
},
|
||||
state: {
|
||||
title: "State",
|
||||
placeHolder: "State..."
|
||||
},
|
||||
city: {
|
||||
title: "City",
|
||||
placeHolder: "City..."
|
||||
},
|
||||
zip: {
|
||||
title: "Zip",
|
||||
placeHolder: "Zip..."
|
||||
}
|
||||
},
|
||||
settingsSection: {
|
||||
shippingAddressSameAsBillingAddress: "Shipping address is the same as my billing address",
|
||||
saveThisInformation: "Save this information for next time"
|
||||
},
|
||||
summarySection: {
|
||||
title: "Your cart",
|
||||
total: "Total ({currency})",
|
||||
promoCode: {
|
||||
placeHolder: "Promo code"
|
||||
},
|
||||
submit: {
|
||||
title: "Redeem"
|
||||
}
|
||||
},
|
||||
paymentSection: {
|
||||
title: "Payment",
|
||||
nameOnCard: {
|
||||
title: "Name on card",
|
||||
placeHolder: "John Doe"
|
||||
},
|
||||
cardNumber: {
|
||||
title: "Credit card number",
|
||||
placeHolder: ""
|
||||
},
|
||||
expiration: {
|
||||
title: "Expiration",
|
||||
placeHolder: "MM/YY"
|
||||
},
|
||||
cvv: {
|
||||
title: "CVV",
|
||||
placeHolder: "123"
|
||||
}
|
||||
},
|
||||
submit: {
|
||||
title: "Continue to checkout"
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
blogCatalog: {
|
||||
titleSection: {
|
||||
title: "Welcome to Blog Home!",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user