Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
112a874
โœจ feat: Table ์ปดํฌ๋„ŒํŠธ์— modal ์ปดํฌ๋„ŒํŠธ/state ์ถ”๊ฐ€
Moon-ju-young Jun 22, 2025
47f5491
โœจ feat: Table ์ปดํฌ๋„ŒํŠธ์— closeModal ํ•จ์ˆ˜ ์ถ”๊ฐ€
Moon-ju-young Jun 22, 2025
78d9140
โœจ feat: modal.dataIndex state ์ถ”๊ฐ€
Moon-ju-young Jun 22, 2025
945dfb2
โœจ feat: clickButton ํ•จ์ˆ˜ ์ถ”๊ฐ€
Moon-ju-young Jun 22, 2025
2e50b76
๐Ÿ”ฅ remove: TableButtons์—์„œ modal ์‚ญ์ œ
Moon-ju-young Jun 22, 2025
72014be
๐Ÿ”ฅ remove: TableButtons์—์„œ modal import ์‚ญ์ œ
Moon-ju-young Jun 22, 2025
dd4e25f
๐Ÿ› fix: TableButtons props ์ˆ˜์ •
Moon-ju-young Jun 22, 2025
72d9ddd
โœจ feat: Table Buttons index prop ์ถ”๊ฐ€
Moon-ju-young Jun 22, 2025
5267691
๐Ÿ› fix: Table ๋‚ด๋ถ€ TableButtons props ์ˆ˜์ •
Moon-ju-young Jun 22, 2025
4986fe5
๐Ÿ”ฅ remove: TableButtons modal state ์‚ญ์ œ
Moon-ju-young Jun 22, 2025
ed3210f
๐Ÿ”ฅ remove: TableButtons closeModal ํ•จ์ˆ˜ ์‚ญ์ œ
Moon-ju-young Jun 22, 2025
ea7b48e
๐Ÿ”ฅ remove: TableButtons handleClick ํ•จ์ˆ˜ ์‚ญ์ œ
Moon-ju-young Jun 22, 2025
93d1eda
โ™ป๏ธ refactor: TableButtons ๋‚ด๋ถ€ Button onClick ๋ณ€๊ฒฝ
Moon-ju-young Jun 22, 2025
43d32b5
โœจ feat: Table handleModalClick ํ•จ์ˆ˜ ์ถ”๊ฐ€
Moon-ju-young Jun 22, 2025
f78ffc6
โœจ feat: Table Modal์— handleModalClick ์ถ”๊ฐ€
Moon-ju-young Jun 22, 2025
cd28863
๐Ÿ”ฅ remove: TableButtons handleModalClick ํ•จ์ˆ˜ ๋ฐ status state ์‚ญ์ œ
Moon-ju-young Jun 22, 2025
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
180 changes: 119 additions & 61 deletions src/components/common/table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { useEffect, useState } from 'react';
import TableStatus from './TableStatus';
import TableButtons from './TableButtons';
import Pagination from '../Pagination';
import Modal from '../Modal';
import formatWorkTime from '@/utils/formatWorkTime';
import {
getNoticeApplications,
getUserApplications,
putNoticeApplications,
} from '@/api/applicationApi';

interface UserProps {
Expand All @@ -32,6 +34,53 @@ export default function Table(props: UserProps | NoticeProps) {
);
const [page, setPage] = useState(1);
const [totalPage, setTotalPage] = useState(1);
const [modal, setModal] = useState<{
isOpen: boolean;
status: 'accepted' | 'rejected';
dataIndex: number;
}>({
isOpen: false,
status: 'accepted',
dataIndex: 0,
});

const closeModal = () =>
setModal((prev) => {
return { ...prev, isOpen: false };
});

const clickButton = (dataIndex: number, status: 'accepted' | 'rejected') => {
setModal({
isOpen: true,
status,
dataIndex,
});
};

const handleModalClick = async () => {
closeModal();
if (mode === 'user') return;

setDatas((prev) => {
prev[modal.dataIndex][3] = modal.status;
return prev;
});
try {
await putNoticeApplications(
props.shopId,
props.noticeId,
datas[modal.dataIndex][4] ?? '',
{
status: modal.status,
},
);
} catch {
setDatas((prev) => {
prev[modal.dataIndex][3] = 'pending';
return prev;
});
}
};

useEffect(() => {
(async () => {
Expand Down Expand Up @@ -97,68 +146,77 @@ export default function Table(props: UserProps | NoticeProps) {
}, [mode, page]);

return (
<div
className={`@container scrollbar-hide overflow-x-auto rounded-[10px] border border-gray-20 bg-white ${className}`}
>
<table className="w-full min-w-888 border-separate border-spacing-0 text-left md:min-w-946">
<thead className="h-39 bg-red-10 text-caption/16 md:h-49 md:text-body2/22">
<tr>
<th className="w-227 border-b border-gray-20 px-7 font-regular md:px-11">
{headers[0]}
</th>
<th className="w-300 border-b border-gray-20 px-8 font-regular md:px-12">
{headers[1]}
</th>
<th className="w-200 border-b border-gray-20 px-8 font-regular md:px-12">
{headers[2]}
</th>
<th className="sticky right-0 border-b border-l border-gray-20 bg-red-10 px-7 font-regular md:px-11 @min-[947px]:border-l-transparent">
{headers[3]}
</th>
</tr>
</thead>
<tbody className="text-body2/22 font-regular md:text-body1/26">
{datas.map((data, index) => (
<tr key={index}>
<td className="border-b border-gray-20 pt-12 pr-8 pb-11 pl-7 md:pt-20 md:pr-12 md:pb-19 md:pl-11">
<div className="line-clamp-1 max-h-22 overflow-hidden md:line-clamp-2 md:max-h-51">
{data[0]}
</div>
</td>
<td className="border-b border-gray-20 px-8 pt-12 pb-11 md:px-12 md:pt-20 md:pb-19">
<div className="line-clamp-1 max-h-22 overflow-hidden md:line-clamp-2 md:max-h-51">
{data[1]}
</div>
</td>
<td className="border-b border-gray-20 px-8 pt-12 pb-11 md:px-12 md:pt-20 md:pb-19">
<div className="line-clamp-1 max-h-22 overflow-hidden md:line-clamp-2 md:max-h-51">
{data[2]}
</div>
</td>
<td className="sticky right-0 border-b border-l border-gray-20 bg-white px-7 pt-1 md:px-11 @min-[947px]:border-l-transparent">
<div className="min-h-44 content-center md:min-h-67">
{mode === 'notice' && data[3] === 'pending' ? (
<TableButtons
shopId={props.shopId}
noticeId={props.noticeId}
applicaitonId={data[4] ?? ''}
/>
) : (
<TableStatus status={data[3] ?? ''} />
)}
</div>
</td>
<>
<div
className={`@container scrollbar-hide overflow-x-auto rounded-[10px] border border-gray-20 bg-white ${className}`}
>
<table className="w-full min-w-888 border-separate border-spacing-0 text-left md:min-w-946">
<thead className="h-39 bg-red-10 text-caption/16 md:h-49 md:text-body2/22">
<tr>
<th className="w-227 border-b border-gray-20 px-7 font-regular md:px-11">
{headers[0]}
</th>
<th className="w-300 border-b border-gray-20 px-8 font-regular md:px-12">
{headers[1]}
</th>
<th className="w-200 border-b border-gray-20 px-8 font-regular md:px-12">
{headers[2]}
</th>
<th className="sticky right-0 border-b border-l border-gray-20 bg-red-10 px-7 font-regular md:px-11 @min-[947px]:border-l-transparent">
{headers[3]}
</th>
</tr>
))}
</tbody>
</table>
<div className="sticky right-0 bottom-0 left-0">
<Pagination
currentPage={page}
setCurrentPage={setPage}
totalPages={totalPage}
/>
</thead>
<tbody className="text-body2/22 font-regular md:text-body1/26">
{datas.map((data, index) => (
<tr key={index}>
<td className="border-b border-gray-20 pt-12 pr-8 pb-11 pl-7 md:pt-20 md:pr-12 md:pb-19 md:pl-11">
<div className="line-clamp-1 max-h-22 overflow-hidden md:line-clamp-2 md:max-h-51">
{data[0]}
</div>
</td>
<td className="border-b border-gray-20 px-8 pt-12 pb-11 md:px-12 md:pt-20 md:pb-19">
<div className="line-clamp-1 max-h-22 overflow-hidden md:line-clamp-2 md:max-h-51">
{data[1]}
</div>
</td>
<td className="border-b border-gray-20 px-8 pt-12 pb-11 md:px-12 md:pt-20 md:pb-19">
<div className="line-clamp-1 max-h-22 overflow-hidden md:line-clamp-2 md:max-h-51">
{data[2]}
</div>
</td>
<td className="sticky right-0 border-b border-l border-gray-20 bg-white px-7 pt-1 md:px-11 @min-[947px]:border-l-transparent">
<div className="min-h-44 content-center md:min-h-67">
{mode === 'notice' && data[3] === 'pending' ? (
<TableButtons index={index} click={clickButton} />
) : (
<TableStatus status={data[3] ?? ''} />
)}
</div>
</td>
</tr>
))}
</tbody>
</table>
<div className="sticky right-0 bottom-0 left-0">
<Pagination
currentPage={page}
setCurrentPage={setPage}
totalPages={totalPage}
/>
</div>
</div>
</div>
{modal.isOpen && (
<Modal
option="action"
yesButtonContent="์˜ˆ"
onYesButtonClick={handleModalClick}
onButtonClick={closeModal}
onClose={closeModal}
>
์‹ ์ฒญ์„ {modal.status === 'accepted' ? '์Šน์ธ' : '๊ฑฐ์ ˆ'}ํ•˜์‹œ๊ฒ ์–ด์š”?
</Modal>
)}
</>
);
}
115 changes: 29 additions & 86 deletions src/components/common/table/TableButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,14 @@
import { useEffect, useState, type MouseEvent } from 'react';
import { useEffect, useState } from 'react';
import Button from '../Button';
import TableStatus from './TableStatus';
import { putNoticeApplications } from '@/api/applicationApi';
import Modal from '../Modal';

interface Props {
shopId: string;
noticeId: string;
applicaitonId: string;
index: number;
click: (dataIndex: number, status: 'accepted' | 'rejected') => void;
}

export default function TableButtons({
shopId,
noticeId,
applicaitonId,
}: Props) {
const [status, setStatus] = useState<'pending' | 'accepted' | 'rejected'>(
'pending',
);
const [modal, setModal] = useState<{
isOpen: boolean;
status: 'accepted' | 'rejected';
}>({
isOpen: false,
status: 'accepted',
});
export default function TableButtons({ index, click }: Props) {
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);

const closeModal = () =>
setModal((prev) => {
return { ...prev, isOpen: false };
});

const handleModalClick = async () => {
closeModal();
setStatus(modal.status);
try {
await putNoticeApplications(shopId, noticeId, applicaitonId, {
status: modal.status,
});
} catch {
setStatus('pending');
}
};

const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
setModal({
isOpen: true,
status: e.currentTarget.value as 'accepted' | 'rejected',
});
};

useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
Expand All @@ -59,45 +17,30 @@ export default function TableButtons({
return () => window.removeEventListener('resize', handleResize);
}, []);

return status === 'pending' ? (
<>
<div className="flex gap-8 md:gap-12">
<Button
solid={false}
size={isMobile ? 'small' : 'medium'}
className="w-69 md:w-92"
value="rejected"
onClick={handleClick}
>
๊ฑฐ์ ˆํ•˜๊ธฐ
</Button>
<Button
solid={false}
size={isMobile ? 'small' : 'medium'}
className="w-69 md:w-92"
style={{
color: 'var(--color-blue-20)',
borderColor: 'var(--color-blue-20)',
}}
value="accepted"
onClick={handleClick}
>
์Šน์ธํ•˜๊ธฐ
</Button>
</div>
{modal.isOpen && (
<Modal
option="action"
onButtonClick={closeModal}
onYesButtonClick={handleModalClick}
yesButtonContent="์˜ˆ"
onClose={closeModal}
>
์‹ ์ฒญ์„ {modal.status === 'accepted' ? '์Šน์ธ' : '๊ฑฐ์ ˆ'}ํ•˜์‹œ๊ฒ ์–ด์š”?
</Modal>
)}
</>
) : (
<TableStatus status={status} />
return (
<div className="flex gap-8 md:gap-12">
<Button
solid={false}
size={isMobile ? 'small' : 'medium'}
className="w-69 md:w-92"
value="rejected"
onClick={() => click(index, 'rejected')}
>
๊ฑฐ์ ˆํ•˜๊ธฐ
</Button>
<Button
solid={false}
size={isMobile ? 'small' : 'medium'}
className="w-69 md:w-92"
style={{
color: 'var(--color-blue-20)',
borderColor: 'var(--color-blue-20)',
}}
value="accepted"
onClick={() => click(index, 'accepted')}
>
์Šน์ธํ•˜๊ธฐ
</Button>
</div>
);
}