erp-platform/ui/src/views/accounting/components/CheckForm.tsx

457 lines
16 KiB
TypeScript
Raw Normal View History

2025-09-15 09:31:47 +00:00
import React, { useState, useEffect } from "react";
import { FaCreditCard, FaSave, FaTimes } from "react-icons/fa";
import {
FiCheck,
CheckTypeEnum,
CheckStatusEnum,
FiCurrentAccount,
} from "../../../types/fi";
interface CheckFormProps {
check?: FiCheck;
currentAccounts: FiCurrentAccount[];
onSave: (
check: Omit<FiCheck, "id" | "creationTime" | "lastModificationTime">
) => void;
onCancel: () => void;
isOpen: boolean;
}
const CheckForm: React.FC<CheckFormProps> = ({
check,
currentAccounts,
onSave,
onCancel,
isOpen,
}) => {
const [formData, setFormData] = useState({
checkNumber: "",
bankName: "",
branchName: "",
accountNumber: "",
drawerName: "",
payeeName: "",
currentAccountId: "",
issueDate: new Date().toISOString().split("T")[0],
dueDate: new Date().toISOString().split("T")[0],
amount: 0,
currency: "TRY",
status: CheckStatusEnum.InHand,
type: CheckTypeEnum.Received,
notes: "",
});
const [errors, setErrors] = useState<Record<string, string>>({});
useEffect(() => {
if (check) {
setFormData({
checkNumber: check.checkNumber,
bankName: check.bankName,
branchName: check.branchName,
accountNumber: check.accountNumber,
drawerName: check.drawerName,
payeeName: check.payeeName,
currentAccountId: check.currentAccountId || "",
issueDate: new Date(check.issueDate).toISOString().split("T")[0],
dueDate: new Date(check.dueDate).toISOString().split("T")[0],
amount: check.amount,
currency: check.currency,
status: check.status,
type: check.type,
notes: check.notes || "",
});
} else {
setFormData({
checkNumber: "",
bankName: "",
branchName: "",
accountNumber: "",
drawerName: "",
payeeName: "",
currentAccountId: "",
issueDate: new Date().toISOString().split("T")[0],
dueDate: new Date().toISOString().split("T")[0],
amount: 0,
currency: "TRY",
status: CheckStatusEnum.InHand,
type: CheckTypeEnum.Received,
notes: "",
});
}
setErrors({});
}, [check, isOpen]);
const validateForm = () => {
const newErrors: Record<string, string> = {};
if (!formData.checkNumber.trim()) {
newErrors.checkNumber = "Çek numarası gereklidir";
}
if (!formData.bankName.trim()) {
newErrors.bankName = "Banka adı gereklidir";
}
if (!formData.drawerName.trim()) {
newErrors.drawerName = "Keşideci adı gereklidir";
}
if (!formData.payeeName.trim()) {
newErrors.payeeName = "Lehtar adı gereklidir";
}
if (formData.amount <= 0) {
newErrors.amount = "Tutar 0'dan büyük olmalıdır";
}
if (new Date(formData.dueDate) < new Date(formData.issueDate)) {
newErrors.dueDate = "Vade tarihi düzenleme tarihinden sonra olmalıdır";
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (validateForm()) {
const checkData = {
...formData,
issueDate: new Date(formData.issueDate),
dueDate: new Date(formData.dueDate),
currentAccount: formData.currentAccountId
? currentAccounts.find((acc) => acc.id === formData.currentAccountId)
: undefined,
};
onSave(checkData);
}
};
const handleInputChange = (
field: string,
value: string | number | CheckTypeEnum | CheckStatusEnum
) => {
setFormData((prev) => ({ ...prev, [field]: value }));
if (errors[field]) {
setErrors((prev) => ({ ...prev, [field]: "" }));
}
};
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg shadow-xl w-full max-w-3xl max-h-[90vh] overflow-y-auto">
<div className="flex items-center justify-between p-4 border-b">
<div className="flex items-center gap-2.5">
<FaCreditCard className="w-5 h-5 text-blue-600" />
<h2 className="text-lg font-semibold text-gray-900">
{check ? "Çek Düzenle" : "Yeni Çek"}
</h2>
</div>
<button
onClick={onCancel}
className="p-2 hover:bg-gray-100 rounded-md"
>
<FaTimes className="w-5 h-5 text-gray-500" />
</button>
</div>
<form onSubmit={handleSubmit} className="p-4 space-y-4">
{/* Çek Bilgileri */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Çek Numarası *
</label>
<input
type="text"
value={formData.checkNumber}
onChange={(e) =>
handleInputChange("checkNumber", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.checkNumber ? "border-red-500" : "border-gray-300"
}`}
placeholder="Çek numarasını giriniz"
/>
{errors.checkNumber && (
<p className="text-red-500 text-xs mt-1">
{errors.checkNumber}
</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Tür *
</label>
<select
value={formData.type}
onChange={(e) =>
handleInputChange("type", e.target.value as CheckTypeEnum)
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value={CheckTypeEnum.Received}>Alınan Çek</option>
<option value={CheckTypeEnum.Issued}>Verilen Çek</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Durum
</label>
<select
value={formData.status}
onChange={(e) =>
handleInputChange("status", e.target.value as CheckStatusEnum)
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value={CheckStatusEnum.InHand}>Elde</option>
<option value={CheckStatusEnum.Deposited}>
Bankaya Verildi
</option>
<option value={CheckStatusEnum.Collected}>Tahsil Edildi</option>
<option value={CheckStatusEnum.Bounced}>Karşılıksız</option>
<option value={CheckStatusEnum.Endorsed}>Ciro Edildi</option>
<option value={CheckStatusEnum.Cancelled}>İptal</option>
</select>
</div>
</div>
{/* Banka Bilgileri */}
<div className="bg-gray-50 p-3 rounded-lg">
<h3 className="text-base font-medium text-gray-900 mb-3">
Banka Bilgileri
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Banka Adı *
</label>
<input
type="text"
value={formData.bankName}
onChange={(e) =>
handleInputChange("bankName", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.bankName ? "border-red-500" : "border-gray-300"
}`}
placeholder="Banka adını giriniz"
/>
{errors.bankName && (
<p className="text-red-500 text-xs mt-1">{errors.bankName}</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Şube Adı
</label>
<input
type="text"
value={formData.branchName}
onChange={(e) =>
handleInputChange("branchName", e.target.value)
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Şube adını giriniz"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Hesap Numarası
</label>
<input
type="text"
value={formData.accountNumber}
onChange={(e) =>
handleInputChange("accountNumber", e.target.value)
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Hesap numarasını giriniz"
/>
</div>
</div>
</div>
{/* Taraf Bilgileri */}
<div className="bg-gray-50 p-3 rounded-lg">
<h3 className="text-base font-medium text-gray-900 mb-3">
Taraf Bilgileri
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Keşideci *
</label>
<input
type="text"
value={formData.drawerName}
onChange={(e) =>
handleInputChange("drawerName", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.drawerName ? "border-red-500" : "border-gray-300"
}`}
placeholder="Keşideci adını giriniz"
/>
{errors.drawerName && (
<p className="text-red-500 text-xs mt-1">
{errors.drawerName}
</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Lehtar *
</label>
<input
type="text"
value={formData.payeeName}
onChange={(e) =>
handleInputChange("payeeName", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.payeeName ? "border-red-500" : "border-gray-300"
}`}
placeholder="Lehtar adını giriniz"
/>
{errors.payeeName && (
<p className="text-red-500 text-xs mt-1">
{errors.payeeName}
</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Cari Hesap
</label>
<select
value={formData.currentAccountId}
onChange={(e) =>
handleInputChange("currentAccountId", e.target.value)
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Cari hesap seçiniz</option>
{currentAccounts.map((account) => (
<option key={account.id} value={account.id}>
{account.accountCode} - {account.businessParty?.name}
</option>
))}
</select>
</div>
</div>
</div>
{/* Tutar ve Tarih Bilgileri */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Tutar *
</label>
<input
type="number"
step="0.01"
min="0"
value={formData.amount}
onChange={(e) =>
handleInputChange("amount", parseFloat(e.target.value) || 0)
}
className={`w-full px-3 py-1.5 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.amount ? "border-red-500" : "border-gray-300"
}`}
placeholder="0.00"
/>
{errors.amount && (
<p className="text-red-500 text-xs mt-1">{errors.amount}</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Para Birimi
</label>
<select
value={formData.currency}
onChange={(e) => handleInputChange("currency", e.target.value)}
className="w-full px-3 py-1.5 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>
<label className="block text-sm font-medium text-gray-700 mb-1">
Düzenleme Tarihi *
</label>
<input
type="date"
value={formData.issueDate}
onChange={(e) => handleInputChange("issueDate", e.target.value)}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Vade Tarihi *
</label>
<input
type="date"
value={formData.dueDate}
onChange={(e) => handleInputChange("dueDate", e.target.value)}
className={`w-full px-3 py-1.5 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.dueDate ? "border-red-500" : "border-gray-300"
}`}
/>
{errors.dueDate && (
<p className="text-red-500 text-xs mt-1">{errors.dueDate}</p>
)}
</div>
</div>
{/* Notlar */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Notlar
</label>
<textarea
value={formData.notes}
onChange={(e) => handleInputChange("notes", e.target.value)}
rows={3}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Ek notlar..."
/>
</div>
{/* Butonlar */}
<div className="flex justify-end gap-3 pt-4 border-t">
<button
type="button"
onClick={onCancel}
className="px-4 py-1.5 text-sm border border-gray-300 text-gray-700 rounded-md hover:bg-gray-50 transition-colors"
>
İptal
</button>
<button
type="submit"
className="flex items-center gap-2 px-4 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
>
<FaSave className="w-4 h-4" />
{check ? "Güncelle" : "Kaydet"}
</button>
</div>
</form>
</div>
</div>
);
};
export default CheckForm;