mirror of
https://github.com/vercel/commerce.git
synced 2025-07-23 04:36:49 +00:00
Merge pull request #83 from KieIO/feature/m2-toggle-product-wishlist
Feature/m2 toggle product wishlist
This commit is contained in:
14
framework/vendure/schema.d.ts
vendored
14
framework/vendure/schema.d.ts
vendored
@@ -3247,10 +3247,22 @@ export type ActiveCustomerQuery = { __typename?: 'Query' } & {
|
|||||||
activeCustomer?: Maybe<
|
activeCustomer?: Maybe<
|
||||||
{ __typename?: 'Customer' } & Pick<
|
{ __typename?: 'Customer' } & Pick<
|
||||||
Customer,
|
Customer,
|
||||||
'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' | 'phoneNumber'
|
'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' | 'phoneNumber'| 'favorites'
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
|
export type FavoriteList = PaginatedList & {
|
||||||
|
items: [Favorite!]!
|
||||||
|
totalItems: Int!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Favorite = Node & {
|
||||||
|
id: ID!
|
||||||
|
createdAt: DateTime!
|
||||||
|
updatedAt: DateTime!
|
||||||
|
product: Product
|
||||||
|
customer: Customer!
|
||||||
|
}
|
||||||
|
|
||||||
export type GetAllProductPathsQueryVariables = Exact<{
|
export type GetAllProductPathsQueryVariables = Exact<{
|
||||||
first?: Maybe<Scalars['Int']>
|
first?: Maybe<Scalars['Int']>
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
export const toggleWishlistMutation = /* GraphQL */ `
|
||||||
|
mutation toggleFavorite($productId:ID!){
|
||||||
|
toggleFavorite(productId:$productId){
|
||||||
|
items{
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
@@ -1,17 +1,35 @@
|
|||||||
|
import { searchResultFragment } from '../fragments/search-result-fragment'
|
||||||
|
|
||||||
export const activeCustomerQuery = /* GraphQL */ `
|
export const activeCustomerQuery = /* GraphQL */ `
|
||||||
query activeCustomer {
|
query activeCustomer {
|
||||||
activeCustomer {
|
activeCustomer {
|
||||||
id
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
emailAddress
|
emailAddress
|
||||||
phoneNumber
|
favorites{
|
||||||
addresses{
|
items{
|
||||||
streetLine1
|
product{
|
||||||
city
|
id
|
||||||
province
|
name
|
||||||
postalCode
|
slug
|
||||||
|
assets{
|
||||||
|
source
|
||||||
|
preview
|
||||||
|
}
|
||||||
|
variants{
|
||||||
|
price
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
phoneNumber
|
||||||
|
addresses{
|
||||||
|
streetLine1
|
||||||
|
city
|
||||||
|
province
|
||||||
|
postalCode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
@@ -2,19 +2,38 @@ import classNames from 'classnames'
|
|||||||
import IconHeart from 'src/components/icons/IconHeart'
|
import IconHeart from 'src/components/icons/IconHeart'
|
||||||
import React, { memo } from 'react'
|
import React, { memo } from 'react'
|
||||||
import s from './ItemWishList.module.scss'
|
import s from './ItemWishList.module.scss'
|
||||||
|
import { useToggleProductWishlist } from '../../../../src/components/hooks/product'
|
||||||
|
import { useMessage } from 'src/components/contexts'
|
||||||
|
import { LANGUAGE } from 'src/utils/language.utils'
|
||||||
interface Props {
|
interface Props {
|
||||||
|
id:string,
|
||||||
isActive?: boolean,
|
isActive?: boolean,
|
||||||
onChange?: () => void
|
onChange?: () => string
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemWishList = memo(({isActive=false, onChange}:Props) => {
|
const ItemWishList = memo(({id,isActive=false, onChange}:Props) => {
|
||||||
|
const {onToggleProductWishlist} = useToggleProductWishlist();
|
||||||
|
const { showMessageSuccess, showMessageError } = useMessage();
|
||||||
|
|
||||||
|
function toggleWishlist(){
|
||||||
|
onToggleProductWishlist({productId:id},onSignupCallBack)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSignupCallBack = (isSuccess: boolean, message?: string) => {
|
||||||
|
if (isSuccess) {
|
||||||
|
// showMessageSuccess("Create account successfully. Please verify your email to login.", 15000)
|
||||||
|
} else {
|
||||||
|
showMessageError(message || LANGUAGE.MESSAGE.ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className={classNames({
|
<div className={classNames({
|
||||||
[s.heartToggle]: true,
|
[s.heartToggle]: true,
|
||||||
[s.isToggleOn]: isActive
|
[s.isToggleOn]: isActive
|
||||||
})}
|
})}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
onClick={toggleWishlist}
|
||||||
>
|
>
|
||||||
<IconHeart />
|
<IconHeart />
|
||||||
</div>
|
</div>
|
||||||
|
@@ -14,9 +14,11 @@ import ProductNotSell from './ProductNotSell/ProductNotSell'
|
|||||||
export interface ProductCardProps extends ProductCard {
|
export interface ProductCardProps extends ProductCard {
|
||||||
buttonText?: string
|
buttonText?: string
|
||||||
isSingleButton?: boolean,
|
isSingleButton?: boolean,
|
||||||
|
activeWishlist?:boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductCardComponent = ({
|
const ProductCardComponent = ({
|
||||||
|
id,
|
||||||
collection,
|
collection,
|
||||||
name,
|
name,
|
||||||
slug,
|
slug,
|
||||||
@@ -27,6 +29,7 @@ const ProductCardComponent = ({
|
|||||||
imageSrc,
|
imageSrc,
|
||||||
isNotSell,
|
isNotSell,
|
||||||
isSingleButton,
|
isSingleButton,
|
||||||
|
activeWishlist
|
||||||
}: ProductCardProps) => {
|
}: ProductCardProps) => {
|
||||||
if (isNotSell) {
|
if (isNotSell) {
|
||||||
return <div className={`${s.productCardWarpper} ${s.notSell}`}>
|
return <div className={`${s.productCardWarpper} ${s.notSell}`}>
|
||||||
@@ -34,6 +37,7 @@ const ProductCardComponent = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={s.productCardWarpper}>
|
<div className={s.productCardWarpper}>
|
||||||
<div className={s.cardTop}>
|
<div className={s.cardTop}>
|
||||||
@@ -63,7 +67,7 @@ const ProductCardComponent = ({
|
|||||||
<div className={s.cardMidBot}>
|
<div className={s.cardMidBot}>
|
||||||
<div className={s.productPrice}>{price} {currencyCode}</div>
|
<div className={s.productPrice}>{price} {currencyCode}</div>
|
||||||
<div className={s.wishList}>
|
<div className={s.wishList}>
|
||||||
<ItemWishList />
|
<ItemWishList isActive={activeWishlist} id={id}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useActiveCustomer } from 'src/components/hooks/auth'
|
||||||
import { DEFAULT_PAGE_SIZE, ROUTE } from 'src/utils/constanst.utils'
|
import { DEFAULT_PAGE_SIZE, ROUTE } from 'src/utils/constanst.utils'
|
||||||
import { ButtonCommon, EmptyCommon } from '..'
|
import { ButtonCommon, EmptyCommon } from '..'
|
||||||
import PaginationCommon from '../PaginationCommon/PaginationCommon'
|
import PaginationCommon from '../PaginationCommon/PaginationCommon'
|
||||||
import ProductCard, { ProductCardProps } from '../ProductCard/ProductCard'
|
import ProductCard, { ProductCardProps } from '../ProductCard/ProductCard'
|
||||||
import s from "./ProductList.module.scss"
|
import s from "./ProductList.module.scss"
|
||||||
|
|
||||||
interface ProductListProps {
|
interface ProductListProps {
|
||||||
data: ProductCardProps[],
|
data: ProductCardProps[],
|
||||||
total?: number,
|
total?: number,
|
||||||
@@ -16,6 +16,8 @@ interface ProductListProps {
|
|||||||
|
|
||||||
const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChange }: ProductListProps) => {
|
const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChange }: ProductListProps) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const {wishlistId } = useActiveCustomer();
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
const handlePageChange = (page: number) => {
|
||||||
onPageChange && onPageChange(page)
|
onPageChange && onPageChange(page)
|
||||||
}
|
}
|
||||||
@@ -33,7 +35,8 @@ const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChan
|
|||||||
<div className={s.list}>
|
<div className={s.list}>
|
||||||
{
|
{
|
||||||
data.map((product, index) => {
|
data.map((product, index) => {
|
||||||
return <ProductCard {...product} key={index} />
|
let activeWishlist = wishlistId?.findIndex((val:string) => val == product.id) !== -1;
|
||||||
|
return <ProductCard activeWishlist={activeWishlist} {...product} key={index} />
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@@ -1,20 +1,24 @@
|
|||||||
import { ActiveCustomerQuery } from '@framework/schema'
|
import { ActiveCustomerQuery,Favorite } from '@framework/schema'
|
||||||
import { activeCustomerQuery } from '@framework/utils/queries/active-customer-query'
|
import { activeCustomerQuery } from '@framework/utils/queries/active-customer-query'
|
||||||
import gglFetcher from 'src/utils/gglFetcher'
|
import gglFetcher from 'src/utils/gglFetcher'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
|
|
||||||
const useActiveCustomer = () => {
|
const useActiveCustomer = () => {
|
||||||
const { data, ...rest } = useSWR<ActiveCustomerQuery>([activeCustomerQuery], gglFetcher)
|
const { data, ...rest } = useSWR<ActiveCustomerQuery>([activeCustomerQuery], gglFetcher)
|
||||||
return {
|
|
||||||
customer: data?.activeCustomer,
|
return {
|
||||||
userInfo:{
|
customer: data?.activeCustomer,
|
||||||
firstName: data?.activeCustomer?.firstName,
|
userInfo:{
|
||||||
lastName:data?.activeCustomer?.lastName,
|
firstName: data?.activeCustomer?.firstName,
|
||||||
email:data?.activeCustomer?.emailAddress,
|
lastName:data?.activeCustomer?.lastName,
|
||||||
phoneNumber: data?.activeCustomer?.phoneNumber,
|
email:data?.activeCustomer?.emailAddress,
|
||||||
address: data?.activeCustomer?.addresses?.[0]
|
phoneNumber: data?.activeCustomer?.phoneNumber,
|
||||||
},
|
address: data?.activeCustomer?.addresses?.[0]
|
||||||
...rest }
|
},
|
||||||
|
itemWishlist:data?.activeCustomer?.favorites?.items,
|
||||||
|
wishlistId: data?.activeCustomer?.favorites?.items.map((val:Favorite)=>val.product.id),
|
||||||
|
...rest
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useActiveCustomer
|
export default useActiveCustomer
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export { default as useSearchProducts } from './useSearchProducts'
|
export { default as useSearchProducts } from './useSearchProducts'
|
||||||
|
export { default as useToggleProductWishlist } from './useToggleProductWishlist'
|
||||||
export { default as useProductDetail } from './useProductDetail'
|
export { default as useProductDetail } from './useProductDetail'
|
||||||
|
|
||||||
|
|
||||||
|
44
src/components/hooks/product/useToggleProductWishlist.tsx
Normal file
44
src/components/hooks/product/useToggleProductWishlist.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import useActiveCustomer from '../auth/useActiveCustomer'
|
||||||
|
import { FavoriteList } from '@framework/schema'
|
||||||
|
import fetcher from 'src/utils/fetcher'
|
||||||
|
import { CommonError } from 'src/domains/interfaces/CommonError'
|
||||||
|
import { toggleWishlistMutation } from '@framework/utils/mutations/toggle-wishlist-mutation'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
productId?:string
|
||||||
|
}
|
||||||
|
|
||||||
|
const useToggleProductWishlist = () => {
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [error, setError] = useState<Error | null>(null)
|
||||||
|
const { mutate } = useActiveCustomer()
|
||||||
|
|
||||||
|
const onToggleProductWishlist = (
|
||||||
|
{ productId }:Props ,
|
||||||
|
fCallBack: (isSuccess: boolean, message?: string) => void
|
||||||
|
) => {
|
||||||
|
setError(null)
|
||||||
|
setLoading(true)
|
||||||
|
fetcher<FavoriteList>({
|
||||||
|
query: toggleWishlistMutation,
|
||||||
|
variables: {
|
||||||
|
productId
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
mutate()
|
||||||
|
fCallBack(true)
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setError(error)
|
||||||
|
fCallBack(false, error.message)
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
return { loading, onToggleProductWishlist, error }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useToggleProductWishlist
|
@@ -13,7 +13,6 @@ import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data';
|
|||||||
import { ACCOUNT_TAB, QUERY_KEY } from "src/utils/constanst.utils"
|
import { ACCOUNT_TAB, QUERY_KEY } from "src/utils/constanst.utils"
|
||||||
import { useRouter } from "next/router"
|
import { useRouter } from "next/router"
|
||||||
import { useActiveCustomer } from 'src/components/hooks/auth'
|
import { useActiveCustomer } from 'src/components/hooks/auth'
|
||||||
import { AccountProps } from "./components/AccountInfomation/AccountInfomation"
|
|
||||||
const waiting = [
|
const waiting = [
|
||||||
{
|
{
|
||||||
id: "NO 123456",
|
id: "NO 123456",
|
||||||
@@ -77,6 +76,8 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => {
|
|||||||
|
|
||||||
const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2)
|
const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2)
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
|
// const { itemWishlist } = useActiveCustomer();
|
||||||
|
// console.log(itemWishlist)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const query = router.query[QUERY_KEY.TAB] as string
|
const query = router.query[QUERY_KEY.TAB] as string
|
||||||
|
Reference in New Issue
Block a user