diff options
Diffstat (limited to 'lib/swp/table/swp-table-toolbar.tsx')
| -rw-r--r-- | lib/swp/table/swp-table-toolbar.tsx | 179 |
1 files changed, 85 insertions, 94 deletions
diff --git a/lib/swp/table/swp-table-toolbar.tsx b/lib/swp/table/swp-table-toolbar.tsx index 03082b26..fc8337f5 100644 --- a/lib/swp/table/swp-table-toolbar.tsx +++ b/lib/swp/table/swp-table-toolbar.tsx @@ -4,13 +4,6 @@ import { useState, useTransition, useMemo } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Popover, PopoverContent, PopoverTrigger, @@ -23,17 +16,20 @@ import { useRouter } from "next/navigation"; import { cn } from "@/lib/utils"; import { useRef } from "react"; import { SwpUploadHelpDialog } from "./swp-help-dialog"; +import { SwpUploadResultDialog } from "./swp-upload-result-dialog"; interface SwpTableToolbarProps { filters: SwpTableFilters; onFiltersChange: (filters: SwpTableFilters) => void; projects?: Array<{ PROJ_NO: string; PROJ_NM: string }>; + vendorCode?: string; // 벤더가 접속했을 때 고정할 벤더 코드 } export function SwpTableToolbar({ filters, onFiltersChange, projects = [], + vendorCode, }: SwpTableToolbarProps) { const [isSyncing, startSync] = useTransition(); const [isUploading, startUpload] = useTransition(); @@ -43,6 +39,8 @@ export function SwpTableToolbar({ const [projectSearchOpen, setProjectSearchOpen] = useState(false); const [projectSearch, setProjectSearch] = useState(""); const fileInputRef = useRef<HTMLInputElement>(null); + const [uploadResults, setUploadResults] = useState<Array<{ fileName: string; success: boolean; error?: string }>>([]); + const [showResultDialog, setShowResultDialog] = useState(false); // 동기화 핸들러 const handleSync = () => { @@ -96,7 +94,7 @@ export function SwpTableToolbar({ const handleUploadFiles = () => { // 프로젝트와 벤더 코드 체크 const projectNo = localFilters.projNo; - const vndrCd = localFilters.vndrCd; + const vndrCd = vendorCode || localFilters.vndrCd; if (!projectNo) { toast({ @@ -130,7 +128,7 @@ export function SwpTableToolbar({ } const projectNo = localFilters.projNo!; - const vndrCd = localFilters.vndrCd!; + const vndrCd = vendorCode || localFilters.vndrCd!; startUpload(async () => { try { @@ -153,41 +151,27 @@ export function SwpTableToolbar({ // 서버 액션 호출 const result = await uploadSwpFilesAction(projectNo, vndrCd, fileInfos); - if (result.success) { - toast({ - title: "업로드 완료", - description: result.message, - }); + // 결과 저장 및 다이얼로그 표시 + setUploadResults(result.details); + setShowResultDialog(true); - // 페이지 새로고침 + // 성공한 파일이 있으면 페이지 새로고침 + const successCount = result.details.filter((d) => d.success).length; + if (successCount > 0) { router.refresh(); - } else { - toast({ - variant: "destructive", - title: "업로드 실패", - description: result.message, - }); - } - - // 실패한 파일이 있으면 상세 정보 표시 - const failedFiles = result.details.filter((d) => !d.success); - if (failedFiles.length > 0) { - console.error("실패한 파일:", failedFiles); - failedFiles.forEach((f) => { - toast({ - variant: "destructive", - title: `${f.fileName} 업로드 실패`, - description: f.error || "알 수 없는 오류", - }); - }); } } catch (error) { console.error("파일 업로드 실패:", error); - toast({ - variant: "destructive", - title: "업로드 실패", - description: error instanceof Error ? error.message : "알 수 없는 오류", - }); + + // 예외 발생 시에도 결과 다이얼로그 표시 + const errorResults = Array.from(selectedFiles).map((file) => ({ + fileName: file.name, + success: false, + error: error instanceof Error ? error.message : "알 수 없는 오류", + })); + + setUploadResults(errorResults); + setShowResultDialog(true); } finally { // 파일 입력 초기화 if (fileInputRef.current) { @@ -222,46 +206,59 @@ export function SwpTableToolbar({ }, [projects, projectSearch]); return ( - <div className="space-y-4"> - {/* 상단 액션 바 */} - <div className="flex items-center justify-between"> - <div className="flex items-center gap-2"> - <Button - onClick={handleSync} - disabled={isSyncing || !localFilters.projNo} - size="sm" - > - <RefreshCw className={`h-4 w-4 mr-2 ${isSyncing ? "animate-spin" : ""}`} /> - {isSyncing ? "동기화 중..." : "SWP 동기화"} - </Button> - - </div> + <> + {/* 업로드 결과 다이얼로그 */} + <SwpUploadResultDialog + open={showResultDialog} + onOpenChange={setShowResultDialog} + results={uploadResults} + /> + + <div className="space-y-4"> + {/* 상단 액션 바 */} + <div className="flex items-center justify-between"> + <div className="flex items-center gap-2"> + <Button + onClick={handleSync} + disabled={isSyncing || !localFilters.projNo} + size="sm" + > + <RefreshCw className={`h-4 w-4 mr-2 ${isSyncing ? "animate-spin" : ""}`} /> + {isSyncing ? "동기화 중..." : "SWP 동기화"} + </Button> + </div> - <div className="text-sm text-muted-foreground"> - SWP 문서 관리 시스템 - </div> - <div className="flex items-center gap-2"> - <input - ref={fileInputRef} - type="file" - multiple - className="hidden" - onChange={handleFileChange} - accept="*/*" - /> - <Button - variant="outline" - size="sm" - onClick={handleUploadFiles} - disabled={isUploading || !localFilters.projNo || !localFilters.vndrCd} - > - <Upload className={`h-4 w-4 mr-2 ${isUploading ? "animate-pulse" : ""}`} /> - {isUploading ? "업로드 중..." : "파일 업로드"} - </Button> + <div className="text-sm text-muted-foreground"> + SWP 문서 관리 시스템 + </div> - <SwpUploadHelpDialog /> + <div className="flex items-center gap-2"> + {/* 벤더만 파일 업로드 기능 사용 가능 */} + {vendorCode && ( + <> + <input + ref={fileInputRef} + type="file" + multiple + className="hidden" + onChange={handleFileChange} + accept="*/*" + /> + <Button + variant="outline" + size="sm" + onClick={handleUploadFiles} + disabled={isUploading || !localFilters.projNo || (!vendorCode && !localFilters.vndrCd)} + > + <Upload className={`h-4 w-4 mr-2 ${isUploading ? "animate-pulse" : ""}`} /> + {isUploading ? "업로드 중..." : "파일 업로드"} + </Button> + + <SwpUploadHelpDialog /> + </> + )} + </div> </div> - </div> {/* 검색 필터 */} <div className="rounded-lg border p-4 space-y-4"> @@ -423,33 +420,26 @@ export function SwpTableToolbar({ <Input id="vndrCd" placeholder="업체 코드" - value={localFilters.vndrCd || ""} + value={vendorCode || localFilters.vndrCd || ""} onChange={(e) => setLocalFilters({ ...localFilters, vndrCd: e.target.value }) } + disabled={!!vendorCode} // 벤더 코드가 제공되면 입력 비활성화 + className={vendorCode ? "bg-muted" : ""} /> </div> {/* 스테이지 */} <div className="space-y-2"> <Label htmlFor="stage">스테이지</Label> - <Select - value={localFilters.stage || "__all__"} - onValueChange={(value) => - setLocalFilters({ ...localFilters, stage: value === "__all__" ? undefined : value }) + <Input + id="stage" + placeholder="스테이지 입력" + value={localFilters.stage || ""} + onChange={(e) => + setLocalFilters({ ...localFilters, stage: e.target.value }) } - > - <SelectTrigger id="stage"> - <SelectValue placeholder="전체" /> - </SelectTrigger> - <SelectContent> - <SelectItem value="__all__">전체</SelectItem> - <SelectItem value="IFA">IFA</SelectItem> - <SelectItem value="IFC">IFC</SelectItem> - <SelectItem value="AFC">AFC</SelectItem> - <SelectItem value="BFC">BFC</SelectItem> - </SelectContent> - </Select> + /> </div> </div> @@ -459,8 +449,9 @@ export function SwpTableToolbar({ 검색 </Button> </div> + </div> </div> - </div> + </> ); } |
