feat(WEB): 회계/HR/주문관리 모듈 개선 및 알림설정 리팩토링
- 회계: 거래처, 매입/매출, 입출금 상세 페이지 개선 - HR: 직원 관리 및 출퇴근 설정 기능 수정 - 주문관리: 상세폼 구조 분리 (cards, dialogs, hooks, tables) - 알림설정: 컴포넌트 구조 단순화 및 리팩토링 - 캘린더: 헤더 및 일정 타입 개선 - 출고관리: 액션 및 타입 정의 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,7 +59,7 @@ export function AccountManagement() {
|
||||
|
||||
// ===== 상태 관리 =====
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [selectedItems, setSelectedItems] = useState<Set<number>>(new Set());
|
||||
const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const itemsPerPage = 20;
|
||||
|
||||
@@ -69,7 +69,7 @@ export function AccountManagement() {
|
||||
|
||||
// 삭제 다이얼로그
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||
const [deleteTargetId, setDeleteTargetId] = useState<number | null>(null);
|
||||
const [deleteTargetId, setDeleteTargetId] = useState<string | null>(null);
|
||||
const [showBulkDeleteDialog, setShowBulkDeleteDialog] = useState(false);
|
||||
|
||||
// API 데이터
|
||||
@@ -98,7 +98,7 @@ export function AccountManagement() {
|
||||
}, [loadData]);
|
||||
|
||||
// ===== 체크박스 핸들러 =====
|
||||
const toggleSelection = useCallback((id: number) => {
|
||||
const toggleSelection = useCallback((id: string) => {
|
||||
setSelectedItems(prev => {
|
||||
const newSet = new Set(prev);
|
||||
if (newSet.has(id)) newSet.delete(id);
|
||||
@@ -132,7 +132,7 @@ export function AccountManagement() {
|
||||
if (selectedItems.size === filteredData.length && filteredData.length > 0) {
|
||||
setSelectedItems(new Set());
|
||||
} else {
|
||||
setSelectedItems(new Set(filteredData.map(item => item.id)));
|
||||
setSelectedItems(new Set(filteredData.map(item => String(item.id))));
|
||||
}
|
||||
}, [selectedItems.size, filteredData]);
|
||||
|
||||
@@ -145,7 +145,7 @@ export function AccountManagement() {
|
||||
router.push(`/ko/settings/accounts/${item.id}?mode=edit`);
|
||||
}, [router]);
|
||||
|
||||
const handleDeleteClick = useCallback((id: number) => {
|
||||
const handleDeleteClick = useCallback((id: string) => {
|
||||
setDeleteTargetId(id);
|
||||
setShowDeleteDialog(true);
|
||||
}, []);
|
||||
@@ -155,10 +155,10 @@ export function AccountManagement() {
|
||||
|
||||
setIsDeleting(true);
|
||||
try {
|
||||
const result = await deleteBankAccount(deleteTargetId);
|
||||
const result = await deleteBankAccount(Number(deleteTargetId));
|
||||
if (result.success) {
|
||||
toast.success('계좌가 삭제되었습니다.');
|
||||
setData(prev => prev.filter(item => item.id !== deleteTargetId));
|
||||
setData(prev => prev.filter(item => String(item.id) !== deleteTargetId));
|
||||
setSelectedItems(prev => {
|
||||
const newSet = new Set(prev);
|
||||
newSet.delete(deleteTargetId);
|
||||
@@ -183,7 +183,7 @@ export function AccountManagement() {
|
||||
}, [selectedItems.size]);
|
||||
|
||||
const handleConfirmBulkDelete = useCallback(async () => {
|
||||
const ids = Array.from(selectedItems);
|
||||
const ids = Array.from(selectedItems).map(id => Number(id));
|
||||
setIsDeleting(true);
|
||||
try {
|
||||
const result = await deleteBankAccounts(ids);
|
||||
@@ -192,7 +192,7 @@ export function AccountManagement() {
|
||||
if (result.error) {
|
||||
toast.warning(result.error);
|
||||
}
|
||||
setData(prev => prev.filter(item => !selectedItems.has(item.id)));
|
||||
setData(prev => prev.filter(item => !selectedItems.has(String(item.id))));
|
||||
setSelectedItems(new Set());
|
||||
} else {
|
||||
toast.error(result.error || '계좌 삭제에 실패했습니다.');
|
||||
@@ -222,7 +222,8 @@ export function AccountManagement() {
|
||||
|
||||
// ===== 테이블 행 렌더링 =====
|
||||
const renderTableRow = useCallback((item: Account, index: number, globalIndex: number) => {
|
||||
const isSelected = selectedItems.has(item.id);
|
||||
const itemIdStr = String(item.id);
|
||||
const isSelected = selectedItems.has(itemIdStr);
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
@@ -231,7 +232,7 @@ export function AccountManagement() {
|
||||
onClick={() => handleRowClick(item)}
|
||||
>
|
||||
<TableCell className="text-center" onClick={(e) => e.stopPropagation()}>
|
||||
<Checkbox checked={isSelected} onCheckedChange={() => toggleSelection(item.id)} />
|
||||
<Checkbox checked={isSelected} onCheckedChange={() => toggleSelection(itemIdStr)} />
|
||||
</TableCell>
|
||||
<TableCell className="text-muted-foreground text-center">{globalIndex}</TableCell>
|
||||
<TableCell>{BANK_LABELS[item.bankCode] || item.bankCode}</TableCell>
|
||||
@@ -257,7 +258,7 @@ export function AccountManagement() {
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleDeleteClick(item.id)}
|
||||
onClick={() => handleDeleteClick(itemIdStr)}
|
||||
title="삭제"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 text-red-500" />
|
||||
@@ -279,7 +280,7 @@ export function AccountManagement() {
|
||||
) => {
|
||||
return (
|
||||
<ListMobileCard
|
||||
id={item.id}
|
||||
id={String(item.id)}
|
||||
title={item.accountName}
|
||||
headerBadges={
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
@@ -321,7 +322,7 @@ export function AccountManagement() {
|
||||
variant="outline"
|
||||
size="default"
|
||||
className="flex-1 min-w-[100px] h-11 border-red-200 text-red-600 hover:border-red-300 bg-transparent"
|
||||
onClick={(e) => { e.stopPropagation(); handleDeleteClick(item.id); }}
|
||||
onClick={(e) => { e.stopPropagation(); handleDeleteClick(String(item.id)); }}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
삭제
|
||||
@@ -358,7 +359,7 @@ export function AccountManagement() {
|
||||
selectedItems={selectedItems}
|
||||
onToggleSelection={toggleSelection}
|
||||
onToggleSelectAll={toggleSelectAll}
|
||||
getItemId={(item: Account) => item.id}
|
||||
getItemId={(item: Account) => String(item.id)}
|
||||
renderTableRow={renderTableRow}
|
||||
renderMobileCard={renderMobileCard}
|
||||
pagination={{
|
||||
|
||||
Reference in New Issue
Block a user