Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
43 changes: 43 additions & 0 deletions src/components/ui/table/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -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<typeof Table> = {
title: 'UI/Table',
component: Table,
argTypes: {
userType: {
control: { type: 'radio' },
options: ['employer', 'employee'],
},
},
};

export default meta;

type Story = StoryObj<typeof Table>;

function TableWithTestApi({ userType }: { userType: UserType }) {
const [headers, setHeaders] = useState<string[]>([]);
const [data, setData] = useState<TableRowProps[]>([]);

useEffect(() => {
const getData = async () => {
const res = await fetchTableData(userType);
setHeaders(res.headers);
setData(res.data as TableRowProps[]);
};
getData();
}, [userType]);

return <Table headers={headers} data={data} userType={userType} />;
}

export const TableExample: Story = {
args: {
userType: 'employer',
},
render: args => <TableWithTestApi userType={args.userType} />,
};
32 changes: 32 additions & 0 deletions src/components/ui/table/Table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import TableRow from '@/components/ui/table/TableRow';
import { TableRowProps } from '@/components/ui/table/TableRowProps';

interface TableProps {
data: TableRowProps[];
headers: string[];
userType: 'employer' | 'employee';
}

// <Table headers={headers} data={data} userType={type} /> type은 확인이 좀 더 필요합니다

export default function Table({ data, headers, userType }: TableProps) {
return (
<div className='overflow-x-auto rounded-lg border border-gray-200'>
<table className='min-w-full'>
<tbody>
<tr className='bg-red-100'>
{headers.map((header, index) => (
<th key={index} className='px-2 py-3 text-left text-sm font-normal'>
{header}
</th>
))}
</tr>
{data.map((row, index) => (
<TableRow key={index} rowData={row} variant={userType} />
))}
</tbody>
</table>
<div className='flex justify-center px-3 py-2'>페이지네이션</div>
</div>
);
}
30 changes: 30 additions & 0 deletions src/components/ui/table/TableRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { TableRowProps } from '@/components/ui/table/TableRowProps';
import { getTime } from '@/lib/utils/getTime';

interface TableTypeVariant {
rowData: TableRowProps;
variant: 'employer' | 'employee';
}

export default function TableRow({ rowData, variant }: TableTypeVariant) {
if (variant === 'employee') {
return (
<tr className='text-left'>
<td className='border-b px-2 py-3'>{rowData.name}</td>
<td className='border-b px-2 py-3'>
{`${getTime(rowData.startsAt, 0)} ~ ${getTime(rowData.startsAt, rowData.workhour)} (${rowData.workhour}시간)`}
</td>
<td className='border-b px-2 py-3'>{rowData.hourlyPay}</td>
<td className='border-b px-2 py-[9px]'>{rowData.status}</td>
</tr>
);
}
return (
<tr className='text-left'>
<td className='border-b px-2 py-3'>{rowData.name}</td>
<td className='border-b px-2 py-3'>{rowData.bio}</td>
<td className='border-b px-2 py-3'>{rowData.phone}</td>
<td className='border-b px-2 py-[9px]'>{rowData.status}</td>
</tr>
);
}
9 changes: 9 additions & 0 deletions src/components/ui/table/TableRowProps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type TableRowProps = {
name: string;
startsAt: string;
workhour: number;
hourlyPay: string;
status: string | JSX.Element;
bio: string;
phone: number;
};
1 change: 1 addition & 0 deletions src/components/ui/table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Table } from '@/components/ui/table/Table';
86 changes: 86 additions & 0 deletions src/components/ui/table/testApi.tsx
Original file line number Diff line number Diff line change
@@ -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',
},
],
});
}
});
});
};
12 changes: 12 additions & 0 deletions src/lib/utils/getTime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function getTime(startsAt: string, workhour: number): string {
const startDate = new Date(startsAt);
startDate.setHours(startDate.getHours() + workhour);

const year = startDate.getFullYear();
const month = String(startDate.getMonth() + 1).padStart(2, '0');
const day = String(startDate.getDate()).padStart(2, '0');
const hours = String(startDate.getHours()).padStart(2, '0');
const minutes = String(startDate.getMinutes()).padStart(2, '0');

return `${year}.${month}.${day} ${hours}:${minutes}`;
}