erp-platform/ui/src/views/mrp/components/MaterialRequirements.tsx

268 lines
7.9 KiB
TypeScript
Raw Normal View History

2025-09-15 09:31:47 +00:00
import React, { useState } from "react";
import {
FaCalendar,
FaBullseye, // Keep for icon consistency if needed elsewhere
} from "react-icons/fa";
import {
MrpMaterialRequirement,
RequirementSourceTypeEnum,
} from "../../../types/mrp";
import DataTable, { Column } from "../../../components/common/DataTable";
import {
getRequirementSourceTypeColor,
getRequirementSourceTypeText,
} from "../../../utils/erp";
interface MaterialRequirementsProps {
materialRequirements: MrpMaterialRequirement[];
}
const MaterialRequirements: React.FC<MaterialRequirementsProps> = ({
materialRequirements,
}) => {
const [searchTerm, setSearchTerm] = useState("");
const [selectedSource, setSelectedSource] = useState<
RequirementSourceTypeEnum | "all"
>("all");
const [sortBy, setSortBy] = useState<"date" | "quantity" | "priority">(
"date"
);
// Event handlers
const handleViewDetails = (requirement: MrpMaterialRequirement) => {
console.log("View requirement details:", requirement);
};
const filteredRequirements = materialRequirements
.filter((req) => {
if (
searchTerm &&
!req.material?.name?.toLowerCase().includes(searchTerm.toLowerCase()) &&
!req.material?.code?.toLowerCase().includes(searchTerm.toLowerCase())
) {
return false;
}
if (selectedSource !== "all" && req.sourceType !== selectedSource) {
return false;
}
return true;
})
.sort((a, b) => {
switch (sortBy) {
case "date":
return (
new Date(a.requirementDate).getTime() -
new Date(b.requirementDate).getTime()
);
case "quantity":
return b.netRequirement - a.netRequirement;
case "priority":
return b.grossRequirement - a.grossRequirement;
default:
return 0;
}
});
const getUrgencyLevel = (requirement: MrpMaterialRequirement) => {
const today = new Date();
const reqDate = new Date(requirement.requirementDate);
const daysUntilRequired = Math.ceil(
(reqDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)
);
if (daysUntilRequired < 0)
return {
level: "overdue",
color: "bg-red-100 text-red-800",
label: "Gecikmiş",
};
if (daysUntilRequired <= 7)
return {
level: "urgent",
color: "bg-orange-100 text-orange-800",
label: "Acil",
};
if (daysUntilRequired <= 30)
return {
level: "soon",
color: "bg-yellow-100 text-yellow-800",
label: "Yakın",
};
return {
level: "normal",
color: "bg-green-100 text-green-800",
label: "Normal",
};
};
const requirementColumns: Column<MrpMaterialRequirement>[] = [
{
key: "material",
header: "Malzeme",
sortable: true,
render: (req: MrpMaterialRequirement) => (
<div>
<div className="font-medium text-gray-900">
{req.material?.name || `Material-${req.materialId.substring(0, 8)}`}
</div>
<div className="text-sm text-gray-500">{req.material?.code}</div>
</div>
),
},
{
key: "sourceType",
header: "Kaynak",
render: (req: MrpMaterialRequirement) => (
<span
className={`px-2 py-1 text-xs font-medium rounded-full ${getRequirementSourceTypeColor(
req.sourceType
)}`}
>
{getRequirementSourceTypeText(req.sourceType)}
</span>
),
},
{
key: "urgency",
header: "Aciliyet",
render: (req: MrpMaterialRequirement) => {
const urgency = getUrgencyLevel(req);
return (
<span
className={`px-2 py-1 text-xs font-medium rounded-full ${urgency.color}`}
>
{urgency.label}
</span>
);
},
},
{
key: "requirements",
header: "İhtiyaçlar",
render: (req: MrpMaterialRequirement) => (
<div className="text-sm">
<div className="flex justify-between">
<span>Brüt:</span>
<span className="font-medium">
{req.grossRequirement.toLocaleString()}
</span>
</div>
<div className="flex justify-between">
<span>Mevcut:</span>
<span className="font-medium">
{req.projectedAvailable.toLocaleString()}
</span>
</div>
<div className="flex justify-between border-t pt-1">
<span>Net:</span>
<span
className={`font-medium ${
req.netRequirement > 0 ? "text-red-600" : "text-green-600"
}`}
>
{req.netRequirement.toLocaleString()}
</span>
</div>
</div>
),
},
{
key: "scheduled",
header: "Planlanan",
render: (req: MrpMaterialRequirement) => (
<div className="text-sm">
<div>Gelen: {req.scheduledReceipts.toLocaleString()}</div>
<div>Sipariş: {req.plannedOrderReceipt.toLocaleString()}</div>
</div>
),
},
{
key: "dates",
header: "Tarihler",
render: (req: MrpMaterialRequirement) => (
<div className="text-sm">
<div className="flex items-center gap-1">
<FaCalendar className="w-3 h-3 text-gray-400" />
<span>
İhtiyaç:{" "}
{new Date(req.requirementDate).toLocaleDateString("tr-TR")}
</span>
</div>
<div className="flex items-center gap-1">
<FaBullseye className="w-3 h-3 text-gray-400" />
<span>
Plan:{" "}
{new Date(req.plannedReceiptDate).toLocaleDateString("tr-TR")}
</span>
</div>
</div>
),
},
{
key: "actions",
header: "İşlemler",
render: (req: MrpMaterialRequirement) => (
<button
onClick={() => handleViewDetails(req)}
className="px-3 py-1 text-sm bg-blue-50 text-blue-600 rounded hover:bg-blue-100 transition-colors"
>
Detay
</button>
),
},
];
return (
<>
{/* Filters */}
<div className="flex gap-2 items-center">
<div className="flex-1">
<input
type="text"
placeholder="Malzeme adı veya kodu ara..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full px-2 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<select
value={selectedSource}
onChange={(e) =>
setSelectedSource(
e.target.value as RequirementSourceTypeEnum | "all"
)
}
className="px-2 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="all">Tüm Kaynaklar</option>
{Object.values(RequirementSourceTypeEnum).map((source) => (
<option key={source} value={source}>
{getRequirementSourceTypeText(source)}
</option>
))}
</select>
<select
value={sortBy}
onChange={(e) =>
setSortBy(e.target.value as "date" | "quantity" | "priority")
}
className="px-2 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="date">Tarihe Göre</option>
<option value="quantity">Miktara Göre</option>
<option value="priority">Önceliğe Göre</option>
</select>
</div>
{/* Data Table */}
<div className="bg-white rounded-lg shadow-sm border">
<DataTable data={filteredRequirements} columns={requirementColumns} />
</div>
</>
);
};
export default MaterialRequirements;