[Airbnb 클론코딩] Category UI
fmf2023.06.25 - [Project/Airbnb Clone] - [Airbnb 클론코딩] Register & Login functionality
[Airbnb 클론코딩] Register & Login functionality
2023.06.17 - [Project/Airbnb Clone] - [Airbnb 클론코딩] Auth UI [Airbnb 클론코딩] Auth UI 2023.06.11 - [Project/Airbnb Clone] - [Airbnb 클론코딩] 환경설정 및 Navbar UI(With. Youtube) [Airbnb 클론코딩] 환경설정 및 Navbar UI(With. Y
hu-bris.tistory.com
Category UI
카테고리를 만들어야하는데 전에 만들었던 Navbar.tsx 파일을 통해 카테고리 컴포넌트를 넣어준다.
<div className='fixed w-full bg-white z-10 shadow-sm'>
<div className='py-4 border-b-[1px]'>
<Container>
<div className="
flex
flex-row
items-center
justify-between
gap-3
md:gap-0
">
<Logo />
<Search />
<UserMenu currentUser={currentUser} />
</div>
</Container>
</div>
<Categories /> // 카테고리 컴포넌트
</div>
이제 카테고리 컴포넌트를 만들어보자..
'use client';
import Container from '../Container';
import { TbBeach, TbMountain, TbPool } from 'react-icons/tb';
import {
GiWindmill,
GiIsland,
GiBoatFishing,
GiCastle,
GiCaveEntrance,
GiForestCamp,
GiCactus,
GiBarn
} from 'react-icons/gi';
import { MdOutlineVilla } from 'react-icons/md';
import { FaSkiing } from 'react-icons/fa';
import { BsSnow } from 'react-icons/bs';
import { IoDiamond } from 'react-icons/io5'
import CategoryBox from '../CategoryBox';
import { usePathname, useSearchParams } from 'next/navigation';
export const categories = [
{
label: 'Beach',
icon: TbBeach,
description: 'This property is close to the beach!'
},
{
label: 'Windmills',
icon: GiWindmill,
description: 'This property has windmills!'
},
{
label: 'Modern',
icon: MdOutlineVilla,
description: 'This property is modern!'
}
]
const Categories = () => {
const params = useSearchParams()
const category = params?.get('category')
const pathname = usePathname()
const isMainPage = pathname === '/'
if (!isMainPage) {
return null
}
return (
<Container>
<div
className="
pt-4
flex
flex-row
items-center
justify-between
overflow-x-auto
"
>
{categories.map((item) => (
<CategoryBox
key={item.label}
label={item.label}
selected={category === item.label}
icon={item.icon}
/>
))}
</div>
</Container>
);
};
export default Categories;
카테고리 데이터를 그냥 배열 형식으로 만들고 이를 map 함수를 통해 하나씩 뽑아 출력하도록 했다.
데이터가 많아 글이 길어질까봐 몇 개 빼고 올렸다.
category라는 파라미터에 오는 값이 해당 카테고리 라벨과 같다면 selected props가 true가 되면서 outline이 나오게 될 것이다.
다음은 CategoryBox이다.
CategoryBox
먼저 필요한 라이브러리를 설치해야 한다.
npm install query-string
URL 쿼리를 파싱하고 문자열화시키는 라이브러리이다.
import { useRouter, useSearchParams } from "next/navigation";
import { useCallback } from "react";
import { IconType } from "react-icons";
import qs from "query-string";
interface CategoryBoxProps {
icon: IconType;
label: string;
selected?: boolean;
}
const CategoryBox: React.FC<CategoryBoxProps> = ({
icon: Icon,
label,
selected
}) => {
const router = useRouter()
const params = useSearchParams()
const handleClick = useCallback(() => {
let currentQuery = {}
if (params) {
currentQuery = qs.parse(params.toString())
}
const updatedQuery: any = {
...currentQuery,
category: label
}
if (params?.get('category') === label) {
delete updatedQuery.category
}
const url = qs.stringifyUrl({
url: '/',
query: updatedQuery
}, { skipNull: true })
router.push(url)
}, [])
return (
<div
onClick={handleClick}
className={`
flex
flex-col
items-center
justify-center
gap-2
p-3
border-b-2
hover:text-neutral-800
transition
cursor-pointer
${selected ? 'border-b-neutral-800' : 'border-transparent'}
${selected ? 'text-neutral-800' : 'text-neutral-500'}
`}
>
<Icon size={26} />
<div className="font-medium text-sm">
{label}
</div>
</div>
);
};
export default CategoryBox;
쿼리를 가져오고 업데이트된 쿼리로는 현재 쿼리에 category 키에 label 값을 넣는다.
category 파라미터가 label과 같으면 업데이트된 쿼리의 category를 지운다. 그리고 이를 '/{updatedQuery}'를 문자열화 시켜 해당 페이지로 이동시킨다.
Login & Register Toggle
이전에 만든 로그인과 회원가입 모달창에 수정을 해야하는 부분이 있다.
푸터에 로그인 페이지에서 계정이 없으면 회원가입 페이지로, 회원가입 페이지에서 계정이 있으면 로그인 페이지로 토글시키는 것이다.
// LoginModal.tsx
const toggle = useCallback(() => {
loginModal.onClose()
registerModal.onOpen()
}, [loginModal, registerModal])
// RegisterModal.tsx
const toggle = useCallback(() => {
registerModal.onClose()
loginModal.onOpen()
}, [registerModal, loginModal])
해당 코드들을 각각의 파일에 넣고 onClick 속성을 이용해 사용해주면 된다.