4
0
forked from crowetic/commerce

normalizations & missing files

This commit is contained in:
cond0r 2021-02-04 15:34:22 +02:00
parent 3c985278c6
commit 2dffcb7bfb
18 changed files with 323 additions and 174 deletions

View File

@ -0,0 +1 @@
export default function () {}

View File

@ -0,0 +1 @@
export default function () {}

View File

@ -0,0 +1 @@
export default function () {}

View File

@ -0,0 +1,103 @@
import { CommerceAPIFetchOptions } from '@commerce/api'
import {
CheckoutCreateInput,
CheckoutCreatePayload,
Maybe,
} from '@framework/schema'
import { getProductQuery } from 'framework/bigcommerce/product/get-product'
import Cookies from 'js-cookie'
import { getConfig, ShopifyConfig } from '..'
const createCheckoutMutation = `
mutation($input) {
checkoutCreate(input: $input) {
checkout {
id
webUrl
lineItems(first: 100) {
edges {
node {
title
quantity
}
}
}
}
}
}
`
const getCheckoutQuery = `
query {
shop {
name
currencyCode
checkout {
id
webUrl
lineItems(first: 100) {
edges {
node {
title
quantity
}
}
}
}
}
}
`
const createCheckout = async (fetcher: any, input: CheckoutCreateInput) => {
return await fetcher(createCheckoutMutation, {
variables: {
input,
},
})
}
const getCheckout = async (req: any, res: any, config: any): Promise<any> => {
console.log(config)
return
config = getConfig(config)
const { data: shop } = await config.fetch(getProductQuery)
const checkout = shop?.checkout
const completedAt = checkout.completedAt
const checkoutId = Cookies.get('nextjs-commerce-shopify-token')
const checkoutCreateInput = {
presentmentCurrencyCode: shop?.currencyCode,
}
// we could have a cart id stored in session storage
// user could be refreshing or navigating back and forthlet checkoutResource
let checkoutCreatePayload: Maybe<CheckoutCreatePayload>
if (checkoutId) {
checkoutCreatePayload = await createCheckout(
config.fetch,
checkoutCreateInput
)
const existingCheckout = checkoutCreatePayload?.checkout
const completedAt = existingCheckout?.completedAt
if (completedAt) {
checkoutCreatePayload = await createCheckout(
config.fetch,
checkoutCreateInput
)
}
} else {
checkoutCreatePayload = await createCheckout(
config.fetch,
checkoutCreateInput
)
}
console.log(checkout)
}
export default getCheckout

View File

@ -0,0 +1 @@
export default function () {}

View File

@ -1,38 +0,0 @@
import { FetcherError } from '@commerce/utils/errors'
import type { LoginHandlers } from '../login'
const loginHandler: LoginHandlers['login'] = async ({
res,
body: { email, password },
config,
}) => {
if (!(email && password)) {
return res.status(400).json({
data: null,
errors: [{ message: 'Invalid request' }],
})
}
try {
} catch (error) {
// Check if the email and password didn't match an existing account
if (error instanceof FetcherError) {
return res.status(401).json({
data: null,
errors: [
{
message:
'Cannot find an account that matches the provided credentials',
code: 'invalid_credentials',
},
],
})
}
throw error
}
res.status(200).json({ data: null })
}
export default loginHandler

View File

@ -9,32 +9,25 @@ import type { Cart } from '@commerce/types'
import checkoutLineItemAddMutation from '../utils/mutations/checkout-line-item-add'
import getCheckoutId from '@framework/utils/get-checkout-id'
import { checkoutToCart } from './utils'
import { AddCartItemBody, CartItemBody } from '@framework/types'
import { AddItemBody } from '../types'
import { MutationCheckoutLineItemsAddArgs } from '@framework/schema'
const defaultOpts = {
query: checkoutLineItemAddMutation,
}
export type AddItemInput = UseAddItemInput<any>
export type AddItemInput = UseAddItemInput<CartItemBody>
export const fetcher: HookFetcher<Cart, any> = async (
options,
{ checkoutId, item },
fetch
) => {
if (
item.quantity &&
(!Number.isInteger(item.quantity) || item.quantity! < 1)
) {
throw new CommerceError({
message: 'The item quantity has to be a valid integer greater than 0',
})
}
const data = await fetch<any, any>({
export const fetcher: HookFetcher<
Cart,
MutationCheckoutLineItemsAddArgs
> = async (options, { checkoutId, lineItems }, fetch) => {
const data = await fetch<any, AddCartItemBody>({
...options,
variables: {
checkoutId,
lineItems: [item],
lineItems,
},
})
@ -49,10 +42,12 @@ export function extendHook(customFetcher: typeof fetcher) {
return useCallback(
async function addItem(input: AddItemInput) {
const data = await fn({
item: {
variantId: input.variantId,
quantity: input.quantity ?? 1,
},
lineItems: [
{
variantId: input.variantId,
quantity: input.quantity ?? 1,
},
],
checkoutId: getCheckoutId(cart?.id),
})
await mutate(data, false)

View File

@ -0,0 +1 @@
export { default as useCustomer } from './use-customer'

View File

@ -0,0 +1,124 @@
import {
Product as ShopifyProduct,
Checkout,
CheckoutLineItemEdge,
SelectedOption,
ImageConnection,
ProductVariantConnection,
ProductOption,
MoneyV2,
} from '@framework/schema'
import type { Cart, LineItem } from '../types'
const money = ({ amount, currencyCode }: MoneyV2) => {
return {
value: +amount,
currencyCode,
}
}
const normalizeProductOption = ({
name: displayName,
values,
...rest
}: ProductOption) => ({
__typename: 'MultipleChoiceOption',
displayName,
values: values.map((value) => ({
label: value,
})),
...rest,
})
const normalizeProductImages = ({ edges }: ImageConnection) =>
edges?.map(({ node: { originalSrc: url, ...rest } }) => ({
url,
...rest,
}))
const normalizeProductVariants = ({ edges }: ProductVariantConnection) =>
edges?.map(({ node: { id, selectedOptions } }) => ({
id,
options: selectedOptions.map(({ name, value }: SelectedOption) =>
normalizeProductOption({
id,
name,
values: [value],
})
),
}))
export function normalizeProduct(productNode: ShopifyProduct): any {
const {
id,
title: name,
vendor,
images,
variants,
description,
handle,
priceRange,
options,
...rest
} = productNode
return {
id: { $set: String(id) },
name,
vendor,
description,
path: `/${handle}`,
slug: handle?.replace(/^\/+|\/+$/g, ''),
price: money(priceRange?.minVariantPrice),
images: normalizeProductImages(images),
variants: variants ? normalizeProductVariants(variants) : null,
options: options ? options.map((o) => normalizeProductOption) : [],
...rest,
}
}
export function normalizeCart(data: Checkout): Cart {
return {
id: data.id,
customerId: '',
email: '',
createdAt: data.createdAt,
currency: {
code: data.currencyCode,
},
taxesIncluded: data.taxesIncluded,
lineItems: data.lineItems?.edges.map(normalizeLineItem),
lineItemsSubtotalPrice: data.subtotalPrice,
subtotalPrice: data.subtotalPrice,
totalPrice: data.totalPrice,
discounts: data.discountApplications?.edges.map(({ value }: any) => ({
value,
})),
}
}
function normalizeLineItem({ node: item }: CheckoutLineItemEdge): LineItem {
return {
id: item.id,
variantId: String(item.variant?.id),
productId: String(item.variant?.id),
name: item.title,
quantity: item.quantity,
variant: {
id: String(item.variant?.id),
sku: item.variant?.sku ?? '',
name: item.title,
image: {
url: item.variant?.image?.originalSrc,
},
requiresShipping: item.variant?.requiresShipping ?? false,
price: item.variant?.price,
listPrice: item.variant?.compareAtPrice,
},
path: '',
discounts: item.discountAllocations.map(({ value }: any) => ({
value,
})),
}
}

View File

@ -1,8 +1,8 @@
import { GraphQLFetcherResult } from '@commerce/api'
import toCommerceProducts from '../utils/to-commerce-products'
import { getConfig, ShopifyConfig } from '../api'
import { Product } from '../schema'
import { Product, ProductEdge } from '../schema'
import { getAllProductsQuery } from '../utils/queries'
import { normalizeProduct } from '@framework/lib/normalize'
export type ProductNode = Product
@ -28,8 +28,9 @@ const getAllProducts = async (options: {
{ variables }
)
const shopifyProducts = data.products?.edges
const products = toCommerceProducts(shopifyProducts)
const products = data?.products?.edges?.map(({ node: p }: ProductEdge) =>
normalizeProduct(p)
)
return {
products,

View File

@ -2,8 +2,8 @@ import { GraphQLFetcherResult } from '@commerce/api'
import { getConfig, ShopifyConfig } from '../api'
import { Product } from '../schema'
import { toCommerceProduct } from '../utils/to-commerce-products'
import getProductQuery from '../utils/queries/get-product-query'
import { normalizeProduct } from '@framework/lib/normalize'
export type ProductNode = Product
@ -25,12 +25,14 @@ const getProduct = async (options: Options): Promise<ReturnType> => {
let { config, variables = { first: 250 } } = options ?? {}
config = getConfig(config)
const {
data: { productByHandle: product },
}: GraphQLFetcherResult = await config.fetch(getProductQuery, { variables })
const { data }: GraphQLFetcherResult = await config.fetch(getProductQuery, {
variables,
})
const product = data?.productByHandle?.product
return {
product: product ? toCommerceProduct(product) : null,
product: product ? normalizeProduct(product) : null,
}
}

View File

@ -1,6 +1,4 @@
import useCommerceSearch from '@commerce/products/use-search'
import toCommerceProducts from '@framework/utils/to-commerce-products'
import getAllProductsQuery from '@framework/utils/queries/get-all-products-query'
import type { Product } from 'framework/bigcommerce/schema'
@ -14,10 +12,7 @@ import {
} from '@framework/utils/get-search-variables'
import sortBy from '@framework/utils/get-sort-variables'
export type CommerceProductEdge = {
node: Product
}
import { normalizeProduct } from '@framework/lib/normalize'
export type SearchProductsInput = {
search?: string
@ -49,8 +44,10 @@ export const fetcher: HookFetcher<
}).then(
({ products }): SearchProductsData => {
return {
products: toCommerceProducts(products.edges),
found: !!products.edges.length,
products: products?.edges?.map(({ node: p }: ProductEdge) =>
normalizeProduct(p)
),
found: !!products?.edges?.length,
}
}
)

View File

@ -0,0 +1,46 @@
import * as Core from '@commerce/types'
import { CheckoutLineItem } from './schema'
export type ShopifyCheckout = {
id: string
webUrl: string
lineItems: CheckoutLineItem[]
}
export interface Cart extends Core.Cart {
lineItems: LineItem[]
}
export interface LineItem extends Core.LineItem {}
/**
* Cart mutations
*/
export type OptionSelections = {
option_id: number
option_value: number | string
}
export interface CartItemBody extends Core.CartItemBody {
productId: string // The product id is always required for BC
optionSelections?: OptionSelections
}
export interface GetCartHandlerBody extends Core.GetCartHandlerBody {}
export interface AddCartItemBody extends Core.AddCartItemBody<CartItemBody> {}
export interface AddCartItemHandlerBody
extends Core.AddCartItemHandlerBody<CartItemBody> {}
export interface UpdateCartItemBody
extends Core.UpdateCartItemBody<CartItemBody> {}
export interface UpdateCartItemHandlerBody
extends Core.UpdateCartItemHandlerBody<CartItemBody> {}
export interface RemoveCartItemBody extends Core.RemoveCartItemBody {}
export interface RemoveCartItemHandlerBody
extends Core.RemoveCartItemHandlerBody {}

View File

@ -35,7 +35,10 @@ const getAllProductsQuery = /* GraphQL */ `
}
edges {
node {
src
originalSrc
altText
width
height
}
}
}

View File

@ -16,6 +16,7 @@ export const checkoutDetailsFragment = /* GraphQL */ `
title
variant {
id
sku
title
image {
src

View File

@ -48,7 +48,10 @@ const getProductQuery = /* GraphQL */ `
}
edges {
node {
src
originalSrc
altText
width
height
}
}
}

View File

@ -1,96 +0,0 @@
import {
Product as ShopifyProduct,
ImageEdge,
SelectedOption,
ProductEdge,
ProductVariantEdge,
MoneyV2,
ProductOption,
} from '../schema'
const money = ({ amount, currencyCode }: MoneyV2) => {
return {
value: +amount,
currencyCode,
}
}
const tranformProductOption = ({
id,
name: displayName,
values,
}: ProductOption) => ({
__typename: 'MultipleChoiceOption',
displayName,
values: values.map((value) => ({
label: value,
})),
})
const transformImages = (images: ImageEdge[]) =>
images.map(({ node: { src: url } }) => ({
url,
}))
export const toCommerceProduct = (product: ShopifyProduct) => {
const {
id,
title: name,
vendor,
images: { edges: images },
variants: { edges: variants },
description,
handle: slug,
priceRange,
options,
} = product
return {
id,
name,
slug,
vendor,
description,
path: `/${slug}`,
price: money(priceRange.minVariantPrice),
images: transformImages(images),
variants: variants.map(
({ node: { id, selectedOptions } }: ProductVariantEdge) => {
return {
id,
options: selectedOptions.map(({ name, value }: SelectedOption) =>
tranformProductOption({
id,
name,
values: [value],
} as ProductOption)
),
}
}
),
options: options.map((option: ProductOption) =>
tranformProductOption(option)
),
}
}
export default function toCommerceProducts(products: ProductEdge[]) {
return products.map(
({
node: {
id,
title: name,
images: { edges: images },
handle: slug,
priceRange,
},
}: ProductEdge) => ({
id,
name,
images: transformImages(images),
price: money(priceRange.minVariantPrice),
slug,
path: `/${slug}`,
})
)
}

View File

@ -34,4 +34,7 @@ module.exports = {
},
]
},
typescript: {
ignoreBuildErrors: true,
},
}