>
+>
-export default useAddItem
+export type UseAddItem = Partial<
+ UseAddItemInput
+> extends UseAddItemInput
+ ? (input?: UseAddItemInput
) => (input: Input) => UseAddItemResult
+ : (input: UseAddItemInput
) => (input: Input) => UseAddItemResult
+
+export const fetcher: HookFetcherFn<
+ Cart,
+ AddCartItemBody
+> = async ({ options, input, fetch }) => {
+ return fetch({ ...options, body: input })
+}
+
+type X = UseAddItemResult
+
+export default function useAddItem(
+ input: UseAddItemInput
+) {
+ const { providerRef, fetcherRef } = useCommerce
()
+
+ const provider = providerRef.current
+ const opts = provider.cart?.useAddItem
+
+ const fetcherFn = opts?.fetcher ?? fetcher
+ const useHook = opts?.useHook ?? (() => () => {})
+ const fetchFn = provider.fetcher ?? fetcherRef.current
+ const action = useHook({ input })
+
+ return useCallback(
+ function addItem(input: Input) {
+ return action({
+ input,
+ fetch({ input }) {
+ return fetcherFn({
+ input,
+ options: opts!.fetchOptions,
+ fetch: fetchFn,
+ })
+ },
+ })
+ },
+ [input, fetchFn, opts?.fetchOptions]
+ )
+}
diff --git a/framework/commerce/index.tsx b/framework/commerce/index.tsx
index d8d882f93..243fba2db 100644
--- a/framework/commerce/index.tsx
+++ b/framework/commerce/index.tsx
@@ -6,7 +6,7 @@ import {
useMemo,
useRef,
} from 'react'
-import { Fetcher, HookHandler } from './utils/types'
+import { Fetcher, HookHandler, MutationHandler } from './utils/types'
import type { FetchCartInput } from './cart/use-cart'
import type { Cart, Wishlist, Customer, SearchProductsData } from './types'
@@ -16,6 +16,7 @@ export type Provider = CommerceConfig & {
fetcher: Fetcher
cart?: {
useCart?: HookHandler
+ useAddItem?: MutationHandler
}
wishlist?: {
useWishlist?: HookHandler
diff --git a/framework/commerce/types.d.ts b/framework/commerce/types.d.ts
deleted file mode 100644
index 9e69ec25d..000000000
--- a/framework/commerce/types.d.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-interface Entity {
- id: string | number
- [prop: string]: any
-}
-
-interface Product extends Entity {
- name: string
- description: string
- slug?: string
- path?: string
- images: ProductImage[]
- variants: ProductVariant[]
- price: ProductPrice
- options: ProductOption[]
- sku?: string
-}
-
-interface ProductOption extends Entity {
- displayName: string
- values: ProductOptionValues[]
-}
-
-interface ProductOptionValues {
- label: string
- hexColors?: string[]
-}
-
-interface ProductImage {
- url: string
- alt?: string
-}
-
-interface ProductVariant {
- id: string | number
- options: ProductOption[]
-}
-
-interface ProductPrice {
- value: number
- currencyCode: 'USD' | 'ARS' | string | undefined
- retailPrice?: number
- salePrice?: number
- listPrice?: number
- extendedSalePrice?: number
- extendedListPrice?: number
-}
-
-interface CartItem extends Entity {
- quantity: number
- productId: Product['id']
- variantId: ProductVariant['id']
- images: ProductImage[]
-}
-
-interface Wishlist extends Entity {
- products: Pick[]
-}
-
-interface Order {}
-
-interface Customer extends Entity {}
-
-type UseCustomerResponse = {
- customer: Customer
-} | null
-
-interface Category extends Entity {
- name: string
-}
-
-interface Brand extends Entity {
- name: string
-}
-
-type Features = 'wishlist' | 'customer'
diff --git a/framework/commerce/types.ts b/framework/commerce/types.ts
index c828e74f9..bf635c9dc 100644
--- a/framework/commerce/types.ts
+++ b/framework/commerce/types.ts
@@ -2,12 +2,12 @@ import type { Wishlist as BCWishlist } from '@framework/api/wishlist'
import type { Customer as BCCustomer } from '@framework/api/customers'
import type { SearchProductsData as BCSearchProductsData } from '@framework/api/catalog/products'
-export interface Discount {
+export type Discount = {
// The value of the discount, can be an amount or percentage
value: number
}
-export interface LineItem {
+export type LineItem = {
id: string
variantId: string
productId: string
@@ -19,19 +19,19 @@ export interface LineItem {
variant: ProductVariant
}
-export interface Measurement {
+export type Measurement = {
value: number
unit: 'KILOGRAMS' | 'GRAMS' | 'POUNDS' | 'OUNCES'
}
-export interface Image {
+export type Image = {
url: string
altText?: string
width?: number
height?: number
}
-export interface ProductVariant {
+export type ProductVariant = {
id: string
// The SKU (stock keeping unit) associated with the product variant.
sku: string
@@ -66,7 +66,7 @@ export interface ProductVariant {
}
// Shopping cart, a.k.a Checkout
-export interface Cart {
+export type Cart = {
id: string
// ID of the customer to which the cart belongs.
customerId?: string
@@ -105,53 +105,99 @@ export interface SearchProductsData extends BCSearchProductsData {}
*/
// Base cart item body used for cart mutations
-export interface CartItemBody {
+export type CartItemBody = {
variantId: string
productId?: string
quantity?: number
}
// Body used by the `getCart` operation handler
-export interface GetCartHandlerBody {
+export type GetCartHandlerBody = {
cartId?: string
}
// Body used by the add item to cart operation
-export interface AddCartItemBody {
+export type AddCartItemBody = {
item: T
}
// Body expected by the add item to cart operation handler
-export interface AddCartItemHandlerBody
- extends Partial> {
+export type AddCartItemHandlerBody = Partial<
+ AddCartItemBody
+> & {
cartId?: string
}
// Body used by the update cart item operation
-export interface UpdateCartItemBody {
+export type UpdateCartItemBody = {
itemId: string
item: T
}
// Body expected by the update cart item operation handler
-export interface UpdateCartItemHandlerBody
- extends Partial> {
+export type UpdateCartItemHandlerBody = Partial<
+ UpdateCartItemBody
+> & {
cartId?: string
}
// Body used by the remove cart item operation
-export interface RemoveCartItemBody {
+export type RemoveCartItemBody = {
itemId: string
}
// Body expected by the remove cart item operation handler
-export interface RemoveCartItemHandlerBody extends Partial {
+export type RemoveCartItemHandlerBody = Partial & {
cartId?: string
}
-// Features API
-type Features = 'wishlist' | 'checkout'
+/**
+ * Temporal types
+ */
-export interface FrameworkConfig {
- features: Record
+interface Entity {
+ id: string | number
+ [prop: string]: any
+}
+
+export interface Product extends Entity {
+ name: string
+ description: string
+ slug?: string
+ path?: string
+ images: ProductImage[]
+ variants: ProductVariant2[]
+ price: ProductPrice
+ options: ProductOption[]
+ sku?: string
+}
+
+interface ProductOption extends Entity {
+ displayName: string
+ values: ProductOptionValues[]
+}
+
+interface ProductOptionValues {
+ label: string
+ hexColors?: string[]
+}
+
+interface ProductImage {
+ url: string
+ alt?: string
+}
+
+interface ProductVariant2 {
+ id: string | number
+ options: ProductOption[]
+}
+
+interface ProductPrice {
+ value: number
+ currencyCode: 'USD' | 'ARS' | string | undefined
+ retailPrice?: number
+ salePrice?: number
+ listPrice?: number
+ extendedSalePrice?: number
+ extendedListPrice?: number
}
diff --git a/framework/commerce/utils/types.ts b/framework/commerce/utils/types.ts
index 98e4ebbae..1d3adef81 100644
--- a/framework/commerce/utils/types.ts
+++ b/framework/commerce/utils/types.ts
@@ -76,6 +76,24 @@ export type HookHandler<
fetcher?: HookFetcherFn
}
+export type MutationHandler<
+ // Data obj returned by the hook and fetch operation
+ Data,
+ // Input expected by the hook
+ Input extends { [k: string]: unknown } = {},
+ // Input expected before doing a fetch operation
+ FetchInput extends { [k: string]: unknown } = {}
+> = {
+ useHook?(context: {
+ input: Input
+ }): (context: {
+ input: FetchInput
+ fetch: (context: { input: FetchInput }) => Data | Promise
+ }) => Data | Promise
+ fetchOptions: HookFetcherOptions
+ fetcher?: HookFetcherFn
+}
+
export type SwrOptions = ConfigInterface<
Data,
CommerceError,
@@ -87,14 +105,18 @@ export type SwrOptions = ConfigInterface<
*/
export type Prop = NonNullable
-export type UseHookParameters> = Parameters<
+export type HookHandlerType =
+ | HookHandler
+ | MutationHandler
+
+export type UseHookParameters = Parameters<
Prop
>
-export type UseHookResponse> = ReturnType<
+export type UseHookResponse = ReturnType<
Prop
>
export type UseHookInput<
- H extends HookHandler
+ H extends HookHandlerType
> = UseHookParameters[0]['input']
diff --git a/framework/commerce/wishlist/use-add-item.tsx b/framework/commerce/wishlist/use-add-item.tsx
index f6c069f2b..d9b513694 100644
--- a/framework/commerce/wishlist/use-add-item.tsx
+++ b/framework/commerce/wishlist/use-add-item.tsx
@@ -1,4 +1,11 @@
import useAction from '../utils/use-action'
+import type { CartItemBody } from '../types'
+
+// Input expected by the action returned by the `useAddItem` hook
+// export interface AddItemInput {
+// includeProducts?: boolean
+// }
+export type AddItemInput = T
const useAddItem = useAction
diff --git a/lib/hooks/useUserAvatar.ts b/lib/hooks/useUserAvatar.ts
new file mode 100644
index 000000000..840daae6d
--- /dev/null
+++ b/lib/hooks/useUserAvatar.ts
@@ -0,0 +1,26 @@
+import { useEffect } from 'react'
+import { useUI } from '@components/ui/context'
+import { getRandomPairOfColors } from '@lib/colors'
+
+export const useUserAvatar = (name = 'userAvatar') => {
+ const { userAvatar, setUserAvatar } = useUI()
+
+ useEffect(() => {
+ if (!userAvatar && localStorage.getItem(name)) {
+ // Get bg from localStorage and push it to the context.
+ setUserAvatar(localStorage.getItem(name))
+ }
+ if (!localStorage.getItem(name)) {
+ // bg not set locally, generating one, setting localStorage and context to persist.
+ const bg = getRandomPairOfColors()
+ const value = `linear-gradient(140deg, ${bg[0]}, ${bg[1]} 100%)`
+ localStorage.setItem(name, value)
+ setUserAvatar(value)
+ }
+ }, [])
+
+ return {
+ userAvatar,
+ setUserAvatar,
+ }
+}
diff --git a/lib/logger.ts b/lib/logger.ts
deleted file mode 100644
index eeda2c325..000000000
--- a/lib/logger.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import bunyan from 'bunyan'
-import PrettyStream from 'bunyan-prettystream'
-
-const prettyStdOut = new PrettyStream()
-
-const log = bunyan.createLogger({
- name: 'Next.js - Commerce',
- level: 'debug',
- streams: [
- {
- level: 'debug',
- type: 'raw',
- stream: prettyStdOut,
- },
- ],
-})
-
-export default log
diff --git a/package.json b/package.json
index ff492a35e..268b8d4a5 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,6 @@
},
"dependencies": {
"@reach/portal": "^0.11.2",
- "@tailwindcss/ui": "^0.6.2",
"@vercel/fetch": "^6.1.0",
"body-scroll-lock": "^3.1.5",
"bowser": "^2.11.0",
@@ -35,18 +34,18 @@
"lodash.debounce": "^4.0.8",
"lodash.random": "^3.2.0",
"lodash.throttle": "^4.1.1",
- "next": "^10.0.5",
+ "next": "^10.0.7-canary.3",
"next-seo": "^4.11.0",
"next-themes": "^0.0.4",
- "normalizr": "^3.6.1",
+ "postcss": "^8.2.4",
"postcss-nesting": "^7.0.1",
- "react": "^16.14.0",
- "react-dom": "^16.14.0",
+ "react": "^17.0.1",
+ "react-dom": "^17.0.1",
"react-merge-refs": "^1.1.0",
"react-ticker": "^1.2.2",
"swr": "^0.4.0",
"tabbable": "^5.1.5",
- "tailwindcss": "^1.9"
+ "tailwindcss": "^2.0.2"
},
"devDependencies": {
"@graphql-codegen/cli": "^1.20.0",
@@ -56,8 +55,6 @@
"@manifoldco/swagger-to-ts": "^2.1.0",
"@next/bundle-analyzer": "^10.0.1",
"@types/body-scroll-lock": "^2.6.1",
- "@types/bunyan": "^1.8.6",
- "@types/bunyan-prettystream": "^0.1.31",
"@types/classnames": "^2.2.10",
"@types/cookie": "^0.4.0",
"@types/js-cookie": "^2.2.6",
@@ -66,8 +63,6 @@
"@types/lodash.throttle": "^4.1.6",
"@types/node": "^14.14.16",
"@types/react": "^17.0.0",
- "bunyan": "^1.8.14",
- "bunyan-prettystream": "^0.1.3",
"graphql": "^15.4.0",
"husky": "^4.3.8",
"lint-staged": "^10.5.3",
diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx
index 3d2971eed..83aeaa54c 100644
--- a/pages/product/[slug].tsx
+++ b/pages/product/[slug].tsx
@@ -61,7 +61,7 @@ export default function Slug({
return router.isFallback ? (
Loading...
// TODO (BC) Add Skeleton Views
) : (
-
+
)
}
diff --git a/pages/search.tsx b/pages/search.tsx
index 97bee34d4..821b5a9f5 100644
--- a/pages/search.tsx
+++ b/pages/search.tsx
@@ -95,7 +95,7 @@ export default function Search({