erp-platform/ui/src/views/hr/components/CostCenterFormModal.tsx

312 lines
11 KiB
TypeScript
Raw Normal View History

2025-09-15 09:31:47 +00:00
import React, { useState, useEffect } from "react";
import { FaSave, FaTimes } from "react-icons/fa";
import { HrCostCenter, CostCenterType } from "../../../types/hr";
import { mockEmployees } from "../../../mocks/mockEmployees";
import { mockCostCenters } from "../../../mocks/mockCostCenters";
import { getCostCenterTypeText } from "../../../utils/erp";
interface CostCenterFormModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (costCenter: Partial<HrCostCenter>) => void;
costCenter?: HrCostCenter;
title: string;
}
const CostCenterFormModal: React.FC<CostCenterFormModalProps> = ({
isOpen,
onClose,
onSave,
costCenter,
title,
}) => {
const [formData, setFormData] = useState({
costCenterCode: "",
name: "",
description: "",
costCenterType: CostCenterType.Standard,
responsibleEmployeeId: "",
parentCostCenterId: "",
budgetedAmount: 0,
actualAmount: 0,
currency: "TRY",
fiscalYear: "2025",
isActive: true,
});
useEffect(() => {
if (costCenter) {
setFormData({
costCenterCode: costCenter.code,
name: costCenter.name,
description: costCenter.description || "",
costCenterType: costCenter.costCenterType,
responsibleEmployeeId: costCenter.responsibleEmployeeId || "",
parentCostCenterId: costCenter.parentCostCenterId || "",
budgetedAmount: costCenter.budgetedAmount,
actualAmount: costCenter.actualAmount,
currency: costCenter.currency,
fiscalYear: costCenter.fiscalYear,
isActive: costCenter.isActive,
});
} else {
setFormData({
costCenterCode: "",
name: "",
description: "",
costCenterType: CostCenterType.Standard,
responsibleEmployeeId: "",
parentCostCenterId: "",
budgetedAmount: 0,
actualAmount: 0,
currency: "TRY",
fiscalYear: "2025",
isActive: true,
});
}
}, [costCenter]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
onSave(formData);
};
return (
isOpen && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-3 w-full max-w-lg max-h-[90vh] overflow-y-auto">
<div className="flex items-center justify-between mb-3">
<h2 className="text-base font-bold text-gray-900">{title}</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-5 h-5" />
</button>
</div>
<form onSubmit={handleSubmit} className="space-y-3">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Maliyet Merkezi Kodu *
</label>
<input
type="text"
value={formData.costCenterCode}
onChange={(e) =>
setFormData({ ...formData, costCenterCode: e.target.value })
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Maliyet Merkezi Adı *
</label>
<input
type="text"
value={formData.name}
onChange={(e) =>
setFormData({ ...formData, name: e.target.value })
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
</div>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
ıklama
</label>
<textarea
value={formData.description}
onChange={(e) =>
setFormData({ ...formData, description: e.target.value })
}
rows={2}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Maliyet Merkezi Tipi
</label>
<select
value={formData.costCenterType}
onChange={(e) =>
setFormData({
...formData,
costCenterType: e.target.value as CostCenterType,
})
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
{Object.values(CostCenterType).map((type) => (
<option key={type} value={type}>
{getCostCenterTypeText(type)}
</option>
))}
</select>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Sorumlu Personel
</label>
<select
value={formData.responsibleEmployeeId}
onChange={(e) =>
setFormData({
...formData,
responsibleEmployeeId: e.target.value,
})
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Seçiniz</option>
{mockEmployees.map((employee) => (
<option key={employee.id} value={employee.id}>
{employee.fullName}
</option>
))}
</select>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Üst Maliyet Merkezi
</label>
<select
value={formData.parentCostCenterId}
onChange={(e) =>
setFormData({
...formData,
parentCostCenterId: e.target.value,
})
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Ana Maliyet Merkezi</option>
{mockCostCenters
.filter((cc) => cc.id !== costCenter?.id)
.map((costCenter) => (
<option key={costCenter.id} value={costCenter.id}>
{costCenter.name}
</option>
))}
</select>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Mali Yıl
</label>
<input
type="text"
value={formData.fiscalYear}
onChange={(e) =>
setFormData({ ...formData, fiscalYear: e.target.value })
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Bütçe Tutarı
</label>
<input
type="number"
value={formData.budgetedAmount}
onChange={(e) =>
setFormData({
...formData,
budgetedAmount: parseFloat(e.target.value) || 0,
})
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Gerçekleşen Tutar
</label>
<input
type="number"
value={formData.actualAmount}
onChange={(e) =>
setFormData({
...formData,
actualAmount: parseFloat(e.target.value) || 0,
})
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Para Birimi
</label>
<select
value={formData.currency}
onChange={(e) =>
setFormData({ ...formData, currency: e.target.value })
}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="TRY">TRY</option>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
</select>
</div>
</div>
<div className="flex items-center">
<input
type="checkbox"
checked={formData.isActive}
onChange={(e) =>
setFormData({ ...formData, isActive: e.target.checked })
}
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
/>
<label className="ml-2 block text-sm text-gray-900">Aktif</label>
</div>
<div className="flex justify-end gap-2 pt-3">
<button
type="button"
onClick={onClose}
className="px-3 py-1 border border-gray-300 rounded-md text-sm text-gray-700 hover:bg-gray-50"
>
İptal
</button>
<button
type="submit"
className="flex items-center gap-2 px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700"
>
<FaSave className="w-4 h-4" />
Kaydet
</button>
</div>
</form>
</div>
</div>
)
);
};
export default CostCenterFormModal;