Skip to content

Commit

Permalink
Merge pull request #82 from FinalDoubleTen/FE-41--feat/ToursQA
Browse files Browse the repository at this point in the history
안기여행지 QA
  • Loading branch information
suehub authored Jan 6, 2024
2 parents f7aa551 + e1878fe commit 8af5ff6
Show file tree
Hide file tree
Showing 16 changed files with 159 additions and 122 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"react-scroll": "^1.9.0",
"recoil": "^0.7.7",
"styled-components": "^6.1.3",
"swiper": "^11.0.5",
"uuid": "^9.0.1"
},
"devDependencies": {
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { BrowserRouter } from 'react-router-dom';
import MainRouter from '@router/mainRouter';
import AuthRouter from '@router/authRouter';
import ScrollToTop from '@router/ScrollToTop';

const queryClient = new QueryClient();

Expand All @@ -15,6 +16,7 @@ const App = () => {
<QueryClientProvider client={queryClient}>
<RecoilRoot>
<BrowserRouter>
<ScrollToTop />
<ThemeProvider theme={theme}>
<GlobalStyle />
<MainRouter />
Expand Down
6 changes: 2 additions & 4 deletions src/components/Tours/CreateTripButton.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { PlusIcon } from '@components/common/icons/Icons';

const CreateTripButton = () => {
return (
<div className="sticky bottom-20 z-[100] ml-auto mr-2 h-[51px] w-[51px] cursor-pointer">
<PlusIcon size={51} color="white" />
<div className="sticky bottom-20 z-[100] ml-auto mr-2 flex h-12 w-[119px] items-center justify-center gap-2 rounded-[30px] bg-[#28d8ff] p-2 shadow-[2px_2px_5px_0_rgba(0,0,0,0.2)]">
<button className="headline1 pt-[2px] text-white">여행 계획하기</button>
</div>
);
};
Expand Down
62 changes: 48 additions & 14 deletions src/components/Tours/ToursCategory.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
import { RegionTypes, ToursCategoryProps } from '@/@types/tours.types';
import ToursCategoryItem from './ToursCategoryItem';
import { getPopularRegion } from '@api/region';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
import ToursCategoryItemSkeleton from './ToursCategoryItemSkeleton';
import { v4 as uuidv4 } from 'uuid';
import { useQuery } from '@tanstack/react-query';
import { useEffect, useState } from 'react';
// import { useEffect, useState } from 'react';

const ToursCategory = ({
selectedRegion,
setSelectedRegion,
}: ToursCategoryProps) => {
const regionsQuery = useQuery({
const { data, isLoading, error } = useQuery({
queryKey: ['regions'],
queryFn: () => getPopularRegion(),
});

if (regionsQuery.error) {
const [showSkeleton, setShowSkeleton] = useState(isLoading);

useEffect(() => {
if (isLoading) {
setShowSkeleton(true);
} else {
const timer = setTimeout(() => setShowSkeleton(false), 200);
return () => clearTimeout(timer);
}
}, [isLoading]);

if (error) {
console.log('error - 예외 처리');
}

Expand All @@ -26,24 +43,41 @@ const ToursCategory = ({
};

// '전체' 항목 추가
const regionsData = regionsQuery.data?.data.data.regions ?? [];
const regionsData = data?.data.data.regions ?? [];
const regions = [
{ name: '전체', areaCode: 0, subAreaCode: 0 },
{ name: '전체', areaCode: uuidv4(), subAreaCode: 0 },
...regionsData,
];

if (showSkeleton) {
return (
<div className="no-scrollbar my-3 flex w-[100%] overflow-scroll overflow-y-hidden bg-white">
<Swiper spaceBetween={8} slidesPerView={'auto'}>
{Array.from({ length: 10 }, (_, index) => (
<SwiperSlide key={index} className="w-[58px]">
<ToursCategoryItemSkeleton />
</SwiperSlide>
))}
</Swiper>
</div>
);
}

return (
<div className="no-scrollbar my-3 flex w-[100%] overflow-scroll overflow-y-hidden bg-white">
{regions.map((region: RegionTypes, index: number) => {
return (
<ToursCategoryItem
key={index}
name={region.name}
isSelected={region.name === selectedRegion}
onSelect={handleSelectRegion}
/>
);
})}
<Swiper spaceBetween={8} slidesPerView={'auto'}>
{regions.map((region: RegionTypes) => {
return (
<SwiperSlide key={uuidv4()} className="w-[58px]">
<ToursCategoryItem
name={region.name}
isSelected={region.name === selectedRegion}
onSelect={handleSelectRegion}
/>
</SwiperSlide>
);
})}
</Swiper>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/Tours/ToursCategoryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const ToursCategoryItem = ({
<button
type="button"
onClick={() => onSelect(name)}
className={`mr-[4px] flex items-center justify-center whitespace-nowrap rounded-[30px] border border-solid bg-[#28D8FF] px-[16px] py-[7px] text-[14px] leading-normal ${buttonStyle}`}>
className={`body4 flex items-center justify-center whitespace-nowrap rounded-[30px] border border-solid bg-[#28D8FF] px-[16px] py-[7px] leading-normal ${buttonStyle}`}>
{name}
</button>
);
Expand Down
9 changes: 9 additions & 0 deletions src/components/Tours/ToursCategoryItemSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const ToursCategoryItemSkeleton = () => {
return (
<div className="flex animate-pulse items-center justify-center">
<div className="h-[40px] w-[58px] rounded-[30px] bg-gray-300 px-[16px] py-[7px]"></div>
</div>
);
};

export default ToursCategoryItemSkeleton;
16 changes: 16 additions & 0 deletions src/components/Tours/ToursItemSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const ToursItemSkeleton = () => {
return (
<div className="flex-col">
<div className="relative">
<div className="rounded-1 h-[134px] max-h-[134px] w-[178px] animate-pulse rounded-[16px] bg-gray-300"></div>
</div>
<p className="headline1 mt-2 h-6 animate-pulse rounded bg-gray-300"></p>
<div className="caption1 ml-[2px] mt-2 flex space-x-2">
<div className="h-4 w-1/3 animate-pulse rounded bg-gray-300"></div>
<div className="h-4 w-1/4 animate-pulse rounded bg-gray-300"></div>
</div>
</div>
);
};

export default ToursItemSkeleton;
75 changes: 49 additions & 26 deletions src/components/Tours/ToursList.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
import { TourType, ToursListProps } from '@/@types/tours.types';
import ToursItem from './ToursItem';
import { getTours } from '@api/tours';
import { useInfiniteQuery } from '@tanstack/react-query';
import React, { useEffect, useState } from 'react';
import InfiniteScroll from 'react-infinite-scroller';
import React from 'react';
import { v4 as uuidv4 } from 'uuid';
import ToursItem from './ToursItem';
import ToursItemSkeleton from './ToursItemSkeleton';

const ToursList = ({ selectedRegion }: ToursListProps) => {
const { fetchNextPage, hasNextPage, data, error } = useInfiniteQuery({
queryKey: ['tours', selectedRegion],
queryFn: ({ pageParam = 0 }) => getTours(selectedRegion, pageParam, 10),
initialPageParam: 0,
getNextPageParam: (lastPage) => {
const currentPage = lastPage?.data.data.pageable.pageNumber;
const totalPages = lastPage?.data.data.totalPages;

if (currentPage < totalPages - 1) {
return currentPage + 1;
}

return undefined;
},
});
const { fetchNextPage, hasNextPage, data, isLoading, error } =
useInfiniteQuery({
queryKey: ['tours', selectedRegion],
queryFn: ({ pageParam = 0 }) => getTours(selectedRegion, pageParam, 10),
initialPageParam: 0,
getNextPageParam: (lastPage) => {
const currentPage = lastPage?.data.data.pageable.pageNumber;
const totalPages = lastPage?.data.data.totalPages;

if (currentPage < totalPages - 1) {
return currentPage + 1;
}

return undefined;
},
});

const [showSkeleton, setShowSkeleton] = useState(isLoading);

useEffect(() => {
if (isLoading) {
setShowSkeleton(true);
} else {
const timer = setTimeout(() => setShowSkeleton(false), 200);
return () => clearTimeout(timer);
}
}, [isLoading]);

if (error) {
return <div>데이터를 불러오는 중 오류가 발생했습니다.</div>;
Expand All @@ -32,18 +46,27 @@ const ToursList = ({ selectedRegion }: ToursListProps) => {
loadMore={() => fetchNextPage()}
hasMore={hasNextPage}
loader={
<div className="loader" key={0}>
Loading ...
<div key={uuidv4()} className="flex justify-center">
<div
className="z-[100] mx-auto h-8 w-8 animate-spin rounded-full border-[3px] border-solid border-current border-t-transparent pt-10 text-[blue-600] dark:text-[#28d8ff]"
role="status"
aria-label="loading">
<div className="sr-only">Loading...</div>
</div>
</div>
}>
<div className="no-scrollbar grid grid-cols-2 gap-[15px] overflow-y-scroll">
{data?.pages.map((group, index) => (
<React.Fragment key={index}>
{group?.data.data.content.map((tour: TourType) => (
<ToursItem key={tour.id} tour={tour} />
<div className="no-scrollbar grid min-h-[500px] grid-cols-2 gap-[15px] overflow-y-scroll">
{showSkeleton
? Array.from({ length: 10 }, (_, index) => (
<ToursItemSkeleton key={index} />
))
: data?.pages.map((group) => (
<React.Fragment key={uuidv4()}>
{group?.data.data.content.map((tour: TourType) => (
<ToursItem key={uuidv4()} tour={tour} />
))}
</React.Fragment>
))}
</React.Fragment>
))}
</div>
</InfiniteScroll>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/Tours/ToursSectionTop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const ToursSectionTop = () => {
const [selectedRegion, setSelectedRegion] = useState<string>('전체');

return (
<div>
<div className="sticky top-0 z-50 bg-white py-0.5">
<div className="mt-3">
<div className="sticky top-0 z-[105] bg-white py-0.5">
<h1 className="title2 pt-3">지금 인기여행지</h1>
<ToursCategory
selectedRegion={selectedRegion}
Expand Down
50 changes: 0 additions & 50 deletions src/components/common/footer/Footer.tsx

This file was deleted.

3 changes: 0 additions & 3 deletions src/components/common/footer/index.tsx

This file was deleted.

12 changes: 6 additions & 6 deletions src/components/common/nav/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,37 @@ const Nav = () => {
const isActive = (path: string) => location.pathname === path;

return (
<nav className="sticky bottom-0 z-50 flex h-16 items-center justify-center bg-white">
<nav className="sticky bottom-0 z-50 mt-auto flex h-16 items-center justify-center bg-white">
<div className="flex w-[100%] items-center justify-evenly space-x-4 bg-inherit">
<div
onClick={() => navigate('/')}
className="cursor-pointer flex-col items-center justify-center px-2">
<div className="flex justify-center">
<HomeIcon fill={isActive('/') ? 'currentColor' : 'none'} />
</div>
<p className="caption2 mt-[3px] text-center"></p>
<p className="caption1 mt-[3px] pr-[1px] text-center"></p>
</div>
<div
onClick={() => navigate('/')}
className="cursor-pointer flex-col items-center justify-center px-2">
<CalendarIcon />
<p className="caption2 mt-[3px] text-center text-xs/[11px]">일정</p>
<p className="caption1 mt-[5px] text-center text-xs/[11px]">일정</p>
</div>
<div
onClick={() => navigate('/')}
className="cursor-pointer flex-col items-center justify-center px-2">
<div className="flex justify-center">
<HeartIcon />
</div>
<p className="caption2 mt-[3px] text-center text-xs/[11px]"></p>
<p className="caption1 mt-[4px] text-center text-xs/[11px]"></p>
</div>
<div
onClick={() => navigate('/signin')}
className="cursor-pointer flex-col items-center justify-center px-1">
className="cursor-pointer flex-col items-center justify-center px-1 pt-[4.5px]">
<div className="flex justify-center">
<UserIcon />
</div>
<p className="caption2 mt-[3px] text-center">내정보</p>
<p className="caption1 mt-[3px] text-center ">내정보</p>
</div>
</div>
</nav>
Expand Down
Loading

0 comments on commit 8af5ff6

Please sign in to comment.