erp-platform/ui/src/views/accounting/components/CheckForm.tsx
2025-09-17 12:02:03 +03:00

390 lines
15 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 { FaCreditCard, FaSave, FaTimes } from 'react-icons/fa'
import { FiCheck, TypeEnum, CheckStatusEnum, FiCurrentAccount } from '../../../types/fi'
import { getCheckStatusText, getTypeText } from '@/utils/erp'
import { mockCurrencies } from '@/mocks/mockCurrencies'
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: TypeEnum.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: TypeEnum.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 | TypeEnum | 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 TypeEnum)}
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"
>
{Object.values(TypeEnum).map((type) => (
<option key={type} value={type}>
{getTypeText(type)}
</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"
>
{Object.values(CheckStatusEnum).map((status) => (
<option key={status} value={status}>
{getCheckStatusText(status)}
</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"
>
{mockCurrencies.map((currency) => (
<option key={currency.value} value={currency.value}>
{currency.value} - {currency.label}
</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