erp-platform/ui/src/views/hr/components/CostCenterFormModal.tsx
2025-09-15 12:31:47 +03:00

311 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;