Skip to content

Commit

Permalink
[#592] [도서 검색] 검색 키워드 및 결과 유지 기능 구현 (#593)
Browse files Browse the repository at this point in the history
* feat: useQueryParams 커스텀 훅 작성

* feat: 검색 키워드 유지 기능 추가

* fix: Skeleton 스타일 수정

* fix: global.css에 warning이 나타나던 문제 해결

* feat: 검색 결과 유지 기능 추가

* chore: 변수명 수정

* chore: 주석 추가

* feat: 도서 검색 Input에 검색어 초기화 기능 추가

* fix: unable to verify the first certificate 인증서를 인식못하던 문제 해결

* refactor: useQueryParams 개선

- 불필요한 state 제거
- useCallback 훅 적용
- 잘못 포함된 '/' 제거
- removeQueryParam의 earlyReturn 문 개선

* refactor: queryParams 개선 (state 사용x)

* fix: 검색창 search 아이콘 LayoutShift 현상 제거

* fix: setQueryParams 개선
  • Loading branch information
hanyugeon authored May 27, 2024
1 parent 474c175 commit d6c5677
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 14 deletions.
6 changes: 3 additions & 3 deletions public/icons/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion scripts/server.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const https = require('https');
const path = require('path');
const { parse } = require('url');
const { execSync } = require('child_process');
const next = require('next');
Expand All @@ -14,7 +15,10 @@ const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();

const SELF_CERTIFICATES_PATH = {
ca: `${execSync('mkcert -CAROOT').toString().replace(/\s/g, '')}/rootCA.pem`,
ca: path.resolve(
execSync('mkcert -CAROOT').toString().replace(/\s$/, ''),
'./rootCA.pem'
),
key: './.certificates/localhost-key.pem',
cert: './.certificates/localhost.pem',
};
Expand Down
19 changes: 18 additions & 1 deletion src/app/book/search/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import bookAPI from '@/apis/book';

import SSRSafeSuspense from '@/components/SSRSafeSuspense';
import useDebounceValue from '@/hooks/useDebounce';
import useQueryParams from '@/hooks/useQueryParams';
import { checkAuthentication } from '@/utils/helpers';

import Loading from '@/v1/base/Loading';
Expand All @@ -28,17 +29,32 @@ type FormValues = {
searchValue: string;
};

const KEYWORD = 'keyword';

const BookSearchPage = () => {
const { getQueryParam, setQueryParams, removeQueryParam } = useQueryParams();

const { register, watch, setValue } = useForm<FormValues>({
mode: 'all',
defaultValues: {
searchValue: '',
searchValue: getQueryParam(KEYWORD) ?? '',
},
});

const watchedKeyword = watch('searchValue');
const debouncedKeyword = useDebounceValue(watchedKeyword, 1000);

/* debounce된 keyword값에 따라 queryParameter를 수정하는 useEffect */
useEffect(() => {
const queryValue = getQueryParam(KEYWORD);

if (debouncedKeyword) {
setQueryParams({ [KEYWORD]: debouncedKeyword });
} else if (!debouncedKeyword && queryValue) {
removeQueryParam(KEYWORD, 'replace');
}
}, [debouncedKeyword, getQueryParam, setQueryParams, removeQueryParam]);

/* TopHeader가 사라졌을 때 input의 위치 top: 5.8rem */
const inputPositionClasses = watchedKeyword && 'sticky top-[5.8rem]';

Expand All @@ -59,6 +75,7 @@ const BookSearchPage = () => {
}`}
>
<Input
type="search"
inputStyle="line"
leftIconType="search"
placeholder="책 제목, 작가를 검색해보세요"
Expand Down
70 changes: 70 additions & 0 deletions src/hooks/useQueryParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useRouter, useSearchParams } from 'next/navigation';
import { useCallback } from 'react';

type RouteOptions = 'push' | 'replace';

type QueryParams = { [key: string]: string };

const useQueryParams = () => {
const router = useRouter();
const searchParams = useSearchParams();

const queryParams = searchParams.toString();

const getQueryParam = useCallback(
(queryKey: string) => {
const queryParam = searchParams.get(queryKey);

return queryParam;
},
[searchParams]
);

const setQueryParams = useCallback(
(queryParams: QueryParams, option?: RouteOptions) => {
const prevParams = new URLSearchParams(searchParams.toString());

for (const queryKey in queryParams) {
prevParams.set(queryKey, queryParams[queryKey]);
}

const newQueryParams = prevParams.toString();

switch (option) {
case 'replace':
router.replace(`?${newQueryParams}`, { shallow: true });
return;
case 'push':
default:
router.push(`?${newQueryParams}`, { shallow: true });
return;
}
},
[router, searchParams]
);

const removeQueryParam = useCallback(
(queryKey: string, option?: RouteOptions) => {
const prevParams = new URLSearchParams(searchParams.toString());
if (!prevParams.has(queryKey)) return;
prevParams.delete(queryKey);

const newQueryParams = prevParams.toString();

switch (option) {
case 'replace':
router.replace(`?${newQueryParams}`, { shallow: true });
return;
case 'push':
default:
router.push(`?${newQueryParams}`, { shallow: true });
return;
}
},
[router, searchParams]
);

return { queryParams, getQueryParam, setQueryParams, removeQueryParam };
};

export default useQueryParams;
13 changes: 13 additions & 0 deletions src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
}

input[type='date'] {
appearance: none;
-webkit-appearance: none;
}

Expand All @@ -67,8 +68,20 @@
}
/* FireFox */
input[type='number'] {
appearance: none;
-moz-appearance: textfield;
}

input[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 2.1rem;
height: 2.1rem;
cursor: pointer;
background-image: url('/icons/close.svg');
background-position: center;
background-repeat: no-repeat;
}
}

@layer utilities {
Expand Down
2 changes: 1 addition & 1 deletion src/v1/base/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const getInputStyleClasses = (inputStyle: InputStyle) => {
const getLeftIconClass = (iconType?: LeftIconType) => {
switch (iconType) {
case 'search':
return 'px-[1rem] before:relative before:top-[0.3rem] before:pr-[1rem] before:content-search';
return 'px-[1rem] before:h-[2.4rem] before:w-[2rem] before:relative before:top-[0.2rem] before:mr-[1rem] before:content-search';
default:
return '';
}
Expand Down
6 changes: 3 additions & 3 deletions src/v1/bookSearch/BestSellers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,10 @@ const BestSellerSkeleton = () => {
export const BestSellersSkeleton = () => {
return (
<Skeleton>
<section className="flex flex-col gap-[1.7rem]">
<section className="flex flex-col gap-[1.5rem]">
<Skeleton.Text width="7rem" fontSize="2xlarge" />
<ul className="flex w-full gap-[1rem] pb-[1rem]">
<Skeleton.Rect width="5.5rem" height="2.7rem" rounded="large" />
<ul className="flex w-full gap-[1rem]">
<Skeleton.Rect width="5.5rem" height="2.5rem" rounded="large" />
</ul>
<ul className="flex w-[12.8rem] flex-row justify-around">
<Skeleton.Text width="2.5rem" fontSize="xsmall" />
Expand Down
10 changes: 5 additions & 5 deletions src/v1/bookSearch/RecentSearchList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ export default RecentSearchList;
export const RecentSearchListSkeleton = () => {
return (
<Skeleton>
<section className="flex animate-pulse flex-col gap-[1.7rem] rounded-[0.5rem]">
<section className="flex animate-pulse flex-col gap-[1.5rem] rounded-[0.5rem]">
<Skeleton.Text width="8rem" fontSize="2xlarge" />
<ul className="flex w-full gap-[1rem] pb-[1rem]">
<Skeleton.Rect width="7.55rem" height="2.8rem" rounded="full" />
<Skeleton.Rect width="7.55rem" height="2.8rem" rounded="full" />
<Skeleton.Rect width="7.55rem" height="2.8rem" rounded="full" />
<Skeleton.Rect width="7.55rem" height="2.8rem" rounded="full" />
<Skeleton.Rect width="7.55rem" height="3.3rem" rounded="full" />
<Skeleton.Rect width="7.55rem" height="3.3rem" rounded="full" />
<Skeleton.Rect width="7.55rem" height="3.3rem" rounded="full" />
<Skeleton.Rect width="7.55rem" height="3.3rem" rounded="full" />
</ul>
</section>
</Skeleton>
Expand Down

0 comments on commit d6c5677

Please sign in to comment.