Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

검색 결과 페이지 구현 #71

Merged
merged 10 commits into from
Nov 13, 2023
74 changes: 73 additions & 1 deletion src/app/(routes)/search/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,77 @@
'use client'

import { CategoryList, Dropdown } from '@/components'
import Space from '@/components/common/Space/Space'
import User from '@/components/common/User/User'
import useSearch from '@/hooks/useSearch'
import { cls } from '@/utils'

const SearchPage = () => {
return <></>
const {
target,
sortIndex,
categoryIndex,
keyword,
result,
handleSortChange,
handleCategoryChange,
} = useSearch()
return (
<>
<div
className={cls(
'flex items-center px-4',
target === 'space' ? 'pt-4' : 'py-4',
)}>
<h2 className="grow overflow-hidden text-ellipsis whitespace-nowrap pr-2 font-bold text-gray9">
&apos;{keyword}&apos; 에 대한{' '}
{target === 'space' ? '스페이스' : target === 'user' ? '유저' : ''}{' '}
검색 결과
</h2>
{target === 'space' && (
<div className="shrink-0">
<Dropdown
type="space"
placement="right"
defaultIndex={sortIndex}
onChange={handleSortChange}
/>
</div>
)}
</div>
{target === 'space' && (
<CategoryList
type="all"
defaultIndex={categoryIndex}
onChange={handleCategoryChange}
/>
)}
<section className="flex flex-col gap-y-2 px-4">
{result.spaces?.map((space) => (
<Space
type="Card"
spaceId={space.spaceId}
userName={space.userName}
spaceName={space.spaceName}
spaceImage={space.spaceImage}
description={space.description}
category={space.category}
scrap={space.scrap}
favorite={space.favorite}
key={space.spaceId}
/>
))}
{result.users?.map((user) => (
<User
id={user.id}
name={user.name}
profile={user.profile}
key={user.id}
/>
))}
</section>
</>
)
}

export default SearchPage
1 change: 1 addition & 0 deletions src/app/(routes)/space/[spaceId]/comment/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const SpaceCommentPage = () => {
{...register('comment', { required: true })}
inputButton={true}
buttonText="작성"
buttonType="submit"
buttonColor="gray"
placeholder="댓글을 작성해 주세요"
/>
Expand Down
4 changes: 2 additions & 2 deletions src/app/(routes)/user/[userId]/favorite/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useForm } from 'react-hook-form'
import { CategoryList, Input } from '@/components'
import Space from '@/components/common/Space/Space'
import { mock_userData2 } from '@/data'
import useSearch from '@/hooks/useSearch'
import useSpaceSearch from '@/hooks/useSpaceSearch'
import { SearchFormValue } from '../space/page'

const UserFavoritePage = () => {
Expand All @@ -14,7 +14,7 @@ const UserFavoritePage = () => {
keyword: '',
},
})
const { handleCategoryChange, onSubmit } = useSearch({ setValue })
const { handleCategoryChange, onSubmit } = useSpaceSearch({ setValue })

return (
<div className="px-4">
Expand Down
4 changes: 2 additions & 2 deletions src/app/(routes)/user/[userId]/space/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useForm } from 'react-hook-form'
import { CategoryList, Input } from '@/components'
import Space from '@/components/common/Space/Space'
import { mock_userData2 } from '@/data'
import useSearch from '@/hooks/useSearch'
import useSpaceSearch from '@/hooks/useSpaceSearch'

export interface SearchFormValue {
keyword: string
Expand All @@ -17,7 +17,7 @@ const UserSpacePage = () => {
keyword: '',
},
})
const { handleCategoryChange, onSubmit } = useSearch({ setValue })
const { handleCategoryChange, onSubmit } = useSpaceSearch({ setValue })

return (
<div className="px-4">
Expand Down
11 changes: 10 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import Space from '@/components/common/Space/Space'
import useHome from '@/hooks/useHome'

export default function Home() {
const { links, spaces, handleSortChange, handleCategoryChange } = useHome()
const {
links,
spaces,
sortIndex,
categoryIndex,
handleSortChange,
handleCategoryChange,
} = useHome()
return (
<>
<section className="px-4 pb-10">
Expand All @@ -27,11 +34,13 @@ export default function Home() {
<Dropdown
type="space"
placement="right"
defaultIndex={sortIndex}
onChange={handleSortChange}
/>
</div>
<CategoryList
type="all_follow"
defaultIndex={categoryIndex}
onChange={handleCategoryChange}
/>
</div>
Expand Down
10 changes: 4 additions & 6 deletions src/components/common/CategoryList/CategoryList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client'

import { useEffect } from 'react'
import { cls } from '@/utils'
import CategoryListItem from './CategoryListItem'
import { CATEGORIES } from './constants'
Expand All @@ -19,11 +18,10 @@ const CategoryList = ({
defaultIndex,
onChange,
}: CategoryListProps) => {
const { index, setIndex, handleClick } = useCategoryList({ onChange })

useEffect(() => {
defaultIndex && setIndex(defaultIndex)
}, [defaultIndex, setIndex])
const { index, handleClick } = useCategoryList({
defaultIndex,
onChange,
})

return (
<ul
Expand Down
5 changes: 3 additions & 2 deletions src/components/common/CategoryList/hooks/useCategoryList.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useState } from 'react'

export interface useCategoryListProps {
defaultIndex?: number
onChange: (e: React.MouseEvent<HTMLButtonElement>) => void
}

const useCategoryList = ({ onChange }: useCategoryListProps) => {
const [index, setIndex] = useState(0)
const useCategoryList = ({ defaultIndex, onChange }: useCategoryListProps) => {
const [index, setIndex] = useState(defaultIndex ?? 0)

const handleClick = (e: React.MouseEvent<HTMLButtonElement>, i: number) => {
setIndex(i)
Expand Down
4 changes: 4 additions & 0 deletions src/components/common/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useRef } from 'react'
import { cls } from '@/utils'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
import { useSearchParams } from 'next/navigation'
import DropdownItem from './DropdownItem'
import { DROPDOWN_OPTIONS, PLACEMENTS, VERTICAL_PADDING } from './constants'
import useDropdown from './hooks/useDropdown'
Expand All @@ -11,6 +12,7 @@ export interface DropdownProps {
type: 'space' | 'link' | 'search' | 'user_edit' | 'user_invite' | 'tag'
size?: 'large' | 'medium' | 'small'
placement?: 'left' | 'right'
defaultIndex?: number
tags?: string[]
onChange: (e: React.MouseEvent<HTMLButtonElement>) => void
}
Expand All @@ -19,6 +21,7 @@ const Dropdown = ({
type,
size = 'medium',
placement = 'left',
defaultIndex,
tags,
onChange,
}: DropdownProps) => {
Expand All @@ -32,6 +35,7 @@ const Dropdown = ({
: tags && ['전체', ...tags]
const dropdownRef = useRef<HTMLDivElement>(null)
const { isOpen, setIsOpen, index, handleClick } = useDropdown({
defaultIndex,
el: dropdownRef,
onChange,
})
Expand Down
6 changes: 3 additions & 3 deletions src/components/common/Dropdown/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ export const DROPDOWN_OPTIONS = {
search: { 스페이스: 'space', 유저: 'user' },
user_edit: { '편집 허용': 'edit', '읽기 허용': 'view', 제거: 'remove' },
user_invite: { '편집 허용': 'eidt', '읽기 허용': 'view' },
} as const
}

export const VERTICAL_PADDING = {
large: 'py-2.5',
medium: 'py-1.5',
small: 'py-0.5',
} as const
}

export const PLACEMENTS = {
left: 'left-0',
right: 'right-0',
} as const
}
4 changes: 3 additions & 1 deletion src/components/common/Dropdown/hooks/useDropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import {
} from 'react'

export interface useDropdownProps {
defaultIndex?: number
el: React.RefObject<HTMLDivElement>
onChange: (e: React.MouseEvent<HTMLButtonElement>) => void
}

const useDropdown = ({
defaultIndex,
el,
onChange,
}: useDropdownProps): {
Expand All @@ -23,7 +25,7 @@ const useDropdown = ({
handleClick: (e: React.MouseEvent<HTMLButtonElement>, i: number) => void
} => {
const [isOpen, setIsOpen] = useState(false)
const [index, setIndex] = useState(0)
const [index, setIndex] = useState(defaultIndex ?? 0)

useEffect(() => {
const handleOutsideClose = (e: { target: any }) => {
Expand Down
37 changes: 35 additions & 2 deletions src/components/common/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,26 @@ const Header = () => {
.split(/[^a-zA-Z]/)[1] // 라우터명
.replace(/^[a-z]/, (char) => char.toUpperCase()) // 첫글자 대문자 치환

const createQueryString = useCallback(
(name: string, value: string) => {
const params = new URLSearchParams(searchParams)
params.set(name, value)

return params.toString()
},
[searchParams],
)

const deleteQueryString = useCallback(
(name: string) => {
const params = new URLSearchParams(searchParams)
params.delete(name)

return params.toString()
},
[searchParams],
)

return (
<>
<div className="fixed z-50 flex w-full max-w-[500px] items-center justify-between border-b border-slate-100 bg-bgColor px-4 py-2.5 dark:border-slate-800">
Expand All @@ -42,7 +62,12 @@ const Header = () => {
</Button>
<Button
className="flex h-8 w-8 items-center justify-center"
onClick={() => router.push(`${pathname}?search=true`)}>
onClick={() =>
router.replace(
pathname + '?' + createQueryString('search', 'true'),
{ scroll: false },
)
}>
<MagnifyingGlassCircleIcon className="h-6 w-6 text-slate9" />
</Button>
<Button
Expand All @@ -53,7 +78,15 @@ const Header = () => {
</div>
</div>
{isSidebarOpen && <Sidebar onClose={() => setIsSidebarOpen(false)} />}
{isSearchModalOpen && <SearchModal onClose={() => router.back()} />}
{isSearchModalOpen && (
<SearchModal
onClose={() =>
router.replace(pathname + '?' + deleteQueryString('search'), {
scroll: false,
})
}
/>
)}
</>
)
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/common/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface InputProps {
placeholder?: string
inputButton?: boolean
buttonText?: string
buttonType?: 'button' | 'submit' | 'reset'
buttonColor?: 'green' | 'gray'
validation?: string
disabled?: boolean
Expand All @@ -21,6 +22,7 @@ const Input = forwardRef(
placeholder,
inputButton,
buttonText = '추가',
buttonType = 'button',
buttonColor = 'green',
validation,
disabled,
Expand Down Expand Up @@ -52,7 +54,7 @@ const Input = forwardRef(
/>
{inputButton && (
<button
type="button"
type={buttonType}
className={cls(
'absolute right-0 top-0 flex rounded-r-md border px-4 py-2.5 text-sm font-semibold text-white',
buttonColor === 'green'
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const Modal = ({
className="fixed left-0 right-0 top-0 z-50 mx-auto flex h-screen w-full max-w-[500px] flex-col justify-center bg-black/40 px-4">
<div
className={cls(
'scrollbar-hide flex w-full flex-col gap-2 overflow-auto overscroll-contain rounded-xl border border-gray3 bg-bgColor p-4 shadow-md',
'flex w-full flex-col gap-2 overflow-auto overscroll-contain rounded-xl border border-gray3 bg-bgColor p-4 shadow-md scrollbar-hide',
type === 'follow' && 'h-4/5',
)}>
<div className="flex items-center justify-between">
Expand Down
1 change: 1 addition & 0 deletions src/components/common/SearchModal/SearchModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const SearchModal = ({ onClose }: SearchModalProps) => {
placeholder="검색어를 입력하세요."
inputButton={true}
buttonText="검색"
buttonType="submit"
/>
</div>
</form>
Expand Down
Loading