Skip to content

Commit

Permalink
hotfix: 드래그 이벤트와 클릭 이벤트 분리 (#687)
Browse files Browse the repository at this point in the history
* feat: useOnClickBlock hook 구현

- 드래그 중인 경우 클릭이 발생하지 않도록 한다.

* refactor: MiniRestaurantCard 컴포넌트 useOnClickBlock 적용

* refactor: CelebProfile 컴포넌트 생성 및 useOnClickBlock 적용

* refactor: BannerSlider 컴포넌트 useOnClickBlock 적용
  • Loading branch information
shackstack authored Apr 5, 2024
1 parent d2ac638 commit 063ee73
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 58 deletions.
33 changes: 33 additions & 0 deletions frontend/src/components/CelebProfile/CelebProfile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import styled from 'styled-components';
import { useNavigate } from 'react-router-dom';
import { Celeb } from '~/@types/celeb.types';
import { FONT_SIZE } from '~/styles/common';
import ProfileImage from '../@common/ProfileImage';
import useOnClickBlock from '~/hooks/useOnClickBlock';

function CelebProfile({ name, profileImageUrl, id }: Celeb) {
const navigate = useNavigate();
const register = useOnClickBlock({
callback: () => navigate(`/celeb/${id}`),
});

return (
<StyledCeleb {...register}>
<ProfileImage name={name} imageUrl={profileImageUrl} size="64px" boxShadow />
<span>{name}</span>
</StyledCeleb>
);
}

export default CelebProfile;

const StyledCeleb = styled.div`
display: flex !important;
flex-direction: column;
align-items: center;
gap: 0.8rem;
font-size: ${FONT_SIZE.sm};
cursor: pointer;
`;
3 changes: 3 additions & 0 deletions frontend/src/components/CelebProfile/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import CelebProfile from './CelebProfile';

export default CelebProfile;
26 changes: 16 additions & 10 deletions frontend/src/components/MiniRestaurantCard/MiniRestaurantCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { css, styled } from 'styled-components';
import { MouseEventHandler, memo } from 'react';
import { MouseEventHandler, memo, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import Love from '~/assets/icons/love.svg';
import { FONT_SIZE, truncateText } from '~/styles/common';
Expand All @@ -10,6 +10,7 @@ import type { Restaurant } from '~/@types/restaurant.types';
import useToggleLikeNotUpdate from '~/hooks/server/useToggleLikeNotUpdate';
import WaterMarkImage from '../@common/WaterMarkImage';
import ProfileImageList from '../@common/ProfileImageList';
import useOnClickBlock from '~/hooks/useOnClickBlock';

interface MiniRestaurantCardProps {
restaurant: Restaurant;
Expand All @@ -36,24 +37,29 @@ function MiniRestaurantCard({
}: MiniRestaurantCardProps) {
const { id, images, name, roadAddress, category, rating, distance } = restaurant;
const { toggleRestaurantLike, isLiked } = useToggleLikeNotUpdate(restaurant);

const navigate = useNavigate();

const onMouseEnter = () => setHoveredId(restaurant.id);
const onMouseLeave = () => setHoveredId(null);
const onClick = () => navigate(`/restaurants/${id}?celebId=${celebs[0].id}`);
const register = useOnClickBlock({ callback: () => navigate(`/restaurants/${id}?celebId=${celebs[0].id}`) });

const handleCardMouseEnter = useCallback(() => {
setHoveredId(restaurant.id);
}, []);

const handleCardMouseLeave = useCallback(() => {
setHoveredId(null);
}, []);

const toggle: MouseEventHandler<HTMLButtonElement> = e => {
const handleToggleLike: MouseEventHandler<HTMLButtonElement> = e => {
e.stopPropagation();

toggleRestaurantLike();
};

return (
<StyledContainer
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
{...register}
onMouseEnter={handleCardMouseEnter}
onMouseLeave={handleCardMouseLeave}
data-cy="음식점 카드"
aria-label={`${name} 카드`}
tabIndex={0}
Expand All @@ -63,7 +69,7 @@ function MiniRestaurantCard({
<StyledImageSection>
<WaterMarkImage imageUrl={images[0]?.name} type="list" sns={images[0]?.sns} />
{showLike && (
<StyledLikeButton aria-label="좋아요" type="button" onClick={toggle}>
<StyledLikeButton aria-label="좋아요" type="button" onClick={handleToggleLike}>
<Love width={20} fill={isLiked ? 'red' : '#000'} fillOpacity={0.8} aria-hidden="true" />
</StyledLikeButton>
)}
Expand Down
26 changes: 26 additions & 0 deletions frontend/src/hooks/useOnClickBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useCallback, useState } from 'react';

interface UseOnClickBlockProps {
callback: () => void;
}

const useOnClickBlock = ({ callback }: UseOnClickBlockProps) => {
const [isDragging, setIsDragging] = useState<boolean>(false);

const handleMouseDown = useCallback(() => {
setIsDragging(false);
}, []);

const handleMouseMove = useCallback(() => {
setIsDragging(true);
}, []);

const handleClick = () => {
if (isDragging) return;
callback();
};

return { onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onClick: handleClick };
};

export default useOnClickBlock;
Original file line number Diff line number Diff line change
@@ -1,26 +1,41 @@
import { Link } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import Slider from 'react-slick';
import styled, { css } from 'styled-components';
import { SERVER_IMG_URL } from '~/constants/url';
import useMediaQuery from '~/hooks/useMediaQuery';
import { BannerCarouselSettings } from '~/constants/carouselSettings';
import { paintSkeleton } from '~/styles/common';
import useOnClickBlock from '~/hooks/useOnClickBlock';

function BannerSlider() {
const { isMobile } = useMediaQuery();
const navigate = useNavigate();
const register1 = useOnClickBlock({
callback: () => {
navigate('/updated-recent');
},
});
const register2 = useOnClickBlock({
callback: () => {
navigate('/event');
},
});

return (
<Slider {...BannerCarouselSettings} arrows={!isMobile}>
<Link to="/updated-recent">
<StyledBanner
alt="최근 업데이트된 맛집"
src={`${SERVER_IMG_URL}banner/recent-updated.jpg`}
isMobile={isMobile}
/>
</Link>
<Link to="/event">
<StyledBanner alt="사진 등록 이벤트" src={`${SERVER_IMG_URL}banner/event-banner.jpeg`} isMobile={isMobile} />
</Link>
<StyledBanner
alt="최근 업데이트된 맛집"
src={`${SERVER_IMG_URL}banner/recent-updated.jpg`}
isMobile={isMobile}
{...register1}
/>

<StyledBanner
alt="사진 등록 이벤트"
src={`${SERVER_IMG_URL}banner/event-banner.jpeg`}
isMobile={isMobile}
{...register2}
/>
</Slider>
);
}
Expand All @@ -34,6 +49,8 @@ const StyledBanner = styled.img<{ isMobile: boolean }>`
overflow: hidden;
cursor: pointer;
${({ isMobile }) =>
isMobile
? css`
Expand Down
44 changes: 7 additions & 37 deletions frontend/src/pages/MainPage/CelebBestSection/CelebBestSection.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,29 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import Slider from 'react-slick';
import styled from 'styled-components';
import ProfileImage from '~/components/@common/ProfileImage';
import CelebProfile from '~/components/CelebProfile';
import { CelebCarouselSettings } from '~/constants/carouselSettings';
import { celebOptions } from '~/constants/celeb';
import useMediaQuery from '~/hooks/useMediaQuery';
import { FONT_SIZE } from '~/styles/common';

function CelebBestSection() {
const { isMobile } = useMediaQuery();
const navigate = useNavigate();

const clickCelebIcon = (id: number) => {
navigate(`/celeb/${id}`);
};

return (
<section>
<StyledTitle>셀럽 BEST</StyledTitle>
{isMobile ? (
<StyledIconBox>
{celebOptions.map(celeb => {
const { name, profileImageUrl, id } = celeb;
return (
<StyledCeleb onClick={() => clickCelebIcon(id)}>
<ProfileImage name={name} imageUrl={profileImageUrl} size="64px" boxShadow />
<span>{name}</span>
</StyledCeleb>
);
})}
{celebOptions.map(celeb => (
<CelebProfile {...celeb} />
))}
</StyledIconBox>
) : (
<StyledSliderContainer>
<Slider {...CelebCarouselSettings}>
{celebOptions.map(celeb => {
const { name, profileImageUrl, id } = celeb;
return (
<StyledCeleb onClick={() => clickCelebIcon(id)}>
<ProfileImage name={name} imageUrl={profileImageUrl} size="64px" boxShadow />
<span>{name}</span>
</StyledCeleb>
);
})}
{celebOptions.map(celeb => (
<CelebProfile {...celeb} />
))}
</Slider>
</StyledSliderContainer>
)}
Expand All @@ -67,17 +48,6 @@ const StyledIconBox = styled.div`
}
`;

const StyledCeleb = styled.div`
display: flex !important;
flex-direction: column;
align-items: center;
gap: 0.8rem;
font-size: ${FONT_SIZE.sm};
cursor: pointer;
`;

const StyledTitle = styled.h5`
margin-left: 1.6rem;
`;
Expand Down

0 comments on commit 063ee73

Please sign in to comment.