mirror of
https://github.com/vercel/commerce.git
synced 2025-05-16 06:26:58 +00:00
Updates & fixes
This commit is contained in:
parent
6699f2fed4
commit
36e68b461f
@ -5,10 +5,12 @@ import type {
|
||||
import type {
|
||||
GetCustomerWishlistOperation,
|
||||
Wishlist,
|
||||
WishlistItem,
|
||||
} from '@vercel/commerce/types/wishlist'
|
||||
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
|
||||
import type { RecursivePartial } from '../utils/types'
|
||||
import { BigcommerceConfig, Provider } from '..'
|
||||
import getAllProducts, { ProductEdge } from './get-all-products'
|
||||
|
||||
import type { Product } from '@vercel/commerce/types/product'
|
||||
|
||||
export default function getCustomerWishlistOperation({
|
||||
commerce,
|
||||
@ -47,6 +49,12 @@ export default function getCustomerWishlistOperation({
|
||||
|
||||
const wishlist = data[0]
|
||||
|
||||
if (!wishlist) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const items: WishlistItem[] = []
|
||||
|
||||
if (includeProducts && wishlist?.items?.length) {
|
||||
const ids = wishlist.items
|
||||
?.map((item) => (item?.productId ? String(item?.productId) : null))
|
||||
@ -57,25 +65,36 @@ export default function getCustomerWishlistOperation({
|
||||
variables: { first: 50, ids },
|
||||
config,
|
||||
})
|
||||
|
||||
// Put the products in an object that we can use to get them by id
|
||||
const productsById = graphqlData.products.reduce<{
|
||||
[k: number]: ProductEdge
|
||||
[k: number]: Product
|
||||
}>((prods, p) => {
|
||||
prods[Number(p.id)] = p as any
|
||||
return prods
|
||||
}, {})
|
||||
|
||||
// Populate the wishlist items with the graphql products
|
||||
wishlist.items.forEach((item) => {
|
||||
const product = item && productsById[Number(item.productId)]
|
||||
if (item && product) {
|
||||
// @ts-ignore Fix this type when the wishlist type is properly defined
|
||||
item.product = product
|
||||
items.push({
|
||||
id: String(item.id),
|
||||
productId: String(item.productId),
|
||||
variantId: String(item.variantId),
|
||||
product,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return { wishlist: wishlist as RecursiveRequired<typeof wishlist> }
|
||||
return {
|
||||
wishlist: {
|
||||
id: String(wishlist.id),
|
||||
items,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return getCustomerWishlist
|
||||
|
@ -100,7 +100,7 @@ export default function getAllProductPathsOperation({
|
||||
const variables: GetProductQueryVariables = {
|
||||
locale,
|
||||
hasLocale: !!locale,
|
||||
path: slug ? `/${slug}` : vars.path!,
|
||||
path: `/${slug}`,
|
||||
}
|
||||
const { data } = await config.fetch<GetProductQuery>(query, { variables })
|
||||
const product = data.site?.route?.node
|
||||
|
@ -83,32 +83,38 @@ export interface ProductVariant {
|
||||
*/
|
||||
image?: Image
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* The product metafield object, which is a custom field attached to a product. It can be used to store additional information about the product in a structured format.
|
||||
* @example `reviews`
|
||||
*/
|
||||
export interface ProductMetafield {
|
||||
/**
|
||||
* The key name for the metafield.
|
||||
* The unique identifier for the metafield.
|
||||
*/
|
||||
key: string
|
||||
|
||||
/**
|
||||
* The namespace for the metafield.
|
||||
* The namespace for the metafield, which is a container for a set of metadata.
|
||||
* @example `rating`
|
||||
*/
|
||||
namespace: string
|
||||
|
||||
/**
|
||||
* The value of the metafield.
|
||||
* The value of the metafield, usually a string that can be might parsed into JSON.
|
||||
* @example `{"value": 5, "scale_max": 5}`
|
||||
*/
|
||||
value: any
|
||||
|
||||
/**
|
||||
* Automatically transformed value of the metafield.
|
||||
* The value of the metafield, complete with HTML formatting.
|
||||
*/
|
||||
html?: string
|
||||
valueHtml?: string
|
||||
|
||||
/**
|
||||
* The type of the metafield.
|
||||
* @example `date`
|
||||
* The type of the metafield, used to determine how the value should be interpreted.
|
||||
* For example: `string`, `integer`, `boolean`, `json` ...
|
||||
*/
|
||||
type?: string
|
||||
|
||||
@ -119,11 +125,12 @@ export interface ProductMetafield {
|
||||
}
|
||||
|
||||
/**
|
||||
* Product Metafields, grouped by namespace.
|
||||
* The namespace is the key of the object, and the value is an object with the metafield key and an object with the metafield data.
|
||||
* The product metafields are custom fields that can be added to a product. They are used to store additional information about the product.
|
||||
* @example
|
||||
* {
|
||||
* // Namespace, the container for a set of metadata
|
||||
* reviews: {
|
||||
* // Key of the metafield, used to differentiate between metafields of the same namespace
|
||||
* rating: {
|
||||
* key: 'rating',
|
||||
* value: 5,
|
||||
@ -132,10 +139,19 @@ export interface ProductMetafield {
|
||||
* }
|
||||
*/
|
||||
export interface ProductMetafields {
|
||||
/**
|
||||
* The namespace for the metafield, which is a container for a set of metadata.
|
||||
* @example `reviews`, `specifications`
|
||||
*/
|
||||
[namespace: string]: {
|
||||
/**
|
||||
* The key of the metafield, which is the name of the metafield.
|
||||
* @example `rating`
|
||||
*/
|
||||
[key: string]: ProductMetafield
|
||||
}
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
/**
|
||||
* The unique identifier for the product.
|
||||
@ -170,8 +186,22 @@ export interface Product {
|
||||
*/
|
||||
images: Image[]
|
||||
/**
|
||||
* The product’s metafields. This is a list of metafields that are attached to the product.
|
||||
*
|
||||
* The products custom fields. They are used to store simple key-value additional information about the product.
|
||||
*/
|
||||
customFields?: Record<string, string>
|
||||
/**
|
||||
* The product metafields are advanced custom fields that can be added to a product. They are used to store additional information about the product, usually in a structured format.
|
||||
* @example
|
||||
* {
|
||||
* // Namespace, the container for a set of metadata
|
||||
* reviews: {
|
||||
* // Key of the metafield, used to differentiate between metafields of the same namespace
|
||||
* rating: {
|
||||
* key: 'rating',
|
||||
* value: 5,
|
||||
* // ... other metafield properties
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
metafields?: ProductMetafields
|
||||
/**
|
||||
@ -265,40 +295,24 @@ export type GetAllProductsOperation = {
|
||||
}
|
||||
}
|
||||
|
||||
export type MetafieldsIdentifiers =
|
||||
| Record<string, string[]>
|
||||
| Array<{
|
||||
namespace: string
|
||||
key: string
|
||||
}>
|
||||
export type MetafieldsIdentifiers = Array<{
|
||||
namespace: string
|
||||
key: string
|
||||
}>
|
||||
|
||||
export type GetProductOperation = {
|
||||
data: { product?: Product }
|
||||
variables:
|
||||
| {
|
||||
path: string
|
||||
slug?: never
|
||||
}
|
||||
| ({
|
||||
path?: never
|
||||
slug: string
|
||||
} & {
|
||||
/**
|
||||
* Metafields identifiers used to fetch the product metafields.
|
||||
* It can be an array of objects with the namespace and key, or an object with the namespace as the key and an array of keys as the value.
|
||||
*
|
||||
* @example
|
||||
* metafields: {
|
||||
* reviews: ['rating', 'count']
|
||||
* }
|
||||
*
|
||||
* // or
|
||||
*
|
||||
* metafields: [
|
||||
* {namespace: 'reviews', key: 'rating'},
|
||||
* {namespace: 'reviews', key: 'count'},
|
||||
* ]
|
||||
*/
|
||||
withMetafields?: MetafieldsIdentifiers
|
||||
})
|
||||
variables: {
|
||||
slug: string
|
||||
/**
|
||||
* Metafields identifiers used to fetch the product metafields, represented as an array of objects with the namespace and key.
|
||||
*
|
||||
* @example
|
||||
* withMetafields: [
|
||||
* {namespace: 'reviews', key: 'rating'},
|
||||
* {namespace: 'reviews', key: 'count'},
|
||||
* ]
|
||||
*/
|
||||
withMetafields?: MetafieldsIdentifiers
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,24 @@
|
||||
import type { OperationContext } from '@vercel/commerce/api/operations'
|
||||
import { normalizeProduct } from '../../utils'
|
||||
import type { GetProductOperation } from '@vercel/commerce/types/product'
|
||||
import type { Provider, SaleorConfig } from '..'
|
||||
|
||||
import { normalizeProduct } from '../../utils'
|
||||
|
||||
import * as Query from '../../utils/queries'
|
||||
|
||||
type Variables = {
|
||||
slug: string
|
||||
}
|
||||
|
||||
type ReturnType = {
|
||||
product: any
|
||||
}
|
||||
|
||||
export default function getProductOperation({
|
||||
commerce,
|
||||
}: OperationContext<Provider>) {
|
||||
async function getProduct({
|
||||
async function getProduct<T extends GetProductOperation>({
|
||||
query = Query.ProductOneBySlug,
|
||||
variables,
|
||||
config: cfg,
|
||||
}: {
|
||||
query?: string
|
||||
variables: Variables
|
||||
variables: T['variables']
|
||||
config?: Partial<SaleorConfig>
|
||||
preview?: boolean
|
||||
}): Promise<ReturnType> {
|
||||
}): Promise<T['data']> {
|
||||
const { fetch, locale } = commerce.getConfig(cfg)
|
||||
|
||||
const { data } = await fetch(
|
||||
@ -37,9 +31,9 @@ export default function getProductOperation({
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
product: data && data.product ? normalizeProduct(data.product) : null,
|
||||
}
|
||||
return data && data.product
|
||||
? { product: normalizeProduct(data.product) }
|
||||
: {}
|
||||
}
|
||||
|
||||
return getProduct
|
||||
|
@ -1,3 +1,5 @@
|
||||
import type { GetProductOperation } from '@vercel/commerce/types/product'
|
||||
|
||||
import { normalizeProduct } from '../../utils'
|
||||
|
||||
import { Product } from '@vercel/commerce/types/product'
|
||||
@ -7,15 +9,15 @@ import { Provider, SwellConfig } from '../'
|
||||
export default function getProductOperation({
|
||||
commerce,
|
||||
}: OperationContext<Provider>) {
|
||||
async function getProduct({
|
||||
async function getProduct<T extends GetProductOperation>({
|
||||
variables,
|
||||
config: cfg,
|
||||
}: {
|
||||
query?: string
|
||||
variables: { slug: string }
|
||||
variables: T['variables']
|
||||
config?: Partial<SwellConfig>
|
||||
preview?: boolean
|
||||
}): Promise<Product | {} | any> {
|
||||
}): Promise<T['data']> {
|
||||
const config = commerce.getConfig(cfg)
|
||||
|
||||
const product = await config.fetch('products', 'get', [variables.slug])
|
||||
@ -24,9 +26,7 @@ export default function getProductOperation({
|
||||
product.variants = product.variants?.results
|
||||
}
|
||||
|
||||
return {
|
||||
product: product ? normalizeProduct(product) : null,
|
||||
}
|
||||
return product ? { product: normalizeProduct(product) } : {}
|
||||
}
|
||||
|
||||
return getProduct
|
||||
|
@ -1,22 +1,26 @@
|
||||
import { Product } from '@vercel/commerce/types/product'
|
||||
import { OperationContext } from '@vercel/commerce/api/operations'
|
||||
import { Provider, VendureConfig } from '../'
|
||||
import { GetProductQuery } from '../../../schema'
|
||||
import type {
|
||||
Product,
|
||||
GetProductOperation,
|
||||
} from '@vercel/commerce/types/product'
|
||||
import type { OperationContext } from '@vercel/commerce/api/operations'
|
||||
import type { Provider, VendureConfig } from '../'
|
||||
|
||||
import type { GetProductQuery } from '../../../schema'
|
||||
import { getProductQuery } from '../../utils/queries/get-product-query'
|
||||
|
||||
export default function getProductOperation({
|
||||
commerce,
|
||||
}: OperationContext<Provider>) {
|
||||
async function getProduct({
|
||||
async function getProduct<T extends GetProductOperation>({
|
||||
query = getProductQuery,
|
||||
variables,
|
||||
config: cfg,
|
||||
}: {
|
||||
query?: string
|
||||
variables: { slug: string }
|
||||
variables: T['variables']
|
||||
config?: Partial<VendureConfig>
|
||||
preview?: boolean
|
||||
}): Promise<Product | {} | any> {
|
||||
}): Promise<T['data']> {
|
||||
const config = commerce.getConfig(cfg)
|
||||
|
||||
const locale = config.locale
|
||||
|
3092
pnpm-lock.yaml
generated
3092
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -94,20 +94,20 @@ const ProductSidebar: FC<ProductSidebarProps> = ({ product, className }) => {
|
||||
<Collapse title="Care">
|
||||
<Text
|
||||
className="leading-0"
|
||||
html={product.metafields.descriptors.care_guide.html}
|
||||
html={product.metafields.descriptors.care_guide.valueHtml}
|
||||
/>
|
||||
</Collapse>
|
||||
)}
|
||||
|
||||
{product.metafields?.my_fields && (
|
||||
<Collapse title="Details">
|
||||
{Object.entries(product.metafields.my_fields).map(([_, field]) => (
|
||||
{Object.values(product.metafields.my_fields).map((field) => (
|
||||
<div
|
||||
key={field.key}
|
||||
className="flex gap-2 border-b py-3 border-accent-2 border-dashed last:border-b-0"
|
||||
>
|
||||
<strong className="leading-7">{field.name}:</strong>
|
||||
<Text html={field.html || field.value} className="!mx-0" />
|
||||
<Text html={field.valueHtml || field.value} className="!mx-0" />
|
||||
</div>
|
||||
))}
|
||||
</Collapse>
|
||||
|
@ -23,8 +23,8 @@
|
||||
"@components/*": ["components/*"],
|
||||
"@commerce": ["../packages/commerce/src"],
|
||||
"@commerce/*": ["../packages/commerce/src/*"],
|
||||
"@framework": ["../packages/shopify/src"],
|
||||
"@framework/*": ["../packages/shopify/src/*"]
|
||||
"@framework": ["../packages/local/src"],
|
||||
"@framework/*": ["../packages/local/src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
||||
|
Loading…
x
Reference in New Issue
Block a user