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

feature: 사용자검색, 포스트 검색 기능 구현 #213

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const App = () => {
<Route path="/post/:postId" element={<Post />} />
<Route path="/newpost" element={<NewPost />} />
<Route path="/profile/:userId" element={<Profile />} />
<Route path="/search/:keyword" element={<Search />} />
<Route path="/search/*" element={<Search />} />
<Route path="/setting/slack" element={<SettingSlack />} />
<Route path="/changePassword" element={<ChangePassword />} />
<Route path="/setting/slack/confirmation" element={<SlackConfirmationWrapper />} />
Expand Down
33 changes: 17 additions & 16 deletions packages/web/src/components/header/components/Input/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FormControl, Input, InputGroup, InputRightElement } from '@chakra-ui/react';
import { FormControl, HStack, Input, InputGroup, InputRightElement } from '@chakra-ui/react';
import { ComponentProps, forwardRef } from 'react';

type Props = ComponentProps<typeof Input> & {
Expand All @@ -7,24 +7,25 @@ type Props = ComponentProps<typeof Input> & {

const InputField = forwardRef(({ icon, ...props }: Props, ref) => {
return (
<FormControl>
<InputGroup>
<Input
ref={ref}
required={true}
w="100%"
_placeholder={{ opacity: 1, color: 'gray03' }}
borderRadius="10px"
borderColor="blue01"
{...props}
/>
{icon && (
<HStack width={'85%'} gap={0}>
<FormControl>
<InputGroup>
<Input
ref={ref}
required={true}
w="100%"
_placeholder={{ opacity: 1, color: 'gray03' }}
borderRadius="0 10px 10px 0"
borderLeft="0"
borderColor="blue01"
{...props}
/>
<InputRightElement h="100%" cursor="pointer">
{icon}
</InputRightElement>
)}
</InputGroup>
</FormControl>
</InputGroup>
</FormControl>
</HStack>
);
});

Expand Down
54 changes: 38 additions & 16 deletions packages/web/src/components/header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { Box, Flex, Image, Icon, useMediaQuery } from '@chakra-ui/react';
import { Box, Flex, Image, Icon, useMediaQuery, Select, FormControl, HStack } from '@chakra-ui/react';
import { SearchIcon } from '@chakra-ui/icons';
import logo from '@/assets/images/logo.png';
import logo_mobile from '@/assets/images/logo_mobile.png';
import InputField from '@/components/header/components/Input';
import { useNavigate } from 'react-router-dom';
import PrimaryButton from './components/Button';
import useAuthCheckQuery from '@/apis/queries/useAuthCheckQuery';
import { SubmitHandler, useForm } from 'react-hook-form';
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
import HeaderMenu from './components/Menu';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';

export const HEADER_HEIGHT = '4rem';

const formSchema = z.object({
keyword: z.string().trim().min(1)
keyword: z.string().trim().min(1),
searchType: z.string().trim()
});

type InputValue = z.infer<typeof formSchema>;
Expand All @@ -24,30 +25,51 @@ const Header = () => {
const logoSrc = isMobile ? logo_mobile : logo;
const navigate = useNavigate();

const { handleSubmit, register, reset } = useForm<InputValue>({
const { handleSubmit, register, reset, control } = useForm<InputValue>({
resolver: zodResolver(formSchema)
});
const { data } = useAuthCheckQuery();

const onSubmit: SubmitHandler<InputValue> = (value: { keyword: string }) => {
navigate(`/search/${value.keyword}`);
const onSubmit: SubmitHandler<InputValue> = (value: { searchType: string; keyword: string }) => {
navigate(`/search/?searchType=${value.searchType}&keyword=${value.keyword}`);
reset();
};

return (
<Box h={HEADER_HEIGHT} px={5} bg={'white'}>
<Flex gap={4} alignItems={'center'} h="100%" justifyContent={'space-between'}>
<Image h={8} cursor="pointer" src={logoSrc} alt="logo" onClick={() => navigate('/')} />
<form style={{ width: '40rem' }} onSubmit={handleSubmit(onSubmit)}>
<InputField
{...register('keyword')}
icon={<Icon as={SearchIcon} onClick={handleSubmit(onSubmit)} />}
id="keyword"
placeholder="사용자 이름을 입력해 주세요"
size="md"
fontSize="14px"
fontWeight="normal"
/>
<form onSubmit={handleSubmit(onSubmit)}>
<HStack gap={'0'} w={'40rem'}>
<FormControl w="15%">
<Controller
defaultValue="user"
name="searchType"
control={control}
render={({ field }) => (
<Select
{...field}
borderRadius="10px 0 0 10px"
borderColor="blue01"
bg="blue01"
placeholder="검색 기준"
cursor="pointer">
<option value="user">사용자</option>
<option value="post">머쓱이</option>
</Select>
)}
/>
</FormControl>
<InputField
{...register('keyword')}
icon={<Icon as={SearchIcon} onClick={handleSubmit(onSubmit)} />}
id="keyword"
placeholder="사용자 이름을 입력해 주세요"
size="md"
fontSize="14px"
fontWeight="normal"
/>
</HStack>
</form>
{data?._id ? (
<HeaderMenu />
Expand Down
61 changes: 43 additions & 18 deletions packages/web/src/pages/Search/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { Box, Heading, Text, VStack, List, HStack, Container } from '@chakra-ui/react';
import { Box, Heading, Text, VStack, List, HStack, Container, Grid } from '@chakra-ui/react';
import UserCard from './components/UserCard';
import { useParams } from 'react-router-dom';
import qs from 'qs';
import useSearchUserQuery from '@/apis/queries/useSearchUserQuery';
import useGetPostsInfoQuery from '@/apis/queries/useGetPostsInfoQuery';
import PostCard from '@/components/PostCard';
import { useNavigate } from 'react-router-dom';

const Search = () => {
const { keyword = '' } = useParams();
const { data: searchList } = useSearchUserQuery(keyword);
const queryString = qs.parse(window.location.search, { ignoreQueryPrefix: true });
const searchType = String(queryString.searchType);
const keyword = String(queryString.keyword);
const navigate = useNavigate();

const { data: searchUserList } = useSearchUserQuery(keyword);
const { data: searchPostList } = useGetPostsInfoQuery({ suspense: true });
return (
<VStack spacing={12} mb={10}>
<Box w="100%" bgGradient="linear-gradient(180deg, #C6FFC1 0%, #F5FFE2 100%)" p="3rem">
Expand All @@ -25,20 +32,38 @@ const Search = () => {
검색결과
</Text>
</HStack>
<Container centerContent maxW={'54rem'} gap={8}>
{searchList &&
searchList.map((user) => (
<List width={'100%'} key={user.email}>
<UserCard
id={user._id}
name={user.username}
email={user.email}
post={user.postCount}
comment={user.commentCount}
/>
</List>
))}
</Container>
{searchType === 'user' ? (
<Container centerContent maxW={'54rem'} gap={8}>
{searchUserList &&
searchUserList.map((user) => (
<List width={'100%'} key={user.email}>
<UserCard
id={user._id}
name={user.username}
email={user.email}
post={user.postCount}
comment={user.commentCount}
/>
</List>
))}
</Container>
) : (
<Grid templateColumns="repeat(2, 1fr)" gap={8} gridAutoFlow={'row'}>
{searchPostList &&
searchPostList.map((post) => (
<List width={'100%'} key={post._id}>
<PostCard
onClick={() => navigate(`/post/${post._id}`)}
imgName={post.musseukImageName}
musseukContent={post.content}
musseukName={post.title}
userName={post.author.username}
letter={post.comments.length}
/>
</List>
))}
</Grid>
)}
</VStack>
);
};
Expand Down