214 lines
6.2 KiB
TypeScript
214 lines
6.2 KiB
TypeScript
import React, { useState, useEffect } from "react";
|
||
import {
|
||
FaTimes,
|
||
FaPlay,
|
||
FaCheckCircle,
|
||
FaSpinner,
|
||
FaClipboardList,
|
||
FaCalculator,
|
||
FaBullseye,
|
||
} from "react-icons/fa";
|
||
|
||
interface RunMrpModalProps {
|
||
isOpen: boolean;
|
||
onClose: () => void;
|
||
onRunComplete: () => void;
|
||
}
|
||
|
||
type Step =
|
||
| "idle"
|
||
| "demand"
|
||
| "inventory"
|
||
| "suggestions"
|
||
| "completed"
|
||
| "error";
|
||
|
||
const RunMrpModal: React.FC<RunMrpModalProps> = ({
|
||
isOpen,
|
||
onClose,
|
||
onRunComplete,
|
||
}) => {
|
||
const [currentStep, setCurrentStep] = useState<Step>("idle");
|
||
const [progress, setProgress] = useState(0);
|
||
|
||
useEffect(() => {
|
||
if (currentStep !== "idle" && currentStep !== "completed") {
|
||
const interval = setInterval(() => {
|
||
setProgress((prev) => {
|
||
if (prev >= 100) {
|
||
clearInterval(interval);
|
||
return 100;
|
||
}
|
||
return prev + 10;
|
||
});
|
||
}, 150);
|
||
return () => clearInterval(interval);
|
||
}
|
||
}, [currentStep]);
|
||
|
||
useEffect(() => {
|
||
if (progress >= 100) {
|
||
if (currentStep === "demand") {
|
||
setCurrentStep("inventory");
|
||
setProgress(0);
|
||
} else if (currentStep === "inventory") {
|
||
setCurrentStep("suggestions");
|
||
setProgress(0);
|
||
} else if (currentStep === "suggestions") {
|
||
onRunComplete(); // Signal completion to parent
|
||
setCurrentStep("completed");
|
||
setProgress(100);
|
||
}
|
||
}
|
||
}, [progress, currentStep, onRunComplete]);
|
||
|
||
const handleStartMrp = () => {
|
||
setCurrentStep("demand");
|
||
setProgress(0);
|
||
};
|
||
|
||
const handleClose = () => {
|
||
setCurrentStep("idle");
|
||
setProgress(0);
|
||
onClose();
|
||
};
|
||
|
||
if (!isOpen) return null;
|
||
|
||
const getStepClass = (step: Step, targetStep: Step) => {
|
||
if (currentStep === step) return "text-blue-600 font-semibold";
|
||
if (
|
||
(targetStep === "demand" && currentStep !== "idle") ||
|
||
(targetStep === "inventory" &&
|
||
(currentStep === "suggestions" || currentStep === "completed")) ||
|
||
(targetStep === "suggestions" && currentStep === "completed")
|
||
) {
|
||
return "text-green-600";
|
||
}
|
||
return "text-gray-500";
|
||
};
|
||
|
||
const renderStep = (
|
||
step: Step,
|
||
targetStep: Step,
|
||
icon: React.ReactNode,
|
||
label: string
|
||
) => (
|
||
<div className="flex items-center gap-4">
|
||
<div
|
||
className={`p-3 rounded-full ${
|
||
currentStep === step
|
||
? "bg-blue-100"
|
||
: getStepClass(step, targetStep) === "text-green-600"
|
||
? "bg-green-100"
|
||
: "bg-gray-100"
|
||
}`}
|
||
>
|
||
{currentStep === step ? (
|
||
<FaSpinner
|
||
className={`w-6 h-6 animate-spin ${getStepClass(step, targetStep)}`}
|
||
/>
|
||
) : getStepClass(step, targetStep) === "text-green-600" ? (
|
||
<FaCheckCircle
|
||
className={`w-6 h-6 ${getStepClass(step, targetStep)}`}
|
||
/>
|
||
) : (
|
||
icon
|
||
)}
|
||
</div>
|
||
<div className="flex-1">
|
||
<h4 className={`text-lg ${getStepClass(step, targetStep)}`}>{label}</h4>
|
||
{currentStep === step && (
|
||
<div className="w-full bg-gray-200 rounded-full h-2.5 mt-2">
|
||
<div
|
||
className="bg-blue-600 h-2.5 rounded-full transition-all duration-150"
|
||
style={{ width: `${progress}%` }}
|
||
></div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
|
||
return (
|
||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||
<div className="bg-white rounded-lg shadow-xl max-w-lg w-full mx-4">
|
||
<div className="flex items-center justify-between p-6 border-b">
|
||
<h2 className="text-xl font-semibold text-gray-900">
|
||
MRP Çalıştırma Süreci
|
||
</h2>
|
||
<button
|
||
onClick={handleClose}
|
||
className="text-gray-400 hover:text-gray-600"
|
||
>
|
||
<FaTimes className="w-5 h-5" />
|
||
</button>
|
||
</div>
|
||
|
||
<div className="p-6 space-y-6">
|
||
{currentStep === "idle" && (
|
||
<div className="text-center">
|
||
<p className="text-gray-600 mb-6">
|
||
MRP sürecini başlatmak için butona tıklayın. Bu işlem mevcut
|
||
ihtiyaç ve önerileri güncelleyecektir.
|
||
</p>
|
||
<button
|
||
onClick={handleStartMrp}
|
||
className="flex items-center justify-center gap-2 w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors text-base font-semibold"
|
||
>
|
||
<FaPlay />
|
||
MRP Çalıştır
|
||
</button>
|
||
</div>
|
||
)}
|
||
|
||
{currentStep !== "idle" && (
|
||
<>
|
||
{renderStep(
|
||
"demand",
|
||
"demand",
|
||
<FaClipboardList className="w-6 h-6 text-gray-500" />,
|
||
"Talep Toplama"
|
||
)}
|
||
{renderStep(
|
||
"inventory",
|
||
"demand",
|
||
<FaCalculator className="w-6 h-6 text-gray-500" />,
|
||
"Stok Kontrolü ve Net İhtiyaç Hesaplama"
|
||
)}
|
||
{renderStep(
|
||
"suggestions",
|
||
"inventory",
|
||
<FaBullseye className="w-6 h-6 text-gray-500" />,
|
||
"Üretim ve Satınalma Önerileri Oluşturma"
|
||
)}
|
||
</>
|
||
)}
|
||
|
||
{currentStep === "completed" && (
|
||
<div className="text-center p-6 bg-green-50 border border-green-200 rounded-lg">
|
||
<FaCheckCircle className="w-12 h-12 text-green-600 mx-auto mb-4" />
|
||
<h3 className="text-xl font-bold text-green-800">
|
||
MRP Süreci Başarıyla Tamamlandı!
|
||
</h3>
|
||
<p className="text-green-700 mt-2">
|
||
İlgili sayfalara giderek sonuçları inceleyebilirsiniz.
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
<div className="flex justify-end p-6 border-t">
|
||
<button
|
||
onClick={handleClose}
|
||
className="px-3 py-1.5 bg-gray-600 text-white rounded-md hover:bg-gray-700 transition-colors text-sm"
|
||
>
|
||
Kapat
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default RunMrpModal;
|