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

248 lines
8.5 KiB
TypeScript
Raw Normal View History

2025-09-15 21:11:40 +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'
2025-09-15 09:31:47 +00:00
const validationSchema = Yup.object({
2025-09-15 21:11:40 +00:00
materialId: Yup.string().required('Malzeme seçimi zorunlu'),
lotNumber: Yup.string().required('Lot numarası zorunlu'),
2025-09-15 09:31:47 +00:00
quantity: Yup.number().min(0, "Miktar 0'dan büyük olmalıdır"),
2025-09-15 21:11:40 +00:00
})
2025-09-15 09:31:47 +00:00
interface LotFormProps {
2025-09-15 21:11:40 +00:00
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'
2025-09-15 09:31:47 +00:00
}
const LotForm: React.FC<LotFormProps> = ({
isOpen,
onClose,
onSave,
onUpdate,
materials,
suppliers = [],
units = [],
initial = null,
2025-09-15 21:11:40 +00:00
mode = 'create',
2025-09-15 09:31:47 +00:00
}) => {
const formik = useFormik({
initialValues: {
2025-09-15 21:11:40 +00:00
materialId: '',
lotNumber: '',
productionDate: '',
expiryDate: '',
2025-09-15 09:31:47 +00:00
quantity: 0,
2025-09-15 21:11:40 +00:00
unitId: 'KG',
supplierId: suppliers.length ? suppliers[0].id : '',
2025-09-15 09:31:47 +00:00
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,
2025-09-15 21:11:40 +00:00
productionDate: values.productionDate ? new Date(values.productionDate) : new Date(),
2025-09-15 09:31:47 +00:00
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,
2025-09-15 21:11:40 +00:00
}
2025-09-15 09:31:47 +00:00
// simulate API
2025-09-15 21:11:40 +00:00
await new Promise((r) => setTimeout(r, 300))
if (mode === 'edit' && onUpdate) {
onUpdate(newLot)
2025-09-15 09:31:47 +00:00
} else {
2025-09-15 21:11:40 +00:00
onSave(newLot)
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:11:40 +00:00
onClose()
2025-09-15 09:31:47 +00:00
},
2025-09-15 21:11:40 +00:00
})
2025-09-15 09:31:47 +00:00
// sync initial values when editing/viewing
React.useEffect(() => {
if (initial) {
2025-09-15 21:11:40 +00:00
const src = initial
2025-09-15 09:31:47 +00:00
formik.setValues({
2025-09-15 21:11:40 +00:00
materialId: src.materialId || '',
lotNumber: src.lotNumber || '',
2025-09-15 09:31:47 +00:00
productionDate: src.productionDate
? new Date(src.productionDate).toISOString().slice(0, 10)
2025-09-15 21:11:40 +00:00
: '',
expiryDate: src.expiryDate ? new Date(src.expiryDate).toISOString().slice(0, 10) : '',
2025-09-15 09:31:47 +00:00
quantity: src.quantity || 0,
2025-09-15 21:11:40 +00:00
unitId: src.unitId || (units.length ? units[0].id : ''),
supplierId: src.supplierId || (suppliers.length ? suppliers[0].id : ''),
2025-09-15 09:31:47 +00:00
qualityStatus: src.qualityStatus || QualityStatusEnum.Pending,
isActive: !!src.isActive,
2025-09-15 21:11:40 +00:00
})
2025-09-15 09:31:47 +00:00
}
// eslint-disable-next-line react-hooks/exhaustive-deps
2025-09-15 21:11:40 +00:00
}, [initial])
2025-09-15 09:31:47 +00:00
2025-09-15 21:11:40 +00:00
if (!isOpen) return null
2025-09-15 09:31:47 +00:00
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>
2025-09-15 21:02:48 +00:00
<h2 className="text-2xl font-bold text-gray-900">
2025-09-15 21:11:40 +00:00
{mode === 'create'
? 'Yeni Lot Kaydı'
: mode === 'edit'
? 'Lot Düzenle'
: 'Lot Detayı'}
2025-09-15 09:31:47 +00:00
</h2>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">
2025-09-15 21:11:40 +00:00
{mode === 'create'
? 'Lot bilgilerini girin'
: mode === 'edit'
? 'Mevcut lot bilgilerini güncelleyin'
: 'Lot bilgileri (sadece gösterim)'}
2025-09-15 09:31:47 +00:00
</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>
2025-09-15 21:11:40 +00:00
{mode !== 'view' && (
2025-09-15 09:31:47 +00:00
<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>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700">Malzeme *</label>
2025-09-15 09:31:47 +00:00
<select
2025-09-15 21:11:40 +00:00
{...formik.getFieldProps('materialId')}
disabled={mode === 'view'}
2025-09-15 09:31:47 +00:00
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>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700">Lot Numarası *</label>
2025-09-15 09:31:47 +00:00
<input
type="text"
2025-09-15 21:11:40 +00:00
{...formik.getFieldProps('lotNumber')}
disabled={mode === 'view'}
2025-09-15 09:31:47 +00:00
className="w-full border rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700">Üretim Tarihi</label>
2025-09-15 09:31:47 +00:00
<input
type="date"
2025-09-15 21:11:40 +00:00
{...formik.getFieldProps('productionDate')}
disabled={mode === 'view'}
2025-09-15 09:31:47 +00:00
className="w-full border rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700">Son Kullanma Tarihi</label>
2025-09-15 09:31:47 +00:00
<input
type="date"
2025-09-15 21:11:40 +00:00
{...formik.getFieldProps('expiryDate')}
disabled={mode === 'view'}
2025-09-15 09:31:47 +00:00
className="w-full border rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700">Miktar</label>
2025-09-15 09:31:47 +00:00
<input
type="number"
step="0.01"
2025-09-15 21:11:40 +00:00
{...formik.getFieldProps('quantity')}
disabled={mode === 'view'}
2025-09-15 09:31:47 +00:00
className="w-full border rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700">Birim</label>
2025-09-15 09:31:47 +00:00
<select
2025-09-15 21:11:40 +00:00
{...formik.getFieldProps('unitId')}
disabled={mode === 'view'}
2025-09-15 09:31:47 +00:00
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>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700">Tedarikçi</label>
2025-09-15 09:31:47 +00:00
<select
2025-09-15 21:11:40 +00:00
{...formik.getFieldProps('supplierId')}
disabled={mode === 'view'}
2025-09-15 09:31:47 +00:00
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>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700">Kalite Durumu</label>
2025-09-15 09:31:47 +00:00
<select
2025-09-15 21:11:40 +00:00
{...formik.getFieldProps('qualityStatus')}
2025-09-15 09:31:47 +00:00
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>
2025-09-15 21:11:40 +00:00
)
}
2025-09-15 09:31:47 +00:00
2025-09-15 21:11:40 +00:00
export default LotForm