refactor: UniversalListPage externalIsLoading 지원 및 스켈레톤 개선
- UniversalListPage에 externalIsLoading prop 추가 - CardTransactionDetailClient DevFill 자동입력 기능 추가 - 여러 컴포넌트 로딩 상태 처리 개선 - skeleton 컴포넌트 확장 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ import { useRouter } from 'next/navigation';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { PageLoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { FormSectionSkeleton } from '@/components/ui/skeleton';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import {
|
||||
Card,
|
||||
@@ -616,12 +616,7 @@ export default function DynamicItemForm({
|
||||
|
||||
// 로딩 상태
|
||||
if (isLoading && selectedItemType) {
|
||||
return (
|
||||
<PageLoadingSpinner
|
||||
text="폼 구조를 불러오는 중..."
|
||||
minHeight="min-h-[40vh]"
|
||||
/>
|
||||
);
|
||||
return <FormSectionSkeleton />;
|
||||
}
|
||||
|
||||
// 에러 상태
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useRouter } from 'next/navigation';
|
||||
import DynamicItemForm from '@/components/items/DynamicItemForm';
|
||||
import type { DynamicFormData, BOMLine } from '@/components/items/DynamicItemForm/types';
|
||||
import type { ItemType } from '@/types/item';
|
||||
import { ContentLoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { DetailPageSkeleton } from '@/components/ui/skeleton';
|
||||
import {
|
||||
isMaterialType,
|
||||
transformMaterialDataForSave,
|
||||
@@ -368,7 +368,7 @@ export function ItemDetailEdit({ itemCode, itemType: urlItemType, itemId: urlIte
|
||||
|
||||
// 로딩 상태
|
||||
if (isLoading) {
|
||||
return <ContentLoadingSpinner text="품목 정보를 불러오는 중..." />;
|
||||
return <DetailPageSkeleton sections={2} fieldsPerSection={6} />;
|
||||
}
|
||||
|
||||
// 에러 상태
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useRouter } from 'next/navigation';
|
||||
import { notFound } from 'next/navigation';
|
||||
import ItemDetailClient from '@/components/items/ItemDetailClient';
|
||||
import type { ItemMaster, ItemType, ProductCategory, PartType, PartUsage } from '@/types/item';
|
||||
import { ContentLoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { DetailPageSkeleton } from '@/components/ui/skeleton';
|
||||
import { ServerErrorPage } from '@/components/common/ServerErrorPage';
|
||||
|
||||
// Materials 타입 (SM, RM, CS는 Material 테이블 사용)
|
||||
@@ -253,7 +253,7 @@ export function ItemDetailView({ itemCode, itemType, itemId }: ItemDetailViewPro
|
||||
|
||||
// 로딩 상태
|
||||
if (isLoading) {
|
||||
return <ContentLoadingSpinner text="품목 정보를 불러오는 중..." />;
|
||||
return <DetailPageSkeleton sections={2} fieldsPerSection={6} />;
|
||||
}
|
||||
|
||||
// 에러 상태
|
||||
|
||||
@@ -18,7 +18,6 @@ import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { TableRow, TableCell } from '@/components/ui/table';
|
||||
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
import { Search, Plus, Edit, Trash2, Package } from 'lucide-react';
|
||||
import { TableLoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { useItemList } from '@/hooks/useItemList';
|
||||
import { handleApiError } from '@/lib/api/error-handler';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
@@ -122,11 +121,6 @@ export default function ItemListClient() {
|
||||
});
|
||||
}, [debouncedSearchTerm, selectedType, search]);
|
||||
|
||||
// 로딩 상태
|
||||
if (isLoading) {
|
||||
return <TableLoadingSpinner text="품목 목록을 불러오는 중..." />;
|
||||
}
|
||||
|
||||
// 유형 변경 핸들러
|
||||
const handleTypeChange = (value: string) => {
|
||||
setSelectedType(value);
|
||||
@@ -491,6 +485,7 @@ export default function ItemListClient() {
|
||||
itemsPerPage: pagination.perPage,
|
||||
onPageChange: handlePageChange,
|
||||
}}
|
||||
externalIsLoading={isLoading}
|
||||
/>
|
||||
|
||||
{/* 개별 삭제 확인 다이얼로그 */}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { PageHeader } from '@/components/organisms/PageHeader';
|
||||
import { useItemMaster } from '@/contexts/ItemMasterContext';
|
||||
import type { SectionTemplate, BOMItem, TemplateField } from '@/contexts/ItemMasterContext';
|
||||
import { MasterFieldTab, HierarchyTab, SectionsTab } from './ItemMasterDataManagement/tabs';
|
||||
import { LoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { DetailPageSkeleton } from '@/components/ui/skeleton';
|
||||
import { ServerErrorPage } from '@/components/common/ServerErrorPage';
|
||||
// 2025-12-24: Phase 2 UI 컴포넌트 분리
|
||||
import { AttributeTabContent } from './ItemMasterDataManagement/components';
|
||||
@@ -450,11 +450,7 @@ function ItemMasterDataManagementContent() {
|
||||
|
||||
// 초기 로딩 중 UI
|
||||
if (isInitialLoading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<LoadingSpinner size="lg" text="데이터를 불러오는 중..." />
|
||||
</div>
|
||||
);
|
||||
return <DetailPageSkeleton />;
|
||||
}
|
||||
|
||||
// 에러 발생 시 UI
|
||||
|
||||
@@ -16,7 +16,7 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { FormInput, Search, Info, Loader2, Hash, Calendar, CheckSquare, ChevronDown, Type, AlignLeft, Database } from 'lucide-react';
|
||||
import { ContentLoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { ContentSkeleton } from '@/components/ui/skeleton';
|
||||
import type { ItemField, ItemMasterField } from '@/contexts/ItemMasterContext';
|
||||
import type { FieldUsageResponse } from '@/types/item-master-api';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
@@ -157,7 +157,7 @@ export function ImportFieldDialog({
|
||||
|
||||
<div className="space-y-4">
|
||||
{isLoading ? (
|
||||
<ContentLoadingSpinner text="필드 목록을 불러오는 중..." />
|
||||
<ContentSkeleton type="list" rows={5} />
|
||||
) : filteredFields.length === 0 ? (
|
||||
<div className="text-center py-8">
|
||||
<FormInput className="h-12 w-12 mx-auto text-muted-foreground mb-4" />
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Package, Folder, Search, Info, Loader2 } from 'lucide-react';
|
||||
import { ContentLoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { ContentSkeleton } from '@/components/ui/skeleton';
|
||||
import type { ItemSection } from '@/contexts/ItemMasterContext';
|
||||
import type { SectionUsageResponse } from '@/types/item-master-api';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
@@ -109,7 +109,7 @@ export function ImportSectionDialog({
|
||||
|
||||
<div className="space-y-4">
|
||||
{isLoading ? (
|
||||
<ContentLoadingSpinner text="섹션 목록을 불러오는 중..." />
|
||||
<ContentSkeleton type="list" rows={5} />
|
||||
) : filteredSections.length === 0 ? (
|
||||
<div className="text-center py-8">
|
||||
<Folder className="h-12 w-12 mx-auto text-muted-foreground mb-4" />
|
||||
|
||||
Reference in New Issue
Block a user