mirror of
https://github.com/vercel/commerce.git
synced 2025-07-23 04:36:49 +00:00
Merge branch 'feature/m1-get-product-detail' of github.com:KieIO/grocery-vercel-commerce into feature/m3-add-product-to-cart-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 = {
|
||||
|
@@ -2,7 +2,7 @@ import { Product } from '@commerce/types/product'
|
||||
import { OperationContext } from '@commerce/api/operations'
|
||||
import { Provider, VendureConfig } from '../'
|
||||
import { GetProductQuery } from '../../schema'
|
||||
import { getProductQuery } from '../../utils/queries/get-product-query'
|
||||
import { getProductQuery, getProductDetailQuery } from '../../utils/queries/get-product-query'
|
||||
|
||||
export default function getProductOperation({
|
||||
commerce,
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
2
framework/vendure/schema.d.ts
vendored
2
framework/vendure/schema.d.ts
vendored
@@ -3303,7 +3303,7 @@ export type GetProductQuery = { __typename?: 'Query' } & {
|
||||
variants: Array<
|
||||
{ __typename?: 'ProductVariant' } & Pick<
|
||||
ProductVariant,
|
||||
'id' | 'priceWithTax' | 'currencyCode'
|
||||
'id' | 'priceWithTax' | 'currencyCode' | 'price'
|
||||
> & {
|
||||
options: Array<
|
||||
{ __typename?: 'ProductOption' } & Pick<
|
||||
|
@@ -39,6 +39,25 @@ export const getProductQuery = /* GraphQL */ `
|
||||
facetValues {
|
||||
id
|
||||
}
|
||||
collections {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
export const getProductDetailQuery = /* GraphQL */ `
|
||||
query GetProductDetail($slug: String! = "hand-trowel") {
|
||||
product(slug: $slug) {
|
||||
name
|
||||
description
|
||||
variants {
|
||||
price
|
||||
priceWithTax
|
||||
}
|
||||
assets {
|
||||
preview
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
3
next-env.d.ts
vendored
3
next-env.d.ts
vendored
@@ -1,6 +1,3 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
|
@@ -26,6 +26,7 @@
|
||||
"body-scroll-lock": "^3.1.5",
|
||||
"classnames": "^2.3.1",
|
||||
"cookie": "^0.4.1",
|
||||
"dns": "^0.2.2",
|
||||
"email-validator": "^2.0.4",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-next": "^11.1.2",
|
||||
@@ -35,6 +36,7 @@
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.random": "^3.2.0",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"net": "^1.0.2",
|
||||
"next": "^11.0.0",
|
||||
"next-seo": "^4.26.0",
|
||||
"next-themes": "^0.0.14",
|
||||
|
@@ -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,11 +1,12 @@
|
||||
import commerce from '@lib/api/commerce';
|
||||
import { GetStaticPropsContext } from 'next';
|
||||
import { ProductCard } from '@commerce/types/product';
|
||||
import { Layout, ListProductCardSkeleton } from 'src/components/common';
|
||||
|
||||
interface Props {
|
||||
products: any
|
||||
productDetail: ProductCard[],
|
||||
}
|
||||
export default function Home({ products }: Props) {
|
||||
export default function Home({ productDetail }: Props) {
|
||||
return (
|
||||
<>
|
||||
{/* <ListProductCardSkeleton /> */}
|
||||
|
1
src/components/hooks/product/index.tsx
Normal file
1
src/components/hooks/product/index.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { default as useProductDetail } from './useProductDetail'
|
16
src/components/hooks/product/useProductDetail.tsx
Normal file
16
src/components/hooks/product/useProductDetail.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { GetProductQuery } from '@framework/schema'
|
||||
import { getProductDetailQuery } from '@framework/utils/queries/get-product-query';
|
||||
import gglFetcher from 'src/utils/gglFetcher'
|
||||
import useSWR from 'swr'
|
||||
|
||||
|
||||
interface ProductDetail {
|
||||
slug: string
|
||||
}
|
||||
|
||||
const useProductDetail = () => {
|
||||
const { data, ...rest } = useSWR<GetProductQuery>([getProductDetailQuery],gglFetcher)
|
||||
return { productDetail: data?.product, ...rest }
|
||||
}
|
||||
|
||||
export default useProductDetail
|
@@ -1,20 +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 { Product } from '@commerce/types/product'
|
||||
import { Collection } from '@framework/schema'
|
||||
import { getCategoryNameFromCollectionId } from 'src/utils/funtion.utils';
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any
|
||||
productDetail: Product,
|
||||
collections: Collection[]
|
||||
}
|
||||
|
||||
const ProductInfoDetail = ({ }: Props) => {
|
||||
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 default ProductInfoDetail
|
||||
|
@@ -3,15 +3,15 @@ import { ImgWithLink } from 'src/components/common'
|
||||
import s from './ProductImgItem.module.scss'
|
||||
|
||||
export interface ProductImgItemProps {
|
||||
src: string
|
||||
url: string
|
||||
alt?: string
|
||||
}
|
||||
|
||||
|
||||
const ProductImgItem = ({ src, alt }: ProductImgItemProps) => {
|
||||
const ProductImgItem = ({ url, alt }: ProductImgItemProps) => {
|
||||
return (
|
||||
<section className={s.productImgItem}>
|
||||
<ImgWithLink src={src} alt={alt} />
|
||||
<ImgWithLink src={url} alt={alt} />
|
||||
</section >
|
||||
)
|
||||
}
|
||||
|
@@ -3,26 +3,12 @@ import { ResponsiveType } from 'react-multi-carousel'
|
||||
import { CarouselCommon } from 'src/components/common'
|
||||
import ProductImgItem, { ProductImgItemProps } from '../ProductImgItem/ProductImgItem'
|
||||
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: {
|
||||
@@ -31,11 +17,11 @@ const RESPONSIVE: ResponsiveType = {
|
||||
slidesToSlide: 1, // optional, default to 1.
|
||||
},
|
||||
}
|
||||
const ProductImgs = ({ }: Props) => {
|
||||
const ProductImgs = ({ productImage }: Props) => {
|
||||
return (
|
||||
<section className={s.productImgs}>
|
||||
<CarouselCommon<ProductImgItemProps>
|
||||
data={DATA}
|
||||
data={productImage}
|
||||
itemKey="product-detail-img"
|
||||
Component={ProductImgItem}
|
||||
responsive={RESPONSIVE}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { Product } from '@commerce/types/product'
|
||||
import React from 'react'
|
||||
import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common'
|
||||
import { IconBuy } from 'src/components/icons'
|
||||
@@ -5,25 +6,25 @@ import { LANGUAGE } from 'src/utils/language.utils'
|
||||
import s from './ProductInfo.module.scss'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any,
|
||||
productInfoDetail: Product
|
||||
}
|
||||
|
||||
const ProductInfo = ({ }: Props) => {
|
||||
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}>SeaPAk</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 32.000</span>
|
||||
<span className={s.number}>Rp {productInfoDetail.price}</span>
|
||||
<LabelCommon type='discount'>-15%</LabelCommon>
|
||||
</div>
|
||||
<div className={s.current}>Rp 27.500</div>
|
||||
<div className={s.current}>Rp {productInfoDetail.price}</div>
|
||||
</div>
|
||||
<div className={s.description}>
|
||||
In a large non-reactive dish, mix together the orange juice, soy sauce, olive oil, lemon juice, parsley
|
||||
{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