Skip to content

Commit

Permalink
Feat: 최근 방문 목록 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
ssumai-kr committed Jul 26, 2024
1 parent 0a09cbf commit d6d2cf6
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 24 deletions.
36 changes: 34 additions & 2 deletions components/ActivityDetails/ActivityDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { useQuery } from '@tanstack/react-query';
Expand All @@ -21,12 +21,14 @@ import {
} from '@/pages/api/activities/apiactivities.types';
import Spinner from '../Spinner/Spinner';
import { userState } from '@/states/userState';
import { useRecoilValue } from 'recoil';
import { useRecoilState, useRecoilValue } from 'recoil';
import { ActivityDetailsPageMeta } from '../MetaData/MetaData';
import useDeleteActivity from '@/hooks/myActivity/useDeleteActivity';
import { usePopup } from '@/hooks/usePopup';
import { darkModeState } from '@/states/themeState';
import { ShareButton } from '../ShareButton/ShareButton';
import { ViewedActivitiesState } from '@/states/ViewedState';
import { ViewedActivityProps } from '../ViewedActivities/ViewedActivities.type';

export default function ActivityDetails({ id }: ActivityDetailsProps) {
const router = useRouter();
Expand All @@ -35,11 +37,13 @@ export default function ActivityDetails({ id }: ActivityDetailsProps) {
const [currentPage, setCurrentPage] = useState<number>(
router.query.page ? parseInt(router.query.page as string, 10) : 1
);
const [ViewedInfo, setViewedInfo] = useRecoilState(ViewedActivitiesState);
const itemsPerPage = 3;
const { openPopup } = usePopup();
const { deleteMyActivityMutation } = useDeleteActivity();
const menuRef = useClickOutside<HTMLDivElement>(() => setIsOpen(false));
const userData = useRecoilValue(userState);

const {
data: activityData,
error: activityError,
Expand All @@ -49,6 +53,24 @@ export default function ActivityDetails({ id }: ActivityDetailsProps) {
queryFn: () => getActivityInfo({ id }),
});

const addViewedActivity = useCallback((newActivity: ViewedActivityProps) => {
setViewedInfo(prevViewedInfo => {
// 중복되는 항목 찾기
const isDuplicate = prevViewedInfo.some(activity => activity.id === newActivity.id);
let updatedViewedInfo = prevViewedInfo.filter(activity => activity.id !== newActivity.id);

// 새로운 항목 추가
updatedViewedInfo = [newActivity, ...updatedViewedInfo];

// 10개를 초과할 경우 가장 오래된 항목 삭제
if (updatedViewedInfo.length > 10) {
updatedViewedInfo.pop();
}

return updatedViewedInfo;
});
}, [setViewedInfo]);

const {
data: reviewData,
error: reviewError,
Expand All @@ -59,6 +81,16 @@ export default function ActivityDetails({ id }: ActivityDetailsProps) {
getActivityReviews({ id, page: currentPage, size: itemsPerPage }),
});

useEffect(() => {
if (activityData?.id !== undefined) {
addViewedActivity({
id: activityData.id,
bannerImage: activityData.bannerImageUrl || '',
title: activityData.title || '',
});
}
}, [activityData, addViewedActivity]);

if (isLoadingActivity || isLoadingReviews) {
return <Spinner />;
}
Expand Down
2 changes: 1 addition & 1 deletion components/Button/TopButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const TopButton = () => {
return (
<>
{showButton && (
<div className="fixed right-[30px] bottom-[30px] z-30">
<div className="fixed right-[30px] m:right-[14px] bottom-[30px] z-30">
<button
onClick={scrollToTop}
type="button"
Expand Down
27 changes: 18 additions & 9 deletions components/ViewedActivities/ViewedActivities.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Image from 'next/image';
import { useEffect, useState } from 'react';
import ViewedActivity from './ViewedActivity';
import useClickOutside from '@/hooks/useClickOutside';
import { useRecoilValue } from 'recoil';
import { ViewedActivitiesState } from '@/states/ViewedState';

function ViewedActivities() {
const [isOpen, setIsOpen] = useState(false);
Expand All @@ -12,6 +14,7 @@ function ViewedActivities() {
const ViewedActivitiesElement = useClickOutside<HTMLDivElement>(() =>
setIsOpen(false)
);
const ViewedActivitiesVlue = useRecoilValue(ViewedActivitiesState);

const openModal = () => {
setAnimationClass('rotate-open');
Expand All @@ -26,7 +29,7 @@ function ViewedActivities() {

return (
<div ref={ViewedActivitiesElement}>
<div className="fixed right-[32px] bottom-[90px] z-30 w-[40px] h-[40px] bg-gray-200 flex items-center justify-center rounded-xl cursor-pointer hover:bg-gray-300">
<div className="fixed right-[32px] m:right-[14px] bottom-[90px] z-30 w-[40px] h-[40px] bg-gray-200 flex items-center justify-center rounded-xl cursor-pointer hover:bg-gray-300">
{!isOpen ? (
<Image
src={RecordImg}
Expand All @@ -49,15 +52,21 @@ function ViewedActivities() {
</div>
{isOpen && (
<div
className={`w-[180px] h-[300px] rounded-lg fixed right-[32px] bottom-[138px] z-30 bg-white border-solid border-4 border-gray-500 ${faded} flex flex-col items-center px-[10px] pt-[10px] gap-[10px] overflow-y-auto overflow-x-hidden pb-[10px] custom-scrollbar`}
className={`w-[180px] h-[300px] rounded-lg fixed right-[32px] m:right-[14px] bottom-[138px] z-30 bg-white border-solid border-4 border-gray-800 ${faded} flex flex-col items-center px-[10px] pt-[10px] gap-[10px] overflow-y-auto overflow-x-hidden pb-[10px] custom-scrollbar`}
>
<ViewedActivity bannerImage="" title="" />
<ViewedActivity bannerImage="" title="" />
<ViewedActivity bannerImage="" title="" />
<ViewedActivity bannerImage="" title="" />
<ViewedActivity bannerImage="" title="" />
<ViewedActivity bannerImage="" title="" />
<ViewedActivity bannerImage="" title="" />
<div className="font-sans text-[14px] font-[600]">
최근 방문한 체험
</div>
<div className='flex flex-col gap-[10px]'>
{ViewedActivitiesVlue.map((activity) => (
<ViewedActivity
id={activity.id}
bannerImage={activity.bannerImage}
title={activity.title}
/>
))}
</div>
{(ViewedActivitiesVlue.length === 10) && <div className='font-sans text-[10px] font-[600]'>*최근 10개 정보까지 볼 수 있습니다.</div>}
</div>
)}
</div>
Expand Down
1 change: 1 addition & 0 deletions components/ViewedActivities/ViewedActivities.type.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface ViewedActivityProps {
id: number;
bannerImage: string;
title: string;
}
31 changes: 19 additions & 12 deletions components/ViewedActivities/ViewedActivity.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import Image from 'next/image';
import TestImg from '@/public/image/TestImage.jpg';
import { ViewedActivityProps } from './ViewedActivities.type';
import Link from 'next/link';
import { useRouter } from 'next/router';

function ViewedActivity({ id, bannerImage, title }: ViewedActivityProps) {
const router = useRouter();
const linkToClick = () => {
router.push(`/activity-details/${id}`);
};

function ViewedActivity({ bannerImage, title }: ViewedActivityProps) {
return (
<div className="min-w-[140px] min-h-[80px] rounded bg-gray-300 flex items-center justify-between cursor-pointer block">
<Image
src={TestImg}
alt="배너이미지"
width={40}
height={40}
className="ml-[10px]"
/>
<div className="mr-[10px] font-sans text-[12px] font-[700] w-[70px] h-[38px] line-clamp-2 overflow-hidden">
[TEST] 체험 제목 체험 제목 체험 제목 체험 제목
<div className="min-w-[140px] min-h-[80px] rounded bg-gray-200 flex items-center justify-between cursor-pointer block hover:bg-gray-300" onClick={linkToClick}>
<Image
src={bannerImage}
alt="배너이미지"
width={42}
height={40}
className="ml-[10px] min-w-[42px] min-h-[40px] max-w-[42px] max-h-[40px]"
/>
<div className="mr-[10px] font-sans text-[12px] font-[700] w-[70px] h-[38px] line-clamp-2 overflow-hidden">
{title}
</div>
</div>
</div>
);
}

Expand Down
11 changes: 11 additions & 0 deletions states/ViewedState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ViewedActivityProps } from '@/components/ViewedActivities/ViewedActivities.type';
import { atom } from 'recoil';
import { recoilPersist } from 'recoil-persist';

const { persistAtom } = recoilPersist();

export const ViewedActivitiesState = atom<ViewedActivityProps[]>({
key: 'ViewedActivitiesState',
default: [],
effects_UNSTABLE: [persistAtom],
});

0 comments on commit d6d2cf6

Please sign in to comment.