From ec0ad538373b784fc4aab8a39af271069958bcbe Mon Sep 17 00:00:00 2001 From: kent Date: Tue, 30 Dec 2025 17:22:19 +0900 Subject: [PATCH] =?UTF-8?q?feat(WEB):=20=EA=B2=B0=EC=9E=AC/=ED=9A=8C?= =?UTF-8?q?=EA=B3=84/=ED=92=88=EB=AA=A9=20=EA=B4=80=EB=A6=AC=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ApprovalLineSection/ReferenceSection: 결재선 설정 개선 - DepositManagement/WithdrawalManagement: 입출금 관리 UI 개선 - bills/pricing-management 페이지 수정 - ItemDetailClient: 품목 상세 표시 개선 --- .../(protected)/accounting/bills/page.tsx | 2 +- .../sales/pricing-management/page.tsx | 4 +- .../accounting/DepositManagement/index.tsx | 38 +++++++++++++++---- .../accounting/WithdrawalManagement/index.tsx | 38 +++++++++++++++---- src/components/items/ItemDetailClient.tsx | 2 +- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/app/[locale]/(protected)/accounting/bills/page.tsx b/src/app/[locale]/(protected)/accounting/bills/page.tsx index 052cd949..0332c219 100644 --- a/src/app/[locale]/(protected)/accounting/bills/page.tsx +++ b/src/app/[locale]/(protected)/accounting/bills/page.tsx @@ -47,7 +47,7 @@ async function getBills(params: { queryParams.append('per_page', '20'); const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/v1/bills?${queryParams.toString()}`, + `${process.env.API_URL}/api/v1/bills?${queryParams.toString()}`, { method: 'GET', headers, cache: 'no-store' } ); diff --git a/src/app/[locale]/(protected)/sales/pricing-management/page.tsx b/src/app/[locale]/(protected)/sales/pricing-management/page.tsx index 5b9ef67e..7934002d 100644 --- a/src/app/[locale]/(protected)/sales/pricing-management/page.tsx +++ b/src/app/[locale]/(protected)/sales/pricing-management/page.tsx @@ -150,7 +150,7 @@ async function getItemsList(): Promise { const headers = await getApiHeaders(); const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/v1/items?group_id=1&size=100`, + `${process.env.API_URL}/api/v1/items?group_id=1&size=100`, { method: 'GET', headers, @@ -183,7 +183,7 @@ async function getPricingList(): Promise { const headers = await getApiHeaders(); const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/v1/pricing?size=100`, + `${process.env.API_URL}/api/v1/pricing?size=100`, { method: 'GET', headers, diff --git a/src/components/accounting/DepositManagement/index.tsx b/src/components/accounting/DepositManagement/index.tsx index 3fae7e02..c36eab20 100644 --- a/src/components/accounting/DepositManagement/index.tsx +++ b/src/components/accounting/DepositManagement/index.tsx @@ -58,7 +58,7 @@ import { DEPOSIT_TYPE_FILTER_OPTIONS, ACCOUNT_SUBJECT_OPTIONS, } from './types'; -import { deleteDeposit, updateDepositTypes } from './actions'; +import { deleteDeposit, updateDepositTypes, getDeposits } from './actions'; import { toast } from 'sonner'; // ===== 컴포넌트 Props ===== @@ -104,6 +104,9 @@ export function DepositManagement({ initialData, initialPagination }: DepositMan // 입금 데이터 (서버에서 전달받은 initialData 사용) const [data, setData] = useState(initialData); + // 로딩 상태 + const [isRefreshing, setIsRefreshing] = useState(false); + // ===== 체크박스 핸들러 ===== const toggleSelection = useCallback((id: string) => { setSelectedItems(prev => { @@ -200,10 +203,30 @@ export function DepositManagement({ initialData, initialPagination }: DepositMan }, [deleteTargetId]); // 새로고침 핸들러 - const handleRefresh = useCallback(() => { - // TODO: API 호출로 최신 데이터 조회 - toast.info('새로고침 기능 준비 중입니다.'); - }, []); + const handleRefresh = useCallback(async () => { + setIsRefreshing(true); + try { + const result = await getDeposits({ + perPage: 100, + startDate, + endDate, + depositType: depositTypeFilter !== 'all' ? depositTypeFilter : undefined, + search: searchQuery || undefined, + }); + if (result.success) { + setData(result.data); + setSelectedItems(new Set()); + setCurrentPage(1); + toast.success('데이터를 새로고침했습니다.'); + } else { + toast.error(result.error || '새로고침에 실패했습니다.'); + } + } catch { + toast.error('새로고침 중 오류가 발생했습니다.'); + } finally { + setIsRefreshing(false); + } + }, [startDate, endDate, depositTypeFilter, searchQuery]); // ===== 통계 카드 (총 입금, 당월 입금, 거래처 미설정, 입금유형 미설정) ===== const statCards: StatCard[] = useMemo(() => { @@ -480,9 +503,10 @@ export function DepositManagement({ initialData, initialPagination }: DepositMan ); diff --git a/src/components/accounting/WithdrawalManagement/index.tsx b/src/components/accounting/WithdrawalManagement/index.tsx index 47b09d1e..b02d7ad5 100644 --- a/src/components/accounting/WithdrawalManagement/index.tsx +++ b/src/components/accounting/WithdrawalManagement/index.tsx @@ -56,7 +56,7 @@ import { WITHDRAWAL_TYPE_FILTER_OPTIONS, ACCOUNT_SUBJECT_OPTIONS, } from './types'; -import { deleteWithdrawal, updateWithdrawalTypes } from './actions'; +import { deleteWithdrawal, updateWithdrawalTypes, getWithdrawals } from './actions'; import { toast } from 'sonner'; // ===== 컴포넌트 Props ===== @@ -102,6 +102,9 @@ export function WithdrawalManagement({ initialData, initialPagination }: Withdra // 출금 데이터 (서버에서 전달받은 initialData 사용) const [data, setData] = useState(initialData); + // 로딩 상태 + const [isRefreshing, setIsRefreshing] = useState(false); + // ===== 체크박스 핸들러 ===== const toggleSelection = useCallback((id: string) => { setSelectedItems(prev => { @@ -198,10 +201,30 @@ export function WithdrawalManagement({ initialData, initialPagination }: Withdra }, [deleteTargetId]); // 새로고침 핸들러 - const handleRefresh = useCallback(() => { - // TODO: API 호출로 최신 데이터 조회 - toast.info('새로고침 기능 준비 중입니다.'); - }, []); + const handleRefresh = useCallback(async () => { + setIsRefreshing(true); + try { + const result = await getWithdrawals({ + perPage: 100, + startDate, + endDate, + withdrawalType: withdrawalTypeFilter !== 'all' ? withdrawalTypeFilter : undefined, + search: searchQuery || undefined, + }); + if (result.success) { + setData(result.data); + setSelectedItems(new Set()); + setCurrentPage(1); + toast.success('데이터를 새로고침했습니다.'); + } else { + toast.error(result.error || '새로고침에 실패했습니다.'); + } + } catch { + toast.error('새로고침 중 오류가 발생했습니다.'); + } finally { + setIsRefreshing(false); + } + }, [startDate, endDate, withdrawalTypeFilter, searchQuery]); // ===== 통계 카드 (총 출금, 당월 출금, 거래처 미설정, 출금유형 미설정) ===== const statCards: StatCard[] = useMemo(() => { @@ -474,9 +497,10 @@ export function WithdrawalManagement({ initialData, initialPagination }: Withdra ); diff --git a/src/components/items/ItemDetailClient.tsx b/src/components/items/ItemDetailClient.tsx index 0097d906..28928983 100644 --- a/src/components/items/ItemDetailClient.tsx +++ b/src/components/items/ItemDetailClient.tsx @@ -86,7 +86,7 @@ function getStorageUrl(path: string | undefined): string | null { return path; } // 상대 경로인 경우 - const apiUrl = process.env.NEXT_PUBLIC_API_URL || ''; + const apiUrl = process.env.API_URL || ''; return `${apiUrl}/storage/${path}`; }