311 lines
11 KiB
TypeScript
311 lines
11 KiB
TypeScript
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">
|
||
Açı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;
|