Skip to content

Commit ef95a6f

Browse files
authored
refactor: 이스터에그 토스트 사용성 개선 및 hook 디렉토리 이동 (#527)
* feat: 페이지 이동 시 렌더링중인 토스트 제거 * refactor: 토스트 발생 높이 재조정 * refactor: easterEgg 로직과 컴포넌트 분리 * refactor: hooks/common > hooks/@common으로 이동
1 parent 89397b8 commit ef95a6f

File tree

15 files changed

+98
-67
lines changed

15 files changed

+98
-67
lines changed

frontend/src/components/@common/Toast/Toast.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,14 @@ const fadeIn = keyframes`
5454
}
5555
to {
5656
opacity: 1;
57-
transform: translateY(-150%);
57+
transform: translateY(0%);
5858
}
5959
`;
6060

6161
const fadeOut = keyframes`
6262
from {
6363
opacity: 1;
64-
transform: translateY(-150%);
64+
transform: translateY(-0%);
6565
}
6666
to {
6767
opacity: 0;

frontend/src/components/PetProfile/PetInfoInForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
22
import { styled } from 'styled-components';
33

44
import CameraIcon from '@/assets/svg/camera_icon.svg';
5-
import { useImageUpload } from '@/hooks/common/useImageUpload';
5+
import { useImageUpload } from '@/hooks/@common/useImageUpload';
66
import { PetProfile } from '@/types/petProfile/client';
77

88
import { getGenderImage, getPetAge } from './PetItem';

frontend/src/components/PetProfile/PetProfileImageUploader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { styled } from 'styled-components';
44
import CameraIcon from '@/assets/svg/camera_icon.svg';
55
import DefaultDogIcon from '@/assets/svg/dog_icon.svg';
66
import { usePetAdditionContext } from '@/context/petProfile/PetAdditionContext';
7-
import { useImageUpload } from '@/hooks/common/useImageUpload';
7+
import { useImageUpload } from '@/hooks/@common/useImageUpload';
88

99
const PetProfileImageUploader = () => {
1010
const { petProfile, updatePetProfile } = usePetAdditionContext();

frontend/src/components/Review/ReviewListAndChart/ReviewControls/AlignSelect/AlignSelect.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import styled, { css } from 'styled-components';
33

44
import { REVIEW_ALIGN_QUERY } from '@/constants/review';
55
import useEasyNavigate from '@/hooks/@common/useEasyNavigate';
6-
import useValidQueryString from '@/hooks/common/useValidQueryString';
6+
import useValidQueryString from '@/hooks/@common/useValidQueryString';
77
import { useReviewListAlignMeta } from '@/hooks/query/review';
88
import { generateQueryString } from '@/router/routes';
99
import { StyledProps } from '@/types/common/utility';

frontend/src/components/Review/ReviewListAndChart/ReviewList/ReviewList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { styled } from 'styled-components';
33

44
import WriteIcon from '@/assets/svg/write_btn.svg';
55
import { useValidParams } from '@/hooks/@common/useValidParams';
6-
import useValidQueryString from '@/hooks/common/useValidQueryString';
6+
import useValidQueryString from '@/hooks/@common/useValidQueryString';
77
import { useReviewListQuery } from '@/hooks/query/review';
88
import { routerPath } from '@/router/routes';
99
import { zipgoLocalStorage } from '@/utils/localStorage';

frontend/src/context/Toast/ToastContext.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import {
33
PropsWithChildren,
44
useCallback,
55
useContext,
6+
useEffect,
67
useMemo,
78
useRef,
89
useState,
910
} from 'react';
1011
import { createPortal } from 'react-dom';
12+
import { useLocation } from 'react-router-dom';
1113
import { styled } from 'styled-components';
1214

1315
import ToastWarningIcon from '@/assets/svg/toast_warning_icon.svg';
@@ -60,6 +62,8 @@ const Portal = ({ children }: PropsWithChildren) =>
6062
const ToastProvider = (props: PropsWithChildren) => {
6163
const { children } = props;
6264

65+
const location = useLocation();
66+
6367
const [toastStates, setToastStates] = useState<ToastInterface[]>([]);
6468
const currentToast = useRef<ToastInterface[]>([]);
6569

@@ -90,6 +94,13 @@ const ToastProvider = (props: PropsWithChildren) => {
9094
timers.current.delete(toastId);
9195
};
9296

97+
const deleteAllToast = () => {
98+
currentToast.current = [];
99+
100+
setToastStates(currentToast.current);
101+
timers.current = new Map();
102+
};
103+
93104
const generateToastId = (): ToastId => toastId.current;
94105

95106
const getToastId = useCallback(
@@ -150,6 +161,8 @@ const ToastProvider = (props: PropsWithChildren) => {
150161
[toast, toastStates],
151162
);
152163

164+
useEffect(deleteAllToast, [location.key]);
165+
153166
return (
154167
<ToastContext.Provider value={memoizedValue}>
155168
<PrefetchImg srcList={[ToastWarningIcon]} />
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { useState } from 'react';
2+
3+
import { useToast } from '@/context/Toast/ToastContext';
4+
5+
const AWAKE_NUMBER = 10;
6+
const DANGER_NUMBER = AWAKE_NUMBER - 1;
7+
8+
let startTime: Date | undefined;
9+
let endTime: Date | undefined;
10+
11+
const calcDuration = () => (Number(endTime) - Number(startTime)) / 1000;
12+
13+
const useEasterEgg = () => {
14+
const { toast } = useToast();
15+
16+
const [dogTouchCount, setDogTouchCount] = useState(1);
17+
const isDogAwake = dogTouchCount > AWAKE_NUMBER;
18+
19+
const onTouchDog = () => {
20+
if (dogTouchCount === AWAKE_NUMBER && startTime) {
21+
endTime = new Date();
22+
23+
toast.success(`${calcDuration()}초 만에 강아지를 깨웠어요!`);
24+
} else if (dogTouchCount === DANGER_NUMBER) {
25+
toast.warning('강아지를 깨우지 않게 조심하세요!');
26+
} else if (dogTouchCount < AWAKE_NUMBER) {
27+
startTime = startTime ?? new Date();
28+
29+
toast.info(`강아지를 ${dogTouchCount}번 쓰다듬었어요.`);
30+
}
31+
32+
if (dogTouchCount <= AWAKE_NUMBER) setDogTouchCount(prev => prev + 1);
33+
};
34+
35+
return { onTouchDog, isDogAwake };
36+
};
37+
38+
export default useEasterEgg;

frontend/src/hooks/food/useFilterSelectionDisplay.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { generateQueryString } from '@/router/routes';
33
import { KeywordEn } from '@/types/food/client';
44

55
import useEasyNavigate from '../@common/useEasyNavigate';
6-
import useValidQueryString from '../common/useValidQueryString';
6+
import useValidQueryString from '../@common/useValidQueryString';
77

88
export const useFilterSelectionDisplay = () => {
99
const { replaceQueryString } = useEasyNavigate();

frontend/src/hooks/food/useInfiniteFoodListScroll.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useCallback, useEffect, useRef } from 'react';
22

33
import { KEYWORD_EN } from '@/constants/food';
4-
import useValidQueryString from '@/hooks/common/useValidQueryString';
4+
import useValidQueryString from '@/hooks/@common/useValidQueryString';
55
import { useFoodListInfiniteQuery } from '@/hooks/query/food';
66
import type { KeywordEn } from '@/types/food/client';
77

frontend/src/hooks/review/useCustomReview.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { usePetProfile } from '@/context/petProfile/PetProfileContext';
44
import { generateQueryString } from '@/router/routes';
55

66
import useEasyNavigate from '../@common/useEasyNavigate';
7-
import useValidQueryString from '../common/useValidQueryString';
7+
import useValidQueryString from '../@common/useValidQueryString';
88

99
export const useCustomReview = () => {
1010
const { replaceQueryString } = useEasyNavigate();

frontend/src/hooks/review/useReviewFilterList.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { FilterControlsMeta } from '@/types/review/client';
55
import { invariantOf } from '@/utils/invariantOf';
66
import { parseCheckList } from '@/utils/parseCheckList';
77

8-
import useValidQueryString from '../common/useValidQueryString';
8+
import useValidQueryString from '../@common/useValidQueryString';
99

1010
const initialFilterList: Record<keyof FilterControlsMeta, Set<number>> = {
1111
petSizes: new Set(),

frontend/src/pages/Landing/Landing.tsx

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { useState } from 'react';
21
import styled from 'styled-components';
32

43
import ZipgoBanner from '@/assets/webp/landing_banner.webp';
@@ -8,66 +7,47 @@ import Template from '@/components/@common/Template';
87
import FilterBottomSheet from '@/components/Food/FilterBottomSheet/FilterBottomSheet';
98
import FoodList from '@/components/Food/FoodList/FoodList';
109
import FoodSelectionGuideBanner from '@/components/FoodSelectionGuideBanner/FoodSelectionGuideBanner';
11-
import { useToast } from '@/context/Toast/ToastContext';
12-
13-
const TARGET_NUMBER = 100;
14-
15-
let startTime: Date | undefined;
16-
let endTime: Date | undefined;
17-
18-
const Landing = () => {
19-
const { toast } = useToast();
20-
const [dogTouchCount, setDogTouchCount] = useState<number>(1);
21-
const isDogAwake = dogTouchCount > TARGET_NUMBER;
22-
23-
const onTouchDog = () => {
24-
if (dogTouchCount === 1) {
25-
startTime = new Date();
26-
toast.info(`강아지를 ${dogTouchCount}번 쓰다듬었어요.`);
27-
} else if (dogTouchCount === TARGET_NUMBER && startTime) {
28-
endTime = new Date();
29-
toast.success(`${(+endTime - +startTime) / 1000}초 만에 강아지를 깨웠어요!`);
30-
} else if (TARGET_NUMBER - dogTouchCount === 10) {
31-
toast.warning('강아지를 깨우지 않게 조심하세요!');
32-
} else if (dogTouchCount < TARGET_NUMBER) {
33-
toast.info(`강아지를 ${dogTouchCount}번 쓰다듬었어요.`);
34-
}
35-
36-
if (dogTouchCount <= TARGET_NUMBER) setDogTouchCount(prev => prev + 1);
37-
};
10+
import useEasterEgg from '@/hooks/@common/useEasterEgg';
11+
12+
const Landing = () => (
13+
<Template staticHeader={Header}>
14+
<FoodSelectionGuideBanner />
15+
<Layout>
16+
<BannerSection>
17+
<BannerText>
18+
<TitleContainer>
19+
<BannerSubTitle>
20+
사료 선택이 어려운
21+
<br />
22+
초보 집사들을 위해
23+
</BannerSubTitle>
24+
<BannerTitle>집사의고민</BannerTitle>
25+
</TitleContainer>
26+
</BannerText>
27+
<EasterEggBanner />
28+
</BannerSection>
29+
<ListSection>
30+
<FilterBottomSheet />
31+
<FoodList />
32+
</ListSection>
33+
</Layout>
34+
</Template>
35+
);
36+
37+
export default Landing;
38+
39+
const EasterEggBanner = () => {
40+
const { isDogAwake, onTouchDog } = useEasterEgg();
3841

3942
return (
40-
<Template staticHeader={Header}>
41-
<FoodSelectionGuideBanner />
42-
<Layout>
43-
<BannerSection>
44-
<BannerText>
45-
<TitleContainer>
46-
<BannerSubTitle>
47-
사료 선택이 어려운
48-
<br />
49-
초보 집사들을 위해
50-
</BannerSubTitle>
51-
<BannerTitle>집사의고민</BannerTitle>
52-
</TitleContainer>
53-
</BannerText>
54-
<BannerImg
55-
src={isDogAwake ? ZipgoBannerAwake : ZipgoBanner}
56-
onClick={onTouchDog}
57-
alt="집사의고민 배너 이미지"
58-
/>
59-
</BannerSection>
60-
<ListSection>
61-
<FilterBottomSheet />
62-
<FoodList />
63-
</ListSection>
64-
</Layout>
65-
</Template>
43+
<BannerImg
44+
src={isDogAwake ? ZipgoBannerAwake : ZipgoBanner}
45+
onClick={onTouchDog}
46+
alt="집사의고민 배너 이미지"
47+
/>
6648
);
6749
};
6850

69-
export default Landing;
70-
7151
const Layout = styled.div`
7252
width: 100%;
7353
height: 100%;

frontend/src/pages/Login/Login.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import ZipgoLogo from '@/assets/svg/zipgo_logo_dark.svg';
88
import ZipgoBanner from '@/assets/webp/landing_banner.webp';
99
import Template from '@/components/@common/Template';
1010
import { KAKAO_HREF } from '@/constants/auth';
11+
import useValidQueryString from '@/hooks/@common/useValidQueryString';
1112
import { useAuth } from '@/hooks/auth';
12-
import useValidQueryString from '@/hooks/common/useValidQueryString';
1313
import { RuntimeError } from '@/utils/errors';
1414

1515
const Login = () => {

0 commit comments

Comments
 (0)