erp-platform/ui/src/views/warehouse/components/LotForm.tsx

273 lines
8.8 KiB
TypeScript
Raw Normal View History

2025-09-15 09:31:47 +00:00
import React from "react";
import { useFormik } from "formik";
import * as Yup from "yup";
import { FaSave, FaTimes } from "react-icons/fa";
import {
QualityStatusEnum,
MmLotNumber,
MmUnit,
MmMaterial,
} from "../../../types/mm";
import { BusinessParty } from "../../../types/common";
const validationSchema = Yup.object({
materialId: Yup.string().required("Malzeme seçimi zorunlu"),
lotNumber: Yup.string().required("Lot numarası zorunlu"),
quantity: Yup.number().min(0, "Miktar 0'dan büyük olmalıdır"),
});
interface LotFormProps {
isOpen: boolean;
onClose: () => void;
onSave: (lot: MmLotNumber) => void;
onUpdate?: (lot: MmLotNumber) => void;
materials: MmMaterial[];
suppliers?: BusinessParty[];
units?: MmUnit[];
initial?: MmLotNumber | null;
mode?: "create" | "edit" | "view";
}
const LotForm: React.FC<LotFormProps> = ({
isOpen,
onClose,
onSave,
onUpdate,
materials,
suppliers = [],
units = [],
initial = null,
mode = "create",
}) => {
const formik = useFormik({
initialValues: {
materialId: "",
lotNumber: "",
productionDate: "",
expiryDate: "",
quantity: 0,
unitId: "KG",
supplierId: suppliers.length ? suppliers[0].id : "",
qualityStatus: QualityStatusEnum.Pending,
isActive: true,
},
validationSchema,
onSubmit: async (values) => {
const newLot: MmLotNumber = {
id: (initial && initial.id) || Date.now().toString(),
materialId: values.materialId,
lotNumber: values.lotNumber,
productionDate: values.productionDate
? new Date(values.productionDate)
: new Date(),
expiryDate: values.expiryDate ? new Date(values.expiryDate) : undefined,
quantity: Number(values.quantity),
unitId: values.unitId,
supplierId: values.supplierId || undefined,
qualityStatus: values.qualityStatus,
isActive: !!values.isActive,
};
// simulate API
await new Promise((r) => setTimeout(r, 300));
if (mode === "edit" && onUpdate) {
onUpdate(newLot);
} else {
onSave(newLot);
}
onClose();
},
});
// sync initial values when editing/viewing
React.useEffect(() => {
if (initial) {
const src = initial;
formik.setValues({
materialId: src.materialId || "",
lotNumber: src.lotNumber || "",
productionDate: src.productionDate
? new Date(src.productionDate).toISOString().slice(0, 10)
: "",
expiryDate: src.expiryDate
? new Date(src.expiryDate).toISOString().slice(0, 10)
: "",
quantity: src.quantity || 0,
unitId: src.unitId || (units.length ? units[0].id : ""),
supplierId: src.supplierId || (suppliers.length ? suppliers[0].id : ""),
qualityStatus: src.qualityStatus || QualityStatusEnum.Pending,
isActive: !!src.isActive,
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [initial]);
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center">
<div className="absolute inset-0 bg-black opacity-40" onClick={onClose} />
<div className="relative bg-white rounded-lg shadow-lg w-full max-w-2xl mx-4">
<form onSubmit={formik.handleSubmit} className="space-y-2 p-3">
<div className="flex items-center justify-between p-2 border-b">
<div>
<h2 className="text-xl font-bold text-gray-900">
{mode === "create"
? "Yeni Lot Kaydı"
: mode === "edit"
? "Lot Düzenle"
: "Lot Detayı"}
</h2>
<p className="text-sm text-gray-600">
{mode === "create"
? "Lot bilgilerini girin"
: mode === "edit"
? "Mevcut lot bilgilerini güncelleyin"
: "Lot bilgileri (sadece gösterim)"}
</p>
</div>
<div className="flex items-center space-x-2">
<button
type="button"
onClick={onClose}
className="px-2.5 py-1 text-sm border rounded-md bg-white hover:bg-gray-50"
>
<FaTimes className="inline mr-1 h-3 w-3" /> Kapat
</button>
{mode !== "view" && (
<button
type="submit"
className="px-2.5 py-1 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center"
>
<FaSave className="inline mr-1 h-3 w-3" /> Kaydet
</button>
)}
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 p-2 gap-x-3 gap-y-2">
<div>
<label className="block text-sm font-medium text-gray-700">
Malzeme *
</label>
<select
{...formik.getFieldProps("materialId")}
disabled={mode === "view"}
className="w-full border rounded-md px-2 py-1 text-sm"
>
<option value="">Seçiniz...</option>
{materials.map((m) => (
<option key={m.id} value={m.id}>
{m.code} - {m.name}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Lot Numarası *
</label>
<input
type="text"
{...formik.getFieldProps("lotNumber")}
disabled={mode === "view"}
className="w-full border rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Üretim Tarihi
</label>
<input
type="date"
{...formik.getFieldProps("productionDate")}
disabled={mode === "view"}
className="w-full border rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Son Kullanma Tarihi
</label>
<input
type="date"
{...formik.getFieldProps("expiryDate")}
disabled={mode === "view"}
className="w-full border rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Miktar
</label>
<input
type="number"
step="0.01"
{...formik.getFieldProps("quantity")}
disabled={mode === "view"}
className="w-full border rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Birim
</label>
<select
{...formik.getFieldProps("unitId")}
disabled={mode === "view"}
className="w-full border rounded-md px-2 py-1 text-sm"
>
{units.map((u) => (
<option key={u.id} value={u.id}>
{u.code}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Tedarikçi
</label>
<select
{...formik.getFieldProps("supplierId")}
disabled={mode === "view"}
className="w-full border rounded-md px-2 py-1 text-sm"
>
<option value="">Seçiniz...</option>
{suppliers.map((s) => (
<option key={s.id} value={s.id}>
{s.code} - {s.name}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Kalite Durumu
</label>
<select
{...formik.getFieldProps("qualityStatus")}
className="w-full border rounded-md px-2 py-1 text-sm"
>
<option value={QualityStatusEnum.Pending}>Beklemede</option>
<option value={QualityStatusEnum.Approved}>Onaylandı</option>
<option value={QualityStatusEnum.Rejected}>Reddedildi</option>
<option value={QualityStatusEnum.Quarantine}>Karantina</option>
</select>
</div>
</div>
</form>
</div>
</div>
);
};
export default LotForm;