diff --git a/src/frontend/apps/web/app/(main)/page.tsx b/src/frontend/apps/web/app/(main)/page.tsx index d32bd1b0..ad066e56 100644 --- a/src/frontend/apps/web/app/(main)/page.tsx +++ b/src/frontend/apps/web/app/(main)/page.tsx @@ -11,9 +11,6 @@ export const metadata = { export default function Page() { return (
-
); diff --git a/src/frontend/apps/web/package.json b/src/frontend/apps/web/package.json index e4a70279..e5010dec 100644 --- a/src/frontend/apps/web/package.json +++ b/src/frontend/apps/web/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@tanstack/react-query": "^5.64.2", + "@tanstack/react-table": "^8.20.6", "@workspace/ui": "workspace:*", "lucide-react": "0.473.0", "next": "^14.2.23", diff --git a/src/frontend/apps/web/src/features/stock/index.tsx b/src/frontend/apps/web/src/features/stock/index.tsx index 9aa7a15f..9aff9863 100644 --- a/src/frontend/apps/web/src/features/stock/index.tsx +++ b/src/frontend/apps/web/src/features/stock/index.tsx @@ -1,2 +1 @@ -export { default as StockDetailLayout } from './ui/stock-detail-layout'; -export { default as StocksList } from './ui/stocks-list'; +export { StockDetailLayout, StocksList } from './ui'; diff --git a/src/frontend/apps/web/src/features/stock/model/index.ts b/src/frontend/apps/web/src/features/stock/model/index.ts new file mode 100644 index 00000000..6925f3d6 --- /dev/null +++ b/src/frontend/apps/web/src/features/stock/model/index.ts @@ -0,0 +1,2 @@ +export { type Stock } from './stock.types'; +export { columns } from './stocks-table.columns'; diff --git a/src/frontend/apps/web/src/features/stock/model/stock.types.ts b/src/frontend/apps/web/src/features/stock/model/stock.types.ts new file mode 100644 index 00000000..804e9ed1 --- /dev/null +++ b/src/frontend/apps/web/src/features/stock/model/stock.types.ts @@ -0,0 +1,8 @@ +export type Stock = { + id: string; + name: string; + currPrice: string; + fluctuation: string; + volume: string; + slug: string; +}; diff --git a/src/frontend/apps/web/src/features/stock/model/stocks-table.columns.tsx b/src/frontend/apps/web/src/features/stock/model/stocks-table.columns.tsx new file mode 100644 index 00000000..ac91ba7b --- /dev/null +++ b/src/frontend/apps/web/src/features/stock/model/stocks-table.columns.tsx @@ -0,0 +1,61 @@ +import { ColumnDef } from '@tanstack/react-table'; +import { Stock } from './stock.types'; +import { Button } from '@workspace/ui/components'; +import { ArrowUpDown } from 'lucide-react'; + +export const columns: ColumnDef[] = [ + { + accessorKey: 'name', + header: () =>
종목명
, + cell: ({ row }) =>
{row.getValue('name')}
, + }, + { + id: 'currPrice', + accessorFn: (row) => parseFloat(row.currPrice), + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const price = parseFloat(row.getValue('currPrice')); + const formatted = new Intl.NumberFormat('en-US', { + style: 'decimal', + currency: 'KRW', + }).format(price); + return
{`${formatted}원`}
; + }, + }, + { + id: 'fluctuation', + accessorFn: (row) => parseFloat(row.fluctuation), + header: ({ column }) => ( + + ), + cell: ({ row }) =>
{row.getValue('fluctuation')}%
, + }, + { + id: 'volume', + accessorFn: (row) => parseFloat(row.volume), + header: ({ column }) => ( + + ), + cell: ({ row }) =>
{row.getValue('volume')}
, + }, +]; diff --git a/src/frontend/apps/web/src/features/stock/ui/index.ts b/src/frontend/apps/web/src/features/stock/ui/index.ts new file mode 100644 index 00000000..9e04e67c --- /dev/null +++ b/src/frontend/apps/web/src/features/stock/ui/index.ts @@ -0,0 +1,2 @@ +export { default as StockDetailLayout } from './stock-detail-layout'; +export { default as StocksList } from './stocks-list-table'; diff --git a/src/frontend/apps/web/src/features/stock/ui/stocks-list-table.tsx b/src/frontend/apps/web/src/features/stock/ui/stocks-list-table.tsx new file mode 100644 index 00000000..4cf4e6c7 --- /dev/null +++ b/src/frontend/apps/web/src/features/stock/ui/stocks-list-table.tsx @@ -0,0 +1,108 @@ +'use client'; + +import { SortingState, flexRender, getCoreRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table'; +import { useState } from 'react'; +import { Stock, columns } from '../model'; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@workspace/ui/components'; +import { useRouter } from 'next/navigation'; + +const Stockdata: Stock[] = [ + { + id: '1', + name: '삼성전자', + currPrice: '53700', + fluctuation: '+0.00', + volume: '1000', + slug: 'samsung-electronics', + }, + { + id: '2', + name: 'SK하이닉스', + currPrice: '221000', + fluctuation: '+0.68', + volume: '1000', + slug: 'sk-hynix', + }, + { + id: '3', + name: '카카오', + currPrice: '35750', + fluctuation: '+0.00', + volume: '1000', + slug: 'kakao', + }, + { + id: '4', + name: '네이버', + currPrice: '204000', + fluctuation: '-0.24', + volume: '1000', + slug: 'naver', + }, + { + id: '5', + name: '한화에어로스페이스', + currPrice: '411500', + fluctuation: '+7.30', + volume: '1000', + slug: 'hanwha-aerospace', + }, +]; + +const StocksListTable = () => { + const [sorting, setSorting] = useState([]); + const router = useRouter(); + + const table = useReactTable({ + data: Stockdata, + columns, + onSortingChange: setSorting, + getCoreRowModel: getCoreRowModel(), + getSortedRowModel: getSortedRowModel(), + state: { + sorting, + }, + }); + return ( +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}; + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + { + router.push(`/${row.original.slug ?? ''}`); + }} + > + {row.getVisibleCells().map((cell) => ( + {flexRender(cell.column.columnDef.cell, cell.getContext())} + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+ ); +}; +export default StocksListTable; diff --git a/src/frontend/apps/web/src/features/stock/ui/stocks-list.tsx b/src/frontend/apps/web/src/features/stock/ui/stocks-list.tsx deleted file mode 100644 index 03e6242b..00000000 --- a/src/frontend/apps/web/src/features/stock/ui/stocks-list.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { DataTable } from '@workspace/ui/components'; - -const StocksList = () => { - const Stockdata = [ - { - id: '1', - name: '삼성전자', - currPrice: '53700', - fluctuation: '+0.00', - volume: '1000', - stockSlug: 'samsung-electronics', - }, - { - id: '2', - name: 'SK하이닉스', - currPrice: '221000', - fluctuation: '+0.68', - volume: '1000', - stockSlug: 'sk-hynix', - }, - { - id: '3', - name: '카카오', - currPrice: '35750', - fluctuation: '+0.00', - volume: '1000', - stockSlug: 'kakao', - }, - { - id: '4', - name: '네이버', - currPrice: '204000', - fluctuation: '-0.24', - volume: '1000', - stockSlug: 'naver', - }, - { - id: '5', - name: '한화에어로스페이스', - currPrice: '411500', - fluctuation: '+7.30', - volume: '1000', - stockSlug: 'hanwha-aerospace', - }, - ]; - return ( -
- -
- ); -}; -export default StocksList; diff --git a/src/frontend/packages/ui/package.json b/src/frontend/packages/ui/package.json index 2df7a6af..0bb5f18f 100644 --- a/src/frontend/packages/ui/package.json +++ b/src/frontend/packages/ui/package.json @@ -20,7 +20,6 @@ "@radix-ui/react-toggle": "^1.1.1", "@radix-ui/react-toggle-group": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.7", - "@tanstack/react-table": "^8.20.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "0.473.0", diff --git a/src/frontend/packages/ui/src/components/DataTable/data-table.stories.tsx b/src/frontend/packages/ui/src/components/DataTable/data-table.stories.tsx deleted file mode 100644 index 31f72e88..00000000 --- a/src/frontend/packages/ui/src/components/DataTable/data-table.stories.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import { DataTable, Stock } from './data-table'; - -const meta: Meta = { - title: 'Widget/DataTable', - component: DataTable, - parameters: { - layout: 'centered', - }, - tags: ['autodocs'], -}; -export default meta; - -type Story = StoryObj; - -const sampleData: Stock[] = [ - { - id: '1', - name: 'Samsung', - currPrice: '10000', - fluctuation: '+0.1', - volume: '1000', - }, - { - id: '2', - name: 'Apple', - currPrice: '20000', - fluctuation: '+0.2', - volume: '2000', - }, - { - id: '3', - name: 'Google', - currPrice: '30000', - fluctuation: '-0.3', - volume: '3000', - }, -]; - -export const Default: Story = { - args: { - data: sampleData, - }, -}; diff --git a/src/frontend/packages/ui/src/components/DataTable/data-table.tsx b/src/frontend/packages/ui/src/components/DataTable/data-table.tsx deleted file mode 100644 index cef02da7..00000000 --- a/src/frontend/packages/ui/src/components/DataTable/data-table.tsx +++ /dev/null @@ -1,122 +0,0 @@ -'use client'; - -import * as React from 'react'; -import { ColumnDef, SortingState, flexRender, getCoreRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table'; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../Table'; -import { Button } from '../Button'; -import { ArrowUpDown } from 'lucide-react'; - -export type Stock = { - id: string; - name: string; - currPrice: string; - fluctuation: string; - volume: string; -}; - -export const columns: ColumnDef[] = [ - { - accessorKey: 'name', - header: () =>
종목명
, - cell: ({ row }) =>
{row.getValue('name')}
, - }, - { - accessorKey: 'currPrice', - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const price = parseFloat(row.getValue('currPrice')); - const formatted = new Intl.NumberFormat('en-US', { - style: 'decimal', - currency: 'KRW', - }).format(price); - return
{`${formatted}원`}
; - }, - }, - { - accessorKey: 'fluctuation', - accessorFn: (row) => parseFloat(row.fluctuation), - header: ({ column }) => ( - - ), - cell: ({ row }) =>
{row.getValue('fluctuation')}%
, - }, - { - accessorKey: 'volume', - header: ({ column }) => ( - - ), - cell: ({ row }) =>
{row.getValue('volume')}
, - }, -]; - -export function DataTable({ data }: { data: Stock[] }) { - const [sorting, setSorting] = React.useState([]); - - const table = useReactTable({ - data, - columns, - onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - state: { - sorting, - }, - }); - - return ( - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}; - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - {flexRender(cell.column.columnDef.cell, cell.getContext())} - ))} - - )) - ) : ( - - - No results. - - - )} - -
- ); -} diff --git a/src/frontend/packages/ui/src/components/DataTable/index.ts b/src/frontend/packages/ui/src/components/DataTable/index.ts deleted file mode 100644 index 28b5088c..00000000 --- a/src/frontend/packages/ui/src/components/DataTable/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { DataTable } from './data-table'; diff --git a/src/frontend/packages/ui/src/components/index.ts b/src/frontend/packages/ui/src/components/index.ts index 64439139..44c7f0c5 100644 --- a/src/frontend/packages/ui/src/components/index.ts +++ b/src/frontend/packages/ui/src/components/index.ts @@ -2,7 +2,6 @@ export * from './Button'; export * from './Badge'; export * from './Textarea'; export * from './Table'; -export * from './DataTable'; export * from './ChatTextarea'; export * from './Toast'; export * from './Resizable'; diff --git a/src/frontend/pnpm-lock.yaml b/src/frontend/pnpm-lock.yaml index 2e7c30f4..2d6a197f 100644 --- a/src/frontend/pnpm-lock.yaml +++ b/src/frontend/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: '@tanstack/react-query': specifier: ^5.64.2 version: 5.64.2(react@18.3.1) + '@tanstack/react-table': + specifier: ^8.20.6 + version: 8.20.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@workspace/ui': specifier: workspace:* version: link:../../packages/ui @@ -158,9 +161,6 @@ importers: '@radix-ui/react-tooltip': specifier: ^1.1.7 version: 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tanstack/react-table': - specifier: ^8.20.6 - version: 8.20.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -5372,11 +5372,11 @@ snapshots: '@tanstack/query-core': 5.64.2 react: 18.3.1 - '@tanstack/react-table@8.20.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@tanstack/react-table@8.20.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/table-core': 8.20.5 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) '@tanstack/table-core@8.20.5': {}