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

[FE] 검색 리스트 컴포넌트 구현. #90

Merged
merged 5 commits into from
Nov 12, 2024
Merged
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
2 changes: 2 additions & 0 deletions FE/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Home from 'page/Home';
import StocksDetail from 'page/StocksDetail';
import Header from 'components/Header';
import Login from 'components/Login';
import SearchModal from './components/Search';

function App() {
return (
Expand All @@ -33,6 +34,7 @@ function Layout() {
<Outlet />
</main>
<Login />
<SearchModal />
</>
);
}
3 changes: 3 additions & 0 deletions FE/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { Link } from 'react-router-dom';
import useAuthStore from 'store/authStore';
import useLoginModalStore from 'store/useLoginModalStore';
import useSearchModalStore from '../store/useSearchModalStore.ts';
import useSearchInputStore from '../store/useSearchInputStore.ts';

export default function Header() {
const { toggleModal } = useLoginModalStore();
const { isLogin, resetToken } = useAuthStore();
const { toggleSearchModal } = useSearchModalStore();
const { searchInput } = useSearchInputStore();

return (
<header className='fixed left-0 top-0 h-[60px] w-full'>
Expand All @@ -26,6 +28,7 @@ export default function Header() {
<input
type='text'
placeholder='Search...'
value={searchInput}
className='h-[36px] w-[280px] rounded-lg bg-juga-grayscale-50 px-4 py-2'
onClick={toggleSearchModal}
/>
Expand Down
27 changes: 27 additions & 0 deletions FE/src/components/Search/SearchCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export default function SearchCard() {
const companyName = '회사명';
const previousClose = 50000;
const priceChange = 2.5;

return (
<li className='h-[52px] w-full rounded-xl hover:cursor-pointer hover:bg-gray-50'>
<div className='my-2 flex w-full items-center justify-between px-4'>
<div className='flex-1'>
<p className='text-left font-medium text-juga-grayscale-black'>
{companyName}
</p>
</div>

<div className='flex flex-col items-end justify-center gap-0.5'>
<p className='text-right text-sm font-medium text-gray-900'>
{previousClose.toLocaleString()}
</p>

<p className={'text-right text-xs font-medium text-red-500'}>
+{Math.abs(priceChange).toFixed(2)}%
</p>
</div>
</div>
</li>
);
}
2 changes: 1 addition & 1 deletion FE/src/components/Search/SearchHistoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function SearchHistoryList({
onDeleteItem,
}: SearchHistoryListProps) {
return (
<div className={'flex w-full flex-col'}>
<div className={'flex w-full flex-col pb-2'}>
<div className={'mb-2 flex items-center justify-between'}>
<div className={'text-start text-sm font-bold'}>최근 검색</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions FE/src/components/Search/SearchInput.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { MagnifyingGlassIcon } from '@heroicons/react/16/solid';
import { useEffect, useRef } from 'react';

interface SearchInputProps {
value: string;
onChange: (value: string) => void;
}

export function SearchInput({ value, onChange }: SearchInputProps) {
const inputRef = useRef<HTMLInputElement>(null);

useEffect(() => {
inputRef.current?.focus();
}, []);

return (
<div
className={
Expand All @@ -14,6 +21,7 @@ export function SearchInput({ value, onChange }: SearchInputProps) {
>
<MagnifyingGlassIcon className={'ml-3 h-4 w-4 fill-juga-grayscale-200'} />
<input
ref={inputRef}
className={
'h-[36px] w-full rounded-lg bg-juga-grayscale-50 py-2 pl-[10px] pr-10 text-sm font-normal focus:outline-none'
}
Expand Down
16 changes: 16 additions & 0 deletions FE/src/components/Search/SearchList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import SearchCard from './SearchCard.tsx';

export default function SearchList() {
return (
<>
<div className={'my-4 flex items-center justify-between'}>
<div className={'text-start text-sm font-bold'}>검색 결과</div>
</div>
<ul className='flex h-full w-full flex-col items-center justify-between overflow-y-auto'>
{Array.from({ length: 30 }, (_, index) => {
return <SearchCard key={index} />;
})}
</ul>
</>
);
}
31 changes: 23 additions & 8 deletions FE/src/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import useSearchModalStore from '../../store/useSearchModalStore';
import Overlay from '../../utils/ModalOveray';
import { SearchInput } from './SearchInput';
import { SearchHistoryList } from './SearchHistoryList';
import SearchList from './SearchList.tsx';
import useSearchInputStore from '../../store/useSearchInputStore.ts';

export default function SearchModal() {
const { isOpen, toggleSearchModal } = useSearchModalStore();
const [searchTerm, setSearchTerm] = useState('');
const { searchInput, setSearchInput } = useSearchInputStore();
const [searchHistory, setSearchHistory] = useState<string[]>([]);

useEffect(() => {
Expand All @@ -22,13 +24,26 @@ export default function SearchModal() {
return (
<>
<Overlay onClick={() => toggleSearchModal()} />
<section className='fixed left-1/2 top-3 flex w-[640px] -translate-x-1/2 flex-col rounded-2xl bg-white shadow-lg'>
<div className={'flex flex-col gap-5 p-3'}>
<SearchInput value={searchTerm} onChange={setSearchTerm} />
<SearchHistoryList
searchHistory={searchHistory}
onDeleteItem={handleDeleteHistoryItem}
/>
<section
className={`${searchInput === '' ? '' : 'h-[520px]'} fixed left-1/2 top-3 flex w-[640px] -translate-x-1/2 flex-col rounded-2xl bg-white shadow-lg`}
>
<div className='flex h-full flex-col p-3'>
<div className='mb-5'>
<SearchInput value={searchInput} onChange={setSearchInput} />
</div>
<div className='flex-1 overflow-hidden'>
<SearchHistoryList
searchHistory={searchHistory}
onDeleteItem={handleDeleteHistoryItem}
/>
{searchInput === '' ? (
<></>
) : (
<div className='h-full overflow-y-auto'>
<SearchList />
</div>
)}
Comment on lines +39 to +45
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 삼항연산자 대신 '&&' 연산자를 사용해서 다음과 같이 표현해도 될 것 같아요!
searchInput === '' && <div> ... </div>

</div>
</div>
</section>
</>
Expand Down
2 changes: 1 addition & 1 deletion FE/src/components/TopFive/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
indicator.style.left = `${currentButton.offsetLeft}px`;
indicator.style.width = `${currentButton.offsetWidth}px`;
}
}, [currentMarket]);

Check warning on line 31 in FE/src/components/TopFive/Nav.tsx

View workflow job for this annotation

GitHub Actions / FE-test-and-build

React Hook useEffect has a missing dependency: 'markets'. Either include it or remove the dependency array

return (
<div className='relative flex gap-1 text-xl font-bold'>
Expand All @@ -43,7 +43,7 @@
key={market}
ref={(el) => (buttonRefs.current[index] = el)}
onClick={() => handleMarketChange(market)}
className={`relative px-2 py-2`}
className={'relative px-2 py-2'}
>
{market}
</button>
Expand Down
1 change: 0 additions & 1 deletion FE/src/page/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import TopFive from 'components/TopFive/TopFive';
import StockIndex from 'components/StockIndex/index.tsx';
import SearchModal from '../components/Search';

export default function Home() {
return (
Expand Down
21 changes: 21 additions & 0 deletions FE/src/store/useSearchInputStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { create } from 'zustand';

interface SearchInputStore {
searchInput: string;
setSearchInput: (input: string) => void;
resetSearchInput: () => void;
}

const useSearchInputStore = create<SearchInputStore>((set) => ({
searchInput: '',

setSearchInput: (input: string) => {
set({ searchInput: input });
},

resetSearchInput: () => {
set({ searchInput: '' });
},
}));

export default useSearchInputStore;
Loading