mirror of
https://github.com/vercel/commerce.git
synced 2025-07-23 04:36:49 +00:00
✨ feat: fresh products
:%s
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { CurrencyCode } from './../../vendure/schema.d';
|
||||||
import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema"
|
import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema"
|
||||||
|
|
||||||
export type ProductImage = {
|
export type ProductImage = {
|
||||||
@@ -46,6 +47,21 @@ export type Product = {
|
|||||||
options: ProductOption[]
|
options: ProductOption[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ProductCard = {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
slug?: string
|
||||||
|
imageSrc: string
|
||||||
|
price: number
|
||||||
|
currencyCode: CurrencyCode
|
||||||
|
oldPrice?: number,
|
||||||
|
discount?: number
|
||||||
|
weight?: number
|
||||||
|
// TODO: collection
|
||||||
|
category?: string,
|
||||||
|
isNotSell?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type SearchProductsBody = {
|
export type SearchProductsBody = {
|
||||||
search?: string
|
search?: string
|
||||||
categoryId?: string | number
|
categoryId?: string | number
|
||||||
|
@@ -1,24 +1,23 @@
|
|||||||
import { Product } from '@commerce/types/product'
|
import { Product, ProductCard } from '@commerce/types/product'
|
||||||
import { Cart } from '@commerce/types/cart'
|
import { Cart } from '@commerce/types/cart'
|
||||||
import { CartFragment, SearchResultFragment } from '../schema'
|
import { CartFragment, SearchResultFragment } from '../schema'
|
||||||
|
|
||||||
export function normalizeSearchResult(item: SearchResultFragment): Product {
|
export function normalizeSearchResult(item: SearchResultFragment): ProductCard {
|
||||||
const imageUrl = item.productAsset?.preview ? item.productAsset?.preview + '?w=800&mode=crop' : ''
|
|
||||||
return {
|
return {
|
||||||
|
|
||||||
id: item.productId,
|
id: item.productId,
|
||||||
name: item.productName,
|
name: item.productName,
|
||||||
description: item.description,
|
|
||||||
slug: item.slug,
|
slug: item.slug,
|
||||||
path: item.slug,
|
imageSrc: item.productAsset?.preview ? item.productAsset?.preview + '?w=800&mode=crop' : '',
|
||||||
images: imageUrl ? [{ url: imageUrl }] : [],
|
price: (item.priceWithTax as any).min / 100,
|
||||||
price: {
|
currencyCode: item.currencyCode,
|
||||||
// TODO: check price
|
|
||||||
value: (item.priceWithTax as any).min / 100,
|
// TODO:
|
||||||
currencyCode: item.currencyCode,
|
// oldPrice: item.price
|
||||||
},
|
// discount
|
||||||
// TODO: check product option
|
// isNotSell
|
||||||
options: [],
|
// weight
|
||||||
sku: item.sku,
|
// category
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@ import { Product } from '@framework/schema';
|
|||||||
import commerce from '@lib/api/commerce';
|
import commerce from '@lib/api/commerce';
|
||||||
import { GetStaticPropsContext } from 'next';
|
import { GetStaticPropsContext } from 'next';
|
||||||
import { Layout } from 'src/components/common';
|
import { Layout } from 'src/components/common';
|
||||||
import { FeaturedProductsCarousel, HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeRecipe, HomeSubscribe, HomeVideo } from 'src/components/modules/home';
|
import { FeaturedProductsCarousel, FreshProducts, HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeRecipe, HomeSubscribe, HomeVideo } from 'src/components/modules/home';
|
||||||
import HomeSpice from 'src/components/modules/home/HomeSpice/HomeSpice';
|
import HomeSpice from 'src/components/modules/home/HomeSpice/HomeSpice';
|
||||||
import { getAllFeaturedFacetId, getFreshProductFacetId } from 'src/utils/funtion.utils';
|
import { getAllFeaturedFacetId, getFreshProductFacetId } from 'src/utils/funtion.utils';
|
||||||
|
|
||||||
@@ -13,13 +13,12 @@ interface Props {
|
|||||||
|
|
||||||
}
|
}
|
||||||
export default function Home({ freshProducts, featuredProducts }: Props) {
|
export default function Home({ freshProducts, featuredProducts }: Props) {
|
||||||
console.log("total: ", freshProducts.length, featuredProducts.length)
|
|
||||||
console.log("rs: ", freshProducts, featuredProducts)
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<HomeBanner />
|
<HomeBanner />
|
||||||
<HomeFeature />
|
<HomeFeature />
|
||||||
<HomeCategories />
|
<HomeCategories />
|
||||||
|
<FreshProducts data={freshProducts}/>
|
||||||
<HomeCollection />
|
<HomeCollection />
|
||||||
<HomeVideo />
|
<HomeVideo />
|
||||||
<HomeSpice />
|
<HomeSpice />
|
||||||
|
BIN
public/assets/images/default_img.jpg
Normal file
BIN
public/assets/images/default_img.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import s from './ImgWithLink.module.scss'
|
import s from './ImgWithLink.module.scss'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { BLUR_DATA_IMG } from 'src/utils/constanst.utils'
|
import { BLUR_DATA_IMG, DEFAULT_IMG } from 'src/utils/constanst.utils'
|
||||||
|
|
||||||
export interface ImgWithLinkProps {
|
export interface ImgWithLinkProps {
|
||||||
src: string,
|
src: string,
|
||||||
@@ -12,7 +12,7 @@ export interface ImgWithLinkProps {
|
|||||||
const ImgWithLink = ({ src, alt, blurDataURL = BLUR_DATA_IMG }: ImgWithLinkProps) => {
|
const ImgWithLink = ({ src, alt, blurDataURL = BLUR_DATA_IMG }: ImgWithLinkProps) => {
|
||||||
return (
|
return (
|
||||||
<div className={s.imgWithLink}>
|
<div className={s.imgWithLink}>
|
||||||
<Image src={src} alt={alt}
|
<Image src={src || DEFAULT_IMG.src} alt={alt}
|
||||||
layout="fill"
|
layout="fill"
|
||||||
className={s.imgWithLink}
|
className={s.imgWithLink}
|
||||||
placeholder="blur"
|
placeholder="blur"
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
|
import { ProductCard } from '@commerce/types/product'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { IconBuy } from 'src/components/icons'
|
import { IconBuy } from 'src/components/icons'
|
||||||
import { ROUTE } from 'src/utils/constanst.utils'
|
import { ROUTE } from 'src/utils/constanst.utils'
|
||||||
import { ProductProps } from 'src/utils/types.utils'
|
|
||||||
import { ImgWithLink } from '..'
|
import { ImgWithLink } from '..'
|
||||||
import ButtonCommon from '../ButtonCommon/ButtonCommon'
|
import ButtonCommon from '../ButtonCommon/ButtonCommon'
|
||||||
import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy'
|
import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy'
|
||||||
@@ -11,16 +11,18 @@ import LabelCommon from '../LabelCommon/LabelCommon'
|
|||||||
import s from './ProductCard.module.scss'
|
import s from './ProductCard.module.scss'
|
||||||
import ProductNotSell from './ProductNotSell/ProductNotSell'
|
import ProductNotSell from './ProductNotSell/ProductNotSell'
|
||||||
|
|
||||||
export interface ProductCardProps extends ProductProps {
|
export interface ProductCardProps extends ProductCard {
|
||||||
buttonText?: string
|
buttonText?: string
|
||||||
isSingleButton?: boolean,
|
isSingleButton?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductCard = ({
|
const ProductCardComponent = ({
|
||||||
category,
|
category,
|
||||||
name,
|
name,
|
||||||
|
slug,
|
||||||
weight,
|
weight,
|
||||||
price,
|
price,
|
||||||
|
currencyCode,
|
||||||
buttonText = 'Buy Now',
|
buttonText = 'Buy Now',
|
||||||
imageSrc,
|
imageSrc,
|
||||||
isNotSell,
|
isNotSell,
|
||||||
@@ -35,24 +37,31 @@ const ProductCard = ({
|
|||||||
return (
|
return (
|
||||||
<div className={s.productCardWarpper}>
|
<div className={s.productCardWarpper}>
|
||||||
<div className={s.cardTop}>
|
<div className={s.cardTop}>
|
||||||
<Link href={`${ROUTE.PRODUCT_DETAIL}/test`}>
|
<Link href={`${ROUTE.PRODUCT_DETAIL}/${slug}`}>
|
||||||
<div className={s.productImage}>
|
<a>
|
||||||
<ImgWithLink src={imageSrc} alt={name}/>
|
<div className={s.productImage}>
|
||||||
</div>
|
<ImgWithLink src={imageSrc} alt={name}/>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
{
|
||||||
|
category &&
|
||||||
<div className={s.productLabel}>
|
<div className={s.productLabel}>
|
||||||
<LabelCommon shape="half">{category}</LabelCommon>
|
<LabelCommon shape="half">{category}</LabelCommon>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className={s.cardMid}>
|
<div className={s.cardMid}>
|
||||||
<div className={s.cardMidTop}>
|
<div className={s.cardMidTop}>
|
||||||
<Link href={`${ROUTE.PRODUCT_DETAIL}/test`}>
|
<Link href={`${ROUTE.PRODUCT_DETAIL}/${slug}`}>
|
||||||
<div className={s.productname}>{name} </div>
|
<a>
|
||||||
|
<div className={s.productname}>{name} </div>
|
||||||
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<div className={s.productWeight}>{weight}</div>
|
<div className={s.productWeight}>{weight}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.cardMidBot}>
|
<div className={s.cardMidBot}>
|
||||||
<div className={s.productPrice}>{price}</div>
|
<div className={s.productPrice}>{price} {currencyCode}</div>
|
||||||
<div className={s.wishList}>
|
<div className={s.wishList}>
|
||||||
<ItemWishList />
|
<ItemWishList />
|
||||||
</div>
|
</div>
|
||||||
@@ -80,4 +89,4 @@ const ProductCard = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProductCard
|
export default ProductCardComponent
|
||||||
|
@@ -1,99 +1,9 @@
|
|||||||
import { Product } from '@framework/schema'
|
import { Product } from '@framework/schema'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { CollectionCarcousel } from '..'
|
import { CollectionCarcousel } from '..'
|
||||||
import image5 from '../../../../../public/assets/images/image5.png'
|
|
||||||
import image6 from '../../../../../public/assets/images/image6.png'
|
|
||||||
import image7 from '../../../../../public/assets/images/image7.png'
|
|
||||||
import image8 from '../../../../../public/assets/images/image8.png'
|
|
||||||
interface FreshProductsProps {
|
interface FreshProductsProps {
|
||||||
data: Product[]
|
data: Product[]
|
||||||
}
|
}
|
||||||
const dataTest = [
|
|
||||||
{
|
|
||||||
name: 'Tomato',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image5.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Cucumber',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image6.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Carrot',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image7.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Salad',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image8.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tomato',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image5.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Cucumber',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image6.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tomato',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image5.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Cucumber',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image6.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Carrot',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image7.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Salad',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image8.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tomato',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image5.src,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Cucumber',
|
|
||||||
weight: '250g',
|
|
||||||
category: 'VEGGIE',
|
|
||||||
price: 'Rp 27.500',
|
|
||||||
imageSrc: image6.src,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const FreshProducts = ({data}: FreshProductsProps) => {
|
const FreshProducts = ({data}: FreshProductsProps) => {
|
||||||
return (
|
return (
|
||||||
@@ -106,41 +16,6 @@ const FreshProducts = ({data}: FreshProductsProps) => {
|
|||||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
||||||
category={"veggie"}
|
category={"veggie"}
|
||||||
/>
|
/>
|
||||||
<CollectionCarcousel
|
|
||||||
data={dataTest}
|
|
||||||
itemKey="product-2"
|
|
||||||
title="VEGGIE"
|
|
||||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
|
||||||
category={"veggie"}
|
|
||||||
/>
|
|
||||||
<CollectionCarcousel
|
|
||||||
data={dataTest}
|
|
||||||
itemKey="product-3"
|
|
||||||
title="VEGGIE"
|
|
||||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
|
||||||
category={"veggie"}
|
|
||||||
/>
|
|
||||||
<CollectionCarcousel
|
|
||||||
data={dataTest}
|
|
||||||
itemKey="product-4"
|
|
||||||
title="VEGGIE"
|
|
||||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
|
||||||
category={"veggie"}
|
|
||||||
/>
|
|
||||||
<CollectionCarcousel
|
|
||||||
data={dataTest}
|
|
||||||
itemKey="product-5"
|
|
||||||
title="VEGGIE"
|
|
||||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
|
||||||
category={"veggie"}
|
|
||||||
/>
|
|
||||||
<CollectionCarcousel
|
|
||||||
data={dataTest}
|
|
||||||
itemKey="product-6"
|
|
||||||
title="VEGGIE"
|
|
||||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
|
||||||
category={"veggie"}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
|
import DefaultImg from '../../public/assets/images/default_img.jpg'
|
||||||
|
|
||||||
export const BLUR_DATA_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN8fBIAApUBruKYvzsAAAAASUVORK5CYII='
|
export const BLUR_DATA_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN8fBIAApUBruKYvzsAAAAASUVORK5CYII='
|
||||||
|
export const DEFAULT_IMG = DefaultImg
|
||||||
|
|
||||||
export const SOCIAL_LINKS = {
|
export const SOCIAL_LINKS = {
|
||||||
FB: 'FB',
|
FB: 'FB',
|
||||||
|
Reference in New Issue
Block a user