diff --git a/src/components/ui/table/Table.stories.tsx b/src/components/ui/table/Table.stories.tsx new file mode 100644 index 0000000..06518d1 --- /dev/null +++ b/src/components/ui/table/Table.stories.tsx @@ -0,0 +1,43 @@ +import Table from '@/components/ui/table/Table'; +import { TableRowProps } from '@/components/ui/table/TableRowProps'; +import { Meta, StoryObj } from '@storybook/nextjs'; +import { useEffect, useState } from 'react'; +import { fetchTableData, UserType } from './testApi'; + +const meta: Meta = { + title: 'UI/Table', + component: Table, + argTypes: { + userType: { + control: { type: 'radio' }, + options: ['employer', 'employee'], + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +function TableWithTestApi({ userType }: { userType: UserType }) { + const [headers, setHeaders] = useState([]); + const [data, setData] = useState([]); + + useEffect(() => { + const getData = async () => { + const res = await fetchTableData(userType); + setHeaders(res.headers); + setData(res.data as TableRowProps[]); + }; + getData(); + }, [userType]); + + return ; +} + +export const TableExample: Story = { + args: { + userType: 'employer', + }, + render: args => , +}; diff --git a/src/components/ui/table/Table.tsx b/src/components/ui/table/Table.tsx new file mode 100644 index 0000000..5a67cb8 --- /dev/null +++ b/src/components/ui/table/Table.tsx @@ -0,0 +1,34 @@ +import TableRow from '@/components/ui/table/TableRow'; +import { TableRowProps } from '@/components/ui/table/TableRowProps'; + +interface TableProps { + data: TableRowProps[]; + headers: string[]; + userType: 'employer' | 'employee'; +} + +//
type은 확인이 좀 더 필요합니다 + +export default function Table({ data, headers, userType }: TableProps) { + return ( +
+
+ + + {headers.map((header, index) => ( + + ))} + + + + {data.map((row, index) => ( + + ))} + +
+ {header} +
+
페이지네이션
+ + ); +} diff --git a/src/components/ui/table/TableRow.tsx b/src/components/ui/table/TableRow.tsx new file mode 100644 index 0000000..dd29886 --- /dev/null +++ b/src/components/ui/table/TableRow.tsx @@ -0,0 +1,32 @@ +import { TableRowProps } from '@/components/ui/table/TableRowProps'; +import { getTime } from '@/lib/utils/getTime'; + +interface TableTypeVariant { + rowData: TableRowProps; + variant: 'employer' | 'employee'; +} + +const TD_BASE = 'border-b px-2 py3'; +const TD_STATUS = 'border-b px-2 py-[9px]'; + +export default function TableRow({ rowData, variant }: TableTypeVariant) { + const { STRAT, END, duration } = getTime(rowData.startsAt, rowData.workhour); + + return ( + + {rowData.name} + {variant === 'employee' ? ( + <> + {`${STRAT} ~ ${END} (${duration})`} + {rowData.hourlyPay} + + ) : ( + <> + {rowData.bio} + {rowData.phone} + + )} + {rowData.status} + + ); +} diff --git a/src/components/ui/table/TableRowProps.tsx b/src/components/ui/table/TableRowProps.tsx new file mode 100644 index 0000000..5544174 --- /dev/null +++ b/src/components/ui/table/TableRowProps.tsx @@ -0,0 +1,9 @@ +export type TableRowProps = { + name: string; + startsAt: string; + workhour: number; + hourlyPay: string; + status: string | JSX.Element; + bio: string; + phone: number; +}; diff --git a/src/components/ui/table/index.tsx b/src/components/ui/table/index.tsx new file mode 100644 index 0000000..e8a4ac3 --- /dev/null +++ b/src/components/ui/table/index.tsx @@ -0,0 +1 @@ +export { default as Table } from '@/components/ui/table/Table'; diff --git a/src/components/ui/table/testApi.tsx b/src/components/ui/table/testApi.tsx new file mode 100644 index 0000000..31756a6 --- /dev/null +++ b/src/components/ui/table/testApi.tsx @@ -0,0 +1,86 @@ +export type UserType = 'employer' | 'employee'; + +export const fetchTableData = async (userType: UserType) => { + return new Promise<{ headers: string[]; data: unknown[] }>(resolve => { + setTimeout(() => { + if (userType === 'employer') { + resolve({ + headers: ['신청자', '소개', '전화번호', '상태'], + data: [ + { + name: '김강현', + bio: '최선을 다해 열심히 일합니다. 다수의 업무 경험을 바탕으로 확실한 일처리 보여드리겠습니다.', + phone: '010-1234-5678', + status: '버튼', + }, + { + name: '서혜진', + bio: '열심히 하겠습니다!', + phone: '010-0000-0000', + status: 'rejected', + }, + { + name: '주진혁', + bio: '성실한 자세로 열심히 일합니다.', + phone: '010-0000-0000', + status: 'accepted', + }, + { + name: '장민혁', + bio: '일을 꼼꼼하게 하는 성격입니다.', + phone: '010-0000-0000', + status: 'accepted', + }, + { + name: '고기훈', + bio: '하루라도 최선을 다해서 일하겠습니다!', + phone: '010-0000-0000', + status: 'accepted', + }, + ], + }); + } else { + resolve({ + headers: ['가게', '일자', '시급', '상태'], + data: [ + { + name: '너구리네 라면집', + startsAt: '2025-10-01T11:00', + workhour: 2, + hourlyPay: '12,500원', + status: 'accepted', + }, + { + name: '너구리네 라면집', + startsAt: '2025-10-01T11:00', + workhour: 2, + hourlyPay: '12,500원', + status: 'rejected', + }, + { + name: '너구리네 라면집', + startsAt: '2025-10-01T11:00', + workhour: 2, + hourlyPay: '12,500원', + status: 'accepted', + }, + { + name: '너구리네 라면집', + startsAt: '2025-10-01T11:00', + workhour: 2, + hourlyPay: '12,500원', + status: 'accepted', + }, + { + name: '너구리네 라면집', + startsAt: '2025-10-01T11:00', + workhour: 2, + hourlyPay: '12,500원', + status: 'accepted', + }, + ], + }); + } + }); + }); +}; diff --git a/src/lib/utils/getTime.ts b/src/lib/utils/getTime.ts new file mode 100644 index 0000000..9771439 --- /dev/null +++ b/src/lib/utils/getTime.ts @@ -0,0 +1,18 @@ +function formatDate(date: Date): string { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + + return `${year}.${month}.${day} ${hours}:${minutes}`; +} + +export function getTime(startsAt: string, workhour: number) { + const START = new Date(startsAt); + const END = new Date(startsAt); + + END.setHours(END.getHours() + workhour); + + return { STRAT: formatDate(START), END: formatDate(END), duration: `${workhour}시간` }; +}