Monorepo with Turborepo (#651)

* Moved everything

* Figuring out how to make imports work

* Updated exports

* Added missing exports

* Added @vercel/commerce-local to `site`

* Updated commerce config

* Updated exports and commerce config

* Updated commerce hoc

* Fixed exports in local

* Added publish config

* Updated imports in site

* It's actually working

* Don't use debugger in dev for better speeds

* Improved DX when editing packages

* Set up eslint with husky

* Updated prettier config

* Added prettier setup to every package

* Moved bigcommerce

* Moved Bigcommerce to src and package updates

* Updated setup of bigcommerce

* Moved definitions script

* Moved commercejs

* Move to src

* Fixed types in commercejs

* Moved kibocommerce

* Moved kibocommerce to src

* Added package/tsconfig to kibocommerce

* Fixed imports and other things

* Moved ordercloud

* Moved ordercloud to src

* Fixed imports

* Added missing prettier files

* Moved Saleor

* Moved Saleor to src

* Fixed imports

* Replaced all imports to @commerce

* Added prettierignore/rc to all providers

* Moved shopify to src

* Build shopify in packages

* Moved Spree

* Moved spree to src

* Updated spree

* Moved swell

* Moved swell to src

* Fixed type imports in swell

* Moved Vendure to packages

* Moved vendure to src

* Fixed imports in vendure

* Added codegen to saleor

* Updated codegen setup for shopify

* Added codegen to vendure

* Added codegen to kibocommerce

* Added all packages to site's deps

* Updated codegen setup in bigcommerce

* Minor fixes

* Updated providers' names in site

* Updated packages based on Bel's changes

* Updated turbo to latest

* Fixed ts complains

* Set npm engine in root

* New lockfile install

* remove engines

* Regen lockfile

* Switched from npm to yarn

* Updated typesVersions in all packages

* Moved dep

* Updated SWR to the just released 1.2.0

* Removed "isolatedModules" from packages

* Updated list of providers and default

* Updated swell declaration

* Removed next import from kibocommerce

* Added COMMERCE_PROVIDER log

* Added another log

* Updated turbo config

* Updated docs

* Removed test logs

Co-authored-by: Jared Palmer <jared@jaredpalmer.com>
This commit is contained in:
Luis Alvarez D
2022-02-01 14:14:05 -05:00
committed by GitHub
parent d0ef346189
commit 0afe686fe9
1326 changed files with 9109 additions and 19494 deletions

View File

@@ -0,0 +1,7 @@
.root {
min-height: calc(100vh - 322px);
}
.lineItemsList {
@apply py-4 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accent-2 border-accent-2;
}

View File

@@ -0,0 +1,122 @@
import Link from 'next/link'
import { FC, useState } from 'react'
import CartItem from '@components/cart/CartItem'
import { Button, Text } from '@components/ui'
import { useUI } from '@components/ui/context'
import SidebarLayout from '@components/common/SidebarLayout'
import useCart from '@framework/cart/use-cart'
import usePrice from '@framework/product/use-price'
import useCheckout from '@framework/checkout/use-checkout'
import ShippingWidget from '../ShippingWidget'
import PaymentWidget from '../PaymentWidget'
import s from './CheckoutSidebarView.module.css'
import { useCheckoutContext } from '../context'
const CheckoutSidebarView: FC = () => {
const [loadingSubmit, setLoadingSubmit] = useState(false)
const { setSidebarView, closeSidebar } = useUI()
const { data: cartData, mutate: refreshCart } = useCart()
const { data: checkoutData, submit: onCheckout } = useCheckout()
const { clearCheckoutFields } = useCheckoutContext()
async function handleSubmit(event: React.ChangeEvent<HTMLFormElement>) {
try {
setLoadingSubmit(true)
event.preventDefault()
await onCheckout()
clearCheckoutFields()
setLoadingSubmit(false)
refreshCart()
closeSidebar()
} catch {
// TODO - handle error UI here.
setLoadingSubmit(false)
}
}
const { price: subTotal } = usePrice(
cartData && {
amount: Number(cartData.subtotalPrice),
currencyCode: cartData.currency.code,
}
)
const { price: total } = usePrice(
cartData && {
amount: Number(cartData.totalPrice),
currencyCode: cartData.currency.code,
}
)
return (
<SidebarLayout
className={s.root}
handleBack={() => setSidebarView('CART_VIEW')}
>
<div className="px-4 sm:px-6 flex-1">
<Link href="/cart">
<a>
<Text variant="sectionHeading">Checkout</Text>
</a>
</Link>
<PaymentWidget
isValid={checkoutData?.hasPayment}
onClick={() => setSidebarView('PAYMENT_VIEW')}
/>
<ShippingWidget
isValid={checkoutData?.hasShipping}
onClick={() => setSidebarView('SHIPPING_VIEW')}
/>
<ul className={s.lineItemsList}>
{cartData!.lineItems.map((item: any) => (
<CartItem
key={item.id}
item={item}
currencyCode={cartData!.currency.code}
variant="display"
/>
))}
</ul>
</div>
<form
onSubmit={handleSubmit}
className="flex-shrink-0 px-6 py-6 sm:px-6 sticky z-20 bottom-0 w-full right-0 left-0 bg-accent-0 border-t text-sm"
>
<ul className="pb-2">
<li className="flex justify-between py-1">
<span>Subtotal</span>
<span>{subTotal}</span>
</li>
<li className="flex justify-between py-1">
<span>Taxes</span>
<span>Calculated at checkout</span>
</li>
<li className="flex justify-between py-1">
<span>Shipping</span>
<span className="font-bold tracking-wide">FREE</span>
</li>
</ul>
<div className="flex justify-between border-t border-accent-2 py-3 font-bold mb-2">
<span>Total</span>
<span>{total}</span>
</div>
<div>
{/* Once data is correctly filled */}
<Button
type="submit"
width="100%"
disabled={!checkoutData?.hasPayment || !checkoutData?.hasShipping}
loading={loadingSubmit}
>
Confirm Purchase
</Button>
</div>
</form>
</SidebarLayout>
)
}
export default CheckoutSidebarView

View File

@@ -0,0 +1 @@
export { default } from './CheckoutSidebarView'

View File

@@ -0,0 +1,17 @@
.fieldset {
@apply flex flex-col my-3;
}
.fieldset .label {
@apply text-accent-7 uppercase text-xs font-medium mb-2;
}
.fieldset .input,
.fieldset .select {
@apply p-2 border border-accent-2 w-full text-sm font-normal;
}
.fieldset .input:focus,
.fieldset .select:focus {
@apply outline-none shadow-outline-normal;
}

View File

@@ -0,0 +1,130 @@
import { FC } from 'react'
import cn from 'classnames'
import useAddCard from '@framework/customer/card/use-add-item'
import { Button, Text } from '@components/ui'
import { useUI } from '@components/ui/context'
import SidebarLayout from '@components/common/SidebarLayout'
import s from './PaymentMethodView.module.css'
interface Form extends HTMLFormElement {
cardHolder: HTMLInputElement
cardNumber: HTMLInputElement
cardExpireDate: HTMLInputElement
cardCvc: HTMLInputElement
firstName: HTMLInputElement
lastName: HTMLInputElement
company: HTMLInputElement
streetNumber: HTMLInputElement
zipCode: HTMLInputElement
city: HTMLInputElement
country: HTMLSelectElement
}
const PaymentMethodView: FC = () => {
const { setSidebarView } = useUI()
const addCard = useAddCard()
async function handleSubmit(event: React.ChangeEvent<Form>) {
event.preventDefault()
await addCard({
cardHolder: event.target.cardHolder.value,
cardNumber: event.target.cardNumber.value,
cardExpireDate: event.target.cardExpireDate.value,
cardCvc: event.target.cardCvc.value,
firstName: event.target.firstName.value,
lastName: event.target.lastName.value,
company: event.target.company.value,
streetNumber: event.target.streetNumber.value,
zipCode: event.target.zipCode.value,
city: event.target.city.value,
country: event.target.country.value,
})
setSidebarView('CHECKOUT_VIEW')
}
return (
<form className="h-full" onSubmit={handleSubmit}>
<SidebarLayout handleBack={() => setSidebarView('CHECKOUT_VIEW')}>
<div className="px-4 sm:px-6 flex-1">
<Text variant="sectionHeading"> Payment Method</Text>
<div>
<div className={s.fieldset}>
<label className={s.label}>Cardholder Name</label>
<input name="cardHolder" className={s.input} />
</div>
<div className="grid gap-3 grid-flow-row grid-cols-12">
<div className={cn(s.fieldset, 'col-span-7')}>
<label className={s.label}>Card Number</label>
<input name="cardNumber" className={s.input} />
</div>
<div className={cn(s.fieldset, 'col-span-3')}>
<label className={s.label}>Expires</label>
<input
name="cardExpireDate"
className={s.input}
placeholder="MM/YY"
/>
</div>
<div className={cn(s.fieldset, 'col-span-2')}>
<label className={s.label}>CVC</label>
<input name="cardCvc" className={s.input} />
</div>
</div>
<hr className="border-accent-2 my-6" />
<div className="grid gap-3 grid-flow-row grid-cols-12">
<div className={cn(s.fieldset, 'col-span-6')}>
<label className={s.label}>First Name</label>
<input name="firstName" className={s.input} />
</div>
<div className={cn(s.fieldset, 'col-span-6')}>
<label className={s.label}>Last Name</label>
<input name="lastName" className={s.input} />
</div>
</div>
<div className={s.fieldset}>
<label className={s.label}>Company (Optional)</label>
<input name="company" className={s.input} />
</div>
<div className={s.fieldset}>
<label className={s.label}>Street and House Number</label>
<input name="streetNumber" className={s.input} />
</div>
<div className={s.fieldset}>
<label className={s.label}>
Apartment, Suite, Etc. (Optional)
</label>
<input className={s.input} name="apartment" />
</div>
<div className="grid gap-3 grid-flow-row grid-cols-12">
<div className={cn(s.fieldset, 'col-span-6')}>
<label className={s.label}>Postal Code</label>
<input name="zipCode" className={s.input} />
</div>
<div className={cn(s.fieldset, 'col-span-6')}>
<label className={s.label}>City</label>
<input name="city" className={s.input} />
</div>
</div>
<div className={s.fieldset}>
<label className={s.label}>Country/Region</label>
<select name="country" className={s.select}>
<option>Hong Kong</option>
</select>
</div>
</div>
</div>
<div className="sticky z-20 bottom-0 w-full right-0 left-0 py-12 bg-accent-0 border-t border-accent-2 px-6">
<Button type="submit" width="100%" variant="ghost">
Continue
</Button>
</div>
</SidebarLayout>
</form>
)
}
export default PaymentMethodView

View File

@@ -0,0 +1 @@
export { default } from './PaymentMethodView'

View File

@@ -0,0 +1,4 @@
.root {
@apply border border-accent-2 px-6 py-5 mb-4 text-center
flex items-center cursor-pointer hover:border-accent-4;
}

View File

@@ -0,0 +1,28 @@
import { FC } from 'react'
import s from './PaymentWidget.module.css'
import { ChevronRight, CreditCard, Check } from '@components/icons'
interface ComponentProps {
onClick?: () => any
isValid?: boolean
}
const PaymentWidget: FC<ComponentProps> = ({ onClick, isValid }) => {
/* Shipping Address
Only available with checkout set to true -
This means that the provider does offer checkout functionality. */
return (
<div onClick={onClick} className={s.root}>
<div className="flex flex-1 items-center">
<CreditCard className="w-5 flex" />
<span className="ml-5 text-sm text-center font-medium">
Add Payment Method
</span>
{/* <span>VISA #### #### #### 2345</span> */}
</div>
<div>{isValid ? <Check /> : <ChevronRight />}</div>
</div>
)
}
export default PaymentWidget

View File

@@ -0,0 +1 @@
export { default } from './PaymentWidget'

View File

@@ -0,0 +1,21 @@
.fieldset {
@apply flex flex-col my-3;
}
.fieldset .label {
@apply text-accent-7 uppercase text-xs font-medium mb-2;
}
.fieldset .input,
.fieldset .select {
@apply p-2 border border-accent-2 w-full text-sm font-normal;
}
.fieldset .input:focus,
.fieldset .select:focus {
@apply outline-none shadow-outline-normal;
}
.radio {
@apply bg-black;
}

View File

@@ -0,0 +1,118 @@
import { FC } from 'react'
import cn from 'classnames'
import Button from '@components/ui/Button'
import { useUI } from '@components/ui/context'
import SidebarLayout from '@components/common/SidebarLayout'
import useAddAddress from '@framework/customer/address/use-add-item'
import s from './ShippingView.module.css'
interface Form extends HTMLFormElement {
cardHolder: HTMLInputElement
cardNumber: HTMLInputElement
cardExpireDate: HTMLInputElement
cardCvc: HTMLInputElement
firstName: HTMLInputElement
lastName: HTMLInputElement
company: HTMLInputElement
streetNumber: HTMLInputElement
zipCode: HTMLInputElement
city: HTMLInputElement
country: HTMLSelectElement
}
const ShippingView: FC = () => {
const { setSidebarView } = useUI()
const addAddress = useAddAddress()
async function handleSubmit(event: React.ChangeEvent<Form>) {
event.preventDefault()
await addAddress({
type: event.target.type.value,
firstName: event.target.firstName.value,
lastName: event.target.lastName.value,
company: event.target.company.value,
streetNumber: event.target.streetNumber.value,
apartments: event.target.streetNumber.value,
zipCode: event.target.zipCode.value,
city: event.target.city.value,
country: event.target.country.value,
})
setSidebarView('CHECKOUT_VIEW')
}
return (
<form className="h-full" onSubmit={handleSubmit}>
<SidebarLayout handleBack={() => setSidebarView('CHECKOUT_VIEW')}>
<div className="px-4 sm:px-6 flex-1">
<h2 className="pt-1 pb-8 text-2xl font-semibold tracking-wide cursor-pointer inline-block">
Shipping
</h2>
<div>
<div className="flex flex-row my-3 items-center">
<input name="type" className={s.radio} type="radio" />
<span className="ml-3 text-sm">Same as billing address</span>
</div>
<div className="flex flex-row my-3 items-center">
<input name="type" className={s.radio} type="radio" />
<span className="ml-3 text-sm">
Use a different shipping address
</span>
</div>
<hr className="border-accent-2 my-6" />
<div className="grid gap-3 grid-flow-row grid-cols-12">
<div className={cn(s.fieldset, 'col-span-6')}>
<label className={s.label}>First Name</label>
<input name="firstName" className={s.input} />
</div>
<div className={cn(s.fieldset, 'col-span-6')}>
<label className={s.label}>Last Name</label>
<input name="lastName" className={s.input} />
</div>
</div>
<div className={s.fieldset}>
<label className={s.label}>Company (Optional)</label>
<input name="company" className={s.input} />
</div>
<div className={s.fieldset}>
<label className={s.label}>Street and House Number</label>
<input name="streetNumber" className={s.input} />
</div>
<div className={s.fieldset}>
<label className={s.label}>
Apartment, Suite, Etc. (Optional)
</label>
<input name="apartments" className={s.input} />
</div>
<div className="grid gap-3 grid-flow-row grid-cols-12">
<div className={cn(s.fieldset, 'col-span-6')}>
<label className={s.label}>Postal Code</label>
<input name="zipCode" className={s.input} />
</div>
<div className={cn(s.fieldset, 'col-span-6')}>
<label className={s.label}>City</label>
<input name="city" className={s.input} />
</div>
</div>
<div className={s.fieldset}>
<label className={s.label}>Country/Region</label>
<select name="country" className={s.select}>
<option>Hong Kong</option>
</select>
</div>
</div>
</div>
<div className="sticky z-20 bottom-0 w-full right-0 left-0 py-12 bg-accent-0 border-t border-accent-2 px-6">
<Button type="submit" width="100%" variant="ghost">
Continue
</Button>
</div>
</SidebarLayout>
</form>
)
}
export default ShippingView

View File

@@ -0,0 +1 @@
export { default } from './ShippingView'

View File

@@ -0,0 +1,4 @@
.root {
@apply border border-accent-2 px-6 py-5 mb-4 text-center
flex items-center cursor-pointer hover:border-accent-4;
}

View File

@@ -0,0 +1,32 @@
import { FC } from 'react'
import s from './ShippingWidget.module.css'
import { ChevronRight, MapPin, Check } from '@components/icons'
import cn from 'classnames'
interface ComponentProps {
onClick?: () => any
isValid?: boolean
}
const ShippingWidget: FC<ComponentProps> = ({ onClick, isValid }) => {
/* Shipping Address
Only available with checkout set to true -
This means that the provider does offer checkout functionality. */
return (
<div onClick={onClick} className={s.root}>
<div className="flex flex-1 items-center">
<MapPin className="w-5 flex" />
<span className="ml-5 text-sm text-center font-medium">
Add Shipping Address
</span>
{/* <span>
1046 Kearny Street.<br/>
San Franssisco, California
</span> */}
</div>
<div>{isValid ? <Check /> : <ChevronRight />}</div>
</div>
)
}
export default ShippingWidget

View File

@@ -0,0 +1 @@
export { default } from './ShippingWidget'

View File

@@ -0,0 +1,111 @@
import React, {
FC,
useCallback,
useMemo,
useReducer,
useContext,
createContext,
} from 'react'
import type { CardFields } from '@commerce/types/customer/card'
import type { AddressFields } from '@commerce/types/customer/address'
export type State = {
cardFields: CardFields
addressFields: AddressFields
}
type CheckoutContextType = State & {
setCardFields: (cardFields: CardFields) => void
setAddressFields: (addressFields: AddressFields) => void
clearCheckoutFields: () => void
}
type Action =
| {
type: 'SET_CARD_FIELDS'
card: CardFields
}
| {
type: 'SET_ADDRESS_FIELDS'
address: AddressFields
}
| {
type: 'CLEAR_CHECKOUT_FIELDS'
}
const initialState: State = {
cardFields: {} as CardFields,
addressFields: {} as AddressFields,
}
export const CheckoutContext = createContext<State | any>(initialState)
CheckoutContext.displayName = 'CheckoutContext'
const checkoutReducer = (state: State, action: Action): State => {
switch (action.type) {
case 'SET_CARD_FIELDS':
return {
...state,
cardFields: action.card,
}
case 'SET_ADDRESS_FIELDS':
return {
...state,
addressFields: action.address,
}
case 'CLEAR_CHECKOUT_FIELDS':
return {
...state,
cardFields: initialState.cardFields,
addressFields: initialState.addressFields,
}
default:
return state
}
}
export const CheckoutProvider: FC = (props) => {
const [state, dispatch] = useReducer(checkoutReducer, initialState)
const setCardFields = useCallback(
(card: CardFields) => dispatch({ type: 'SET_CARD_FIELDS', card }),
[dispatch]
)
const setAddressFields = useCallback(
(address: AddressFields) =>
dispatch({ type: 'SET_ADDRESS_FIELDS', address }),
[dispatch]
)
const clearCheckoutFields = useCallback(
() => dispatch({ type: 'CLEAR_CHECKOUT_FIELDS' }),
[dispatch]
)
const cardFields = useMemo(() => state.cardFields, [state.cardFields])
const addressFields = useMemo(() => state.addressFields, [state.addressFields])
const value = useMemo(
() => ({
cardFields,
addressFields,
setCardFields,
setAddressFields,
clearCheckoutFields,
}),
[cardFields, addressFields, setCardFields, setAddressFields, clearCheckoutFields]
)
return <CheckoutContext.Provider value={value} {...props} />
}
export const useCheckoutContext = () => {
const context = useContext<CheckoutContextType>(CheckoutContext)
if (context === undefined) {
throw new Error(`useCheckoutContext must be used within a CheckoutProvider`)
}
return context
}