209 lines
7.8 KiB
TypeScript
209 lines
7.8 KiB
TypeScript
/**
|
|
* 스케줄 생성 확인 다이얼로그
|
|
*
|
|
* 스케줄 자동 생성 시 미리보기 결과를 표시하고 확인을 받는 다이얼로그입니다.
|
|
*/
|
|
|
|
"use client";
|
|
|
|
import React from "react";
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
} from "@/components/ui/alert-dialog";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
import { Calendar, Plus, Trash2, RefreshCw } from "lucide-react";
|
|
import type { SchedulePreviewResult } from "./ScheduleGeneratorService";
|
|
|
|
interface ScheduleConfirmDialogProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
preview: SchedulePreviewResult | null;
|
|
onConfirm: () => void;
|
|
onCancel: () => void;
|
|
isLoading?: boolean;
|
|
}
|
|
|
|
export function ScheduleConfirmDialog({
|
|
open,
|
|
onOpenChange,
|
|
preview,
|
|
onConfirm,
|
|
onCancel,
|
|
isLoading = false,
|
|
}: ScheduleConfirmDialogProps) {
|
|
if (!preview) return null;
|
|
|
|
const { summary, toCreate, toDelete, toUpdate } = preview;
|
|
|
|
return (
|
|
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
|
<AlertDialogContent className="max-w-[95vw] sm:max-w-[600px]">
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle className="flex items-center gap-2 text-base sm:text-lg">
|
|
<Calendar className="h-5 w-5" />
|
|
스케줄 생성 확인
|
|
</AlertDialogTitle>
|
|
<AlertDialogDescription className="text-xs sm:text-sm">
|
|
다음과 같이 스케줄이 변경됩니다. 계속하시겠습니까?
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
|
|
{/* 요약 정보 */}
|
|
<div className="grid grid-cols-3 gap-3 py-4">
|
|
<div className="flex flex-col items-center rounded-lg border bg-green-50 p-3 dark:bg-green-900/20">
|
|
<Plus className="mb-1 h-5 w-5 text-green-600" />
|
|
<span className="text-2xl font-bold text-green-600">
|
|
{summary.createCount}
|
|
</span>
|
|
<span className="text-xs text-muted-foreground">생성</span>
|
|
</div>
|
|
<div className="flex flex-col items-center rounded-lg border bg-red-50 p-3 dark:bg-red-900/20">
|
|
<Trash2 className="mb-1 h-5 w-5 text-red-600" />
|
|
<span className="text-2xl font-bold text-red-600">
|
|
{summary.deleteCount}
|
|
</span>
|
|
<span className="text-xs text-muted-foreground">삭제</span>
|
|
</div>
|
|
<div className="flex flex-col items-center rounded-lg border bg-blue-50 p-3 dark:bg-blue-900/20">
|
|
<RefreshCw className="mb-1 h-5 w-5 text-blue-600" />
|
|
<span className="text-2xl font-bold text-blue-600">
|
|
{summary.updateCount}
|
|
</span>
|
|
<span className="text-xs text-muted-foreground">수정</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 상세 정보 */}
|
|
<ScrollArea className="max-h-[300px]">
|
|
<div className="space-y-4">
|
|
{/* 생성될 스케줄 */}
|
|
{toCreate.length > 0 && (
|
|
<div>
|
|
<h4 className="mb-2 flex items-center gap-2 text-sm font-medium">
|
|
<Badge variant="default" className="bg-green-600">
|
|
생성
|
|
</Badge>
|
|
{toCreate.length}건
|
|
</h4>
|
|
<div className="space-y-1 rounded-md border p-2">
|
|
{toCreate.slice(0, 5).map((item, index) => (
|
|
<div
|
|
key={index}
|
|
className="flex items-center justify-between text-xs"
|
|
>
|
|
<span className="font-medium">
|
|
{item.resource_name || item.resource_id}
|
|
</span>
|
|
<span className="text-muted-foreground">
|
|
{item.start_date} ~ {item.end_date} / {item.plan_qty}개
|
|
</span>
|
|
</div>
|
|
))}
|
|
{toCreate.length > 5 && (
|
|
<div className="text-center text-xs text-muted-foreground">
|
|
... 외 {toCreate.length - 5}건
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 삭제될 스케줄 */}
|
|
{toDelete.length > 0 && (
|
|
<div>
|
|
<h4 className="mb-2 flex items-center gap-2 text-sm font-medium">
|
|
<Badge variant="destructive">삭제</Badge>
|
|
{toDelete.length}건
|
|
</h4>
|
|
<div className="space-y-1 rounded-md border border-red-200 bg-red-50/50 p-2 dark:border-red-800 dark:bg-red-900/10">
|
|
{toDelete.slice(0, 5).map((item, index) => (
|
|
<div
|
|
key={index}
|
|
className="flex items-center justify-between text-xs"
|
|
>
|
|
<span className="font-medium">
|
|
{item.resource_name || item.resource_id}
|
|
</span>
|
|
<span className="text-muted-foreground">
|
|
{item.start_date} ~ {item.end_date}
|
|
</span>
|
|
</div>
|
|
))}
|
|
{toDelete.length > 5 && (
|
|
<div className="text-center text-xs text-muted-foreground">
|
|
... 외 {toDelete.length - 5}건
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 수정될 스케줄 */}
|
|
{toUpdate.length > 0 && (
|
|
<div>
|
|
<h4 className="mb-2 flex items-center gap-2 text-sm font-medium">
|
|
<Badge variant="secondary">수정</Badge>
|
|
{toUpdate.length}건
|
|
</h4>
|
|
<div className="space-y-1 rounded-md border border-blue-200 bg-blue-50/50 p-2 dark:border-blue-800 dark:bg-blue-900/10">
|
|
{toUpdate.slice(0, 5).map((item, index) => (
|
|
<div
|
|
key={index}
|
|
className="flex items-center justify-between text-xs"
|
|
>
|
|
<span className="font-medium">
|
|
{item.resource_name || item.resource_id}
|
|
</span>
|
|
<span className="text-muted-foreground">
|
|
{item.start_date} ~ {item.end_date}
|
|
</span>
|
|
</div>
|
|
))}
|
|
{toUpdate.length > 5 && (
|
|
<div className="text-center text-xs text-muted-foreground">
|
|
... 외 {toUpdate.length - 5}건
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</ScrollArea>
|
|
|
|
{/* 총 수량 */}
|
|
<div className="flex items-center justify-between rounded-md bg-muted p-3">
|
|
<span className="text-sm font-medium">총 계획 수량</span>
|
|
<span className="text-lg font-bold">
|
|
{summary.totalQty.toLocaleString()}개
|
|
</span>
|
|
</div>
|
|
|
|
<AlertDialogFooter className="gap-2 sm:gap-0">
|
|
<AlertDialogCancel
|
|
onClick={onCancel}
|
|
disabled={isLoading}
|
|
className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
|
|
>
|
|
취소
|
|
</AlertDialogCancel>
|
|
<AlertDialogAction
|
|
onClick={onConfirm}
|
|
disabled={isLoading}
|
|
className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
|
|
>
|
|
{isLoading ? "처리 중..." : "확인 및 적용"}
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
);
|
|
}
|