Skip to content

Commit

Permalink
feat: complete swiper gallery of product page
Browse files Browse the repository at this point in the history
  • Loading branch information
pooriaset committed May 18, 2024
1 parent 86d5408 commit 8874722
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ export interface GalleryItemProps {
alt: string | undefined | null;
src: string | undefined | null;
isActive?: boolean;
width: number;
height: number;
}
const GalleryItem: FC<GalleryItemProps> = ({
onClick,
alt,
src,
width,
height,
isActive = false,
}) => {
return (
Expand All @@ -24,16 +28,16 @@ const GalleryItem: FC<GalleryItemProps> = ({
: 'divider',
transition: 'all 200ms ease',
borderRadius: 1,
width: 72,
height: 72,
width: width,
height: height,
position: 'relative',
}}
>
<Image
onClick={onClick}
draggable={false}
width={72}
height={72}
width={width}
height={height}
alt={alt}
src={src}
style={{
Expand Down
159 changes: 110 additions & 49 deletions src/app/[locale]/(main)/products/[...id]/components/ProductGallery.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
'use client';

import Image from '@/components/common/Image';
import { Box } from '@mui/material';
import { useTranslations } from 'next-intl';
import { FC, useState } from 'react';
import { Box, IconButton, Stack, useTheme } from '@mui/material';
import { FC, useCallback, useRef, useState } from 'react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Product } from '../../types/common';
import GalleryItem from './GalleryItem';
import { ExpandLess, ExpandMore } from '@mui/icons-material';

export type ProductImages = Extract<
export type GalleryImages = Extract<
Product['galleryImages'],
{ __typename?: 'ProductToMediaItemConnection' }
>['nodes'];

export interface ProductImagesProps {
galleryImages?: ProductImages;
export interface ProductGalleryProps {
galleryImages?: GalleryImages;
thumbnail: Product['image'];
}

Expand All @@ -22,11 +23,23 @@ interface ISelected {
alt: string;
}

const ProductImages: FC<ProductImagesProps> = ({
const ProductGallery: FC<ProductGalleryProps> = ({
galleryImages = [],
thumbnail,
}) => {
const t = useTranslations();
const theme = useTheme();

const sliderRef = useRef<any>(null);

const handlePrev = useCallback(() => {
if (!sliderRef.current) return;
sliderRef.current.swiper.slidePrev();
}, []);

const handleNext = useCallback(() => {
if (!sliderRef.current) return;
sliderRef.current.swiper.slideNext();
}, []);

const [selected, setSelected] = useState<ISelected>({
src: thumbnail?.sourceUrl!,
Expand All @@ -39,49 +52,97 @@ const ProductImages: FC<ProductImagesProps> = ({

const _galleryImages = [thumbnail, ...galleryImages];

const height = 500;

return (
<>
<Image
width={500}
height={500}
src={selected?.src}
alt={selected?.alt}
draggable={false}
style={{
userSelect: 'none',
width: '100%',
borderRadius: 8,
}}
/>

<Box
sx={{
maxWidth: '100%',
display: 'flex',
gap: 1,
}}
>
{_galleryImages?.map((item) => {
const handleClickOnItem = () => {
setSelected({
src: item?.sourceUrl!,
alt: item?.altText!,
});
};

return (
<GalleryItem
onClick={handleClickOnItem}
alt={item?.altText}
src={item?.sourceUrl}
key={item?.id}
isActive={item?.sourceUrl === selected.src}
/>
);
})}
<Stack direction="row" spacing={2}>
<Box>
<IconButton
size="large"
onClick={handlePrev}
sx={{
left: '50%',
transform: 'translateX(-50%)',
}}
>
<ExpandLess />
</IconButton>

<Swiper
ref={sliderRef}
dir={theme.direction}
direction="vertical"
style={{
height: height - 2 * 48,
}}
breakpoints={{
[theme.breakpoints.values.xs]: {
slidesPerView: 1,
},
[theme.breakpoints.values.sm]: {
slidesPerView: 2,
},
[theme.breakpoints.values.md]: {
slidesPerView: 4,
},
}}
spaceBetween={theme.spacing(2)}
>
{_galleryImages?.map((item) => {
const handleClickOnItem = () => {
setSelected({
src: item?.sourceUrl!,
alt: item?.altText!,
});
};

return (
<SwiperSlide
key={item?.id}
style={{
height: 'auto',
boxSizing: 'border-box',
}}
>
<GalleryItem
onClick={handleClickOnItem}
alt={item?.altText}
src={item?.sourceUrl}
isActive={item?.sourceUrl === selected.src}
width={72}
height={72}
/>
</SwiperSlide>
);
})}
</Swiper>
<IconButton
size="large"
onClick={handleNext}
sx={{
left: '50%',
transform: 'translateX(-50%)',
}}
>
<ExpandMore />
</IconButton>
</Box>
<Box>
<Image
width={height}
height={height}
src={selected?.src}
alt={selected?.alt}
draggable={false}
style={{
userSelect: 'none',
maxWidth: '100%',
borderRadius: 8,
}}
/>
</Box>
</>
</Stack>
);
};

export default ProductImages;
export default ProductGallery;
18 changes: 7 additions & 11 deletions src/app/[locale]/(main)/products/[...id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from '@mui/material';
import type { Metadata } from 'next';
import FindYourSize from './components/FindYourSize';
import ProductImages from './components/ProductGallery';
import ProductGallery from './components/ProductGallery';
import ProductTabs from './components/ProductTabs';
import SizeSelector from './components/SizeSelector';
import ProductProvider from './providers/ProductProvider';
Expand Down Expand Up @@ -71,17 +71,13 @@ const Page: FC<PageProps> = async ({ params: { id } }) => {
}}
>
<Grid container spacing={2}>
<Grid item md={4} xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<ProductImages
thumbnail={product.image}
galleryImages={product?.galleryImages?.nodes}
/>
</Grid>
</Grid>
</Grid>
<Grid item md={5} xs={12}>
<ProductGallery
thumbnail={product.image}
galleryImages={product?.galleryImages?.nodes}
/>
</Grid>
<Grid item md={4} xs={12}>
<Breadcrumbs items={breadcrumbItems} />
<Typography
variant="h1"
Expand Down

0 comments on commit 8874722

Please sign in to comment.