Skip to content

Commit

Permalink
Merge pull request #39 from boostcampwm-2024/feature/connect/topfive-#11
Browse files Browse the repository at this point in the history
[FE] 상위 / 하위 종목 API 연동 #11
  • Loading branch information
dongree authored Nov 7, 2024
2 parents bea670e + bffb800 commit 6a593bf
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 52 deletions.
36 changes: 26 additions & 10 deletions FE/src/components/TopFive/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
type CardProps = {
name: string;
price: number;
change: number;
price: string;
changePercentage: string;
changePrice: string;
index: number;
};

export default function Card({ name, price, change, index }: CardProps) {
const changeColor = change > 0 ? 'text-juga-red-60' : 'text-juga-blue-50';
export default function Card({
name,
price,
changePercentage,
changePrice,
index,
}: CardProps) {
const changeValue =
typeof changePercentage === 'string'
? Number(changePercentage)
: changePercentage;
const changeColor =
changeValue > 0 ? 'text-juga-red-60' : 'text-juga-blue-50';

return (
<div className='flex flex-row items-center px-4 py-3'>
<div className='flex flex-row items-center justify-between py-3'>
<div className={'mx-0 font-medium text-juga-blue-50'}>{index + 1}</div>
<div className='ml-4 w-[260px] text-start'>
<div className='ml-4 w-[180px] text-start'>
<p className='font-medium text-juga-grayscale-black'>{name}</p>
</div>
<div className='w-[130px] text-right'>
<p className='font-medium text-juga-grayscale-black'>
<div className='w-[120px] text-right'>
<p className='font-normal text-juga-grayscale-black'>
{price?.toLocaleString()}
</p>
</div>
<div className={`w-[130px] text-right ${changeColor}`}>
<p className='font-medium'>{change > 0 ? `+${change}` : `${change}`}</p>
<div className={`w-[150px] text-right ${changeColor}`}>
<p className='font-normal'>
{changeValue > 0
? `${changePrice}(${changeValue}%)`
: `${changePrice}(${Math.abs(changeValue)}%)`}
</p>
</div>
</div>
);
Expand Down
61 changes: 27 additions & 34 deletions FE/src/components/TopFive/List.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,41 @@
import Card from './Card';

type Stock = {
name: string;
price: number;
change: number;
index: number;
};
import { SkeletonCard } from './SkeletonCard.tsx';
import { StockData } from './type.ts';

type ListProps = {
listTitle: string;
data: StockData[];
isLoading: boolean;
};

export default function List({ listTitle }: ListProps) {
const topStocks: Stock[] = [
{ name: '삼성전자', price: 76800, change: 2.1, index: 1 },
{ name: 'SK하이닉스', price: 156000, change: -1.2, index: 2 },
{ name: 'NAVER', price: 203000, change: 0.5, index: 3 },
{ name: '카카오', price: 58700, change: -0.8, index: 4 },
{ name: '현대차', price: 187000, change: 1.5, index: 5 },
];

export default function List({ listTitle, data, isLoading }: ListProps) {
return (
<div className='w-[520px] rounded-lg bg-white'>
<div className={'my-5 flex gap-1 px-6 text-xl font-bold'}>
<div className='w-[520px] rounded-lg bg-white px-2'>
<div className={'my-5 flex gap-1 px-1 text-xl font-bold'}>
{listTitle}
</div>
<div className='flex flex-row px-4 py-3 text-sm font-medium text-gray-600'>
<div className='w-[260px] text-start'>종목</div>
<div className='w-[130px] text-right'>현재가</div>
<div className='w-[130px] text-right'>등락률</div>
<div className='flex flex-row items-center justify-between py-3 text-sm font-medium text-gray-600'>
<div className='w-[200px] text-start'>종목</div>
<div className='w-[140px] p-1 text-right'>현재가</div>
<div className='w-[150px] p-1 text-right'>등락</div>
</div>

{/* 리스트 */}
<ul className='divide-y divide-gray-100'>
{topStocks.map((stock, index) => (
<li key={index} className='transition-colors hover:bg-gray-50'>
<Card
name={stock.name}
price={stock.price}
change={stock.change}
index={index}
/>
</li>
))}
<ul>
{isLoading
? Array.from({ length: 5 }).map((_, index) => (
<SkeletonCard key={`skeleton-${index}`} />
))
: data.map((stock: StockData, index) => (
<li key={index} className='transition-colors hover:bg-gray-50'>
<Card
name={stock.hts_kor_isnm}
price={stock.stck_prpr}
changePercentage={stock.prdy_ctrt}
changePrice={stock.prdy_vrss}
index={index}
/>
</li>
))}
</ul>
</div>
);
Expand Down
7 changes: 3 additions & 4 deletions FE/src/components/TopFive/Nav.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { useSearchParams } from 'react-router-dom';
import { useEffect, useRef } from 'react';

type MarketType = '전체' | '코스피' | '코스닥' | '나스닥';
import { MarketType } from './type.ts';

export default function Nav() {
const [searchParams, setSearchParams] = useSearchParams();
const currentMarket = searchParams.get('top') || '전체';
const indicatorRef = useRef<HTMLDivElement>(null);
const buttonRefs = useRef<(HTMLButtonElement | null)[]>([]);

const markets: MarketType[] = ['전체', '코스피', '코스닥', '나스닥'];
const markets: MarketType[] = ['전체', '코스피', '코스닥', '코스피200'];

const handleMarketChange = (market: MarketType) => {
if (market === '전체') {
Expand All @@ -32,7 +31,7 @@ export default function Nav() {
}, [currentMarket]);

return (
<div className='relative flex gap-1 px-3 text-xl font-bold'>
<div className='relative flex gap-1 text-xl font-bold'>
<div
ref={indicatorRef}
className='absolute bottom-0 h-1 bg-juga-grayscale-black transition-all duration-300'
Expand Down
12 changes: 12 additions & 0 deletions FE/src/components/TopFive/SkeletonCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function SkeletonCard() {
return (
<li className='animate-pulse px-4 py-3'>
<div className='flex items-center space-x-4'>
<div className='h-4 w-4 rounded bg-gray-200'></div>
<div className='h-4 w-[200px] rounded bg-gray-200'></div>
<div className='ml-auto h-4 w-[100px] rounded bg-gray-200'></div>
<div className='h-4 w-[80px] rounded bg-gray-200'></div>
</div>
</li>
);
}
33 changes: 31 additions & 2 deletions FE/src/components/TopFive/TopFive.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
import List from './List';
import Nav from './Nav';
import { useSearchParams } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { MarketType } from './type.ts';

const paramsMap = {
전체: 'ALL',
코스피: 'KOSPI',
코스닥: 'KOSDAQ',
코스피200: 'KOSPI200',
};

export default function TopFive() {
const [searchParams] = useSearchParams();
const currentMarket = (searchParams.get('top') || '전체') as MarketType;

const { data, isLoading } = useQuery({
queryKey: ['topfive', currentMarket],
queryFn: () =>
fetch(
`http://223.130.151.42:3000/api/stocks/topfive?market=${paramsMap[currentMarket]}`,
).then((res) => res.json()),
keepPreviousData: true,
});
return (
<div className='flex flex-col gap-4'>
<Nav />
<div className={'flex flex-row gap-[64px]'}>
<List listTitle={'급상승 Top 5'} />
<List listTitle={'급하락 Top 5'} />
<List
listTitle={'급상승 Top 5'}
data={data?.high}
isLoading={isLoading}
/>
<List
listTitle={'급하락 Top 5'}
data={data?.low}
isLoading={isLoading}
/>
</div>
</div>
);
Expand Down
9 changes: 9 additions & 0 deletions FE/src/components/TopFive/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type StockData = {
hts_kor_isnm: string;
stck_prpr: string;
prdy_vrss: string;
prdy_vrss_sign: string;
prdy_ctrt: string;
};

export type MarketType = '전체' | '코스피' | '코스닥' | '코스피200';
9 changes: 7 additions & 2 deletions FE/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.tsx';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</StrictMode>,
);

0 comments on commit 6a593bf

Please sign in to comment.