mirror of
https://github.com/vercel/commerce.git
synced 2025-07-23 04:36:49 +00:00
feat: get-product-detail
This commit is contained in:
@@ -47,6 +47,8 @@ export type Product = {
|
||||
currencyCode: CurrencyCode
|
||||
options: ProductOption[]
|
||||
facetValueIds?: string[]
|
||||
collectionIds?: string[]
|
||||
collection?: string,
|
||||
}
|
||||
|
||||
export type ProductCard = {
|
||||
|
@@ -53,7 +53,8 @@ export default function getProductOperation({
|
||||
displayName: og.name,
|
||||
values: og.options.map((o) => ({ label: o.name })),
|
||||
})),
|
||||
facetValueIds: product.facetValues.map(item=> item.id)
|
||||
facetValueIds: product.facetValues.map(item=> item.id),
|
||||
collectionIds: product.collections.map(item => item.id)
|
||||
} as Product
|
||||
}
|
||||
|
||||
|
@@ -39,6 +39,9 @@ export const getProductQuery = /* GraphQL */ `
|
||||
facetValues {
|
||||
id
|
||||
}
|
||||
collections {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
@@ -12,7 +12,7 @@ import { PromiseWithKey } from 'src/utils/types.utils'
|
||||
export default function Slug({ product, relevantProducts, collections }: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||
|
||||
return <>
|
||||
<ProductInfoDetail />
|
||||
<ProductInfoDetail productDetail={product} collections={collections}/>
|
||||
<RecipeDetail ingredients={INGREDIENT_DATA_TEST} />
|
||||
<RecommendedRecipes data={RECIPE_DATA_TEST} />
|
||||
<ReleventProducts data={relevantProducts} collections={collections}/>
|
||||
|
@@ -1,83 +1,28 @@
|
||||
import React from 'react'
|
||||
import React, { useMemo } from 'react';
|
||||
import ProductImgs from './components/ProductImgs/ProductImgs'
|
||||
import ProductInfo from './components/ProductInfo/ProductInfo'
|
||||
import s from './ProductInfoDetail.module.scss'
|
||||
import { GetStaticPropsContext, GetStaticPathsContext, InferGetStaticPropsType } from 'next'
|
||||
import commerce from '@lib/api/commerce'
|
||||
import { PromiseWithKey } from 'src/utils/types.utils'
|
||||
import { getAllPromies } from 'src/utils/funtion.utils'
|
||||
import { ProductCard } from '@commerce/types/product';
|
||||
import { useRouter } from 'next/router'
|
||||
import { Product } from '@commerce/types/product'
|
||||
import { Collection } from '@framework/schema'
|
||||
import { getCategoryNameFromCollectionId } from 'src/utils/funtion.utils';
|
||||
|
||||
interface Props {
|
||||
productDetail: ProductCard[],
|
||||
productDetail: Product,
|
||||
collections: Collection[]
|
||||
}
|
||||
|
||||
const ProductInfoDetail = ({ product }: InferGetStaticPropsType<typeof getStaticProps>) => {
|
||||
console.log(product)
|
||||
const ProductInfoDetail = ({ productDetail, collections }: Props) => {
|
||||
const dataWithCategoryName = useMemo(() => {
|
||||
return {
|
||||
...productDetail,
|
||||
collection: getCategoryNameFromCollectionId(collections, productDetail.collectionIds ? productDetail.collectionIds[0] : undefined)
|
||||
}
|
||||
}, [productDetail, collections])
|
||||
return (
|
||||
<section className={s.productInfoDetail}>
|
||||
<ProductImgs/>
|
||||
<ProductInfo/>
|
||||
<ProductImgs productImage={productDetail.images}/>
|
||||
<ProductInfo productInfoDetail={dataWithCategoryName}/>
|
||||
</section >
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
locale,
|
||||
locales,
|
||||
preview,
|
||||
}: GetStaticPropsContext<{ slug: string }>) {
|
||||
const config = { locale, locales }
|
||||
const pagesPromise = commerce.getAllPages({ config, preview })
|
||||
const siteInfoPromise = commerce.getSiteInfo({ config, preview })
|
||||
const productPromise = commerce.getProduct({
|
||||
variables: { slug: params!.slug },
|
||||
config,
|
||||
preview,
|
||||
})
|
||||
|
||||
// const allProductsPromise = commerce.getAllProducts({
|
||||
// variables: { first: 4 },
|
||||
// config,
|
||||
// preview,
|
||||
// })
|
||||
const { pages } = await pagesPromise
|
||||
const { categories } = await siteInfoPromise
|
||||
const { product } = await productPromise
|
||||
// const { products: relatedProducts } = await allProductsPromise
|
||||
|
||||
if (!product) {
|
||||
throw new Error(`Product with slug '${params!.slug}' not found`)
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
pages,
|
||||
product,
|
||||
// relatedProducts,
|
||||
categories,
|
||||
},
|
||||
revalidate: 200,
|
||||
}
|
||||
}
|
||||
|
||||
// export async function getStaticPaths({ locales }: GetStaticPathsContext) {
|
||||
// const { products } = await commerce.getAllProductPaths()
|
||||
|
||||
// return {
|
||||
// paths: locales
|
||||
// ? locales.reduce<string[]>((arr, locale) => {
|
||||
// // Add a product path for every locale
|
||||
// products.forEach((product: any) => {
|
||||
// arr.push(`/${locale}/product${product.path}`)
|
||||
// })
|
||||
// return arr
|
||||
// }, [])
|
||||
// : products.map((product: any) => `/product${product.path}`),
|
||||
// fallback: 'blocking',
|
||||
// }
|
||||
// }
|
||||
|
||||
export default ProductInfoDetail
|
||||
|
@@ -3,15 +3,15 @@ import { ImgWithLink } from 'src/components/common'
|
||||
import s from './ProductImgItem.module.scss'
|
||||
|
||||
export interface ProductImgItemProps {
|
||||
preview: string
|
||||
name?: string
|
||||
url: string
|
||||
alt?: string
|
||||
}
|
||||
|
||||
|
||||
const ProductImgItem = ({ preview, name }: ProductImgItemProps) => {
|
||||
const ProductImgItem = ({ url, alt }: ProductImgItemProps) => {
|
||||
return (
|
||||
<section className={s.productImgItem}>
|
||||
<ImgWithLink src={preview} alt={name} />
|
||||
<ImgWithLink src={url} alt={alt} />
|
||||
</section >
|
||||
)
|
||||
}
|
||||
|
@@ -2,28 +2,13 @@ import React from 'react'
|
||||
import { ResponsiveType } from 'react-multi-carousel'
|
||||
import { CarouselCommon } from 'src/components/common'
|
||||
import ProductImgItem, { ProductImgItemProps } from '../ProductImgItem/ProductImgItem'
|
||||
import { useProductDetail } from 'src/components/hooks/product'
|
||||
import s from './ProductImgs.module.scss'
|
||||
import { ProductImage } from '@commerce/types/product';
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any,
|
||||
productImage: ProductImage[]
|
||||
}
|
||||
|
||||
const DATA = [
|
||||
{
|
||||
src: 'https://user-images.githubusercontent.com/76729908/133026929-199799fc-bd75-4445-a24d-15c0e41796eb.png',
|
||||
alt: 'Meat',
|
||||
},
|
||||
{
|
||||
src: 'https://user-images.githubusercontent.com/76729908/130574371-3b75fa72-9552-4605-aba9-a4b31cd9dce7.png',
|
||||
alt: 'Broccoli',
|
||||
},
|
||||
{
|
||||
src: 'https://user-images.githubusercontent.com/76729908/130574371-3b75fa72-9552-4605-aba9-a4b31cd9dce7.png',
|
||||
alt: 'Broccoli',
|
||||
}
|
||||
]
|
||||
|
||||
const RESPONSIVE: ResponsiveType = {
|
||||
desktop: {
|
||||
@@ -32,12 +17,11 @@ const RESPONSIVE: ResponsiveType = {
|
||||
slidesToSlide: 1, // optional, default to 1.
|
||||
},
|
||||
}
|
||||
const ProductImgs = ({ }: Props) => {
|
||||
const { productDetail } = useProductDetail()
|
||||
const ProductImgs = ({ productImage }: Props) => {
|
||||
return (
|
||||
<section className={s.productImgs}>
|
||||
<CarouselCommon<ProductImgItemProps>
|
||||
data={productDetail?.assets ?? []}
|
||||
data={productImage}
|
||||
itemKey="product-detail-img"
|
||||
Component={ProductImgItem}
|
||||
responsive={RESPONSIVE}
|
||||
|
@@ -1,31 +1,30 @@
|
||||
import { Product } from '@commerce/types/product'
|
||||
import React from 'react'
|
||||
import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common'
|
||||
import { IconBuy } from 'src/components/icons'
|
||||
import { LANGUAGE } from 'src/utils/language.utils'
|
||||
import { useProductDetail } from 'src/components/hooks/product'
|
||||
import s from './ProductInfo.module.scss'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any,
|
||||
productInfoDetail: Product
|
||||
}
|
||||
|
||||
const ProductInfo = ({ }: Props) => {
|
||||
const {productDetail} = useProductDetail()
|
||||
const ProductInfo = ({ productInfoDetail }: Props) => {
|
||||
console.log(productInfoDetail)
|
||||
return (
|
||||
<section className={s.productInfo}>
|
||||
<div className={s.info}>
|
||||
<LabelCommon shape='half'>SEAFOOD</LabelCommon>
|
||||
<h2 className={s.heading}>{productDetail?.name}</h2>
|
||||
<LabelCommon shape='half'>{productInfoDetail.collection}</LabelCommon>
|
||||
<h2 className={s.heading}>{productInfoDetail.name}</h2>
|
||||
<div className={s.price}>
|
||||
<div className={s.old}>
|
||||
<span className={s.number}>Rp {productDetail?.variants[0].priceWithTax}</span>
|
||||
<span className={s.number}>Rp {productInfoDetail.price}</span>
|
||||
<LabelCommon type='discount'>-15%</LabelCommon>
|
||||
</div>
|
||||
<div className={s.current}>Rp {productDetail?.variants[0].price}</div>
|
||||
<div className={s.current}>Rp {productInfoDetail.price}</div>
|
||||
</div>
|
||||
<div className={s.description}>
|
||||
{productDetail?.description}
|
||||
{productInfoDetail.description}
|
||||
</div>
|
||||
</div>
|
||||
<div className={s.actions}>
|
||||
|
@@ -23,7 +23,6 @@ const ReleventProducts = ({ data, collections }: Props) => {
|
||||
if (data.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<ListProductWithInfo
|
||||
title="Relevant Products"
|
||||
|
Reference in New Issue
Block a user