From 5ace99922d3a188c5b686f067ecf7c009530ce66 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Thu, 30 Sep 2021 18:14:14 +0700 Subject: [PATCH 01/27] intt: product-collection --- src/components/hooks/useGetActiveOrder.tsx | 20 ++++++++ .../hooks/useGetProductListByCollection.tsx | 47 +++++++++++++++++++ .../modules/home/HomeBanner/HomeBanner.tsx | 8 +++- src/utils/enum.ts | 0 src/utils/types.utils.ts | 2 + 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/components/hooks/useGetActiveOrder.tsx create mode 100644 src/components/hooks/useGetProductListByCollection.tsx create mode 100644 src/utils/enum.ts diff --git a/src/components/hooks/useGetActiveOrder.tsx b/src/components/hooks/useGetActiveOrder.tsx new file mode 100644 index 000000000..818ca9e9a --- /dev/null +++ b/src/components/hooks/useGetActiveOrder.tsx @@ -0,0 +1,20 @@ +import { ActiveOrderQuery } from '@framework/schema' +import { cartFragment } from '@framework/utils/fragments/cart-fragment' +import { gql } from 'graphql-request' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' +const query = gql` + query activeOrder { + activeOrder { + ...Cart + } + } + ${ cartFragment } +` + +const useGetActiveOrder = () => { + const { data, ...rest } = useSWR([query], gglFetcher) + return { order: data?.activeOrder, ...rest } +} + +export default useGetActiveOrder diff --git a/src/components/hooks/useGetProductListByCollection.tsx b/src/components/hooks/useGetProductListByCollection.tsx new file mode 100644 index 000000000..49ec4c81b --- /dev/null +++ b/src/components/hooks/useGetProductListByCollection.tsx @@ -0,0 +1,47 @@ +// import { gql } from 'graphql-request' +import { useMemo, useState } from 'react' +// import useActiveCustomer from './useActiveCustomer' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { + CollectionList, + CollectionListOptions, + GetCollectionsQuery, + GetCollectionsQueryVariables, + LoginMutation, +} from '@framework/schema' +import { gql } from 'graphql-request' + +import { getCollectionsQuery } from '@framework/utils/queries/get-collections-query' +import useSWR from 'swr' +import gglFetcher from 'src/utils/gglFetcher' + +const query = gql` + query getCollections($option: CollectionListOptions) { + collections(options:$option) { + items { + id + name + description + slug + productVariants { + totalItems + } + parent { + id + } + children { + id + } + } + } + } +` + +const useGetProductListByCollection = (options: any) => { + + const { data, ...rest } = useSWR([query, options], gglFetcher) + return { collections: data?.collections, ...rest } +} + +export default useGetProductListByCollection diff --git a/src/components/modules/home/HomeBanner/HomeBanner.tsx b/src/components/modules/home/HomeBanner/HomeBanner.tsx index ebb9af6bf..e5e678893 100644 --- a/src/components/modules/home/HomeBanner/HomeBanner.tsx +++ b/src/components/modules/home/HomeBanner/HomeBanner.tsx @@ -1,5 +1,7 @@ -import React from 'react' +import { CollectionListOptions, GetCollectionsQuery } from '@framework/schema' +import React, { useEffect, useMemo, useState } from 'react' import { Banner, StaticImage } from 'src/components/common' +import useGetProductListByCollection from 'src/components/hooks/useGetProductListByCollection' import { ROUTE } from 'src/utils/constanst.utils' import BannerImgRight from './assets/banner_full.png' import HomeBannerImg from './assets/home_banner.png' @@ -11,6 +13,10 @@ interface Props { } const HomeBanner = ({ }: Props) => { + // const variables = useMemo(() => { + // return {option: {filter: {name: {eq: "Computers" }}}} + // }, []) + // const {collections} = useGetProductListByCollection(variables) return (
diff --git a/src/utils/enum.ts b/src/utils/enum.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index e2ce516d4..fe1a4df07 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -1,3 +1,5 @@ +import { SortOrder } from "@framework/schema"; + export interface ProductProps { category?: string name: string From 6238026b14a3c859643341d4e57937603f821ff2 Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Fri, 1 Oct 2021 10:26:06 +0700 Subject: [PATCH 02/27] khong co gitthay doi --- next-env.d.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/next-env.d.ts b/next-env.d.ts index 9bc3dd46b..c6643fda1 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,3 @@ /// /// /// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. From 19c826722057c1d0cfb5df77203838e13d565c18 Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Fri, 1 Oct 2021 18:28:17 +0700 Subject: [PATCH 03/27] feat: create RequestPasswordReset --- framework/vendure/schema.d.ts | 39 ++++++++++++++++++- .../request-password-reset-mutation.ts | 14 +++++++ .../mutations/reset-password-mutation.ts | 15 +++++++ 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 framework/vendure/utils/mutations/request-password-reset-mutation.ts create mode 100644 framework/vendure/utils/mutations/reset-password-mutation.ts diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index b0b0170d7..af6eb5051 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -1,3 +1,5 @@ +import { ResetPassword } from './schema.d'; +import { requestPasswordReset } from '@framework/schema'; export type Maybe = T | null export type Exact = { [K in keyof T]: T[K] @@ -3095,6 +3097,36 @@ export type LoginMutation = { __typename?: 'Mutation' } & { >) } +export type ResetPasswordMutation = { __typename?: 'Mutation' } & { + resetPassword: + | ({ __typename: 'CurrentUser' } & Pick) + | ({ __typename: 'PasswordResetTokenInvalidError' } & Pick< + PasswordResetTokenInvalidError, + 'errorCode' | 'message' + >) + | ({ __typename: 'PasswordResetTokenExpiredError' } & Pick< + PasswordResetTokenExpiredError, + 'errorCode' | 'message' + >) + | ({ __typename: 'NativeAuthStrategyError' } & Pick< + NativeAuthStrategyError, + 'errorCode' | 'message' + >) +} + +export type SignupMutation = { __typename?: 'Mutation' } & { + registerCustomerAccount: + | ({ __typename: 'Success' } & Pick) + | ({ __typename: 'MissingPasswordError' } & Pick< + MissingPasswordError, + 'errorCode' | 'message' + >) + | ({ __typename: 'NativeAuthStrategyError' } & Pick< + NativeAuthStrategyError, + 'errorCode' | 'message' + >) +} + export type VerifyCustomerAccountVariables = Exact<{ token: Scalars['String'] password?: Maybe @@ -3148,8 +3180,9 @@ export type SignupMutationVariables = Exact<{ input: RegisterCustomerInput }> -export type SignupMutation = { __typename?: 'Mutation' } & { - registerCustomerAccount: + +export type RequestPasswordReset = { __typename?: 'Mutation' } & { + requestPasswordReset: | ({ __typename: 'Success' } & Pick) | ({ __typename: 'MissingPasswordError' } & Pick< MissingPasswordError, @@ -3161,6 +3194,8 @@ export type SignupMutation = { __typename?: 'Mutation' } & { >) } + + export type ActiveCustomerQueryVariables = Exact<{ [key: string]: never }> export type ActiveCustomerQuery = { __typename?: 'Query' } & { diff --git a/framework/vendure/utils/mutations/request-password-reset-mutation.ts b/framework/vendure/utils/mutations/request-password-reset-mutation.ts new file mode 100644 index 000000000..474d8f33f --- /dev/null +++ b/framework/vendure/utils/mutations/request-password-reset-mutation.ts @@ -0,0 +1,14 @@ +export const requestPasswordReset = /* GraphQL */ ` +mutation RequestPasswordReset($emailAddress: String!) { + requestPasswordReset(emailAddress: $emailAddress) { + __typename + ...on Success{ + success + } + ...on ErrorResult{ + errorCode + message + } + } +} +` \ No newline at end of file diff --git a/framework/vendure/utils/mutations/reset-password-mutation.ts b/framework/vendure/utils/mutations/reset-password-mutation.ts new file mode 100644 index 000000000..8ff4058ed --- /dev/null +++ b/framework/vendure/utils/mutations/reset-password-mutation.ts @@ -0,0 +1,15 @@ +export const resetPasswordMutation = /* GraphQL */ ` +mutation resetPassword($token: String!,$password: String!){ + resetPassword(token: $token,password: $password){ + __typename + ...on CurrentUser{ + id + identifier + } + ...on ErrorResult{ + errorCode + message + } + } +} +` \ No newline at end of file From 7f927a0ba34960c17b4726796e5a7824f5c6c14a Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Mon, 4 Oct 2021 09:14:58 +0700 Subject: [PATCH 04/27] feat: RequestPasswordReset --- pages/forgot-password.tsx | 10 ++ pages/reset-password.tsx | 10 ++ .../FormForgot/FormForgot.module.scss | 22 ++++ .../ForgotPassword/FormForgot/FormForgot.tsx | 89 +++++++++++++++ .../FormResetPassword.module.scss | 27 +++++ .../FormResetPassword/FormResetPassword.tsx | 108 ++++++++++++++++++ .../components/HeaderMenu/HeaderMenu.tsx | 4 + src/components/common/index.ts | 2 + src/components/hooks/auth/index.ts | 2 + .../hooks/auth/useRequestPasswordReset.tsx | 50 ++++++++ .../hooks/auth/useResetPassword.tsx | 52 +++++++++ 11 files changed, 376 insertions(+) create mode 100644 pages/forgot-password.tsx create mode 100644 pages/reset-password.tsx create mode 100644 src/components/common/ForgotPassword/FormForgot/FormForgot.module.scss create mode 100644 src/components/common/ForgotPassword/FormForgot/FormForgot.tsx create mode 100644 src/components/common/ForgotPassword/FormResetPassword/FormResetPassword.module.scss create mode 100644 src/components/common/ForgotPassword/FormResetPassword/FormResetPassword.tsx create mode 100644 src/components/hooks/auth/useRequestPasswordReset.tsx create mode 100644 src/components/hooks/auth/useResetPassword.tsx diff --git a/pages/forgot-password.tsx b/pages/forgot-password.tsx new file mode 100644 index 000000000..8d4b1e570 --- /dev/null +++ b/pages/forgot-password.tsx @@ -0,0 +1,10 @@ +import { FormForgot, Layout } from 'src/components/common' + +export default function NotFound() { + return ( +
+ +
+ ) +} +NotFound.Layout = Layout diff --git a/pages/reset-password.tsx b/pages/reset-password.tsx new file mode 100644 index 000000000..bc8905da3 --- /dev/null +++ b/pages/reset-password.tsx @@ -0,0 +1,10 @@ +import { FormResetPassword, Layout } from 'src/components/common' + +export default function NotFound() { + return ( +
+ +
+ ) +} +NotFound.Layout = Layout diff --git a/src/components/common/ForgotPassword/FormForgot/FormForgot.module.scss b/src/components/common/ForgotPassword/FormForgot/FormForgot.module.scss new file mode 100644 index 000000000..57b39c56c --- /dev/null +++ b/src/components/common/ForgotPassword/FormForgot/FormForgot.module.scss @@ -0,0 +1,22 @@ +@import '../../../../styles/utilities'; +.formAuthen{ + width: 50%; + margin: 0 auto; + padding: 4rem 0 ; + .title{ + @apply font-heading heading-3; + padding: 0 1.6rem 0 0.8rem; + margin-bottom: 2rem; + } + .bottom { + @apply flex justify-between items-center; + margin: 4rem auto; + .remembered { + @apply font-bold cursor-pointer; + color: var(--primary); + } + } + .socialAuthen{ + margin-bottom: 3rem; + } +} diff --git a/src/components/common/ForgotPassword/FormForgot/FormForgot.tsx b/src/components/common/ForgotPassword/FormForgot/FormForgot.tsx new file mode 100644 index 000000000..834c65919 --- /dev/null +++ b/src/components/common/ForgotPassword/FormForgot/FormForgot.tsx @@ -0,0 +1,89 @@ +import { Form, Formik } from 'formik'; +import React, { useRef } from 'react'; +import { ButtonCommon, InputFiledInForm } from 'src/components/common'; +import { useModalCommon } from 'src/components/hooks'; +import useRequestPasswordReset from 'src/components/hooks/auth/useRequestPasswordReset'; +import { CustomInputCommon } from 'src/utils/type.utils'; +import * as Yup from 'yup'; +import ModalAuthenticate from '../../ModalAuthenticate/ModalAuthenticate'; +import { default as s, default as styles } from './FormForgot.module.scss'; +import { useMessage } from 'src/components/contexts' +import { LANGUAGE } from 'src/utils/language.utils' + +interface Props { + +} +const DisplayingErrorMessagesSchema = Yup.object().shape({ + email: Yup.string().email('Your email was wrong').required('Required') +}) + +const FormForgot = ({ }: Props) => { + const {requestPassword} = useRequestPasswordReset(); + const { showMessageSuccess, showMessageError } = useMessage(); + + const emailRef = useRef(null); + + const { visible: visibleModalAuthen,closeModal: closeModalAuthen, openModal: openModalAuthen } = useModalCommon({ initialValue: false }); + + const onForgot = (values: { email: string }) => { + requestPassword({email: values.email},onForgotPasswordCallBack); + } + + const onForgotPasswordCallBack = (isSuccess: boolean, message?: string) => { + if (isSuccess) { + showMessageSuccess("Request forgot password successfully. Please verify your email to login.") + } else { + showMessageError(message || LANGUAGE.MESSAGE.ERROR) + } + } + + return ( +
+
+
+
Forgot Password
+ + {({ errors, touched, isValid, submitForm }) => ( +
+
+ +
+
+
+ I Remembered My Password? +
+ + Reset Password + +
+
+ )} +
+
+ +
+
+ ) + + +} + + +export default FormForgot; \ No newline at end of file diff --git a/src/components/common/ForgotPassword/FormResetPassword/FormResetPassword.module.scss b/src/components/common/ForgotPassword/FormResetPassword/FormResetPassword.module.scss new file mode 100644 index 000000000..faf1b7f06 --- /dev/null +++ b/src/components/common/ForgotPassword/FormResetPassword/FormResetPassword.module.scss @@ -0,0 +1,27 @@ +@import '../../../../styles/utilities'; +.formAuthen{ + width: 50%; + margin: 0 auto; + padding: 4rem 0 ; + .title{ + @apply font-heading heading-3; + padding: 0 1.6rem 0 0.8rem; + margin-bottom: 2rem; + } + .passwordNote { + @apply text-center caption text-label; + margin-top: 0.8rem; + } + .bottom { + @apply flex justify-center items-center; + margin: 4rem auto; + .remembered { + @apply font-bold cursor-pointer; + color: var(--primary); + } + } + .confirmPassword{ + margin-top: 2rem; + } + +} diff --git a/src/components/common/ForgotPassword/FormResetPassword/FormResetPassword.tsx b/src/components/common/ForgotPassword/FormResetPassword/FormResetPassword.tsx new file mode 100644 index 000000000..ad41396ab --- /dev/null +++ b/src/components/common/ForgotPassword/FormResetPassword/FormResetPassword.tsx @@ -0,0 +1,108 @@ +import { Form, Formik } from 'formik'; +import React, { useRef } from 'react'; +import { ButtonCommon, InputPasswordFiledInForm } from 'src/components/common'; +import { useMessage } from 'src/components/contexts'; +import useRequestPasswordReset from 'src/components/hooks/auth/useRequestPasswordReset'; +import { LANGUAGE } from 'src/utils/language.utils'; +import { CustomInputCommon } from 'src/utils/type.utils'; +import * as Yup from 'yup'; +import { useRouter } from 'next/router' +import { default as s, default as styles } from './FormResetPassword.module.scss'; +import { useResetPassword } from 'src/components/hooks/auth'; + +interface Props { + +} +const DisplayingErrorMessagesSchema = Yup.object().shape({ + password: Yup.string() + .matches( + /^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])((?=.*[0-9!@#$%^&*()\-_=+{};:,<.>]){1}).*$/, + 'Must contain 8 characters with at least 1 uppercase and 1 lowercase letter and either 1 number or 1 special character.' + ) + .max(30, 'Password is too long') + .required('Required'), + confirmPassword: Yup.string() + .label('Password Confirm') + .required() + .oneOf([Yup.ref('password')], 'Passwords does not match'), +}) + +const FormResetPassword = ({ }: Props) => { + const router = useRouter(); + + const {resetPassword} = useResetPassword(); + + const { showMessageSuccess, showMessageError } = useMessage(); + + const onReset = (values: {password: string }) => { + const { token } = router.query; + resetPassword({token:token,password: values.password},onResetPasswordCallBack); + } + + const onResetPasswordCallBack = (isSuccess: boolean, message?: string) => { + if (isSuccess) { + showMessageSuccess("Reset password successfully. Please to login.") + } else { + showMessageError(message || LANGUAGE.MESSAGE.ERROR) + } + } + + return ( +
+
+
+
Reset Password
+ + {({ errors, touched, isValid, submitForm }) => ( +
+
+ +
+
+ +
+ +
+ Must contain 8 characters with at least 1 uppercase and 1 + lowercase letter and either 1 number or 1 special character. +
+
+ + Change Password + +
+
+ )} +
+
+
+
+ ) +} + + +export default FormResetPassword; \ No newline at end of file diff --git a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx index 4f7e5d21a..5922e5017 100644 --- a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx +++ b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx @@ -60,6 +60,10 @@ const HeaderMenu = memo( onClick: openModalRegister, name: 'Create account', }, + { + link: '/forgot-password', + name: 'Forgot Password', + }, ], [openModalLogin, openModalRegister] ) diff --git a/src/components/common/index.ts b/src/components/common/index.ts index eaa33176c..42d326690 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -51,5 +51,7 @@ export { default as LayoutCheckout} from './LayoutCheckout/LayoutCheckout' export { default as InputPasswordFiledInForm} from './InputPasswordFiledInForm/InputPasswordFiledInForm' export { default as InputFiledInForm} from './InputFiledInForm/InputFiledInForm' export { default as MessageCommon} from './MessageCommon/MessageCommon' +export { default as FormForgot} from './ForgotPassword/FormForgot/FormForgot' +export { default as FormResetPassword} from './ForgotPassword/FormResetPassword/FormResetPassword' diff --git a/src/components/hooks/auth/index.ts b/src/components/hooks/auth/index.ts index 845617bcd..ffd93b6e6 100644 --- a/src/components/hooks/auth/index.ts +++ b/src/components/hooks/auth/index.ts @@ -3,4 +3,6 @@ export { default as useLogin } from './useLogin' export { default as useLogout } from './useLogout' export { default as useVerifyCustomer } from './useVerifyCustomer' export { default as useActiveCustomer } from './useActiveCustomer' +export { default as useRequestPasswordReset } from './useRequestPasswordReset' +export { default as useResetPassword } from './useResetPassword' diff --git a/src/components/hooks/auth/useRequestPasswordReset.tsx b/src/components/hooks/auth/useRequestPasswordReset.tsx new file mode 100644 index 000000000..f30c1ab44 --- /dev/null +++ b/src/components/hooks/auth/useRequestPasswordReset.tsx @@ -0,0 +1,50 @@ +import { useState } from 'react' +import useActiveCustomer from './useActiveCustomer' +import fetcher from 'src/utils/fetcher' +import { CommonError } from 'src/domains/interfaces/CommonError' +import { requestPasswordReset } from '@framework/utils/mutations/request-password-reset-mutation' +import { RequestPasswordReset } from '@framework/schema' + +interface ForgotPassword { + email: string +} + +const useRequestPasswordReset = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + // const { mutate } = useActiveCustomer() + + const requestPassword = ( + {email}: ForgotPassword, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + fetcher({ + query: requestPasswordReset, + variables: { + emailAddress: email + }, + }) + .then((data) => { + if (data.requestPasswordReset.__typename !== 'Success') { + throw CommonError.create( + data.requestPasswordReset.message, + data.requestPasswordReset.errorCode + ) + } + // mutate() + fCallBack(true) + return data + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, requestPassword, error } +} + +export default useRequestPasswordReset diff --git a/src/components/hooks/auth/useResetPassword.tsx b/src/components/hooks/auth/useResetPassword.tsx new file mode 100644 index 000000000..788d496df --- /dev/null +++ b/src/components/hooks/auth/useResetPassword.tsx @@ -0,0 +1,52 @@ +import { useState } from 'react' +import useActiveCustomer from './useActiveCustomer' +import fetcher from 'src/utils/fetcher' +import { CommonError } from 'src/domains/interfaces/CommonError' +import { resetPasswordMutation } from '@framework/utils/mutations/reset-password-mutation' +import { ResetPasswordMutation } from '@framework/schema' + +interface Props { + token?: string| string[] , + password:string +} + +const useResetPassword = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) +// const { mutate } = useActiveCustomer() + + const resetPassword = ( + {token,password}: Props, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + fetcher({ + query: resetPasswordMutation, + variables: { + token: token, + password:password + }, + }) + .then((data) => { + if (data.resetPassword.__typename !== 'CurrentUser') { + throw CommonError.create( + data.resetPassword.message, + data.resetPassword.errorCode + ) + } + // mutate() + fCallBack(true) + return data + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, resetPassword, error } +} + +export default useResetPassword From 4c6b8a39e87c0b0dc12e132ef31dcb9360b13d3e Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Mon, 4 Oct 2021 11:07:00 +0700 Subject: [PATCH 05/27] Merge branch 'fixbug-13/9/2021-datnguyen' of github.com:KieIO/grocery-vercel-commerce into fixbug-13/9/2021-datnguyen --- src/components/common/CartDrawer/CartDrawer.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/common/CartDrawer/CartDrawer.tsx b/src/components/common/CartDrawer/CartDrawer.tsx index 03cb966ad..87d357b2a 100644 --- a/src/components/common/CartDrawer/CartDrawer.tsx +++ b/src/components/common/CartDrawer/CartDrawer.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { useCartDrawer } from 'src/components/contexts'; +import useGetActiveOrder from 'src/components/hooks/useGetActiveOrder'; import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data'; import { DrawerCommon } from '..'; import s from './CartDrawer.module.scss'; @@ -14,9 +15,10 @@ interface Props { const CartDrawer = ({ }: Props) => { const { cartVisible, closeCartDrawer } = useCartDrawer() + const {order} = useGetActiveOrder() return (
From e12c43f3935e7e153b4d7fee3fa5767c04fc8721 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Mon, 4 Oct 2021 16:38:02 +0700 Subject: [PATCH 06/27] get veggie --- .../api/operations/get-all-products.ts | 3 +- pages/index.tsx | 57 +++++++++++-------- .../common/CartDrawer/CartDrawer.tsx | 2 +- src/components/hooks/cart/index.ts | 2 + .../hooks/cart/useAddProductToCart.tsx | 40 +++++++++++++ .../hooks/{ => cart}/useGetActiveOrder.tsx | 0 src/utils/constanst.utils.ts | 6 ++ src/utils/funtion.utils.ts | 7 +++ src/utils/types.utils.ts | 11 +++- 9 files changed, 100 insertions(+), 28 deletions(-) create mode 100644 src/components/hooks/cart/index.ts create mode 100644 src/components/hooks/cart/useAddProductToCart.tsx rename src/components/hooks/{ => cart}/useGetActiveOrder.tsx (100%) diff --git a/framework/vendure/api/operations/get-all-products.ts b/framework/vendure/api/operations/get-all-products.ts index 1f558a7cb..c9cbc2f19 100644 --- a/framework/vendure/api/operations/get-all-products.ts +++ b/framework/vendure/api/operations/get-all-products.ts @@ -5,7 +5,7 @@ import { normalizeSearchResult } from '../../utils/normalize' import { getAllProductsQuery } from '../../utils/queries/get-all-products-query' import { OperationContext } from '@commerce/api/operations' -export type ProductVariables = { first?: number, facetValueIds?: string[] } +export type ProductVariables = { first?: number, facetValueIds?: string[], collectionSlug?:string } export default function getAllProductsOperation({ commerce, @@ -31,6 +31,7 @@ export default function getAllProductsOperation({ input: { take: vars.first, facetValueIds: vars.facetValueIds, + collectionSlug : vars.collectionSlug, groupByProduct: true, }, } diff --git a/pages/index.tsx b/pages/index.tsx index 3082d1790..55b5dd5a5 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,20 +1,21 @@ import { ProductVariables } from '@framework/api/operations/get-all-products'; -import { Product } from '@framework/schema'; +import { Facet, Product } from '@framework/schema'; import commerce from '@lib/api/commerce'; +import { ifError } from 'assert'; import { GetStaticPropsContext } from 'next'; import { Layout } from 'src/components/common'; import { FeaturedProductsCarousel, HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeRecipe, HomeSubscribe, HomeVideo } from 'src/components/modules/home'; import HomeSpice from 'src/components/modules/home/HomeSpice/HomeSpice'; -import { getAllFeaturedFacetId, getFreshProductFacetId } from 'src/utils/funtion.utils'; +import { FACET } from 'src/utils/constanst.utils'; +import { getAllFeaturedFacetId, getFacetIdByName, getFreshProductFacetId } from 'src/utils/funtion.utils'; interface Props { - freshProducts: Product[], - featuredProducts: Product[], - + veggie: Product[], + facets:Facet[] } -export default function Home({ freshProducts, featuredProducts }: Props) { - console.log("total: ", freshProducts.length, featuredProducts.length) - console.log("rs: ", freshProducts, featuredProducts) +export default function Home({ veggie, facets }: Props) { + // console.log("total: ", freshProducts.length, featuredProducts.length) + console.log("rs: ", veggie) return ( <> @@ -46,37 +47,43 @@ export async function getStaticProps({ config, preview, }) - - + const freshProductvariables: ProductVariables = {} - const freshFacetId = getFreshProductFacetId(facets) - - if (freshFacetId) { - freshProductvariables.facetValueIds = [freshFacetId] + // const freshFacetId = getFreshProductFacetId(facets) + const veggieId = getFacetIdByName(facets,FACET.CATEGORY.PARENT_NAME,FACET.CATEGORY.VEGGIE) + console.log("veggieId",veggieId) + console.log("facets",facets) + if (veggieId) { + freshProductvariables.facetValueIds = [veggieId] } + // if (freshFacetId) { + // freshProductvariables.facetValueIds = [freshFacetId] + // } const freshProductsPromise = commerce.getAllProducts({ variables: freshProductvariables, config, preview, }) - const allFeaturedFacetId = getAllFeaturedFacetId(facets) - const featuredProductsPromise = commerce.getAllProducts({ - variables: { - facetValueIds: allFeaturedFacetId - }, - config, - preview, - }) + // const allFeaturedFacetId = getAllFeaturedFacetId(facets) + // const featuredProductsPromise = commerce.getAllProducts({ + // variables: { + // facetValueIds: allFeaturedFacetId + // }, + // config, + // preview, + // }) try { - const rs = await Promise.all([freshProductsPromise, featuredProductsPromise]) + const rs = await Promise.all([freshProductsPromise]) + // const rs = await Promise.all([freshProductsPromise, featuredProductsPromise]) return { props: { - freshProducts: rs[0].products, - featuredProducts: rs[1].products + veggie: rs[0].products, + // featuredProducts: rs[1].products + facets }, revalidate: 60, } diff --git a/src/components/common/CartDrawer/CartDrawer.tsx b/src/components/common/CartDrawer/CartDrawer.tsx index 87d357b2a..daeae0513 100644 --- a/src/components/common/CartDrawer/CartDrawer.tsx +++ b/src/components/common/CartDrawer/CartDrawer.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useCartDrawer } from 'src/components/contexts'; -import useGetActiveOrder from 'src/components/hooks/useGetActiveOrder'; +import useGetActiveOrder from 'src/components/hooks/cart/useGetActiveOrder'; import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data'; import { DrawerCommon } from '..'; import s from './CartDrawer.module.scss'; diff --git a/src/components/hooks/cart/index.ts b/src/components/hooks/cart/index.ts new file mode 100644 index 000000000..c0235c81c --- /dev/null +++ b/src/components/hooks/cart/index.ts @@ -0,0 +1,2 @@ +export { default as useAddProductToCart } from './useAddProductToCart' +export { default as useGetActiveOrder } from './useGetActiveOrder' \ No newline at end of file diff --git a/src/components/hooks/cart/useAddProductToCart.tsx b/src/components/hooks/cart/useAddProductToCart.tsx new file mode 100644 index 000000000..2e6c538e2 --- /dev/null +++ b/src/components/hooks/cart/useAddProductToCart.tsx @@ -0,0 +1,40 @@ +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { AddItemToOrderMutation, AddItemToOrderMutationVariables } from '@framework/schema' +import { errorMapping } from 'src/utils/errrorMapping' +import { useGetActiveOrder } from '.' +import { addItemToOrderMutation } from '@framework/utils/mutations/add-item-to-order-mutation' + +const useAddProductToCart = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrder() + + const addProduct = (options:AddItemToOrderMutationVariables, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: addItemToOrderMutation , + variables: options, + }) + .then(({ data }) => { + if (data.addItemToOrder.__typename !== "Order") { + throw CommonError.create(errorMapping(data.addItemToOrder.message), data.addItemToOrder.errorCode) + } + mutate() + fCallBack(true) + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, addProduct, error } +} + +export default useAddProductToCart diff --git a/src/components/hooks/useGetActiveOrder.tsx b/src/components/hooks/cart/useGetActiveOrder.tsx similarity index 100% rename from src/components/hooks/useGetActiveOrder.tsx rename to src/components/hooks/cart/useGetActiveOrder.tsx diff --git a/src/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index f66d6a7ea..2d85951a7 100644 --- a/src/utils/constanst.utils.ts +++ b/src/utils/constanst.utils.ts @@ -1,3 +1,5 @@ +import { FacetConstant } from "./types.utils" + export const BLUR_DATA_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN8fBIAApUBruKYvzsAAAAASUVORK5CYII=' export const SOCIAL_LINKS = { @@ -113,6 +115,10 @@ export const FACET = { PARENT_NAME: 'Featured', FRESH: 'Fresh', BEST_SELLERS: 'Best seller' + }, + CATEGORY: { + PARENT_NAME:"category", + VEGGIE:"veggie" } } diff --git a/src/utils/funtion.utils.ts b/src/utils/funtion.utils.ts index d2ad83be1..4c0265a19 100644 --- a/src/utils/funtion.utils.ts +++ b/src/utils/funtion.utils.ts @@ -21,6 +21,13 @@ export function getFreshProductFacetId(facets: Facet[]) { return freshFacetValue?.id } +export function getFacetIdByName(facets: Facet[], facetName: string, valueName:string) { + const featuredFacet = facets.find((item: Facet) => item.name === facetName) + const freshFacetValue = featuredFacet?.values.find((item: FacetValue) => item.name === valueName) + return freshFacetValue?.id +} + + export function getAllFeaturedFacetId(facets: Facet[]) { const featuredFacet = facets.find((item: Facet) => item.name === FACET.FEATURE.PARENT_NAME) const rs = featuredFacet?.values.map((item: FacetValue) => item.id) diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index fe1a4df07..7936675e8 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -52,4 +52,13 @@ export type filterContextType = { visible: boolean; open: () => void; close: () => void; -}; \ No newline at end of file +}; + +export interface StringMap { [key: string]: string; } + +export interface FacetMap extends StringMap{ + PARENT_NAME: string +} +export interface FacetConstant{ + [key: string]: FacetMap; +} \ No newline at end of file From c2c0531663e05f3ad361e5df97d4c7a94741314a Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Tue, 5 Oct 2021 11:52:11 +0700 Subject: [PATCH 07/27] bug: edit form user info --- framework/vendure/schema.d.ts | 5 +++- .../vendure/utils/queries/user-info-query.ts | 15 ++++++++++++ next-env.d.ts | 3 --- src/components/hooks/user/useUserInfo.tsx | 12 ++++++++++ .../account/AccountPage/AccountPage.tsx | 23 ++++++++++++++++--- .../AccountInfomation/AccountInfomation.tsx | 16 ++++++------- .../EditInfoModal/EditInfoModal.tsx | 11 ++++----- 7 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 framework/vendure/utils/queries/user-info-query.ts create mode 100644 src/components/hooks/user/useUserInfo.tsx diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index b0b0170d7..91be7742d 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -317,6 +317,9 @@ export type Address = Node & { customFields?: Maybe } + + + export type Asset = Node & { __typename?: 'Asset' id: Scalars['ID'] @@ -3167,7 +3170,7 @@ export type ActiveCustomerQuery = { __typename?: 'Query' } & { activeCustomer?: Maybe< { __typename?: 'Customer' } & Pick< Customer, - 'id' | 'firstName' | 'lastName' | 'emailAddress' + 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' > > } diff --git a/framework/vendure/utils/queries/user-info-query.ts b/framework/vendure/utils/queries/user-info-query.ts new file mode 100644 index 000000000..a10acd365 --- /dev/null +++ b/framework/vendure/utils/queries/user-info-query.ts @@ -0,0 +1,15 @@ +export const userInfoQuery = /* GraphQL */ ` + query activeCustomer{ + activeCustomer{ + emailAddress + addresses{ + name:fullName + address:streetLine1 + city + state:province + postalCode + phoneNumber + } + } + } +` diff --git a/next-env.d.ts b/next-env.d.ts index 9bc3dd46b..c6643fda1 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,3 @@ /// /// /// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/src/components/hooks/user/useUserInfo.tsx b/src/components/hooks/user/useUserInfo.tsx new file mode 100644 index 000000000..69b80a467 --- /dev/null +++ b/src/components/hooks/user/useUserInfo.tsx @@ -0,0 +1,12 @@ +import { ActiveCustomerQuery } from '@framework/schema' +import { userInfoQuery } from '@framework/utils/queries/user-info-query' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' + +const useUserInfo = () => { + const { data } = useSWR([userInfoQuery], gglFetcher) + + return { userInfo: data?.activeCustomer} +} + +export default useUserInfo diff --git a/src/components/modules/account/AccountPage/AccountPage.tsx b/src/components/modules/account/AccountPage/AccountPage.tsx index db5801235..e7154f46f 100644 --- a/src/components/modules/account/AccountPage/AccountPage.tsx +++ b/src/components/modules/account/AccountPage/AccountPage.tsx @@ -12,7 +12,9 @@ import EditInfoModal from './components/EditInfoModal/EditInfoModal' import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data'; import { ACCOUNT_TAB, QUERY_KEY } from "src/utils/constanst.utils" import { useRouter } from "next/router" - +import { useActiveCustomer } from 'src/components/hooks/auth' +import useUserInfo from "src/components/hooks/user/useUserInfo" +import { AccountProps } from "./components/AccountInfomation/AccountInfomation" const waiting = [ { id: "NO 123456", @@ -53,9 +55,10 @@ const delivered = [ ] let account = { - name: "vu duong", + firstName: "Nhân", + lastName: "Trần", email: "vuduong@gmail.com", - address: "234 Dien Bien Phu Bis, Dakao ward", + address: "235 Dien Bien Phu Bis, Dakao ward", state: "District 1", city: "HCMC", postalCode: "700000", @@ -80,6 +83,20 @@ const getTabIndex = (tab?: string): number => { const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { const router = useRouter() + + const {userInfo} = useUserInfo(); + + // const email = userInfo?.emailAddress; + // const [info] = userInfo?.addresses || []; + + // const accountInfo = {...info,userInfo?.emailAddress}; + + // const clone:AccountProps = Object.create(accountInfo); + // Object.assign(clone, accountInfo); + + + console.log(); + const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2) const [modalVisible, setModalVisible] = useState(false); diff --git a/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx index b025d5744..dc32db71a 100644 --- a/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx +++ b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx @@ -7,14 +7,14 @@ import avatar from '../../assets/avatar.png' import { ButtonCommon } from 'src/components/common' import { useActiveCustomer } from 'src/components/hooks/auth' -interface AccountProps { - name: string - email: string - address: string - state: string - city: string - postalCode: string - phoneNumber: string +export interface AccountProps { + name?: string + email?: string + address?: string + state?: string + city?: string + postalCode?: string + phoneNumber?: string } interface AccountInfomationProps { diff --git a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx index 06e6b2124..f9e4aebd5 100644 --- a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx +++ b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx @@ -4,7 +4,7 @@ import s from './EditInfoModal.module.scss' import { ModalCommon, Inputcommon, SelectCommon, ButtonCommon } from '../../../../../common' interface EditInfoModalProps { - accountInfo: {name: string, email: string, address: string, state: string, city: string, postalCode: string, phoneNumber: string}; + accountInfo: {firstName: string,lastName: string, email: string, address: string, state: string, city: string, postalCode: string, phoneNumber: string}; visible: boolean; closeModal: () => void; } @@ -25,12 +25,11 @@ const EditInfoModal = ({ accountInfo, visible = false, closeModal }: EditInfoMod
- -
- -
- +
+
+ +
From dcfa1a1ecedafe965c7696d8996d35200d924751 Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Wed, 6 Oct 2021 12:10:04 +0700 Subject: [PATCH 08/27] feat: get-edit-user-info --- framework/vendure/schema.d.ts | 16 +- .../update-customer-address-mutation.ts | 14 ++ .../mutations/update-customer-mutation.ts | 13 ++ .../utils/queries/active-customer-query.ts | 7 + .../vendure/utils/queries/user-info-query.ts | 9 +- .../SelectCommon/SelectCommon.module.scss | 2 +- .../common/SelectCommon/SelectCommon.tsx | 10 +- .../hooks/auth/useActiveCustomer.tsx | 11 +- src/components/hooks/auth/useSignup.tsx | 1 - src/components/hooks/index.ts | 3 + .../hooks/user/useEditCustomerAddress.tsx | 55 +++++ src/components/hooks/user/useEditUserInfo.tsx | 51 +++++ src/components/hooks/user/useUserInfo.tsx | 12 - .../account/AccountPage/AccountPage.tsx | 30 +-- .../AccountInfomation/AccountInfomation.tsx | 23 +- .../EditInfoModal/EditInfoModal.module.scss | 10 + .../EditInfoModal/EditInfoModal.tsx | 209 +++++++++++++++--- 17 files changed, 380 insertions(+), 96 deletions(-) create mode 100644 framework/vendure/utils/mutations/update-customer-address-mutation.ts create mode 100644 framework/vendure/utils/mutations/update-customer-mutation.ts create mode 100644 src/components/hooks/user/useEditCustomerAddress.tsx create mode 100644 src/components/hooks/user/useEditUserInfo.tsx delete mode 100644 src/components/hooks/user/useUserInfo.tsx diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index 709b1f48b..b3ea2a038 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -1,4 +1,4 @@ -import { FacetValue } from './schema.d'; +import { FacetValue, UpdateAddressInput } from './schema.d'; export type Maybe = T | null export type Exact = { [K in keyof T]: T[K] @@ -304,6 +304,11 @@ export type MutationResetPasswordArgs = { } export type Address = Node & { + updateCustomerAddress: + | { + __typename?: 'Address' + id: Scalars['ID'] + } __typename?: 'Address' id: Scalars['ID'] createdAt: Scalars['DateTime'] @@ -1462,6 +1467,11 @@ export type CustomerListOptions = { } export type Customer = Node & { + updateCustomer: + | { + __typename?: 'Customer' + id: Scalars['ID'] + } __typename?: 'Customer' id: Scalars['ID'] createdAt: Scalars['DateTime'] @@ -1469,7 +1479,7 @@ export type Customer = Node & { title?: Maybe firstName: Scalars['String'] lastName: Scalars['String'] - phoneNumber?: Maybe + phoneNumber?: Maybe emailAddress: Scalars['String'] addresses?: Maybe> orders: OrderList @@ -3201,7 +3211,7 @@ export type ActiveCustomerQuery = { __typename?: 'Query' } & { activeCustomer?: Maybe< { __typename?: 'Customer' } & Pick< Customer, - 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' + 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' | 'phoneNumber' > > } diff --git a/framework/vendure/utils/mutations/update-customer-address-mutation.ts b/framework/vendure/utils/mutations/update-customer-address-mutation.ts new file mode 100644 index 000000000..4cac594ed --- /dev/null +++ b/framework/vendure/utils/mutations/update-customer-address-mutation.ts @@ -0,0 +1,14 @@ +export const updateCustomerAddress = /* GraphQL */ ` + mutation updateCustomerAddress($input: UpdateAddressInput!){ + updateCustomerAddress(input: $input){ + __typename + ...on Address{ + id + streetLine1 + city + postalCode + province + } + } + } +` diff --git a/framework/vendure/utils/mutations/update-customer-mutation.ts b/framework/vendure/utils/mutations/update-customer-mutation.ts new file mode 100644 index 000000000..535f80eee --- /dev/null +++ b/framework/vendure/utils/mutations/update-customer-mutation.ts @@ -0,0 +1,13 @@ +export const updateCustomer = /* GraphQL */ ` + mutation updateCustomer($input: UpdateCustomerInput!){ + updateCustomer(input:$input){ + __typename + ...on Customer{ + id + firstName + lastName + phoneNumber + } + } + } +` diff --git a/framework/vendure/utils/queries/active-customer-query.ts b/framework/vendure/utils/queries/active-customer-query.ts index 65b280743..b1598d8de 100644 --- a/framework/vendure/utils/queries/active-customer-query.ts +++ b/framework/vendure/utils/queries/active-customer-query.ts @@ -5,6 +5,13 @@ export const activeCustomerQuery = /* GraphQL */ ` firstName lastName emailAddress + phoneNumber + addresses{ + streetLine1 + city + province + postalCode + } } } ` diff --git a/framework/vendure/utils/queries/user-info-query.ts b/framework/vendure/utils/queries/user-info-query.ts index a10acd365..5e5fa24cb 100644 --- a/framework/vendure/utils/queries/user-info-query.ts +++ b/framework/vendure/utils/queries/user-info-query.ts @@ -1,14 +1,15 @@ export const userInfoQuery = /* GraphQL */ ` query activeCustomer{ activeCustomer{ + lastName + firstName emailAddress + phoneNumber addresses{ - name:fullName - address:streetLine1 + streetLine1 city - state:province + province postalCode - phoneNumber } } } diff --git a/src/components/common/SelectCommon/SelectCommon.module.scss b/src/components/common/SelectCommon/SelectCommon.module.scss index 82ce46f5b..3f213b567 100644 --- a/src/components/common/SelectCommon/SelectCommon.module.scss +++ b/src/components/common/SelectCommon/SelectCommon.module.scss @@ -11,7 +11,7 @@ width: 20.6rem; .selectTrigger { width: 20.6rem; - padding: 1.2rem 1.6rem; + padding: 1.6rem; } } &.large { diff --git a/src/components/common/SelectCommon/SelectCommon.tsx b/src/components/common/SelectCommon/SelectCommon.tsx index 9b8c88e24..122d9a78d 100644 --- a/src/components/common/SelectCommon/SelectCommon.tsx +++ b/src/components/common/SelectCommon/SelectCommon.tsx @@ -1,10 +1,12 @@ import s from './SelectCommon.module.scss' import classNames from 'classnames' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { IconVectorDown } from 'src/components/icons' import SelectOption from './SelectOption/SelectOption' interface Props { + selected?:string|null, + initValue?:string|null, placeholder? : string, size?: 'base' | 'large', type?: 'default' | 'custom', @@ -12,10 +14,14 @@ interface Props { onChange?: (value: string) => void, } -const SelectCommon = ({ type = 'default', size = 'base', option, placeholder, onChange}: Props) => { +const SelectCommon = ({selected,initValue, type = 'default', size = 'base', option, placeholder, onChange}: Props) => { const [selectedName, setSelectedName] = useState(placeholder) const [selectedValue, setSelectedValue] = useState('') + useEffect(()=>{ + setSelectedValue(selected ?? ''); + setSelectedValue(initValue ?? ''); + }) const changeSelectedName = (item:string, value: string) => { setSelectedValue(value) setSelectedName(item) diff --git a/src/components/hooks/auth/useActiveCustomer.tsx b/src/components/hooks/auth/useActiveCustomer.tsx index f0f4f6fef..353ce8ad9 100644 --- a/src/components/hooks/auth/useActiveCustomer.tsx +++ b/src/components/hooks/auth/useActiveCustomer.tsx @@ -5,7 +5,16 @@ import useSWR from 'swr' const useActiveCustomer = () => { const { data, ...rest } = useSWR([activeCustomerQuery], gglFetcher) - return { customer: data?.activeCustomer, ...rest } + return { + customer: data?.activeCustomer, + userInfo:{ + firstName: data?.activeCustomer?.firstName, + lastName:data?.activeCustomer?.lastName, + email:data?.activeCustomer?.emailAddress, + phoneNumber: data?.activeCustomer?.phoneNumber, + address: data?.activeCustomer?.addresses?.[0] + }, + ...rest } } export default useActiveCustomer diff --git a/src/components/hooks/auth/useSignup.tsx b/src/components/hooks/auth/useSignup.tsx index 922460c77..d9b085b0e 100644 --- a/src/components/hooks/auth/useSignup.tsx +++ b/src/components/hooks/auth/useSignup.tsx @@ -4,7 +4,6 @@ import { SignupMutation } from '@framework/schema' import fetcher from 'src/utils/fetcher' import { CommonError } from 'src/domains/interfaces/CommonError' import { signupMutation } from '@framework/utils/mutations/sign-up-mutation' - interface SignupInput { email: string firstName?: string diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index cf83feb42..f2775d5bb 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -1 +1,4 @@ export { default as useModalCommon } from './useModalCommon' +export { default as useEditUserInfo } from './user/useEditUserInfo' +export { default as useEditCustomerAddress } from './user/useEditCustomerAddress' + diff --git a/src/components/hooks/user/useEditCustomerAddress.tsx b/src/components/hooks/user/useEditCustomerAddress.tsx new file mode 100644 index 000000000..5caae3eb1 --- /dev/null +++ b/src/components/hooks/user/useEditCustomerAddress.tsx @@ -0,0 +1,55 @@ +import { Address } from '@framework/schema' +import { updateCustomerAddress } from '@framework/utils/mutations/update-customer-address-mutation' +import { useState } from 'react' +import fetcher from 'src/utils/fetcher' +import { useActiveCustomer } from '../auth' + +interface Props { + address?:string, + city?:string|null, + postalCode?:string|null, + state?:string +} + +const useEditCustomerAddress = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const {customer,mutate} = useActiveCustomer(); + + const editCustomerAddress = ( + { address,city,postalCode,state}: Props, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + + fetcher
({ + query: updateCustomerAddress, + variables: { + input: { + id:customer?.id, + streetLine1:address, + city, + postalCode, + province:state + }, + }, + }) .then((data) => { + + if(data.updateCustomerAddress.__typename == 'Address'){ + mutate(); + fCallBack(true) + return data + } + + }) .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + + } + return { loading, editCustomerAddress, error } +} + +export default useEditCustomerAddress diff --git a/src/components/hooks/user/useEditUserInfo.tsx b/src/components/hooks/user/useEditUserInfo.tsx new file mode 100644 index 000000000..c2c8b1a83 --- /dev/null +++ b/src/components/hooks/user/useEditUserInfo.tsx @@ -0,0 +1,51 @@ +import { useState } from 'react' +import { Customer } from '@framework/schema' +import fetcher from 'src/utils/fetcher' +import { updateCustomer } from '@framework/utils/mutations/update-customer-mutation' +import { useActiveCustomer } from '../auth' + +interface Props { + firstName?: string; + lastName?: string, + phoneNumber?:string, +} + +const useEditUserInfo = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const {mutate} = useActiveCustomer(); + + const editUserInfo = ( + { firstName,lastName,phoneNumber}: Props, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + + fetcher({ + query: updateCustomer, + variables: { + input: { + firstName, + lastName, + phoneNumber + }, + }, + }) + .then((data) => { + if (data.updateCustomer.__typename == 'Customer') { + mutate(); + return data + } + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, editUserInfo, error } +} + +export default useEditUserInfo diff --git a/src/components/hooks/user/useUserInfo.tsx b/src/components/hooks/user/useUserInfo.tsx deleted file mode 100644 index 69b80a467..000000000 --- a/src/components/hooks/user/useUserInfo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { ActiveCustomerQuery } from '@framework/schema' -import { userInfoQuery } from '@framework/utils/queries/user-info-query' -import gglFetcher from 'src/utils/gglFetcher' -import useSWR from 'swr' - -const useUserInfo = () => { - const { data } = useSWR([userInfoQuery], gglFetcher) - - return { userInfo: data?.activeCustomer} -} - -export default useUserInfo diff --git a/src/components/modules/account/AccountPage/AccountPage.tsx b/src/components/modules/account/AccountPage/AccountPage.tsx index e7154f46f..d8c169647 100644 --- a/src/components/modules/account/AccountPage/AccountPage.tsx +++ b/src/components/modules/account/AccountPage/AccountPage.tsx @@ -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 { useRouter } from "next/router" import { useActiveCustomer } from 'src/components/hooks/auth' -import useUserInfo from "src/components/hooks/user/useUserInfo" import { AccountProps } from "./components/AccountInfomation/AccountInfomation" const waiting = [ { @@ -54,17 +53,6 @@ const delivered = [ } ] -let account = { - firstName: "Nhân", - lastName: "Trần", - email: "vuduong@gmail.com", - address: "235 Dien Bien Phu Bis, Dakao ward", - state: "District 1", - city: "HCMC", - postalCode: "700000", - phoneNumber: "(+84) 937 937 195" -} - interface AccountPageProps { defaultActiveContent?: "info" | "orders" | "favorites" } @@ -84,18 +72,8 @@ const getTabIndex = (tab?: string): number => { const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { const router = useRouter() - const {userInfo} = useUserInfo(); - - // const email = userInfo?.emailAddress; - // const [info] = userInfo?.addresses || []; - - // const accountInfo = {...info,userInfo?.emailAddress}; - - // const clone:AccountProps = Object.create(accountInfo); - // Object.assign(clone, accountInfo); - - - console.log(); + const {userInfo} = useActiveCustomer(); + const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2) const [modalVisible, setModalVisible] = useState(false); @@ -123,7 +101,7 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { - + @@ -133,7 +111,7 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => {
- + ) } diff --git a/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx index dc32db71a..362d449ac 100644 --- a/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx +++ b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx @@ -6,17 +6,21 @@ import avatar from '../../assets/avatar.png' import { ButtonCommon } from 'src/components/common' import { useActiveCustomer } from 'src/components/hooks/auth' +import { Address } from '@framework/schema' export interface AccountProps { - name?: string + firstName?: string + lastName?: string email?: string - address?: string - state?: string - city?: string - postalCode?: string - phoneNumber?: string + phoneNumber?:string|null + address?: Address } +const states = [ + {name: "District 1", value: "D1"}, + {name: "District 2", value: "D2"}, + {name: "District 3", value: "D3"} +] interface AccountInfomationProps { account: AccountProps onClick: () => void @@ -24,11 +28,10 @@ interface AccountInfomationProps { const AccountInfomation = ({ account, onClick }: AccountInfomationProps) => { const { customer } = useActiveCustomer() - // need to handle call back when edit account information const showEditForm = () => onClick() - + const state = states.find((val)=>val.value == account.address?.province); return (
@@ -45,8 +48,8 @@ const AccountInfomation = ({ account, onClick }: AccountInfomationProps) => {
Shipping Infomation
- {account.address + - `, ${account.state}, ${account.city}, ${account.postalCode}`} + {account.address?.streetLine1 + + `, ${state?.name}, ${account.address?.city}, ${account.address?.postalCode}`}
{account.phoneNumber}
diff --git a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss index 20acd257b..e098b9af7 100644 --- a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss +++ b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss @@ -1,6 +1,15 @@ @import '../../../../../../styles/utilities'; .editInfoModal { + .u-form{ + width: 60rem; + } + .inputName{ + @apply flex justify-between; + .input{ + width: 48.5%; + } + } .input { @apply bg-white; margin-bottom: 1.6rem; @@ -23,6 +32,7 @@ .inputPostalCode { @apply bg-white; margin-left: 0.8rem; + width: 100%; } .inputPhoneNumber { diff --git a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx index f9e4aebd5..c3a2b1e34 100644 --- a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx +++ b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx @@ -1,19 +1,34 @@ -import React from "react" +import React, { useState } from "react" import s from './EditInfoModal.module.scss' -import { ModalCommon, Inputcommon, SelectCommon, ButtonCommon } from '../../../../../common' - +import { ModalCommon, SelectCommon, ButtonCommon } from '../../../../../common' +import { Address } from "@framework/schema"; +import { + InputFiledInForm, + } from 'src/components/common' +import * as Yup from 'yup' +import { Form, Formik } from 'formik' +import { useEditCustomerAddress, useEditUserInfo } from "src/components/hooks"; +import { LANGUAGE } from 'src/utils/language.utils' +import { useMessage } from 'src/components/contexts' interface EditInfoModalProps { - accountInfo: {firstName: string,lastName: string, email: string, address: string, state: string, city: string, postalCode: string, phoneNumber: string}; + accountInfo: { + firstName?: string + lastName?: string + email?: string + phoneNumber?:string|null + address?: Address + }; visible: boolean; closeModal: () => void; } const EditInfoModal = ({ accountInfo, visible = false, closeModal }: EditInfoModalProps) => { + const [stateValue,setStateValue] = useState(''); + const { loading, editUserInfo } = useEditUserInfo(); + const {editCustomerAddress} = useEditCustomerAddress(); + const { showMessageSuccess, showMessageError } = useMessage() - function saveInfo() { - closeModal(); - } const states = [ {name: "District 1", value: "D1"}, @@ -21,43 +36,165 @@ const EditInfoModal = ({ accountInfo, visible = false, closeModal }: EditInfoMod {name: "District 3", value: "D3"} ] + const DisplayingErrorMessagesSchema = Yup.object().shape({ + firstName: Yup.string().required('Required'), + lastName: Yup.string().required('Required'), + address: Yup.string().required('Required'), + city: Yup.string().required('Required'), + postalCode: Yup.string(), + phoneNumber: Yup.string(), + }) + + function onEditUserInfo ( + values: { + firstName: string|undefined; + lastName: string|undefined, + address:string|undefined, + city?:string|null, + postalCode?:string|null, + phoneNumber?:string|null + }) { + + editUserInfo( + { + firstName: values.firstName, + lastName: values.lastName, + phoneNumber:values.phoneNumber ?? '', + },onChangUserInfoCallBack); + + editCustomerAddress( + { + address: values.address , + city:values.city, + postalCode:values.postalCode, + state:stateValue + }, + onChangUserInfoCallBack); + } + + function onChangUserInfoCallBack(isSuccess: boolean, message?: string){ + if (isSuccess) { + closeModal(); + showMessageSuccess("Change Your Information Successfully.", 15000) + } else { + showMessageError(LANGUAGE.MESSAGE.ERROR) + } + } + function state(state:string){ + setStateValue(state); + } return (
-
- -
-
- -
- -
- -
- -
- -
- - -
-
- + + {({ errors, touched, isValid, submitForm }) => ( +
+
+
+ +
+
+ +
-
- +
+
-
+ +
+ +
+ -
- -
+
+
+ +
-
- Cancel - Save -
+
+ +
+
+ +
+ +
+ +
+ Cancel + Save +
+
+ )} +
) From a8aa755b792d77e583d906570ac20cb4c93028b2 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Wed, 6 Oct 2021 16:59:37 +0700 Subject: [PATCH 09/27] add product to cart, update product in cart, remove product form cart --- framework/commerce/types/cart.ts | 1 + framework/commerce/types/product.ts | 1 + framework/vendure/schema.d.ts | 2 +- .../utils/fragments/search-result-fragment.ts | 1 + framework/vendure/utils/normalize.ts | 3 +- pages/index.tsx | 1 + .../common/CartDrawer/CartDrawer.tsx | 5 +- .../ProductCartItem/ProductCartItem.tsx | 89 ++++++++++++++----- .../ProductsInCart/ProductsInCart.tsx | 16 ++-- .../common/ModalConfirm/ModalConfirm.tsx | 4 +- .../common/ProductCard/ProductCard.tsx | 20 ++++- .../common/QuanittyInput/QuanittyInput.tsx | 11 ++- src/components/hooks/cart/index.ts | 1 + .../hooks/cart/useGetActiveOrder.tsx | 5 +- .../hooks/cart/useRemoveProductInCart.tsx | 41 +++++++++ .../hooks/cart/useUpdateProductInCart.tsx | 40 +++++++++ src/domains/enums/Message.ts | 2 + 17 files changed, 195 insertions(+), 48 deletions(-) create mode 100644 src/components/hooks/cart/useRemoveProductInCart.tsx create mode 100644 src/components/hooks/cart/useUpdateProductInCart.tsx create mode 100644 src/domains/enums/Message.ts diff --git a/framework/commerce/types/cart.ts b/framework/commerce/types/cart.ts index e4af878de..b3d3b1e59 100644 --- a/framework/commerce/types/cart.ts +++ b/framework/commerce/types/cart.ts @@ -17,6 +17,7 @@ export type LineItem = { quantity: number discounts: Discount[] // A human-friendly unique string automatically generated from the product’s name + slug: string path: string variant: ProductVariant options?: SelectedOption[] diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index 39f594a7a..6d01b8c2d 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -60,6 +60,7 @@ export type ProductCard = { // TODO: collection category?: string, isNotSell?: boolean + productVariantId?:string } export type SearchProductsBody = { diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index a817d6799..7095ce02f 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3038,7 +3038,7 @@ export type SearchResultFragment = { __typename?: 'SearchResult' } & Pick< SearchResult, 'productId' | 'sku' | 'productName' | 'description' | 'slug' | 'sku' | 'currencyCode' | 'productAsset' | 'price' | 'priceWithTax' | 'currencyCode' - | 'collectionIds' + | 'collectionIds' | 'productVariantId' > & { productAsset?: Maybe< { __typename?: 'SearchResultAsset' } & Pick< diff --git a/framework/vendure/utils/fragments/search-result-fragment.ts b/framework/vendure/utils/fragments/search-result-fragment.ts index 6155b5b47..b3fc4d561 100644 --- a/framework/vendure/utils/fragments/search-result-fragment.ts +++ b/framework/vendure/utils/fragments/search-result-fragment.ts @@ -7,6 +7,7 @@ export const searchResultFragment = /* GraphQL */ ` slug sku currencyCode + productVariantId productAsset { id preview diff --git a/framework/vendure/utils/normalize.ts b/framework/vendure/utils/normalize.ts index a5cb96c8a..939460930 100644 --- a/framework/vendure/utils/normalize.ts +++ b/framework/vendure/utils/normalize.ts @@ -11,6 +11,7 @@ export function normalizeSearchResult(item: SearchResultFragment): ProductCard { imageSrc: item.productAsset?.preview ? item.productAsset?.preview + '?w=800&mode=crop' : '', price: (item.priceWithTax as any).min / 100, currencyCode: item.currencyCode, + productVariantId: item.productVariantId?item.productVariantId:"", // TODO: // oldPrice: item.price @@ -35,7 +36,7 @@ export function normalizeCart(order: CartFragment): Cart { id: l.id, name: l.productVariant.name, quantity: l.quantity, - url: l.productVariant.product.slug, + slug: l.productVariant.product.slug, variantId: l.productVariant.id, productId: l.productVariant.productId, images: [{ url: l.featuredAsset?.preview + '?preset=thumb' || '' }], diff --git a/pages/index.tsx b/pages/index.tsx index 4fc797c26..cf279d399 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -17,6 +17,7 @@ interface Props { featuredProducts: ProductCard[], } export default function Home({ freshProducts, featuredProducts, veggie }: Props) { + // console.log("veggie",veggie) return ( <> diff --git a/src/components/common/CartDrawer/CartDrawer.tsx b/src/components/common/CartDrawer/CartDrawer.tsx index daeae0513..089e8b620 100644 --- a/src/components/common/CartDrawer/CartDrawer.tsx +++ b/src/components/common/CartDrawer/CartDrawer.tsx @@ -1,3 +1,4 @@ +import { normalizeCart } from '@framework/utils/normalize'; import React from 'react'; import { useCartDrawer } from 'src/components/contexts'; import useGetActiveOrder from 'src/components/hooks/cart/useGetActiveOrder'; @@ -18,12 +19,12 @@ const CartDrawer = ({ }: Props) => { const {order} = useGetActiveOrder() return (
- +
diff --git a/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx b/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx index 7ec3ecbdb..ef219d31d 100644 --- a/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx +++ b/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx @@ -1,25 +1,64 @@ -import React from 'react'; +import React, { useCallback, useState } from 'react' import Link from 'next/link' -import { QuanittyInput } from 'src/components/common'; -import { IconDelete } from 'src/components/icons'; -import { ROUTE } from 'src/utils/constanst.utils'; -import { ProductProps } from 'src/utils/types.utils'; -import ImgWithLink from '../../../ImgWithLink/ImgWithLink'; -import LabelCommon from '../../../LabelCommon/LabelCommon'; -import s from './ProductCartItem.module.scss'; +import { ModalConfirm, QuanittyInput } from 'src/components/common' +import { IconDelete } from 'src/components/icons' +import { ROUTE } from 'src/utils/constanst.utils' +import ImgWithLink from '../../../ImgWithLink/ImgWithLink' +import LabelCommon from '../../../LabelCommon/LabelCommon' +import s from './ProductCartItem.module.scss' +import { LineItem } from '@commerce/types/cart' +import { useUpdateProductInCart } from 'src/components/hooks/cart' +import { debounce } from 'lodash' +import useRemoveProductInCart from 'src/components/hooks/cart/useRemoveProductInCart' -export interface ProductCartItempProps extends ProductProps { - quantity: number, +export interface ProductCartItempProps extends LineItem { + currency: { code: string } } -const ProductCartItem = ({ name, slug, weight, price, oldPrice, discount, imageSrc, quantity }: ProductCartItempProps) => { +const ProductCartItem = ({ + slug, + discounts, + quantity, + variant, + name, + currency, + id +}: ProductCartItempProps) => { + const [visible, setVisible] = useState(false) + const {updateProduct} = useUpdateProductInCart() + const {removeProduct, loading} = useRemoveProductInCart() + const handleQuantityChangeCallback = (isSuccess:boolean,mess?:string) => { + if(!isSuccess){ + console.log(mess) + } + } + const handleRemoveCallback = (isSuccess:boolean,mess?:string) => { + if(!isSuccess){ + console.log(mess) + }else{ + setVisible(false) + } + } + const handleQuantityChange = (value:number) => { + updateProduct({orderLineId:id,quantity:value},handleQuantityChangeCallback) + } + const debounceFn = useCallback(debounce(handleQuantityChange, 500), []); + const handleCancel = () => { + setVisible(false) + } + const handleOpen = () => { + setVisible(true) + } + const handleConfirm = () => { + removeProduct({orderLineId:id},handleRemoveCallback) + } return (
- +
@@ -27,30 +66,32 @@ const ProductCartItem = ({ name, slug, weight, price, oldPrice, discount, imageS
- {name} {weight ? `(${weight})` : ''} + {name} {variant?.weight ? `(${variant.weight})` : ''}
- { - oldPrice && -
- {oldPrice} - {discount} -
- } -
{price}
+ {discounts.length > 0 && ( +
+ {/* {oldPrice} */} + {discounts[0]} +
+ )} +
{variant?.price} {currency?.code}
-
+
- +
+ + Are you sure want to remove {name} form your cart +
) } -export default ProductCartItem; \ No newline at end of file +export default ProductCartItem diff --git a/src/components/common/CartDrawer/components/ProductsInCart/ProductsInCart.tsx b/src/components/common/CartDrawer/components/ProductsInCart/ProductsInCart.tsx index b455d4d73..7d6432a9d 100644 --- a/src/components/common/CartDrawer/components/ProductsInCart/ProductsInCart.tsx +++ b/src/components/common/CartDrawer/components/ProductsInCart/ProductsInCart.tsx @@ -1,25 +1,21 @@ +import { LineItem } from '@commerce/types/cart'; import React from 'react'; import ProductCartItem, { ProductCartItempProps } from '../ProductCartItem/ProductCartItem'; import s from './ProductsInCart.module.scss'; interface Props { - data: ProductCartItempProps[] + data: LineItem[] + currency: { code: string } } -const ProductsInCart = ({ data }: Props) => { +const ProductsInCart = ({ data, currency }: Props) => { return (
    { data.map(item =>
  • ) } diff --git a/src/components/common/ModalConfirm/ModalConfirm.tsx b/src/components/common/ModalConfirm/ModalConfirm.tsx index 1e425482f..a41dd41d7 100644 --- a/src/components/common/ModalConfirm/ModalConfirm.tsx +++ b/src/components/common/ModalConfirm/ModalConfirm.tsx @@ -5,6 +5,7 @@ import s from './ModalConfirm.module.scss' interface ModalConfirmProps extends ModalCommonProps { okText?: String cancelText?: String + loading?:boolean onOk?: () => void onCancel?: () => void } @@ -16,6 +17,7 @@ const ModalConfirm = ({ onCancel, children, title = 'Confirm', + loading, ...props }: ModalConfirmProps) => { return ( @@ -25,7 +27,7 @@ const ModalConfirm = ({
    {cancelText}
    - {okText} + {okText}
) diff --git a/src/components/common/ProductCard/ProductCard.tsx b/src/components/common/ProductCard/ProductCard.tsx index b9c351aab..19cbdc6da 100644 --- a/src/components/common/ProductCard/ProductCard.tsx +++ b/src/components/common/ProductCard/ProductCard.tsx @@ -10,13 +10,14 @@ import ItemWishList from '../ItemWishList/ItemWishList' import LabelCommon from '../LabelCommon/LabelCommon' import s from './ProductCard.module.scss' import ProductNotSell from './ProductNotSell/ProductNotSell' - +import {useAddProductToCart} from "../../hooks/cart" export interface ProductCardProps extends ProductCard { buttonText?: string isSingleButton?: boolean, } const ProductCardComponent = ({ + id, category, name, slug, @@ -27,7 +28,18 @@ const ProductCardComponent = ({ imageSrc, isNotSell, isSingleButton, + productVariantId, }: ProductCardProps) => { + + const {addProduct,loading,error} = useAddProductToCart() + const handleAddToCart = () => { + if(productVariantId){ + addProduct({variantId:productVariantId,quantity:1},handleAddToCartCallback) + } + } + const handleAddToCartCallback = () => { + + } if (isNotSell) { return
@@ -71,12 +83,12 @@ const ProductCardComponent = ({ { isSingleButton ?
- } size='small'>Add to cart + } size='small' >Add to cart
: <> -
- +
+
{buttonText} diff --git a/src/components/common/QuanittyInput/QuanittyInput.tsx b/src/components/common/QuanittyInput/QuanittyInput.tsx index e31abb880..e2229830f 100644 --- a/src/components/common/QuanittyInput/QuanittyInput.tsx +++ b/src/components/common/QuanittyInput/QuanittyInput.tsx @@ -26,10 +26,6 @@ const QuanittyInput = ({ }: QuanittyInputProps) => { const [value, setValue] = useState(0) - useEffect(() => { - onChange && onChange(value) - }, [value]) - useEffect(() => { initValue && setValue(initValue) }, [initValue]) @@ -37,16 +33,20 @@ const QuanittyInput = ({ const onPlusClick = () => { if (max && value + step > max) { setValue(max) + onChange && onChange(max) } else { setValue(value + step) + onChange && onChange(value + step) } } const onMinusClick = () => { if (min && value - step < min) { setValue(min) + onChange && onChange(min) } else { setValue(value - step) + onChange && onChange(value - step) } } @@ -54,10 +54,13 @@ const QuanittyInput = ({ let value = Number(e.target.value) || 0 if (min && value < min) { setValue(min) + onChange && onChange(min) } else if (max && value > max) { setValue(max) + onChange && onChange(max) } else { setValue(value) + onChange && onChange(value) } } diff --git a/src/components/hooks/cart/index.ts b/src/components/hooks/cart/index.ts index c0235c81c..950b32e7d 100644 --- a/src/components/hooks/cart/index.ts +++ b/src/components/hooks/cart/index.ts @@ -1,2 +1,3 @@ export { default as useAddProductToCart } from './useAddProductToCart' +export { default as useUpdateProductInCart } from './useUpdateProductInCart' export { default as useGetActiveOrder } from './useGetActiveOrder' \ No newline at end of file diff --git a/src/components/hooks/cart/useGetActiveOrder.tsx b/src/components/hooks/cart/useGetActiveOrder.tsx index 818ca9e9a..4c26a1786 100644 --- a/src/components/hooks/cart/useGetActiveOrder.tsx +++ b/src/components/hooks/cart/useGetActiveOrder.tsx @@ -1,5 +1,7 @@ +import { Cart } from '@commerce/types/cart' import { ActiveOrderQuery } from '@framework/schema' import { cartFragment } from '@framework/utils/fragments/cart-fragment' +import { normalizeCart } from '@framework/utils/normalize' import { gql } from 'graphql-request' import gglFetcher from 'src/utils/gglFetcher' import useSWR from 'swr' @@ -14,7 +16,8 @@ const query = gql` const useGetActiveOrder = () => { const { data, ...rest } = useSWR([query], gglFetcher) - return { order: data?.activeOrder, ...rest } + return { order: data?.activeOrder ? normalizeCart(data!.activeOrder) : null, ...rest } + } export default useGetActiveOrder diff --git a/src/components/hooks/cart/useRemoveProductInCart.tsx b/src/components/hooks/cart/useRemoveProductInCart.tsx new file mode 100644 index 000000000..d66fd4306 --- /dev/null +++ b/src/components/hooks/cart/useRemoveProductInCart.tsx @@ -0,0 +1,41 @@ +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { AdjustOrderLineMutationVariables,AdjustOrderLineMutation, RemoveOrderLineMutation, RemoveOrderLineMutationVariables } from '@framework/schema' +import { errorMapping } from 'src/utils/errrorMapping' +import { useGetActiveOrder } from '.' +import { adjustOrderLineMutation } from '@framework/utils/mutations/adjust-order-line-mutation' +import { removeOrderLineMutation } from '@framework/utils/mutations/remove-order-line-mutation' + +const useRemoveProductInCart = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrder() + + const removeProduct = (options:RemoveOrderLineMutationVariables, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: removeOrderLineMutation , + variables: options, + }) + .then(({ data }) => { + if (data.removeOrderLine.__typename !== "Order") { + throw CommonError.create(errorMapping(data.removeOrderLine.message), data.removeOrderLine.errorCode) + } + mutate() + fCallBack(true) + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, removeProduct, error } +} + +export default useRemoveProductInCart diff --git a/src/components/hooks/cart/useUpdateProductInCart.tsx b/src/components/hooks/cart/useUpdateProductInCart.tsx new file mode 100644 index 000000000..b2a0423bb --- /dev/null +++ b/src/components/hooks/cart/useUpdateProductInCart.tsx @@ -0,0 +1,40 @@ +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { AdjustOrderLineMutationVariables,AdjustOrderLineMutation } from '@framework/schema' +import { errorMapping } from 'src/utils/errrorMapping' +import { useGetActiveOrder } from '.' +import { adjustOrderLineMutation } from '@framework/utils/mutations/adjust-order-line-mutation' + +const useUpdateProductInCart = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrder() + + const updateProduct = (options:AdjustOrderLineMutationVariables, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: adjustOrderLineMutation , + variables: options, + }) + .then(({ data }) => { + if (data.adjustOrderLine.__typename !== "Order") { + throw CommonError.create(errorMapping(data.adjustOrderLine.message), data.adjustOrderLine.errorCode) + } + mutate() + fCallBack(true) + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, updateProduct, error } +} + +export default useUpdateProductInCart diff --git a/src/domains/enums/Message.ts b/src/domains/enums/Message.ts new file mode 100644 index 000000000..3d8b4e288 --- /dev/null +++ b/src/domains/enums/Message.ts @@ -0,0 +1,2 @@ + + \ No newline at end of file From c51fd1bd4c311f94b6d22fad2a392be7b980fd6a Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Thu, 7 Oct 2021 11:01:41 +0700 Subject: [PATCH 10/27] bug: fix bug select common --- src/components/common/SelectCommon/SelectCommon.tsx | 7 +++++-- .../hooks/{user => account}/useEditCustomerAddress.tsx | 0 src/components/hooks/{user => account}/useEditUserInfo.tsx | 0 src/components/hooks/index.ts | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) rename src/components/hooks/{user => account}/useEditCustomerAddress.tsx (100%) rename src/components/hooks/{user => account}/useEditUserInfo.tsx (100%) diff --git a/src/components/common/SelectCommon/SelectCommon.tsx b/src/components/common/SelectCommon/SelectCommon.tsx index 122d9a78d..6e24a7020 100644 --- a/src/components/common/SelectCommon/SelectCommon.tsx +++ b/src/components/common/SelectCommon/SelectCommon.tsx @@ -19,9 +19,12 @@ const SelectCommon = ({selected,initValue, type = 'default', size = 'base', opti const [selectedValue, setSelectedValue] = useState('') useEffect(()=>{ - setSelectedValue(selected ?? ''); + const nameSelect = option.find((val)=>val.value === selected); + setSelectedName(nameSelect?.name); setSelectedValue(initValue ?? ''); - }) + onChange && onChange(initValue ?? ''); + },[]) + const changeSelectedName = (item:string, value: string) => { setSelectedValue(value) setSelectedName(item) diff --git a/src/components/hooks/user/useEditCustomerAddress.tsx b/src/components/hooks/account/useEditCustomerAddress.tsx similarity index 100% rename from src/components/hooks/user/useEditCustomerAddress.tsx rename to src/components/hooks/account/useEditCustomerAddress.tsx diff --git a/src/components/hooks/user/useEditUserInfo.tsx b/src/components/hooks/account/useEditUserInfo.tsx similarity index 100% rename from src/components/hooks/user/useEditUserInfo.tsx rename to src/components/hooks/account/useEditUserInfo.tsx diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index f2775d5bb..d01d505ea 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -1,4 +1,4 @@ export { default as useModalCommon } from './useModalCommon' -export { default as useEditUserInfo } from './user/useEditUserInfo' -export { default as useEditCustomerAddress } from './user/useEditCustomerAddress' +export { default as useEditUserInfo } from './account/useEditUserInfo' +export { default as useEditCustomerAddress } from './account/useEditCustomerAddress' From 69996ec7d28912865834d21b889a80a4f02f227d Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Thu, 7 Oct 2021 11:02:41 +0700 Subject: [PATCH 11/27] bug: fix bug select common 2 --- src/components/common/SelectCommon/SelectCommon.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/common/SelectCommon/SelectCommon.tsx b/src/components/common/SelectCommon/SelectCommon.tsx index 6e24a7020..0ee282987 100644 --- a/src/components/common/SelectCommon/SelectCommon.tsx +++ b/src/components/common/SelectCommon/SelectCommon.tsx @@ -20,7 +20,7 @@ const SelectCommon = ({selected,initValue, type = 'default', size = 'base', opti useEffect(()=>{ const nameSelect = option.find((val)=>val.value === selected); - setSelectedName(nameSelect?.name); + setSelectedName(nameSelect?.name ?? 'State'); setSelectedValue(initValue ?? ''); onChange && onChange(initValue ?? ''); },[]) From 99803aa7fcd980dc6a4b225beb5f6a004778f522 Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Thu, 7 Oct 2021 18:04:54 +0700 Subject: [PATCH 12/27] feat: feature get user order --- framework/vendure/schema.d.ts | 2 +- .../utils/queries/get-user-order-query.ts | 19 +++++++++++++ src/components/hooks/account/index.ts | 3 ++ .../hooks/account/useGetUserOrder.tsx | 20 +++++++++++++ src/components/hooks/index.ts | 2 -- .../account/AccountPage/AccountPage.tsx | 22 +++++---------- .../EditInfoModal/EditInfoModal.tsx | 2 +- .../OrderInformation/OrderInformation.tsx | 28 +++++++++---------- .../account/DeliveryItem/DeliveryItem.tsx | 3 +- .../components/Products/Products.tsx | 12 ++++---- 10 files changed, 73 insertions(+), 40 deletions(-) create mode 100644 framework/vendure/utils/queries/get-user-order-query.ts create mode 100644 src/components/hooks/account/index.ts create mode 100644 src/components/hooks/account/useGetUserOrder.tsx diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index b3ea2a038..a09e8421c 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3211,7 +3211,7 @@ export type ActiveCustomerQuery = { __typename?: 'Query' } & { activeCustomer?: Maybe< { __typename?: 'Customer' } & Pick< Customer, - 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' | 'phoneNumber' + 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' | 'phoneNumber' | 'orders' > > } diff --git a/framework/vendure/utils/queries/get-user-order-query.ts b/framework/vendure/utils/queries/get-user-order-query.ts new file mode 100644 index 000000000..adf75365c --- /dev/null +++ b/framework/vendure/utils/queries/get-user-order-query.ts @@ -0,0 +1,19 @@ +export const getUserOrderQuery = /* GraphQL */ ` + query activeCustomer { + activeCustomer { + orders{ + items{ + lines{ + productVariant{ + name + } + quantity + } + total + state + code + } + } + } + } +` diff --git a/src/components/hooks/account/index.ts b/src/components/hooks/account/index.ts new file mode 100644 index 000000000..34f1b545e --- /dev/null +++ b/src/components/hooks/account/index.ts @@ -0,0 +1,3 @@ +export { default as useGetUserOrder } from './useGetUserOrder'; +export { default as useEditUserInfo } from './useEditUserInfo' +export { default as useEditCustomerAddress } from './useEditCustomerAddress' diff --git a/src/components/hooks/account/useGetUserOrder.tsx b/src/components/hooks/account/useGetUserOrder.tsx new file mode 100644 index 000000000..9ef249fbd --- /dev/null +++ b/src/components/hooks/account/useGetUserOrder.tsx @@ -0,0 +1,20 @@ +import { ActiveCustomerQuery, Order } from '@framework/schema' +import { getUserOrderQuery } from '@framework/utils/queries/get-user-order-query' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' + +const useGetUserOrder = () => { + const { data, ...rest } = useSWR([getUserOrderQuery], gglFetcher) + console.log(data); + const addingItem = data?.activeCustomer?.orders.items.filter((val:Order) =>val.state == 'AddingItems'); + const arrangingPayment = data?.activeCustomer?.orders.items.filter((val:Order) =>val.state == 'ArrangingPayment'); + const cancelled = data?.activeCustomer?.orders.items.filter((val:Order) =>val.state == "Cancelled"); + return { + addingItem: addingItem, + arrangingPayment: arrangingPayment, + cancelled: cancelled, + ...rest + } +} + +export default useGetUserOrder diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index d01d505ea..2d4c2da24 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -1,4 +1,2 @@ export { default as useModalCommon } from './useModalCommon' -export { default as useEditUserInfo } from './account/useEditUserInfo' -export { default as useEditCustomerAddress } from './account/useEditCustomerAddress' diff --git a/src/components/modules/account/AccountPage/AccountPage.tsx b/src/components/modules/account/AccountPage/AccountPage.tsx index d8c169647..d40ba1845 100644 --- a/src/components/modules/account/AccountPage/AccountPage.tsx +++ b/src/components/modules/account/AccountPage/AccountPage.tsx @@ -12,20 +12,10 @@ import EditInfoModal from './components/EditInfoModal/EditInfoModal' import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data'; import { ACCOUNT_TAB, QUERY_KEY } from "src/utils/constanst.utils" import { useRouter } from "next/router" -import { useActiveCustomer } from 'src/components/hooks/auth' +import { useActiveCustomer} from 'src/components/hooks/auth' +import { useGetUserOrder} from 'src/components/hooks/account' import { AccountProps } from "./components/AccountInfomation/AccountInfomation" -const waiting = [ - { - id: "NO 123456", - products: ["Tomato", "Fish", "Pork", "Onion"], - totalPrice : 1000 - }, - { - id: "NO 123457", - products: ["Tomato", "Fish", "Pork", "Onion"], - totalPrice : 1000 - } -] + const delivering = [ { @@ -73,7 +63,9 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { const router = useRouter() const {userInfo} = useActiveCustomer(); - + + const {addingItem,arrangingPayment,cancelled} = useGetUserOrder(); + const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2) const [modalVisible, setModalVisible] = useState(false); @@ -104,7 +96,7 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { - + diff --git a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx index c3a2b1e34..3a86210a7 100644 --- a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx +++ b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx @@ -8,7 +8,7 @@ import { } from 'src/components/common' import * as Yup from 'yup' import { Form, Formik } from 'formik' -import { useEditCustomerAddress, useEditUserInfo } from "src/components/hooks"; +import { useEditCustomerAddress, useEditUserInfo } from "src/components/hooks/account"; import { LANGUAGE } from 'src/utils/language.utils' import { useMessage } from 'src/components/contexts' interface EditInfoModalProps { diff --git a/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.tsx b/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.tsx index 211cebe3b..9e825696e 100644 --- a/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.tsx +++ b/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.tsx @@ -4,50 +4,50 @@ import s from './OrderInformation.module.scss' import { TabCommon } from '../../../../../common' import TabPane from 'src/components/common/TabCommon/components/TabPane/TabPane' import DeliveryItem from '../../../DeliveryItem/DeliveryItem' +import { Order } from "@framework/schema" interface OrderInformationProps { - waiting: {id: string, products: string[], totalPrice: number}[], - delivering: {id: string, products: string[], totalPrice: number}[], - delivered: {id: string, products: string[], totalPrice: number}[], + addingItem?: Order[], + arrangingPayment?: Order[], + cancelled?: Order[], } -const OrderInformation = ({ waiting, delivering, delivered} : OrderInformationProps) => { - +const OrderInformation = ({ addingItem, arrangingPayment, cancelled} : OrderInformationProps) => { return (
Order Information
- +
{ - waiting.map((order, i) => { + addingItem?.map((order, i) => { return ( - + ) }) }
- +
{ - delivering.map((order, i) => { + arrangingPayment?.map((order, i) => { return ( - + ) }) }
- +
{ - delivered.map((order, i) => { + cancelled?.map((order, i) => { return ( - + ) }) } diff --git a/src/components/modules/account/DeliveryItem/DeliveryItem.tsx b/src/components/modules/account/DeliveryItem/DeliveryItem.tsx index b42a0f91e..71432264a 100644 --- a/src/components/modules/account/DeliveryItem/DeliveryItem.tsx +++ b/src/components/modules/account/DeliveryItem/DeliveryItem.tsx @@ -5,12 +5,13 @@ import IdAndStatus from './components/IdAndStatus/IdAndStatus' import Products from './components/Products/Products' import TotalPrice from './components/TotalPrice/TotalPrice' import ReOrder from './components/ReOrder/ReOrder' +import { OrderLine } from "@framework/schema" interface DeliveryItemProps { id: string; status: "waiting" | "delivering" | "delivered"; - products: string[]; + products?: OrderLine[]; totalPrice: number; } diff --git a/src/components/modules/account/DeliveryItem/components/Products/Products.tsx b/src/components/modules/account/DeliveryItem/components/Products/Products.tsx index fdbba2c73..0e054a171 100644 --- a/src/components/modules/account/DeliveryItem/components/Products/Products.tsx +++ b/src/components/modules/account/DeliveryItem/components/Products/Products.tsx @@ -1,19 +1,19 @@ +import { OrderLine } from "@framework/schema"; import React from "react" import s from './Products.module.scss' interface ProductsProps { - products: string[]; + products?: OrderLine[]; } const Products = ({ products } : ProductsProps) => { - - function toString(products:string[]): string { + function toString(products?:OrderLine[]): string { let strProducts = ""; - products.map((prod, i) => { + products?.map((prod, i) => { if (i === 0) { - strProducts += prod; + strProducts += prod.productVariant?.name; } else { - strProducts += `, ${prod}` + strProducts += `, ${prod.productVariant?.name}` } }); return strProducts; From 1126030abc2775fec7d0aa1786224071514314f2 Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Sun, 10 Oct 2021 14:45:44 +0700 Subject: [PATCH 13/27] feat: edit activeCustomer --- .../vendure/utils/queries/active-customer-query.ts | 7 +++++++ next-env.d.ts | 3 --- src/components/common/ItemWishList/ItemWishList.tsx | 10 ++++++++-- src/components/common/ProductCard/ProductCard.tsx | 4 +++- src/components/common/ProductList/ProductList.tsx | 2 ++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/framework/vendure/utils/queries/active-customer-query.ts b/framework/vendure/utils/queries/active-customer-query.ts index 65b280743..014ea130e 100644 --- a/framework/vendure/utils/queries/active-customer-query.ts +++ b/framework/vendure/utils/queries/active-customer-query.ts @@ -5,6 +5,13 @@ export const activeCustomerQuery = /* GraphQL */ ` firstName lastName emailAddress + favorites{ + items{ + product{ + id + } + } + } } } ` diff --git a/next-env.d.ts b/next-env.d.ts index 9bc3dd46b..c6643fda1 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,3 @@ /// /// /// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/src/components/common/ItemWishList/ItemWishList.tsx b/src/components/common/ItemWishList/ItemWishList.tsx index 74d0b3b04..f8be07cd4 100644 --- a/src/components/common/ItemWishList/ItemWishList.tsx +++ b/src/components/common/ItemWishList/ItemWishList.tsx @@ -4,16 +4,22 @@ import React, { memo } from 'react' import s from './ItemWishList.module.scss' interface Props { + id:string, isActive?: boolean, - onChange?: () => void + onChange?: () => string } -const ItemWishList = memo(({isActive=false, onChange}:Props) => { +const ItemWishList = memo(({id,isActive=false, onChange}:Props) => { + // function toggleFavorite(id:string):string|undefined{ + // // alert(id); + // return id; + // } return(
diff --git a/src/components/common/ProductCard/ProductCard.tsx b/src/components/common/ProductCard/ProductCard.tsx index 4761aac92..50df7695f 100644 --- a/src/components/common/ProductCard/ProductCard.tsx +++ b/src/components/common/ProductCard/ProductCard.tsx @@ -17,6 +17,7 @@ export interface ProductCardProps extends ProductCard { } const ProductCardComponent = ({ + id, collection, name, slug, @@ -34,6 +35,7 @@ const ProductCardComponent = ({
} + return (
@@ -63,7 +65,7 @@ const ProductCardComponent = ({
{price} {currencyCode}
- +
diff --git a/src/components/common/ProductList/ProductList.tsx b/src/components/common/ProductList/ProductList.tsx index c901b4d46..5c3d9058a 100644 --- a/src/components/common/ProductList/ProductList.tsx +++ b/src/components/common/ProductList/ProductList.tsx @@ -33,6 +33,8 @@ const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChan
{ data.map((product, index) => { + console.log(product); + return }) } From 391bba5d31a2e35723d16d801b952563edd27fd9 Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Sun, 10 Oct 2021 22:06:14 +0700 Subject: [PATCH 14/27] feat: toggle wishlist --- framework/vendure/schema.d.ts | 9 +++++++-- src/components/common/ProductList/ProductList.tsx | 8 +++++--- src/components/hooks/auth/useActiveCustomer.tsx | 9 ++++++--- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index d83b0276a..a6ab64d19 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3198,10 +3198,15 @@ export type ActiveCustomerQuery = { __typename?: 'Query' } & { activeCustomer?: Maybe< { __typename?: 'Customer' } & Pick< Customer, - 'id' | 'firstName' | 'lastName' | 'emailAddress' - > + 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'favorites' + >, > } +export type FavoriteList = { + items: [Favorite!]! + totalItems: Int! +} + export type GetAllProductPathsQueryVariables = Exact<{ first?: Maybe diff --git a/src/components/common/ProductList/ProductList.tsx b/src/components/common/ProductList/ProductList.tsx index 5c3d9058a..59884eca8 100644 --- a/src/components/common/ProductList/ProductList.tsx +++ b/src/components/common/ProductList/ProductList.tsx @@ -1,12 +1,13 @@ import classNames from 'classnames' import { useRouter } from 'next/router' import React from 'react' +import { useActiveCustomer } from 'src/components/hooks/auth' import { DEFAULT_PAGE_SIZE, ROUTE } from 'src/utils/constanst.utils' import { ButtonCommon, EmptyCommon } from '..' import PaginationCommon from '../PaginationCommon/PaginationCommon' import ProductCard, { ProductCardProps } from '../ProductCard/ProductCard' import s from "./ProductList.module.scss" - +import { FavoriteList } from '@framework/schema' interface ProductListProps { data: ProductCardProps[], total?: number, @@ -16,6 +17,8 @@ interface ProductListProps { const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChange }: ProductListProps) => { const router = useRouter() + const {wishlist:FavoriteList } = useActiveCustomer(); + const handlePageChange = (page: number) => { onPageChange && onPageChange(page) } @@ -33,8 +36,7 @@ const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChan
{ data.map((product, index) => { - console.log(product); - + return }) } diff --git a/src/components/hooks/auth/useActiveCustomer.tsx b/src/components/hooks/auth/useActiveCustomer.tsx index f0f4f6fef..b4891c44d 100644 --- a/src/components/hooks/auth/useActiveCustomer.tsx +++ b/src/components/hooks/auth/useActiveCustomer.tsx @@ -1,11 +1,14 @@ -import { ActiveCustomerQuery } from '@framework/schema' +import { ActiveCustomerQuery,FavoriteList } from '@framework/schema' import { activeCustomerQuery } from '@framework/utils/queries/active-customer-query' import gglFetcher from 'src/utils/gglFetcher' import useSWR from 'swr' - const useActiveCustomer = () => { const { data, ...rest } = useSWR([activeCustomerQuery], gglFetcher) - return { customer: data?.activeCustomer, ...rest } + + return { + customer: data?.activeCustomer, + wishlist:data?.activeCustomer?.favorites, + ...rest } } export default useActiveCustomer From 279c20e1af9e62250cff43b44e9e3f1487872541 Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Mon, 11 Oct 2021 09:59:46 +0700 Subject: [PATCH 15/27] feat: create toggle product wishlist --- framework/vendure/schema.d.ts | 10 ++++- .../mutations/toggle-wishlist-mutation.tsx | 9 ++++ .../utils/queries/active-customer-query.ts | 11 +++++ .../common/ItemWishList/ItemWishList.tsx | 25 ++++++++--- .../common/ProductCard/ProductCard.tsx | 4 +- .../common/ProductList/ProductList.tsx | 9 ++-- .../hooks/auth/useActiveCustomer.tsx | 21 ++++++--- src/components/hooks/product/index.ts | 1 + .../product/useToggleProductWishlist.tsx | 44 +++++++++++++++++++ .../account/AccountPage/AccountPage.tsx | 3 ++ 10 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 framework/vendure/utils/mutations/toggle-wishlist-mutation.tsx create mode 100644 src/components/hooks/product/useToggleProductWishlist.tsx diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index a6ab64d19..705e340c2 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3198,15 +3198,23 @@ export type ActiveCustomerQuery = { __typename?: 'Query' } & { activeCustomer?: Maybe< { __typename?: 'Customer' } & Pick< Customer, + FavoriteList, 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'favorites' >, > } -export type FavoriteList = { +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<{ first?: Maybe diff --git a/framework/vendure/utils/mutations/toggle-wishlist-mutation.tsx b/framework/vendure/utils/mutations/toggle-wishlist-mutation.tsx new file mode 100644 index 000000000..d3dcb7c18 --- /dev/null +++ b/framework/vendure/utils/mutations/toggle-wishlist-mutation.tsx @@ -0,0 +1,9 @@ +export const toggleWishlistMutation = /* GraphQL */ ` + mutation toggleFavorite($productId:ID!){ + toggleFavorite(productId:$productId){ + items{ + id + } + } + } +` diff --git a/framework/vendure/utils/queries/active-customer-query.ts b/framework/vendure/utils/queries/active-customer-query.ts index 014ea130e..7384dde78 100644 --- a/framework/vendure/utils/queries/active-customer-query.ts +++ b/framework/vendure/utils/queries/active-customer-query.ts @@ -1,3 +1,5 @@ +import { searchResultFragment } from '../fragments/search-result-fragment' + export const activeCustomerQuery = /* GraphQL */ ` query activeCustomer { activeCustomer { @@ -9,6 +11,15 @@ export const activeCustomerQuery = /* GraphQL */ ` items{ product{ id + name + slug + assets{ + source + preview + } + variants{ + price + } } } } diff --git a/src/components/common/ItemWishList/ItemWishList.tsx b/src/components/common/ItemWishList/ItemWishList.tsx index f8be07cd4..ac72c6879 100644 --- a/src/components/common/ItemWishList/ItemWishList.tsx +++ b/src/components/common/ItemWishList/ItemWishList.tsx @@ -2,7 +2,9 @@ import classNames from 'classnames' import IconHeart from 'src/components/icons/IconHeart' import React, { memo } from 'react' 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 { id:string, isActive?: boolean, @@ -10,17 +12,28 @@ interface Props { } const ItemWishList = memo(({id,isActive=false, onChange}:Props) => { - // function toggleFavorite(id:string):string|undefined{ - // // alert(id); - // return id; - // } + 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(
diff --git a/src/components/common/ProductCard/ProductCard.tsx b/src/components/common/ProductCard/ProductCard.tsx index 50df7695f..51038c9d6 100644 --- a/src/components/common/ProductCard/ProductCard.tsx +++ b/src/components/common/ProductCard/ProductCard.tsx @@ -14,6 +14,7 @@ import ProductNotSell from './ProductNotSell/ProductNotSell' export interface ProductCardProps extends ProductCard { buttonText?: string isSingleButton?: boolean, + activeWishlist?:boolean } const ProductCardComponent = ({ @@ -28,6 +29,7 @@ const ProductCardComponent = ({ imageSrc, isNotSell, isSingleButton, + activeWishlist }: ProductCardProps) => { if (isNotSell) { return
@@ -65,7 +67,7 @@ const ProductCardComponent = ({
{price} {currencyCode}
- +
diff --git a/src/components/common/ProductList/ProductList.tsx b/src/components/common/ProductList/ProductList.tsx index 59884eca8..041ccbf94 100644 --- a/src/components/common/ProductList/ProductList.tsx +++ b/src/components/common/ProductList/ProductList.tsx @@ -7,7 +7,6 @@ import { ButtonCommon, EmptyCommon } from '..' import PaginationCommon from '../PaginationCommon/PaginationCommon' import ProductCard, { ProductCardProps } from '../ProductCard/ProductCard' import s from "./ProductList.module.scss" -import { FavoriteList } from '@framework/schema' interface ProductListProps { data: ProductCardProps[], total?: number, @@ -17,8 +16,8 @@ interface ProductListProps { const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChange }: ProductListProps) => { const router = useRouter() - const {wishlist:FavoriteList } = useActiveCustomer(); - + const {wishlist } = useActiveCustomer(); + const handlePageChange = (page: number) => { onPageChange && onPageChange(page) } @@ -36,8 +35,8 @@ const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChan
{ data.map((product, index) => { - - return + let activeWishlist = wishlist?.findIndex((val:string) => val == product.id) !== -1; + return }) } { diff --git a/src/components/hooks/auth/useActiveCustomer.tsx b/src/components/hooks/auth/useActiveCustomer.tsx index b4891c44d..67aa798cf 100644 --- a/src/components/hooks/auth/useActiveCustomer.tsx +++ b/src/components/hooks/auth/useActiveCustomer.tsx @@ -1,14 +1,23 @@ -import { ActiveCustomerQuery,FavoriteList } from '@framework/schema' +import { ActiveCustomerQuery,Favorite } from '@framework/schema' import { activeCustomerQuery } from '@framework/utils/queries/active-customer-query' import gglFetcher from 'src/utils/gglFetcher' import useSWR from 'swr' + const useActiveCustomer = () => { const { data, ...rest } = useSWR([activeCustomerQuery], gglFetcher) - - return { - customer: data?.activeCustomer, - wishlist:data?.activeCustomer?.favorites, - ...rest } + console.log(data); + return { + customer: data?.activeCustomer, + userInfo:{ + firstName: data?.activeCustomer?.firstName, + lastName:data?.activeCustomer?.lastName, + email:data?.activeCustomer?.emailAddress, + phoneNumber: data?.activeCustomer?.phoneNumber, + address: data?.activeCustomer?.addresses?.[0] + }, + wishlist: data?.activeCustomer?.favorites?.items.map((val:Favorite)=>val.product.id), + ...rest + } } export default useActiveCustomer diff --git a/src/components/hooks/product/index.ts b/src/components/hooks/product/index.ts index ea2afe03a..68325a40b 100644 --- a/src/components/hooks/product/index.ts +++ b/src/components/hooks/product/index.ts @@ -1,3 +1,4 @@ export { default as useSearchProducts } from './useSearchProducts' +export { default as useToggleProductWishlist } from './useToggleProductWishlist' diff --git a/src/components/hooks/product/useToggleProductWishlist.tsx b/src/components/hooks/product/useToggleProductWishlist.tsx new file mode 100644 index 000000000..452707f46 --- /dev/null +++ b/src/components/hooks/product/useToggleProductWishlist.tsx @@ -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(null) + const { mutate } = useActiveCustomer() + + const onToggleProductWishlist = ( + { productId }:Props , + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + fetcher({ + 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 diff --git a/src/components/modules/account/AccountPage/AccountPage.tsx b/src/components/modules/account/AccountPage/AccountPage.tsx index db5801235..5a83135cb 100644 --- a/src/components/modules/account/AccountPage/AccountPage.tsx +++ b/src/components/modules/account/AccountPage/AccountPage.tsx @@ -12,6 +12,7 @@ import EditInfoModal from './components/EditInfoModal/EditInfoModal' import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data'; import { ACCOUNT_TAB, QUERY_KEY } from "src/utils/constanst.utils" import { useRouter } from "next/router" +import { useActiveCustomer } from 'src/components/hooks/auth' const waiting = [ { @@ -82,6 +83,8 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { const router = useRouter() const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2) const [modalVisible, setModalVisible] = useState(false); + // const { itemWishlist } = useActiveCustomer(); + // console.log(itemWishlist) useEffect(() => { const query = router.query[QUERY_KEY.TAB] as string From 71475d66ec69a2370b7b94ed4840343e03c688ed Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Mon, 11 Oct 2021 10:05:16 +0700 Subject: [PATCH 16/27] bug: edit const --- src/components/common/ProductList/ProductList.tsx | 4 ++-- src/components/hooks/auth/useActiveCustomer.tsx | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/common/ProductList/ProductList.tsx b/src/components/common/ProductList/ProductList.tsx index 041ccbf94..de9cb94d5 100644 --- a/src/components/common/ProductList/ProductList.tsx +++ b/src/components/common/ProductList/ProductList.tsx @@ -16,7 +16,7 @@ interface ProductListProps { const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChange }: ProductListProps) => { const router = useRouter() - const {wishlist } = useActiveCustomer(); + const {wishlistId } = useActiveCustomer(); const handlePageChange = (page: number) => { onPageChange && onPageChange(page) @@ -35,7 +35,7 @@ const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChan
{ data.map((product, index) => { - let activeWishlist = wishlist?.findIndex((val:string) => val == product.id) !== -1; + let activeWishlist = wishlistId?.findIndex((val:string) => val == product.id) !== -1; return }) } diff --git a/src/components/hooks/auth/useActiveCustomer.tsx b/src/components/hooks/auth/useActiveCustomer.tsx index 67aa798cf..a3d8ce34a 100644 --- a/src/components/hooks/auth/useActiveCustomer.tsx +++ b/src/components/hooks/auth/useActiveCustomer.tsx @@ -15,7 +15,8 @@ const useActiveCustomer = () => { phoneNumber: data?.activeCustomer?.phoneNumber, address: data?.activeCustomer?.addresses?.[0] }, - wishlist: data?.activeCustomer?.favorites?.items.map((val:Favorite)=>val.product.id), + itemWishlist:data?.activeCustomer?.favorites?.items, + wishlistId: data?.activeCustomer?.favorites?.items.map((val:Favorite)=>val.product.id), ...rest } } From 820e93652f9c66e2ba19130bc4dd723d7a12cbd5 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Mon, 11 Oct 2021 10:18:23 +0700 Subject: [PATCH 17/27] :sparkles: feat: buynow :%s --- .../common/ProductCard/ProductCard.tsx | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/components/common/ProductCard/ProductCard.tsx b/src/components/common/ProductCard/ProductCard.tsx index 9e2b7087f..2a15dfb5e 100644 --- a/src/components/common/ProductCard/ProductCard.tsx +++ b/src/components/common/ProductCard/ProductCard.tsx @@ -11,6 +11,8 @@ import LabelCommon from '../LabelCommon/LabelCommon' import s from './ProductCard.module.scss' import ProductNotSell from './ProductNotSell/ProductNotSell' import {useAddProductToCart} from "../../hooks/cart" +import { useCartDrawer } from 'src/components/contexts' +import Router from 'next/router' export interface ProductCardProps extends ProductCard { buttonText?: string isSingleButton?: boolean, @@ -31,21 +33,36 @@ const ProductCardComponent = ({ productVariantId, }: ProductCardProps) => { - const {addProduct,loading,error} = useAddProductToCart() + const {addProduct,loading} = useAddProductToCart() + const { openCartDrawer } = useCartDrawer() + const handleAddToCart = () => { if(productVariantId){ addProduct({variantId:productVariantId,quantity:1},handleAddToCartCallback) } } const handleAddToCartCallback = () => { - + openCartDrawer && openCartDrawer() } + + const handleBuyNowCallback = (success:boolean) => { + if(success){ + Router.push(ROUTE.CHECKOUT) + } + } + + const handleBuyNow = () => { + if(productVariantId){ + addProduct({variantId:productVariantId,quantity:1},handleBuyNowCallback) + } + } + if (isNotSell) { return
- } + return (
@@ -83,7 +100,7 @@ const ProductCardComponent = ({ { isSingleButton ?
- } size='small' >Add to cart + } size='small' onClick={handleAddToCart}>Add to cart
: <> @@ -91,7 +108,7 @@ const ProductCardComponent = ({
- {buttonText} + {buttonText}
} From 587eb5d1bcb846ee5ea434a615f6c7daeb47adce Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Mon, 11 Oct 2021 13:38:48 +0700 Subject: [PATCH 18/27] :hammer: refactor: filter one product vatiant :%s --- framework/commerce/types/product.ts | 1 + .../vendure/api/operations/get-all-products.ts | 4 ++-- framework/vendure/schema.d.ts | 2 +- .../utils/fragments/search-result-fragment.ts | 1 + framework/vendure/utils/normalize.ts | 1 + pages/index.tsx | 10 +++++----- src/components/common/ProductCard/ProductCard.tsx | 3 ++- src/utils/funtion.utils.ts | 13 +++++++++++++ 8 files changed, 26 insertions(+), 9 deletions(-) diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index a3bccc83e..95429736f 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -64,6 +64,7 @@ export type ProductCard = { collection?: string, isNotSell?: boolean productVariantId?:string + productVariantName?:string } export type SearchProductsBody = { diff --git a/framework/vendure/api/operations/get-all-products.ts b/framework/vendure/api/operations/get-all-products.ts index 8a6d952de..bf6a3e997 100644 --- a/framework/vendure/api/operations/get-all-products.ts +++ b/framework/vendure/api/operations/get-all-products.ts @@ -5,7 +5,7 @@ import { normalizeSearchResult } from '../../utils/normalize' import { getAllProductsQuery } from '../../utils/queries/get-all-products-query' import { OperationContext } from '@commerce/api/operations' -export type ProductVariables = { first?: number, facetValueIds?: string[], collectionSlug?:string } +export type ProductVariables = { first?: number, facetValueIds?: string[], collectionSlug?:string, groupByProduct?:boolean } export default function getAllProductsOperation({ commerce, @@ -32,7 +32,7 @@ export default function getAllProductsOperation({ take: vars.first, facetValueIds: vars.facetValueIds, collectionSlug : vars.collectionSlug, - groupByProduct: true, + groupByProduct: vars.groupByProduct??true, }, } const { data } = await config.fetch(query, { diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index bf09eeed9..8a947dc63 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3039,7 +3039,7 @@ export type SearchResultFragment = { __typename?: 'SearchResult' } & Pick< SearchResult, 'productId' | 'sku' | 'productName' | 'description' | 'slug' | 'sku' | 'currencyCode' | 'productAsset' | 'price' | 'priceWithTax' | 'currencyCode' - | 'collectionIds' | 'productVariantId' | 'facetValueIds' + | 'collectionIds' | 'productVariantId' | 'facetValueIds' | "productVariantName" > & { productAsset?: Maybe< { __typename?: 'SearchResultAsset' } & Pick< diff --git a/framework/vendure/utils/fragments/search-result-fragment.ts b/framework/vendure/utils/fragments/search-result-fragment.ts index 6408aeb1e..5a5998dca 100644 --- a/framework/vendure/utils/fragments/search-result-fragment.ts +++ b/framework/vendure/utils/fragments/search-result-fragment.ts @@ -8,6 +8,7 @@ export const searchResultFragment = /* GraphQL */ ` sku currencyCode productVariantId + productVariantName productAsset { id preview diff --git a/framework/vendure/utils/normalize.ts b/framework/vendure/utils/normalize.ts index f1bd38fd0..66a0e525d 100644 --- a/framework/vendure/utils/normalize.ts +++ b/framework/vendure/utils/normalize.ts @@ -11,6 +11,7 @@ export function normalizeSearchResult(item: SearchResultFragment): ProductCard { price: (item.priceWithTax as any).min / 100, currencyCode: item.currencyCode, productVariantId: item.productVariantId, + productVariantName:item.productVariantName, facetValueIds: item.facetValueIds, collectionIds: item.collectionIds, diff --git a/pages/index.tsx b/pages/index.tsx index 7c287c230..dc709f813 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,15 +1,13 @@ import { ProductCard } from '@commerce/types/product'; import { ProductVariables } from '@framework/api/operations/get-all-products'; -import { Facet, Product } from '@framework/schema'; import { Collection, FacetValue } from '@framework/schema'; import commerce from '@lib/api/commerce'; -import { ifError } from 'assert'; import { GetStaticPropsContext } from 'next'; import { Layout } from 'src/components/common'; 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 { FACET } from 'src/utils/constanst.utils'; -import { getAllFeaturedFacetId, getFacetIdByName, getFreshProductFacetId } from 'src/utils/funtion.utils'; +import { FilterOneVatiant, getFacetIdByName } from 'src/utils/funtion.utils'; import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED } from 'src/utils/constanst.utils'; import { getAllFacetValueIdsByParentCode, getAllFacetValuesForFeatuedProducts, getAllPromies, getFreshFacetId } from 'src/utils/funtion.utils'; import { PromiseWithKey } from 'src/utils/types.utils'; @@ -78,7 +76,9 @@ export async function getStaticProps({ props.freshProducts = [] } - const veggieProductvariables: ProductVariables = {} + const veggieProductvariables: ProductVariables = { + groupByProduct:false + } const veggieId = getFacetIdByName(facets,FACET.CATEGORY.PARENT_NAME,FACET.CATEGORY.VEGGIE) if (veggieId) { veggieProductvariables.facetValueIds = [veggieId] @@ -121,7 +121,7 @@ export async function getStaticProps({ const rs = await Promise.all(promises) promisesWithKey.map((item, index) => { - props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index] + props[item.key] = item.keyResult ? FilterOneVatiant(rs[index][item.keyResult]) : rs[index] return null }) diff --git a/src/components/common/ProductCard/ProductCard.tsx b/src/components/common/ProductCard/ProductCard.tsx index 2a15dfb5e..e457f6a1a 100644 --- a/src/components/common/ProductCard/ProductCard.tsx +++ b/src/components/common/ProductCard/ProductCard.tsx @@ -31,6 +31,7 @@ const ProductCardComponent = ({ isNotSell, isSingleButton, productVariantId, + productVariantName }: ProductCardProps) => { const {addProduct,loading} = useAddProductToCart() @@ -84,7 +85,7 @@ const ProductCardComponent = ({
-
{name}
+
{productVariantName}
{weight}
diff --git a/src/utils/funtion.utils.ts b/src/utils/funtion.utils.ts index cc1571ade..e1ea6cb50 100644 --- a/src/utils/funtion.utils.ts +++ b/src/utils/funtion.utils.ts @@ -1,4 +1,5 @@ import { Facet } from "@commerce/types/facet"; +import { ProductCard } from "@commerce/types/product"; import { Collection, FacetValue, SearchResultSortParameter } from './../../framework/vendure/schema.d'; import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED, CODE_FACET_FEATURED_VARIANT, FACET, PRODUCT_SORT_OPTION_VALUE } from "./constanst.utils"; import { PromiseWithKey, SortOrder } from "./types.utils"; @@ -139,4 +140,16 @@ export const getCategoryNameFromCollectionId = (colelctions: Collection[], colle export function getAllPromies(promies: PromiseWithKey[]) { return promies.map(item => item.promise) +} + +export const FilterOneVatiant = (products:ProductCard[]) => { + let idList:string[] = [] + let filtedProduct: ProductCard[]=[] + products.map((product:ProductCard)=>{ + if(!idList.includes(product.id)){ + filtedProduct.push(product) + idList.push(product.id) + } + }) + return filtedProduct } \ No newline at end of file From 694c3ac78305f4622e2c24b109df4687a9cbb568 Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Tue, 12 Oct 2021 14:33:35 +0700 Subject: [PATCH 19/27] feat: get favorite products --- framework/vendure/schema.d.ts | 16 ++++++++++ .../utils/queries/active-customer-query.ts | 11 ------- .../queries/get-favorite-product-query.ts | 27 ++++++++++++++++ .../common/ProductList/ProductList.tsx | 12 +++---- src/components/hooks/account/index.ts | 1 + .../hooks/account/useGetFavoriteProduct.tsx | 25 +++++++++++++++ .../hooks/auth/useActiveCustomer.tsx | 2 +- .../AccountPage/AccountPage.module.scss | 13 +++++++- .../account/AccountPage/AccountPage.tsx | 29 ++++++++++++++--- .../FavouriteProducts/FavouriteProducts.tsx | 32 ++++++++++++++----- 10 files changed, 136 insertions(+), 32 deletions(-) create mode 100644 framework/vendure/utils/queries/get-favorite-product-query.ts create mode 100644 src/components/hooks/account/index.ts create mode 100644 src/components/hooks/account/useGetFavoriteProduct.tsx diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index 705e340c2..d3ca320f0 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3203,6 +3203,16 @@ export type ActiveCustomerQuery = { __typename?: 'Query' } & { >, > } + +export type QueryFavorite = { + options: FavoriteListOptions +} + +export type FavoriteListOptions = { + skip?: Maybe + take?: Maybe +} + export type FavoriteList = PaginatedList & { items: [Favorite!]! totalItems: Int! @@ -3216,6 +3226,12 @@ type Favorite = Node & { customer: Customer! } + + +type FavouriteOption = Customer & { + favorites(options: FavoriteListOptions): FavoriteList! +} + export type GetAllProductPathsQueryVariables = Exact<{ first?: Maybe }> diff --git a/framework/vendure/utils/queries/active-customer-query.ts b/framework/vendure/utils/queries/active-customer-query.ts index 7384dde78..014ea130e 100644 --- a/framework/vendure/utils/queries/active-customer-query.ts +++ b/framework/vendure/utils/queries/active-customer-query.ts @@ -1,5 +1,3 @@ -import { searchResultFragment } from '../fragments/search-result-fragment' - export const activeCustomerQuery = /* GraphQL */ ` query activeCustomer { activeCustomer { @@ -11,15 +9,6 @@ export const activeCustomerQuery = /* GraphQL */ ` items{ product{ id - name - slug - assets{ - source - preview - } - variants{ - price - } } } } diff --git a/framework/vendure/utils/queries/get-favorite-product-query.ts b/framework/vendure/utils/queries/get-favorite-product-query.ts new file mode 100644 index 000000000..aff1a2bf5 --- /dev/null +++ b/framework/vendure/utils/queries/get-favorite-product-query.ts @@ -0,0 +1,27 @@ +export const getFavoriteProductQuery = /* GraphQL */ ` +query activeCustomer($options: FavoriteListOptions) { + activeCustomer { + id + firstName + lastName + emailAddress + favorites(options: $options){ + items{ + product{ + id + name + slug + assets{ + source + preview + } + variants{ + price + } + } + } + totalItems + } + } +} +` diff --git a/src/components/common/ProductList/ProductList.tsx b/src/components/common/ProductList/ProductList.tsx index de9cb94d5..111173fa9 100644 --- a/src/components/common/ProductList/ProductList.tsx +++ b/src/components/common/ProductList/ProductList.tsx @@ -14,10 +14,10 @@ interface ProductListProps { onPageChange?: (page: number) => void } -const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChange }: ProductListProps) => { +const ProductList = ({ data, total = data?.length, defaultCurrentPage, onPageChange }: ProductListProps) => { const router = useRouter() const {wishlistId } = useActiveCustomer(); - + const handlePageChange = (page: number) => { onPageChange && onPageChange(page) } @@ -34,20 +34,20 @@ const ProductList = ({ data, total = data.length, defaultCurrentPage, onPageChan
{ - data.map((product, index) => { + data?.map((product, index) => { let activeWishlist = wishlistId?.findIndex((val:string) => val == product.id) !== -1; return }) } { - data.length === 0 &&
+ data?.length === 0 &&
Show all products
}
-
- +
+
) diff --git a/src/components/hooks/account/index.ts b/src/components/hooks/account/index.ts new file mode 100644 index 000000000..73fbcc66b --- /dev/null +++ b/src/components/hooks/account/index.ts @@ -0,0 +1 @@ +export { default as useGetFavoriteProduct } from './useGetFavoriteProduct' \ No newline at end of file diff --git a/src/components/hooks/account/useGetFavoriteProduct.tsx b/src/components/hooks/account/useGetFavoriteProduct.tsx new file mode 100644 index 000000000..4cc94ed5e --- /dev/null +++ b/src/components/hooks/account/useGetFavoriteProduct.tsx @@ -0,0 +1,25 @@ +import { ActiveCustomerQuery,QueryFavorite,Favorite } from '@framework/schema' +import { getFavoriteProductQuery } from '@framework/utils/queries/get-favorite-product-query' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' + +const useGetFavoriteProduct = (options:QueryFavorite) => { + const { data, ...rest } = useSWR([getFavoriteProductQuery, options], gglFetcher) + console.log(options); + return { + itemWishlist: + data?.activeCustomer?.favorites?.items?.map((val:Favorite)=>({ + id: val.product?.id, + name:val.product?.name, + slug:val.product?.slug, + price:val.product?.variants?.[0].price, + imageSrc: val.product?.assets?.[0].preview, + currencyCode: val.product?.variants?.[0].currencyCode + }) + ), + totalItems: data?.activeCustomer?.favorites?.totalItems, + ...rest + } +} + +export default useGetFavoriteProduct diff --git a/src/components/hooks/auth/useActiveCustomer.tsx b/src/components/hooks/auth/useActiveCustomer.tsx index a3d8ce34a..6f841c523 100644 --- a/src/components/hooks/auth/useActiveCustomer.tsx +++ b/src/components/hooks/auth/useActiveCustomer.tsx @@ -5,7 +5,7 @@ import useSWR from 'swr' const useActiveCustomer = () => { const { data, ...rest } = useSWR([activeCustomerQuery], gglFetcher) - console.log(data); + return { customer: data?.activeCustomer, userInfo:{ diff --git a/src/components/modules/account/AccountPage/AccountPage.module.scss b/src/components/modules/account/AccountPage/AccountPage.module.scss index 89beebd86..240c369a8 100644 --- a/src/components/modules/account/AccountPage/AccountPage.module.scss +++ b/src/components/modules/account/AccountPage/AccountPage.module.scss @@ -4,7 +4,17 @@ @apply bg-background-gray; padding: 3.2rem 2rem; min-height: 70rem; - + @screen xl { + section{ + div{ + div{ + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + } + } + } + + } + @screen md { padding-left: 2.8rem; padding-right: 2.8rem; @@ -28,4 +38,5 @@ margin-bottom: 3.8rem; } } + } \ No newline at end of file diff --git a/src/components/modules/account/AccountPage/AccountPage.tsx b/src/components/modules/account/AccountPage/AccountPage.tsx index 5a83135cb..d1fe6625e 100644 --- a/src/components/modules/account/AccountPage/AccountPage.tsx +++ b/src/components/modules/account/AccountPage/AccountPage.tsx @@ -8,11 +8,13 @@ import AccountInfomation from "./components/AccountInfomation/AccountInfomation" import FavouriteProducts from "./components/FavouriteProducts/FavouriteProducts" import OrderInfomation from './components/OrderInformation/OrderInformation' import EditInfoModal from './components/EditInfoModal/EditInfoModal' - 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,DEFAULT_PAGE_SIZE } from "src/utils/constanst.utils" import { useRouter } from "next/router" import { useActiveCustomer } from 'src/components/hooks/auth' +import { useGetFavoriteProduct } from 'src/components/hooks/account' +import { QueryFavorite } from "@framework/schema" +import { getPageFromQuery} from 'src/utils/funtion.utils' const waiting = [ { @@ -79,13 +81,30 @@ const getTabIndex = (tab?: string): number => { } } + +const DEFAULT_FAVORITE_ARGS = { + options:{ + skip:1, take:DEFAULT_PAGE_SIZE + } +} + const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { const router = useRouter() const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2) const [modalVisible, setModalVisible] = useState(false); - // const { itemWishlist } = useActiveCustomer(); - // console.log(itemWishlist) + const [optionQueryFavorite, setoptionQueryFavorite] = useState(DEFAULT_FAVORITE_ARGS) + const { itemWishlist,totalItems }= useGetFavoriteProduct(optionQueryFavorite); + console.log(itemWishlist,totalItems) + // skip + useEffect(() => { + const query = { ...DEFAULT_FAVORITE_ARGS } as QueryFavorite; + const page = getPageFromQuery(router.query[QUERY_KEY.PAGE] as string); + query.options.skip = page * DEFAULT_PAGE_SIZE; + setoptionQueryFavorite(query); + },[router.query]) + + useEffect(() => { const query = router.query[QUERY_KEY.TAB] as string const index = getTabIndex(query) @@ -115,7 +134,7 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { - +
diff --git a/src/components/modules/account/AccountPage/components/FavouriteProducts/FavouriteProducts.tsx b/src/components/modules/account/AccountPage/components/FavouriteProducts/FavouriteProducts.tsx index f88605242..f82266c81 100644 --- a/src/components/modules/account/AccountPage/components/FavouriteProducts/FavouriteProducts.tsx +++ b/src/components/modules/account/AccountPage/components/FavouriteProducts/FavouriteProducts.tsx @@ -1,18 +1,34 @@ -import React from "react" -import s from './FavouriteProducts.module.scss' -import {ProductList} from '../../../../../common' +import { useRouter } from 'next/router' +import React, { useState } from "react" +import { QUERY_KEY, ROUTE } from 'src/utils/constanst.utils' +import { ProductList } from '../../../../../common' import { ProductCardProps } from '../../../../../common/ProductCard/ProductCard' - - +import s from './FavouriteProducts.module.scss' interface FavouriteProductsProps { - products: ProductCardProps[]; + products: ProductCardProps[], + totalItems:number } -const FavouriteProducts = ({ products } : FavouriteProductsProps) => { +const FavouriteProducts = ({ products,totalItems } : FavouriteProductsProps) => { + const router = useRouter() + const [currentPage, setCurrentPage] = useState(0); + + function onPageChange(page:number){ + setCurrentPage(page) + router.push({ + pathname: ROUTE.ACCOUNT, + query: { + ...router.query, + [QUERY_KEY.PAGE]: page + } + }, + undefined, { shallow: true } + ) + } return (
- +
) } From de664810999bd3c03466624dd72859ba57e6656f Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Thu, 14 Oct 2021 10:33:12 +0700 Subject: [PATCH 20/27] bug: fix favorite products --- .../api/operations/get-all-products.ts | 4 +-- framework/vendure/utils/normalize.ts | 14 +++++++++- .../queries/get-favorite-product-query.ts | 3 +- pages/index.tsx | 21 ++++++++++---- .../hooks/account/useGetFavoriteProduct.tsx | 14 ++-------- .../account/AccountPage/AccountPage.tsx | 28 ++++++++++--------- .../home/FreshProducts/FreshProducts.tsx | 1 + .../modules/home/HomeSpice/HomeSpice.tsx | 8 +++--- src/utils/constanst.utils.ts | 1 + 9 files changed, 56 insertions(+), 38 deletions(-) diff --git a/framework/vendure/api/operations/get-all-products.ts b/framework/vendure/api/operations/get-all-products.ts index 5fb458f67..f70b4bcf3 100644 --- a/framework/vendure/api/operations/get-all-products.ts +++ b/framework/vendure/api/operations/get-all-products.ts @@ -5,7 +5,7 @@ import { normalizeSearchResult } from '../../utils/normalize' import { getAllProductsQuery } from '../../utils/queries/get-all-products-query' import { OperationContext } from '@commerce/api/operations' -export type ProductVariables = { first?: number, facetValueIds?: string[] } +export type ProductVariables = { first?: number, facetValueIds?: string[],collectionSlug?:string } export default function getAllProductsOperation({ commerce, @@ -31,13 +31,13 @@ export default function getAllProductsOperation({ input: { take: vars.first, facetValueIds: vars.facetValueIds, + collectionSlug: vars.collectionSlug, groupByProduct: true, }, } const { data } = await config.fetch(query, { variables, }) - return { products: data.search.items.map((item) => normalizeSearchResult(item)), totalItems: data.search.totalItems as number, diff --git a/framework/vendure/utils/normalize.ts b/framework/vendure/utils/normalize.ts index cc76e5f97..d088b2579 100644 --- a/framework/vendure/utils/normalize.ts +++ b/framework/vendure/utils/normalize.ts @@ -1,6 +1,6 @@ import { Cart } from '@commerce/types/cart' import { ProductCard } from '@commerce/types/product' -import { CartFragment, SearchResultFragment } from '../schema' +import { CartFragment, SearchResultFragment,Favorite,ActiveCustomerQuery } from '../schema' export function normalizeSearchResult(item: SearchResultFragment): ProductCard { return { @@ -21,6 +21,18 @@ export function normalizeSearchResult(item: SearchResultFragment): ProductCard { } } +export function normalizeFavoriteProductResult(item: Favorite) { + return { + id: item.product.id, + name: item.product.name, + slug: item.product.slug, + imageSrc: item.product.assets[0].preview ? item.product.assets[0].preview + '?w=800&mode=crop' : '', + price: item.product.variants[0].priceWithTax as number / 100, + currencyCode: item.product.variants[0].currencyCode, + } +} + + export function normalizeCart(order: CartFragment): Cart { return { id: order.id.toString(), diff --git a/framework/vendure/utils/queries/get-favorite-product-query.ts b/framework/vendure/utils/queries/get-favorite-product-query.ts index aff1a2bf5..f73e0fb26 100644 --- a/framework/vendure/utils/queries/get-favorite-product-query.ts +++ b/framework/vendure/utils/queries/get-favorite-product-query.ts @@ -16,7 +16,8 @@ query activeCustomer($options: FavoriteListOptions) { preview } variants{ - price + priceWithTax + currencyCode } } } diff --git a/pages/index.tsx b/pages/index.tsx index 010094de4..ab86005e5 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -6,7 +6,7 @@ import { GetStaticPropsContext } from 'next'; import { Layout } from 'src/components/common'; 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 { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED } from 'src/utils/constanst.utils'; +import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED,COLLECTION_SLUG_SPICE } from 'src/utils/constanst.utils'; import { getAllFacetValueIdsByParentCode, getAllFacetValuesForFeatuedProducts, getAllPromies, getFreshFacetId } from 'src/utils/funtion.utils'; import { PromiseWithKey } from 'src/utils/types.utils'; @@ -15,11 +15,12 @@ interface Props { freshProducts: ProductCard[], featuredProducts: ProductCard[], collections: Collection[] - + spiceProducts:ProductCard[] } export default function Home({ featuredAndDiscountFacetsValue, freshProducts, featuredProducts, - collections }: Props) { + collections,spiceProducts }: Props) { + return ( <> @@ -28,7 +29,7 @@ export default function Home({ featuredAndDiscountFacetsValue, - + {spiceProducts.length>0 && } @@ -99,16 +100,24 @@ export async function getStaticProps({ }) promisesWithKey.push({ key: 'collections', promise: collectionsPromise, keyResult: 'collections' }) + // spiceProducts + const spiceProducts = commerce.getAllProducts({ + variables: { + collectionSlug: COLLECTION_SLUG_SPICE, + }, + config, + preview, + }) + promisesWithKey.push({ key: 'spiceProducts', promise: spiceProducts, keyResult: 'products' }) try { const promises = getAllPromies(promisesWithKey) const rs = await Promise.all(promises) - + promisesWithKey.map((item, index) => { props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index] return null }) - return { props, revalidate: 60, diff --git a/src/components/hooks/account/useGetFavoriteProduct.tsx b/src/components/hooks/account/useGetFavoriteProduct.tsx index 4cc94ed5e..157bc91a3 100644 --- a/src/components/hooks/account/useGetFavoriteProduct.tsx +++ b/src/components/hooks/account/useGetFavoriteProduct.tsx @@ -1,22 +1,14 @@ import { ActiveCustomerQuery,QueryFavorite,Favorite } from '@framework/schema' +import { normalizeFavoriteProductResult } from '@framework/utils/normalize' import { getFavoriteProductQuery } from '@framework/utils/queries/get-favorite-product-query' import gglFetcher from 'src/utils/gglFetcher' import useSWR from 'swr' const useGetFavoriteProduct = (options:QueryFavorite) => { const { data, ...rest } = useSWR([getFavoriteProductQuery, options], gglFetcher) - console.log(options); + // console.log( data?.activeCustomer?.favorites?.items); return { - itemWishlist: - data?.activeCustomer?.favorites?.items?.map((val:Favorite)=>({ - id: val.product?.id, - name:val.product?.name, - slug:val.product?.slug, - price:val.product?.variants?.[0].price, - imageSrc: val.product?.assets?.[0].preview, - currencyCode: val.product?.variants?.[0].currencyCode - }) - ), + itemWishlist: data?.activeCustomer?.favorites?.items?.map((item:Favorite) => normalizeFavoriteProductResult(item)), totalItems: data?.activeCustomer?.favorites?.totalItems, ...rest } diff --git a/src/components/modules/account/AccountPage/AccountPage.tsx b/src/components/modules/account/AccountPage/AccountPage.tsx index d1fe6625e..ffba6b811 100644 --- a/src/components/modules/account/AccountPage/AccountPage.tsx +++ b/src/components/modules/account/AccountPage/AccountPage.tsx @@ -1,20 +1,20 @@ +import { QueryFavorite } from "@framework/schema" +import commerce from '@lib/api/commerce' +import { GetStaticPropsContext } from 'next' +import { useRouter } from "next/router" import React, { useEffect, useState } from "react" -import s from './AccountPage.module.scss' - import { HeadingCommon, TabPane } from "src/components/common" - +import { useGetFavoriteProduct } from 'src/components/hooks/account' +import { ACCOUNT_TAB, DEFAULT_PAGE_SIZE, QUERY_KEY } from "src/utils/constanst.utils" +import { getPageFromQuery } from 'src/utils/funtion.utils' +import { PromiseWithKey } from 'src/utils/types.utils' import AccountNavigation from '../AccountNavigation/AccountNavigation' +import s from './AccountPage.module.scss' import AccountInfomation from "./components/AccountInfomation/AccountInfomation" +import EditInfoModal from './components/EditInfoModal/EditInfoModal' import FavouriteProducts from "./components/FavouriteProducts/FavouriteProducts" import OrderInfomation from './components/OrderInformation/OrderInformation' -import EditInfoModal from './components/EditInfoModal/EditInfoModal' -import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data'; -import { ACCOUNT_TAB, QUERY_KEY,DEFAULT_PAGE_SIZE } from "src/utils/constanst.utils" -import { useRouter } from "next/router" -import { useActiveCustomer } from 'src/components/hooks/auth' -import { useGetFavoriteProduct } from 'src/components/hooks/account' -import { QueryFavorite } from "@framework/schema" -import { getPageFromQuery} from 'src/utils/funtion.utils' + const waiting = [ { @@ -93,8 +93,9 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2) const [modalVisible, setModalVisible] = useState(false); const [optionQueryFavorite, setoptionQueryFavorite] = useState(DEFAULT_FAVORITE_ARGS) + const { itemWishlist,totalItems }= useGetFavoriteProduct(optionQueryFavorite); - console.log(itemWishlist,totalItems) + // skip useEffect(() => { @@ -143,4 +144,5 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { ) } -export default AccountPage \ No newline at end of file +export default AccountPage + diff --git a/src/components/modules/home/FreshProducts/FreshProducts.tsx b/src/components/modules/home/FreshProducts/FreshProducts.tsx index 6d30459f3..8a628fe2f 100644 --- a/src/components/modules/home/FreshProducts/FreshProducts.tsx +++ b/src/components/modules/home/FreshProducts/FreshProducts.tsx @@ -10,6 +10,7 @@ interface FreshProductsProps { } const FreshProducts = ({ data, collections }: FreshProductsProps) => { + const dataWithCategory = useMemo(() => { return data.map(item => { return { diff --git a/src/components/modules/home/HomeSpice/HomeSpice.tsx b/src/components/modules/home/HomeSpice/HomeSpice.tsx index 5c24f1809..25d528766 100644 --- a/src/components/modules/home/HomeSpice/HomeSpice.tsx +++ b/src/components/modules/home/HomeSpice/HomeSpice.tsx @@ -2,16 +2,16 @@ import React from 'react' import { ProductCarousel } from 'src/components/common' import { SPICE_DATA_TEST } from "../../../../utils/demo-data" import s from './HomeSpice.module.scss' - +import { ProductCard } from '@commerce/types/product' interface HomeSpice { - + data: ProductCard[] } -const HomeSpice = ({}: HomeSpice) => { +const HomeSpice = ({data}: HomeSpice) => { return (
- +
) } diff --git a/src/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index 7d0cf9ba5..108e96265 100644 --- a/src/utils/constanst.utils.ts +++ b/src/utils/constanst.utils.ts @@ -184,3 +184,4 @@ export const STATE_OPTIONS = [ }, ] +export const COLLECTION_SLUG_SPICE ="spice"; From 833c5205b23f889b5b497520dc3b0dc5a242afe5 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Thu, 14 Oct 2021 14:17:23 +0700 Subject: [PATCH 21/27] :sparkles: feat: add product to cart :%s --- framework/commerce/types/product.ts | 3 +- .../vendure/api/operations/get-product.ts | 3 +- framework/vendure/schema.d.ts | 2 +- .../utils/queries/get-product-query.ts | 1 + next-env.d.ts | 3 + .../MenuFilterItem/MenuFilterItem.tsx | 1 - .../ProductInfoDetail/ProductInfoDetail.tsx | 14 +-- .../ProductDetailOption.module.scss | 37 ++++++++ .../ProductDetailOption.tsx | 55 ++++++++++++ .../components/ProductInfo/ProductInfo.tsx | 89 +++++++++++++++++-- src/utils/funtion.utils.ts | 24 ++++- src/utils/types.utils.ts | 2 + 12 files changed, 215 insertions(+), 19 deletions(-) create mode 100644 src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.module.scss create mode 100644 src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.tsx diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index 5152054a3..eb69371db 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -48,7 +48,8 @@ export type Product = { options: ProductOption[] facetValueIds?: string[] collectionIds?: string[] - collection?: string, + collection?: string[], + variants?: ProductVariant[] } export type ProductCard = { diff --git a/framework/vendure/api/operations/get-product.ts b/framework/vendure/api/operations/get-product.ts index 0aa761ab0..b7ddc5c42 100644 --- a/framework/vendure/api/operations/get-product.ts +++ b/framework/vendure/api/operations/get-product.ts @@ -54,7 +54,8 @@ export default function getProductOperation({ values: og.options.map((o) => ({ label: o.name })), })), facetValueIds: product.facetValues.map(item=> item.id), - collectionIds: product.collections.map(item => item.id) + collectionIds: product.collections.map(item => item.id), + collection:product.collections.map(item => item.name), } as Product } diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index 24119e9e6..ad7662bec 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3347,7 +3347,7 @@ export type GetProductQuery = { __typename?: 'Query' } & { collections: Array< { __typename?: 'Collection' } & Pick< Collection, - 'id' + 'id'|"name" > > } diff --git a/framework/vendure/utils/queries/get-product-query.ts b/framework/vendure/utils/queries/get-product-query.ts index 6db960a96..2eb7ee278 100644 --- a/framework/vendure/utils/queries/get-product-query.ts +++ b/framework/vendure/utils/queries/get-product-query.ts @@ -41,6 +41,7 @@ export const getProductQuery = /* GraphQL */ ` } collections { id + name } } } diff --git a/next-env.d.ts b/next-env.d.ts index c6643fda1..9bc3dd46b 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,3 +1,6 @@ /// /// /// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/src/components/common/MenuFilter/MenuFilterItem/MenuFilterItem.tsx b/src/components/common/MenuFilter/MenuFilterItem/MenuFilterItem.tsx index eeb96fae1..b694e7da8 100644 --- a/src/components/common/MenuFilter/MenuFilterItem/MenuFilterItem.tsx +++ b/src/components/common/MenuFilter/MenuFilterItem/MenuFilterItem.tsx @@ -1,5 +1,4 @@ import classNames from 'classnames'; -import { route } from 'next/dist/server/router'; import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; import s from './MenuFilterItem.module.scss'; diff --git a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx index 072c1fd56..556acc9c5 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx @@ -12,16 +12,16 @@ interface Props { } const ProductInfoDetail = ({ productDetail, collections }: Props) => { - const dataWithCategoryName = useMemo(() => { - return { - ...productDetail, - collection: getCategoryNameFromCollectionId(collections, productDetail.collectionIds ? productDetail.collectionIds[0] : undefined) - } - }, [productDetail, collections]) + // const dataWithCategoryName = useMemo(() => { + // return { + // ...productDetail, + // collection: getCategoryNameFromCollectionId(collections, productDetail.collectionIds ? productDetail.collectionIds[0] : undefined) + // } + // }, [productDetail, collections]) return (
- +
) } diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.module.scss b/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.module.scss new file mode 100644 index 000000000..d22660a4a --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.module.scss @@ -0,0 +1,37 @@ +.warpper{ + display: flex; + justify-content: flex-start; + flex-direction: column; + align-items: flex-start; + .name{ + margin-bottom: 0.5rem; + margin-top: 0.5rem; + font-size: 2rem; + font-weight: 700; + text-transform: capitalize; + } + .option{ + display: flex; + justify-content: flex-start; + align-items: flex-start; + // > button { + // margin-right: 1rem; + // } + } + .button { + margin: 1rem 0; + padding: 0; + div { + padding: 0.8rem 1.6rem; + margin-right: 0.8rem; + background-color: var(--gray); + border-radius: 0.8rem; + cursor: pointer; + &.active { + color: var(--white); + background-color: var(--primary); + } + } + } + +} \ No newline at end of file diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.tsx new file mode 100644 index 000000000..0d7e13c84 --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.tsx @@ -0,0 +1,55 @@ +import { ProductOption, ProductOptionValues } from '@commerce/types/product' +import classNames from 'classnames' +import React, { useEffect, useState } from 'react' +import { SelectedOptions } from 'src/utils/types.utils' +import s from './ProductDetailOption.module.scss' +interface Props { + option: ProductOption + onChane: (values: SelectedOptions) => void +} + +const ProductDetailOption = React.memo(({ option, onChane }: Props) => { + const [selected, setSelected] = useState('') + useEffect(() => { + if (option) { + setSelected(option.values[0].label) + } + }, [option]) + const handleClick = (value:string) => { + setSelected(value) + onChane && onChane({[option.displayName]:value}) + } + return ( +
+
{option.displayName}:
+
+ {option.values.map((value) => { + return + })} +
+
+ ) +}) +interface ProductDetailOptionButtonProps { + value: ProductOptionValues + selected: string + onClick: (value: string) => void +} +const ProductDetailOptionButton = ({ + value, + selected, + onClick, +}: ProductDetailOptionButtonProps) => { + const handleClick = () => { + onClick && onClick(value.label) + } + return ( +
+
+ {value.label} +
+
+ ) +} + +export default ProductDetailOption diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx index c3e51d46d..961d8e29b 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx @@ -1,8 +1,15 @@ import { Product } from '@commerce/types/product' -import React from 'react' +import Router from 'next/router' +import React, { useEffect, useState } from 'react' import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common' +import { useCartDrawer, useMessage } from 'src/components/contexts' +import { useAddProductToCart } from 'src/components/hooks/cart' import { IconBuy } from 'src/components/icons' +import { ROUTE } from 'src/utils/constanst.utils' +import { getProductVariant } from 'src/utils/funtion.utils' import { LANGUAGE } from 'src/utils/language.utils' +import { SelectedOptions } from 'src/utils/types.utils' +import ProductDetailOption from '../ProductDetailOption/ProductDetailOption' import s from './ProductInfo.module.scss' interface Props { @@ -10,11 +17,73 @@ interface Props { } const ProductInfo = ({ productInfoDetail }: Props) => { - console.log(productInfoDetail) + const [option, setOption] = useState({}) + const [quanitty, setQuanitty] = useState(0) + const [addToCartLoading, setAddToCartLoading] = useState(false) + const [buyNowLoading, setBuyNowLoading] = useState(false) + const { showMessageSuccess, showMessageError } = useMessage() + useEffect(() => { + let defaultOption:SelectedOptions = {} + productInfoDetail.options.map((option)=>{ + defaultOption[option.displayName] = option.values[0].label + return null + }) + }, [productInfoDetail]) + + const {addProduct} = useAddProductToCart() + const { openCartDrawer } = useCartDrawer() + + function handleAddToCart() { + setAddToCartLoading(true) + const variant = getProductVariant(productInfoDetail, option) + if (variant) { + addProduct({ variantId: variant.id.toString(), quantity: quanitty }, handleAddToCartCallback) + }else{ + setAddToCartLoading(false) + } + } + const handleAddToCartCallback = (isSuccess:boolean,message?:string) => { + setAddToCartLoading(false) + if(isSuccess){ + showMessageSuccess("Add to cart successfully!", 4000) + openCartDrawer && openCartDrawer() + }else{ + showMessageError(message||"Error") + } + + } + + const handleBuyNowCallback = (success:boolean,message?:string) => { + setBuyNowLoading(false) + if(success){ + Router.push(ROUTE.CHECKOUT) + }else{ + showMessageError(message||"Error") + } + } + + const handleBuyNow = () => { + setBuyNowLoading(true) + const variant = getProductVariant(productInfoDetail, option) + if (variant) { + addProduct({ variantId: variant.id.toString(), quantity: quanitty }, handleBuyNowCallback) + }else{ + setBuyNowLoading(false) + } + } + + const handleQuanittyChange = (value:number) => { + setQuanitty(value) + } + const onSelectOption = (value:SelectedOptions) => { + setOption({...option,...value}) + // let variant = getProductVariant(productInfoDetail,value) + // console.log(variant) + } return (
- {productInfoDetail.collection} + {productInfoDetail.collection?.[0]}

{productInfoDetail.name}

@@ -26,14 +95,22 @@ const ProductInfo = ({ productInfoDetail }: Props) => {
{productInfoDetail.description}
+
+ { + productInfoDetail.options.map((option)=>{ + return + }) + } + +
- +
{/* {LANGUAGE.BUTTON_LABEL.PREORDER} */} - {LANGUAGE.BUTTON_LABEL.BUY_NOW} + {LANGUAGE.BUTTON_LABEL.BUY_NOW} - + {LANGUAGE.BUTTON_LABEL.ADD_TO_CARD} diff --git a/src/utils/funtion.utils.ts b/src/utils/funtion.utils.ts index e1ea6cb50..73cd6094a 100644 --- a/src/utils/funtion.utils.ts +++ b/src/utils/funtion.utils.ts @@ -1,8 +1,8 @@ import { Facet } from "@commerce/types/facet"; -import { ProductCard } from "@commerce/types/product"; +import { Product, ProductCard, ProductOption, ProductOptionValues } from "@commerce/types/product"; import { Collection, FacetValue, SearchResultSortParameter } from './../../framework/vendure/schema.d'; import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED, CODE_FACET_FEATURED_VARIANT, FACET, PRODUCT_SORT_OPTION_VALUE } from "./constanst.utils"; -import { PromiseWithKey, SortOrder } from "./types.utils"; +import { PromiseWithKey, SelectedOptions, SortOrder } from "./types.utils"; export function isMobile() { return window.innerWidth < 768 @@ -152,4 +152,24 @@ export const FilterOneVatiant = (products:ProductCard[]) => { } }) return filtedProduct +} + +export const convertOption = (values :ProductOptionValues[]) => { + return values.map((value)=>{ return {name:value.label,value:value.label}}) +} + +export function getProductVariant(product: Product, opts: SelectedOptions) { + const variant = product.variants?.find((variant) => { + return Object.entries(opts).every(([key, value]) => + variant.options.find((option) => { + if ( + option.__typename === 'MultipleChoiceOption' && + option.displayName.toLowerCase() === key.toLowerCase() + ) { + return option.values.find((v) => v.label.toLowerCase() === value) + } + }) + ) + }) + return variant } \ No newline at end of file diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index 7f91711bb..78d813f2f 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -71,3 +71,5 @@ export type PromiseWithKey = { promise: PromiseLike keyResult?: string, } + +export type SelectedOptions = Record \ No newline at end of file From 45d7cc2c9a3e39340dbce424672600aaf13c239f Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Thu, 14 Oct 2021 14:54:34 +0700 Subject: [PATCH 22/27] :hammer: refactor: remove product/index.tsx :%s --- src/components/hooks/product/index.ts | 1 + src/components/hooks/product/index.tsx | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/components/hooks/product/index.tsx diff --git a/src/components/hooks/product/index.ts b/src/components/hooks/product/index.ts index ea2afe03a..5fb85680c 100644 --- a/src/components/hooks/product/index.ts +++ b/src/components/hooks/product/index.ts @@ -1,3 +1,4 @@ export { default as useSearchProducts } from './useSearchProducts' +export { default as useProductDetail } from './useProductDetail' diff --git a/src/components/hooks/product/index.tsx b/src/components/hooks/product/index.tsx deleted file mode 100644 index bfe1abac2..000000000 --- a/src/components/hooks/product/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default as useProductDetail } from './useProductDetail' \ No newline at end of file From d2727c8b6d236e0ed0983249ca4050d75a61b578 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Thu, 14 Oct 2021 15:00:39 +0700 Subject: [PATCH 23/27] remove comment code --- .../ProductInfoDetail/ProductInfoDetail.tsx | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx index 556acc9c5..64a00f7e6 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx @@ -1,23 +1,15 @@ -import React, { useMemo } from 'react'; +import React 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 { productDetail: Product, - collections: Collection[] } -const ProductInfoDetail = ({ productDetail, collections }: Props) => { - // const dataWithCategoryName = useMemo(() => { - // return { - // ...productDetail, - // collection: getCategoryNameFromCollectionId(collections, productDetail.collectionIds ? productDetail.collectionIds[0] : undefined) - // } - // }, [productDetail, collections]) +const ProductInfoDetail = ({ productDetail }: Props) => { return (
From b0e47d2671450346c6407d63795c92e4ffa693c0 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Thu, 14 Oct 2021 15:25:18 +0700 Subject: [PATCH 24/27] remove colecttion --- pages/product/[slug].tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx index 2da14a995..b66cfb026 100644 --- a/pages/product/[slug].tsx +++ b/pages/product/[slug].tsx @@ -12,7 +12,7 @@ import { PromiseWithKey } from 'src/utils/types.utils' export default function Slug({ product, relevantProducts, collections }: InferGetStaticPropsType) { return <> - + From 14fa6537135433aa3d21f152c26d372b04edb287 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Fri, 15 Oct 2021 11:18:29 +0700 Subject: [PATCH 25/27] viewed prodyct --- framework/commerce/types/product.ts | 1 + .../vendure/api/operations/get-product.ts | 1 + framework/vendure/schema.d.ts | 2 +- framework/vendure/utils/normalize.ts | 17 +++++++- .../utils/queries/get-product-query.ts | 1 + pages/product/[slug].tsx | 41 +++++++++++++++---- src/components/hooks/useLocalStorage.tsx | 36 ++++++++++++++++ .../ProductInfoDetail/ProductInfoDetail.tsx | 1 - .../ReleventProducts/ReleventProducts.tsx | 2 +- .../ViewedProducts/ViewedProducts.tsx | 23 +++++++++-- src/utils/constanst.utils.ts | 3 +- src/utils/funtion.utils.ts | 3 +- 12 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 src/components/hooks/useLocalStorage.tsx diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index eb69371db..e31f34df9 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -30,6 +30,7 @@ export type ProductOptionValues = { export type ProductVariant = { id: string | number + name:string, options: ProductOption[] availableForSale?: boolean } diff --git a/framework/vendure/api/operations/get-product.ts b/framework/vendure/api/operations/get-product.ts index b7ddc5c42..66f798ee1 100644 --- a/framework/vendure/api/operations/get-product.ts +++ b/framework/vendure/api/operations/get-product.ts @@ -36,6 +36,7 @@ export default function getProductOperation({ })), variants: product.variants.map((v) => ({ id: v.id, + name:v.name, options: v.options.map((o) => ({ // This __typename property is required in order for the correct // variant selection to work, see `components/product/helpers.ts` diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index ad7662bec..465f33cfb 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3303,7 +3303,7 @@ export type GetProductQuery = { __typename?: 'Query' } & { variants: Array< { __typename?: 'ProductVariant' } & Pick< ProductVariant, - 'id' | 'priceWithTax' | 'currencyCode' | 'price' + 'id' | 'priceWithTax' | 'currencyCode' | 'price' | "name" > & { options: Array< { __typename?: 'ProductOption' } & Pick< diff --git a/framework/vendure/utils/normalize.ts b/framework/vendure/utils/normalize.ts index 66a0e525d..afe453f52 100644 --- a/framework/vendure/utils/normalize.ts +++ b/framework/vendure/utils/normalize.ts @@ -1,5 +1,5 @@ import { Cart } from '@commerce/types/cart' -import { ProductCard } from '@commerce/types/product' +import { ProductCard, Product } from '@commerce/types/product' import { CartFragment, SearchResultFragment } from '../schema' export function normalizeSearchResult(item: SearchResultFragment): ProductCard { @@ -57,3 +57,18 @@ export function normalizeCart(order: CartFragment): Cart { })), } } + +export function normalizeProductCard(product: Product): ProductCard { + return { + id: product.id, + name: product.name, + slug: product.slug, + imageSrc: product.images[0].url, + price: product.price, + currencyCode: product.currencyCode, + productVariantId: product.variants?.[0].id.toString(), + productVariantName:product.variants?.[0].name, + facetValueIds: product.facetValueIds, + collectionIds: product.collectionIds, + } +} \ No newline at end of file diff --git a/framework/vendure/utils/queries/get-product-query.ts b/framework/vendure/utils/queries/get-product-query.ts index 2eb7ee278..1ff057e61 100644 --- a/framework/vendure/utils/queries/get-product-query.ts +++ b/framework/vendure/utils/queries/get-product-query.ts @@ -12,6 +12,7 @@ export const getProductQuery = /* GraphQL */ ` } variants { id + name priceWithTax currencyCode options { diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx index 2da14a995..7b45f7270 100644 --- a/pages/product/[slug].tsx +++ b/pages/product/[slug].tsx @@ -1,22 +1,48 @@ -import { Product } from '@framework/schema' +import { Collection } from '@commerce/types/collection' +import { Product, ProductCard } from '@commerce/types/product' import commerce from '@lib/api/commerce' import { GetStaticPathsContext, GetStaticPropsContext, InferGetStaticPropsType } from 'next' +import { useEffect } from 'react' import { Layout, RecipeDetail, RecommendedRecipes, RelevantBlogPosts } from 'src/components/common' +import { useLocalStorage } from 'src/components/hooks/useLocalStorage' import { ProductInfoDetail, ReleventProducts, ViewedProducts } from 'src/components/modules/product-detail' -import { MAX_PRODUCT_CAROUSEL, REVALIDATE_TIME } from 'src/utils/constanst.utils' +import { LOCAL_STORAGE_KEY, MAX_PRODUCT_CAROUSEL, REVALIDATE_TIME } from 'src/utils/constanst.utils' import { BLOGS_DATA_TEST, INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data' import { getAllPromies } from 'src/utils/funtion.utils' import { PromiseWithKey } from 'src/utils/types.utils' - -export default function Slug({ product, relevantProducts, collections }: InferGetStaticPropsType) { - +interface Props { + relevantProducts: ProductCard[], + product: Product, + collections: Collection[] +} +export default function Slug({ product, relevantProducts, collections }: Props) { + const [viewedProduct,setViewedProduct] = useLocalStorage(LOCAL_STORAGE_KEY.VIEWEDPRODUCT, []); + useEffect(() => { + // const local = localStorage.getItem(LOCAL_STORAGE_KEY.VIEWEDPRODUCT) + // if(local){ + // const oldList:Product[] = JSON.parse(local) + // if(!oldList.find(p => p.id === product.id)){ + // localStorage.setItem(LOCAL_STORAGE_KEY.VIEWEDPRODUCT,JSON.stringify([...oldList,product])) + // } + // }else{ + // localStorage.setItem(LOCAL_STORAGE_KEY.VIEWEDPRODUCT,JSON.stringify([product])) + // } + if(viewedProduct){ + if(!viewedProduct.find(p => p.id === product.id)){ + setViewedProduct([...viewedProduct, product]) + } + }else{ + setViewedProduct([product]) + } + }, [product]) + return <> - + - + } @@ -68,7 +94,6 @@ export async function getStaticProps({ }) promisesWithKey.push({ key: 'collections', promise: collectionsPromise, keyResult: 'collections' }) - try { const promises = getAllPromies(promisesWithKey) const rs = await Promise.all(promises) diff --git a/src/components/hooks/useLocalStorage.tsx b/src/components/hooks/useLocalStorage.tsx new file mode 100644 index 000000000..b265ded9a --- /dev/null +++ b/src/components/hooks/useLocalStorage.tsx @@ -0,0 +1,36 @@ +import { useState } from "react"; + +// Hook +export function useLocalStorage(key: string, initialValue: T) { + // State to store our value + // Pass initial state function to useState so logic is only executed once + const [storedValue, setStoredValue] = useState(() => { + try { + // Get from local storage by key + const item = localStorage.getItem(key); + // Parse stored json or if none return initialValue + return item ? JSON.parse(item) : initialValue; + } catch (error) { + // If error also return initialValue + // console.log(error); + return initialValue; + } + }); + // Return a wrapped version of useState's setter function that ... + // ... persists the new value to localStorage. + const setValue = (value: T | ((val: T) => T)) => { + try { + // Allow value to be a function so we have same API as useState + const valueToStore = + value instanceof Function ? value(storedValue) : value; + // Save state + setStoredValue(valueToStore); + // Save to local storage + localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) { + // A more advanced implementation would handle the error case + // console.log(error); + } + }; + return [storedValue, setValue] as const; +} \ No newline at end of file diff --git a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx index 64a00f7e6..5e51bd090 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx @@ -3,7 +3,6 @@ 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' interface Props { productDetail: Product, diff --git a/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx b/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx index d1afde538..9e2581833 100644 --- a/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx +++ b/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx @@ -1,5 +1,5 @@ +import { Collection } from '@commerce/types/collection'; import { ProductCard } from '@commerce/types/product'; -import { Collection } from '@framework/schema'; import React, { useMemo } from 'react'; import ListProductWithInfo from 'src/components/common/ListProductWithInfo/ListProductWithInfo'; import { getCategoryNameFromCollectionId } from 'src/utils/funtion.utils'; diff --git a/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx b/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx index 87e600416..7d10f761d 100644 --- a/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx +++ b/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx @@ -1,13 +1,28 @@ -import React from 'react'; +import { Product } from '@commerce/types/product'; +import React, { useEffect, useState } from 'react'; import ListProductWithInfo from 'src/components/common/ListProductWithInfo/ListProductWithInfo'; -import { PRODUCT_DATA_TEST } from 'src/utils/demo-data'; +import { ProductCardProps } from 'src/components/common/ProductCard/ProductCard'; +import { LOCAL_STORAGE_KEY } from 'src/utils/constanst.utils' +import { normalizeProductCard } from '@framework/utils/normalize'; +import { useLocalStorage } from 'src/components/hooks/useLocalStorage'; +interface Props { +} +const ViewedProducts = ({}:Props) => { + const [data, setData] = useState([]) + const [viewedProduct] = useLocalStorage(LOCAL_STORAGE_KEY.VIEWEDPRODUCT, []); -const ViewedProducts = () => { + useEffect(() => { + setData(viewedProduct.map((p)=>normalizeProductCard(p))) + }, [viewedProduct]) + + if (data.length>0){ + return
+ } return ( ); diff --git a/src/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index 082154f5c..9d03994a3 100644 --- a/src/utils/constanst.utils.ts +++ b/src/utils/constanst.utils.ts @@ -44,7 +44,8 @@ export const ACCOUNT_TAB = { } export const LOCAL_STORAGE_KEY = { - TOKEN: 'token' + TOKEN: 'token', + VIEWEDPRODUCT: "viewed-product" } export const QUERY_SPLIT_SEPERATOR = ',' diff --git a/src/utils/funtion.utils.ts b/src/utils/funtion.utils.ts index 73cd6094a..94521e072 100644 --- a/src/utils/funtion.utils.ts +++ b/src/utils/funtion.utils.ts @@ -1,6 +1,7 @@ +import { Collection } from '@commerce/types/collection'; import { Facet } from "@commerce/types/facet"; import { Product, ProductCard, ProductOption, ProductOptionValues } from "@commerce/types/product"; -import { Collection, FacetValue, SearchResultSortParameter } from './../../framework/vendure/schema.d'; +import { FacetValue, SearchResultSortParameter } from './../../framework/vendure/schema.d'; import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED, CODE_FACET_FEATURED_VARIANT, FACET, PRODUCT_SORT_OPTION_VALUE } from "./constanst.utils"; import { PromiseWithKey, SelectedOptions, SortOrder } from "./types.utils"; From bd06e1d8157fec36e54d2a9b5f6ada81790fa7da Mon Sep 17 00:00:00 2001 From: Quangnhankie Date: Fri, 15 Oct 2021 17:23:42 +0700 Subject: [PATCH 26/27] delete console.log --- src/components/hooks/account/useGetUserOrder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/hooks/account/useGetUserOrder.tsx b/src/components/hooks/account/useGetUserOrder.tsx index 9ef249fbd..26e945abf 100644 --- a/src/components/hooks/account/useGetUserOrder.tsx +++ b/src/components/hooks/account/useGetUserOrder.tsx @@ -5,7 +5,7 @@ import useSWR from 'swr' const useGetUserOrder = () => { const { data, ...rest } = useSWR([getUserOrderQuery], gglFetcher) - console.log(data); + const addingItem = data?.activeCustomer?.orders.items.filter((val:Order) =>val.state == 'AddingItems'); const arrangingPayment = data?.activeCustomer?.orders.items.filter((val:Order) =>val.state == 'ArrangingPayment'); const cancelled = data?.activeCustomer?.orders.items.filter((val:Order) =>val.state == "Cancelled"); From 59039e57df6d3a40a98b798e91921226bfba9fb2 Mon Sep 17 00:00:00 2001 From: DatNguyen Date: Mon, 18 Oct 2021 11:25:42 +0700 Subject: [PATCH 27/27] fix config --- pages/index.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index c4abbb3bd..51127909a 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -6,9 +6,9 @@ import { GetStaticPropsContext } from 'next'; import { Layout } from 'src/components/common'; 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 { COLLECTION_SLUG_SPICE, FACET } from 'src/utils/constanst.utils'; +import { FACET } from 'src/utils/constanst.utils'; import { FilterOneVatiant, getFacetIdByName } from 'src/utils/funtion.utils'; -import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED } from 'src/utils/constanst.utils'; +import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED,COLLECTION_SLUG_SPICE } from 'src/utils/constanst.utils'; import { getAllFacetValueIdsByParentCode, getAllFacetValuesForFeatuedProducts, getAllPromies, getFreshFacetId } from 'src/utils/funtion.utils'; import { PromiseWithKey } from 'src/utils/types.utils'; @@ -17,11 +17,12 @@ interface Props { freshProducts: ProductCard[], featuredProducts: ProductCard[], collections: Collection[] - spiceProducts:ProductCard[], + spiceProducts:ProductCard[] veggie: ProductCard[], + } -export default function Home({ featuredAndDiscountFacetsValue, - freshProducts, featuredProducts, veggie, +export default function Home({ featuredAndDiscountFacetsValue, veggie, + freshProducts, featuredProducts, collections,spiceProducts }: Props) { return ( @@ -78,6 +79,7 @@ export async function getStaticProps({ props.freshProducts = [] } + //veggie const veggieProductvariables: ProductVariables = { groupByProduct:false }