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