From f0490d0ba72c7b68eb44f790218292d04b582f64 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 31 Jan 2024 10:36:32 +0700 Subject: [PATCH] sync demo --- app/components/Icon.tsx | 67 ++++++++++++++++++- app/components/StarRating.tsx | 20 ++++++ .../product-form/judgeme-review.tsx | 16 ++--- app/components/product-form/product-media.tsx | 53 +++++++++++---- .../($locale).products.$productHandle.tsx | 24 ++++--- app/sections/product-information/index.tsx | 5 +- package.json | 1 - 7 files changed, 147 insertions(+), 39 deletions(-) create mode 100644 app/components/StarRating.tsx diff --git a/app/components/Icon.tsx b/app/components/Icon.tsx index b9553c8..3c7f60f 100644 --- a/app/components/Icon.tsx +++ b/app/components/Icon.tsx @@ -370,8 +370,71 @@ export function IconVideoBlank(props: IconProps) { export function IconArrowInput(props: IconProps) { return ( - - + + + + ); +} + +export function IconFilledStar(props: IconProps) { + return ( + + + + + ); +} +export function IconStar(props: IconProps) { + return ( + + + + + ); +} +export function IconHalfFilledStar(props: IconProps) { + return ( + + + ); } diff --git a/app/components/StarRating.tsx b/app/components/StarRating.tsx new file mode 100644 index 0000000..5d2e9c3 --- /dev/null +++ b/app/components/StarRating.tsx @@ -0,0 +1,20 @@ +import { IconFilledStar, IconHalfFilledStar, IconStar } from "." + +export function StarRating({ rating }: { rating: number }) { + let filledStar = ( + + ) + let halfFilledStar = ( + + ) + let star = + return ( +
+ {rating >= 1 ? filledStar : rating >= 0.5 ? halfFilledStar : star} + {rating >= 2 ? filledStar : rating >= 1.5 ? halfFilledStar : star} + {rating >= 3 ? filledStar : rating >= 2.5 ? halfFilledStar : star} + {rating >= 4 ? filledStar : rating >= 3.5 ? halfFilledStar : star} + {rating >= 5 ? filledStar : rating >= 4.5 ? halfFilledStar : star} +
+ ) +} diff --git a/app/components/product-form/judgeme-review.tsx b/app/components/product-form/judgeme-review.tsx index e6983d6..6d2cceb 100644 --- a/app/components/product-form/judgeme-review.tsx +++ b/app/components/product-form/judgeme-review.tsx @@ -2,11 +2,11 @@ import type { HydrogenComponentProps, HydrogenComponentSchema, } from '@weaverse/hydrogen'; -import StarsRating from 'react-star-rate'; import {useParentInstance} from '@weaverse/hydrogen'; import {useFetcher, useLoaderData} from '@remix-run/react'; import {forwardRef, useEffect} from 'react'; import {usePrefixPathWithLocale} from '~/lib/utils'; +import {StarRating} from '../StarRating'; type JudgemeReviewsData = { rating: number; reviewNumber: number; @@ -44,16 +44,10 @@ let JudgemeReview = forwardRef( return (
- {' '} - ({reviewNumber}) +
+ + ({reviewNumber}) +
); }, diff --git a/app/components/product-form/product-media.tsx b/app/components/product-form/product-media.tsx index b77f4bb..e8b5a10 100644 --- a/app/components/product-form/product-media.tsx +++ b/app/components/product-form/product-media.tsx @@ -13,11 +13,35 @@ interface ProductMediaProps { } export function ProductMedia(props: ProductMediaProps) { - let {selectedVariant, media, showThumbnails, numberOfThumbnails, spacing} = - props; + let { + selectedVariant, + media: _media, + showThumbnails, + numberOfThumbnails, + spacing, + } = props; + let media = _media.filter((med) => med.__typename === 'MediaImage'); + + let slideOptions = { + initial: 0, + loop: true, + slides: { + perView: 1, + spacing: 0, + }, + }; + + let thumbnailOptions = { + initial: 0, + slides: { + perView: numberOfThumbnails, + spacing: spacing, + }, + }; + let [activeInd, setAcitveInd] = useState(0); const [sliderRef, instanceRef] = useKeenSlider({ - loop: true, + ...slideOptions, slideChanged(slider) { let pos = slider.track.details.rel; setAcitveInd(pos); @@ -39,26 +63,29 @@ export function ProductMedia(props: ProductMediaProps) { }, [instanceRef], ); - const [thumbnailRef, thumbnailInstance] = useKeenSlider({ - initial: 0, - slides: { - perView: numberOfThumbnails, - spacing: spacing, - }, - }); + const [thumbnailRef, thumbnailInstance] = useKeenSlider(thumbnailOptions); let handleClickThumbnail = (idx: number) => { moveToIdx(idx); }; + useEffect(() => { + // instanceRef.current?.update(slideOptions); + // thumbnailInstance.current?.update(thumbnailOptions); let selectedInd = media.findIndex((med) => { if (med.__typename !== 'MediaImage') return false; return med.image?.url === selectedVariant.image.url; }); moveToIdx(selectedInd); - }, [selectedVariant, media, moveToIdx]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedVariant?.id, moveToIdx]); return ( -
-
+
+
{media.map((med, i) => { let image = med.__typename === 'MediaImage' diff --git a/app/routes/($locale).products.$productHandle.tsx b/app/routes/($locale).products.$productHandle.tsx index 15ba178..ae799d9 100644 --- a/app/routes/($locale).products.$productHandle.tsx +++ b/app/routes/($locale).products.$productHandle.tsx @@ -1,10 +1,6 @@ -import type { - ShopifyAnalyticsProduct} from '@shopify/hydrogen'; -import { - AnalyticsPageType, - getSelectedProductOptions -} from '@shopify/hydrogen'; -import type { LoaderFunctionArgs} from '@shopify/remix-oxygen'; +import type {ShopifyAnalyticsProduct} from '@shopify/hydrogen'; +import {AnalyticsPageType, getSelectedProductOptions} from '@shopify/hydrogen'; +import type {LoaderFunctionArgs} from '@shopify/remix-oxygen'; import {defer} from '@shopify/remix-oxygen'; import type {ProductRecommendationsQuery} from 'storefrontapi.generated'; import invariant from 'tiny-invariant'; @@ -20,7 +16,7 @@ import {WeaverseContent} from '~/weaverse'; import {useLoaderData, useSearchParams} from '@remix-run/react'; import type {SelectedOptionInput} from '@shopify/hydrogen/storefront-api-types'; import {useEffect} from 'react'; -import { getJudgemeReviews } from '~/lib/judgeme'; +import {getJudgemeReviews} from '~/lib/judgeme'; export const headers = routeHeaders; @@ -88,7 +84,11 @@ export async function loader({params, request, context}: LoaderFunctionArgs) { let judgemeReviews = null; if (judgeme_API_TOKEN) { let shop_domain = context.env.PUBLIC_STORE_DOMAIN; - judgemeReviews = await getJudgemeReviews(judgeme_API_TOKEN, shop_domain, productHandle); + judgemeReviews = await getJudgemeReviews( + judgeme_API_TOKEN, + shop_domain, + productHandle, + ); } return defer({ @@ -105,7 +105,7 @@ export async function loader({params, request, context}: LoaderFunctionArgs) { }, seo, weaverseData: await context.weaverse.loadPage(), - judgemeReviews + judgemeReviews, }); } @@ -141,7 +141,9 @@ let useApplyFirstVariant = () => { selectedOptions?.forEach((option: SelectedOptionInput) => { searchParams.set(option.name, option.value); }); - setSearchParams(searchParams); + setSearchParams(searchParams, { + replace: true, // prevent adding a new entry to the history stack + }); } // eslint-disable-next-line }, [product]); diff --git a/app/sections/product-information/index.tsx b/app/sections/product-information/index.tsx index 9426cfb..57ec752 100644 --- a/app/sections/product-information/index.tsx +++ b/app/sections/product-information/index.tsx @@ -72,8 +72,11 @@ let ProductInformation = forwardRef( useEffect(() => { if (!selectedVariant) { setSelectedVariant(variants?.nodes?.[0]); + } else if (selectedVariant?.id !== product?.selectedVariant?.id) { + setSelectedVariant(product?.selectedVariant); } - }, [selectedVariant, variants?.nodes]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [product?.id]); let {swatches} = useThemeSettings(); let handleSelectedVariantChange = (variant: any) => { diff --git a/package.json b/package.json index 2f4539e..031fc13 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "react-dom": "18.2.0", "react-intersection-observer": "9.5.3", "react-player": "^2.14.1", - "react-star-rate": "^0.2.0", "react-use": "17.4.2", "schema-dts": "1.1.2", "tiny-invariant": "1.3.1",