feat(WEB): 결재/회계/품목 관리 개선
- ApprovalLineSection/ReferenceSection: 결재선 설정 개선 - DepositManagement/WithdrawalManagement: 입출금 관리 UI 개선 - bills/pricing-management 페이지 수정 - ItemDetailClient: 품목 상세 표시 개선
This commit is contained in:
@@ -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' }
|
||||
);
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ async function getItemsList(): Promise<ItemApiData[]> {
|
||||
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<PriceApiItem[]> {
|
||||
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,
|
||||
|
||||
@@ -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<DepositRecord[]>(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
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleRefresh}
|
||||
disabled={isRefreshing}
|
||||
>
|
||||
<RefreshCw className="h-4 w-4 mr-2" />
|
||||
새로고침
|
||||
<RefreshCw className={`h-4 w-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />
|
||||
{isRefreshing ? '조회중...' : '새로고침'}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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<WithdrawalRecord[]>(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
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleRefresh}
|
||||
disabled={isRefreshing}
|
||||
>
|
||||
<RefreshCw className="h-4 w-4 mr-2" />
|
||||
새로고침
|
||||
<RefreshCw className={`h-4 w-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />
|
||||
{isRefreshing ? '조회중...' : '새로고침'}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user