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
|
currencyCode: CurrencyCode
|
||||||
options: ProductOption[]
|
options: ProductOption[]
|
||||||
facetValueIds?: string[]
|
facetValueIds?: string[]
|
||||||
|
collectionIds?: string[]
|
||||||
|
collection?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProductCard = {
|
export type ProductCard = {
|
||||||
|
@@ -53,7 +53,8 @@ export default function getProductOperation({
|
|||||||
displayName: og.name,
|
displayName: og.name,
|
||||||
values: og.options.map((o) => ({ label: o.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
|
} as Product
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,6 +39,9 @@ export const getProductQuery = /* GraphQL */ `
|
|||||||
facetValues {
|
facetValues {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
collections {
|
||||||
|
id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@@ -12,7 +12,7 @@ import { PromiseWithKey } from 'src/utils/types.utils'
|
|||||||
export default function Slug({ product, relevantProducts, collections }: InferGetStaticPropsType<typeof getStaticProps>) {
|
export default function Slug({ product, relevantProducts, collections }: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<ProductInfoDetail />
|
<ProductInfoDetail productDetail={product} collections={collections}/>
|
||||||
<RecipeDetail ingredients={INGREDIENT_DATA_TEST} />
|
<RecipeDetail ingredients={INGREDIENT_DATA_TEST} />
|
||||||
<RecommendedRecipes data={RECIPE_DATA_TEST} />
|
<RecommendedRecipes data={RECIPE_DATA_TEST} />
|
||||||
<ReleventProducts data={relevantProducts} collections={collections}/>
|
<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 ProductImgs from './components/ProductImgs/ProductImgs'
|
||||||
import ProductInfo from './components/ProductInfo/ProductInfo'
|
import ProductInfo from './components/ProductInfo/ProductInfo'
|
||||||
import s from './ProductInfoDetail.module.scss'
|
import s from './ProductInfoDetail.module.scss'
|
||||||
import { GetStaticPropsContext, GetStaticPathsContext, InferGetStaticPropsType } from 'next'
|
import { Product } from '@commerce/types/product'
|
||||||
import commerce from '@lib/api/commerce'
|
import { Collection } from '@framework/schema'
|
||||||
import { PromiseWithKey } from 'src/utils/types.utils'
|
import { getCategoryNameFromCollectionId } from 'src/utils/funtion.utils';
|
||||||
import { getAllPromies } from 'src/utils/funtion.utils'
|
|
||||||
import { ProductCard } from '@commerce/types/product';
|
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
productDetail: ProductCard[],
|
productDetail: Product,
|
||||||
|
collections: Collection[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductInfoDetail = ({ product }: InferGetStaticPropsType<typeof getStaticProps>) => {
|
const ProductInfoDetail = ({ productDetail, collections }: Props) => {
|
||||||
console.log(product)
|
const dataWithCategoryName = useMemo(() => {
|
||||||
|
return {
|
||||||
|
...productDetail,
|
||||||
|
collection: getCategoryNameFromCollectionId(collections, productDetail.collectionIds ? productDetail.collectionIds[0] : undefined)
|
||||||
|
}
|
||||||
|
}, [productDetail, collections])
|
||||||
return (
|
return (
|
||||||
<section className={s.productInfoDetail}>
|
<section className={s.productInfoDetail}>
|
||||||
<ProductImgs/>
|
<ProductImgs productImage={productDetail.images}/>
|
||||||
<ProductInfo/>
|
<ProductInfo productInfoDetail={dataWithCategoryName}/>
|
||||||
</section >
|
</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
|
export default ProductInfoDetail
|
||||||
|
@@ -3,15 +3,15 @@ import { ImgWithLink } from 'src/components/common'
|
|||||||
import s from './ProductImgItem.module.scss'
|
import s from './ProductImgItem.module.scss'
|
||||||
|
|
||||||
export interface ProductImgItemProps {
|
export interface ProductImgItemProps {
|
||||||
preview: string
|
url: string
|
||||||
name?: string
|
alt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ProductImgItem = ({ preview, name }: ProductImgItemProps) => {
|
const ProductImgItem = ({ url, alt }: ProductImgItemProps) => {
|
||||||
return (
|
return (
|
||||||
<section className={s.productImgItem}>
|
<section className={s.productImgItem}>
|
||||||
<ImgWithLink src={preview} alt={name} />
|
<ImgWithLink src={url} alt={alt} />
|
||||||
</section >
|
</section >
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -2,28 +2,13 @@ import React from 'react'
|
|||||||
import { ResponsiveType } from 'react-multi-carousel'
|
import { ResponsiveType } from 'react-multi-carousel'
|
||||||
import { CarouselCommon } from 'src/components/common'
|
import { CarouselCommon } from 'src/components/common'
|
||||||
import ProductImgItem, { ProductImgItemProps } from '../ProductImgItem/ProductImgItem'
|
import ProductImgItem, { ProductImgItemProps } from '../ProductImgItem/ProductImgItem'
|
||||||
import { useProductDetail } from 'src/components/hooks/product'
|
|
||||||
import s from './ProductImgs.module.scss'
|
import s from './ProductImgs.module.scss'
|
||||||
|
import { ProductImage } from '@commerce/types/product';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
productImage: ProductImage[]
|
||||||
children?: any,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = {
|
const RESPONSIVE: ResponsiveType = {
|
||||||
desktop: {
|
desktop: {
|
||||||
@@ -32,12 +17,11 @@ const RESPONSIVE: ResponsiveType = {
|
|||||||
slidesToSlide: 1, // optional, default to 1.
|
slidesToSlide: 1, // optional, default to 1.
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const ProductImgs = ({ }: Props) => {
|
const ProductImgs = ({ productImage }: Props) => {
|
||||||
const { productDetail } = useProductDetail()
|
|
||||||
return (
|
return (
|
||||||
<section className={s.productImgs}>
|
<section className={s.productImgs}>
|
||||||
<CarouselCommon<ProductImgItemProps>
|
<CarouselCommon<ProductImgItemProps>
|
||||||
data={productDetail?.assets ?? []}
|
data={productImage}
|
||||||
itemKey="product-detail-img"
|
itemKey="product-detail-img"
|
||||||
Component={ProductImgItem}
|
Component={ProductImgItem}
|
||||||
responsive={RESPONSIVE}
|
responsive={RESPONSIVE}
|
||||||
|
@@ -1,31 +1,30 @@
|
|||||||
|
import { Product } from '@commerce/types/product'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common'
|
import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common'
|
||||||
import { IconBuy } from 'src/components/icons'
|
import { IconBuy } from 'src/components/icons'
|
||||||
import { LANGUAGE } from 'src/utils/language.utils'
|
import { LANGUAGE } from 'src/utils/language.utils'
|
||||||
import { useProductDetail } from 'src/components/hooks/product'
|
|
||||||
import s from './ProductInfo.module.scss'
|
import s from './ProductInfo.module.scss'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
productInfoDetail: Product
|
||||||
children?: any,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductInfo = ({ }: Props) => {
|
const ProductInfo = ({ productInfoDetail }: Props) => {
|
||||||
const {productDetail} = useProductDetail()
|
console.log(productInfoDetail)
|
||||||
return (
|
return (
|
||||||
<section className={s.productInfo}>
|
<section className={s.productInfo}>
|
||||||
<div className={s.info}>
|
<div className={s.info}>
|
||||||
<LabelCommon shape='half'>SEAFOOD</LabelCommon>
|
<LabelCommon shape='half'>{productInfoDetail.collection}</LabelCommon>
|
||||||
<h2 className={s.heading}>{productDetail?.name}</h2>
|
<h2 className={s.heading}>{productInfoDetail.name}</h2>
|
||||||
<div className={s.price}>
|
<div className={s.price}>
|
||||||
<div className={s.old}>
|
<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>
|
<LabelCommon type='discount'>-15%</LabelCommon>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.current}>Rp {productDetail?.variants[0].price}</div>
|
<div className={s.current}>Rp {productInfoDetail.price}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.description}>
|
<div className={s.description}>
|
||||||
{productDetail?.description}
|
{productInfoDetail.description}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.actions}>
|
<div className={s.actions}>
|
||||||
|
@@ -23,7 +23,6 @@ const ReleventProducts = ({ data, collections }: Props) => {
|
|||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListProductWithInfo
|
<ListProductWithInfo
|
||||||
title="Relevant Products"
|
title="Relevant Products"
|
||||||
|
Reference in New Issue
Block a user