(feat): car and checkout static texts

This commit is contained in:
Maksym Sadovnychyy 2022-06-27 10:13:46 +02:00
parent bfd3cb9f0a
commit 25da28f001
21 changed files with 664 additions and 65 deletions

View File

@ -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>
)

View File

@ -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>
}

View File

@ -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

View File

@ -28,7 +28,8 @@ export interface FeatureModel {
export interface FormItemModel {
title?: string,
placeHolder?: string
optional?: string,
placeHolder?: string,
}
export interface ImageModel {

View File

@ -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
}

View File

@ -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
}

View File

@ -39,3 +39,5 @@ export interface GetShopItemRequestModel extends RequestModel {
}
export interface GetShopRelatedRequestModel extends RequestModel { }
export interface GetShopCartRequestModel extends RequestModel {}

View File

@ -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,

View File

@ -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]

View File

@ -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 = {

View File

@ -0,0 +1,5 @@
const Profile = () => {}
export {
Profile
}

View 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 &amp; 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
}

View File

@ -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 = {

View 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 Bootstraps 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
}

View File

@ -0,0 +1,3 @@
.container {
max-width: 960px;
}

View File

@ -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 <>

View File

@ -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
}

View File

@ -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,

View 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
}

View File

@ -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 Bootstraps 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!",