Skip to content

Commit

Permalink
Merge pull request #536 from woowacourse-teams/feat/489-search
Browse files Browse the repository at this point in the history
검색 기능 구현
  • Loading branch information
solo5star authored Oct 5, 2023
2 parents 93aeea9 + d249278 commit 8fbe5cb
Show file tree
Hide file tree
Showing 10 changed files with 350 additions and 29 deletions.
16 changes: 15 additions & 1 deletion client/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AuthProvider, AuthUrl, Cafe, CafeMapLocation, CafeMenu, LikedCafe, MapBounds, Rank, User } from './types';
import type { AuthProvider, AuthUrl, Cafe, CafeMapLocation, CafeMenu, LikedCafe, MapBounds, Rank, SearchedCafe, User } from './types';

export class ClientNetworkError extends Error {
constructor() {
Expand Down Expand Up @@ -104,6 +104,20 @@ class Client {
return this.fetchJson<CafeMenu>(`/cafes/${cafeId}/menus`);
}

searchCafes(searchParams: { name: string; menu?: string; address?: string }) {
const sanitizedSearchParams = Object.fromEntries(
Object.entries({
cafeName: searchParams.name.trim(),
menu: searchParams.menu?.trim() ?? '',
address: searchParams.address?.trim() ?? '',
}).filter(([, value]) => (value?.length ?? 0) >= 2),
);
if (Object.keys(sanitizedSearchParams).length === 0) {
return Promise.resolve([]);
}
return this.fetchJson<SearchedCafe[]>(`/cafes/search?${new URLSearchParams(sanitizedSearchParams).toString()}`);
}

getCafesNearLocation(
longitude: MapBounds['longitude'],
latitude: MapBounds['latitude'],
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const ButtonVariants = {
};

const Container = styled.button<ButtonProps>`
padding: ${({ theme }) => theme.space['1.5']} 0;
padding: ${({ theme }) => theme.space['1.5']} ${({ theme }) => theme.space[2]};
font-size: 16px;
font-weight: 500;
border-radius: 40px;
Expand Down
57 changes: 32 additions & 25 deletions client/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Suspense, useState } from 'react';
import { FaSearch } from 'react-icons/fa';
import { FaRankingStar } from 'react-icons/fa6';
import { Link } from 'react-router-dom';
import { styled } from 'styled-components';
import useUser from '../hooks/useUser';
import Resource from '../utils/Resource';
import Button from './Button';
import LoginModal from './LoginModal';

Expand All @@ -20,20 +21,21 @@ const Navbar = () => {

return (
<Container>
<LogoContainer>
<Link to="/">
<Logo />
</Link>
</LogoContainer>
<Link to="/">
<Logo />
</Link>
<ButtonContainer>
<RankButtonContainer>
<Link to="/rank">
<Button $fullWidth $fullHeight $variant="secondary">
랭킹
</Button>
</Link>
</RankButtonContainer>
<LoginAndProfileButtonContainer>
<Link to="/rank">
<IconButton>
<FaRankingStar />
</IconButton>
</Link>
<Link to="/search">
<IconButton>
<FaSearch />
</IconButton>
</Link>
<UserButtonContainer>
{user ? (
<Link to="/my-profile">
<Button $variant="outlined" $fullWidth $fullHeight>
Expand All @@ -45,7 +47,7 @@ const Navbar = () => {
로그인
</Button>
)}
</LoginAndProfileButtonContainer>
</UserButtonContainer>
</ButtonContainer>
<Suspense>{isLoginModalOpen && <LoginModal onClose={closeLoginModal} />}</Suspense>
</Container>
Expand All @@ -66,22 +68,27 @@ const Container = styled.nav`

const ButtonContainer = styled.div`
display: flex;
gap: ${({ theme }) => theme.space[2]};
align-items: center;
margin-left: auto;
`;

const LogoContainer = styled.div`
flex: 6;
const Logo = styled.img.attrs({ src: '/assets/logo.svg' })`
height: ${({ theme }) => theme.fontSize['3xl']};
`;

const Logo = styled.img.attrs({ src: Resource.getAssetUrl({ filename: 'logo.svg' }) })`
height: ${({ theme }) => theme.fontSize['4xl']};
const UserButtonContainer = styled.div`
width: 100px;
`;

const RankButtonContainer = styled.div`
width: 44px;
margin-right: ${({ theme }) => theme.space[2]};
`;
const IconButton = styled.button`
cursor: pointer;
display: flex;
align-items: center;
padding: ${({ theme }) => theme.space[2]};
const LoginAndProfileButtonContainer = styled.div`
width: 133px;
font-size: ${({ theme }) => theme.fontSize['2xl']};
color: ${({ theme }) => theme.color.primary};
`;
36 changes: 36 additions & 0 deletions client/src/components/SearchInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { ComponentPropsWithoutRef } from 'react';
import styled, { css } from 'styled-components';

type SearchInputVariant = 'small' | 'large';

type SearchInputProps = ComponentPropsWithoutRef<'input'> & {
variant?: SearchInputVariant;
};

const SearchInput = (props: SearchInputProps) => {
const { variant = 'small', ...restProps } = props;

return <Input $variant={variant} {...restProps} />;
};

export default SearchInput;

const Variants = {
large: css`
padding: ${({ theme }) => theme.space[3]};
font-size: ${({ theme }) => theme.fontSize.lg};
`,
small: css`
padding: ${({ theme }) => theme.space[2]};
font-size: ${({ theme }) => theme.fontSize.base};
`,
};

const Input = styled.input<{ $variant: SearchInputVariant }>`
width: 100%;
border: 1px solid #d0d0d0;
border-radius: 4px;
outline: none;
${({ $variant }) => Variants[$variant || 'small']}
`;
21 changes: 21 additions & 0 deletions client/src/hooks/useSearchCafes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import client from '../client';
import type { SearchedCafe } from '../types';
import useSuspenseQuery from './useSuspenseQuery';

type SearchCafesQuery = {
searchName: string;
searchMenu?: string | undefined;
searchAddress?: string | undefined;
};

const useSearchCafes = (query: SearchCafesQuery) => {
const { searchName, searchMenu, searchAddress } = query;

return useSuspenseQuery<SearchedCafe[]>({
queryKey: ['searchCafes', query],
retry: false,
queryFn: () => client.searchCafes({ name: searchName, menu: searchMenu, address: searchAddress }),
});
};

export default useSearchCafes;
33 changes: 32 additions & 1 deletion client/src/mocks/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { rest } from 'msw';
import { RankCafes, cafeMarker, cafeMenus, cafes } from '../data/mockData';
import type { CafeMapLocation, Identity, User } from '../types';
import type { CafeMapLocation, Identity, SearchedCafe, User } from '../types';

let pageState = 1;

Expand Down Expand Up @@ -122,6 +122,37 @@ const handlers = [
return res(ctx.status(200), ctx.json(RankCafes.slice(start, end)));
}),

rest.get('/api/cafes/search', (req, res, ctx) => {
const {
cafeName: searchName,
menu: searchMenu,
address: searchAddress,
} = Object.fromEntries(req.url.searchParams.entries());

let searchedCafes: SearchedCafe[] = cafes.map((cafe) => ({
id: cafe.id,
name: cafe.name,
address: cafe.address,
likeCount: cafe.likeCount,
image: cafe.images[0],
}));

if (searchName?.length >= 2) {
searchedCafes = searchedCafes.filter((cafe) => cafe.name.includes(searchName));
}

if (searchMenu?.length >= 2) {
searchedCafes = searchedCafes.filter((cafe) =>
cafeMenus.find((cafeMenu) => cafeMenu.cafeId === cafe.id)?.menus.some((menu) => menu.name.includes(searchMenu)),
);
}
if (searchAddress?.length >= 2) {
searchedCafes = searchedCafes.filter((cafe) => cafe.address.includes(searchAddress));
}

return res(ctx.status(200), ctx.json(searchedCafes));
}),

// 좋아요 한 목록 조회
rest.get('/api/members/:memberId/liked-cafes', (req, res, ctx) => {
const PAGINATE_UNIT = 15;
Expand Down
Loading

0 comments on commit 8fbe5cb

Please sign in to comment.