erp-platform/ui/src/views/supplychain/components/SupplierCardModal.tsx
2025-09-17 12:46:58 +03:00

370 lines
14 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 { FaTimes, FaSave, FaCreditCard, FaStar } from 'react-icons/fa'
import { SupplierCardTypeEnum, SupplierTypeEnum } from '../../../types/mm'
import { mockBusinessPartyNew } from '../../../mocks/mockBusinessParties'
import { BusinessParty, PartyType, PaymentTerms } from '../../../types/common'
import { getPaymentTermsText, getSupplierCardTypeText } from '@/utils/erp'
interface SupplierCardModalProps {
isOpen: boolean
onClose: () => void
onSave: (supplierCard: BusinessParty) => void
supplierCard?: BusinessParty | null
mode: 'create' | 'view' | 'edit'
}
const SupplierCardModal: React.FC<SupplierCardModalProps> = ({
isOpen,
onClose,
onSave,
supplierCard,
mode,
}) => {
const [formData, setFormData] = useState<Partial<BusinessParty>>(mockBusinessPartyNew)
useEffect(() => {
if (mode === 'create') {
setFormData(mockBusinessPartyNew)
} else if (supplierCard) {
setFormData(supplierCard)
}
}, [supplierCard, mode])
const handleInputChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
) => {
const { name, value, type } = e.target
setFormData((prev) => ({
...prev,
[name]:
type === 'number'
? parseFloat(value) || 0
: type === 'checkbox'
? (e.target as HTMLInputElement).checked
: value,
}))
}
const handleSpecialConditionsChange = (value: string) => {
const conditions = value.split('\n').filter((condition) => condition.trim() !== '')
setFormData((prev) => ({
...prev,
specialConditions: conditions,
}))
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (mode !== 'view') {
const newSupplierCard: BusinessParty = {
id: supplierCard?.id || `SC-${Date.now()}`,
code: formData.code || '',
cardNumber:
formData.cardNumber ||
`SC-${new Date().getFullYear()}-${Date.now().toString().slice(-3)}`,
cardType: formData.cardType || SupplierCardTypeEnum.Standard,
validFrom: formData.validFrom || new Date(),
validTo: formData.validTo,
creditLimit: formData.creditLimit || 0,
currentBalance: formData.currentBalance || 0,
paymentTerms: formData.paymentTerms || PaymentTerms.Net30,
discountRate: formData.discountRate,
specialConditions: formData.specialConditions || [],
isActive: formData.isActive ?? true,
lastOrderDate: formData.lastOrderDate,
performanceMetrics: formData.performanceMetrics || {
deliveryPerformance: 0,
qualityRating: 0,
priceCompetitiveness: 0,
responsiveness: 0,
complianceRating: 0,
overallScore: 0,
lastEvaluationDate: new Date(),
},
creationTime: supplierCard?.creationTime || new Date(),
lastModificationTime: new Date(),
supplierType: SupplierTypeEnum.Distributor,
name: '',
currency: '',
certifications: [],
bankAccounts: [],
contacts: [],
partyType: PartyType.Supplier,
}
onSave(newSupplierCard)
}
onClose()
}
if (!isOpen) return null
const isReadOnly = mode === 'view'
const modalTitle =
mode === 'create'
? 'Yeni Tedarikçi Kartı'
: mode === 'edit'
? 'Tedarikçi Kartını Düzenle'
: 'Tedarikçi Kartı Detayları'
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg w-full max-w-3xl max-h-[90vh] overflow-y-auto">
<div className="flex items-center justify-between p-4 border-b">
<h3 className="text-base font-semibold text-gray-900 flex items-center">
<FaCreditCard className="mr-2 text-blue-600" />
{modalTitle}
</h3>
<button onClick={onClose} className="p-1 text-gray-400 hover:text-gray-600">
<FaTimes />
</button>
</div>
<form onSubmit={handleSubmit} className="p-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Temel Bilgiler */}
<div className="space-y-3">
<h4 className="text-sm font-medium text-gray-900 border-b pb-1.5">Temel Bilgiler</h4>
<div>
<label className="block text-sm font-medium text-gray-700">Tedarikçi</label>
<input
type="text"
name="customerCode"
value={formData.code || ''}
onChange={handleInputChange}
readOnly={isReadOnly}
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Kart Numarası</label>
<input
type="text"
name="cardNumber"
value={formData.cardNumber || ''}
onChange={handleInputChange}
readOnly={isReadOnly}
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Kart Tipi</label>
<select
name="cardType"
value={formData.cardType || SupplierCardTypeEnum.Standard}
onChange={handleInputChange}
disabled={isReadOnly}
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
>
{Object.values(SupplierCardTypeEnum).map((type) => (
<option key={type} value={type}>
{getSupplierCardTypeText(type)}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Geçerlilik Başlangıcı
</label>
<input
type="date"
name="validFrom"
value={
formData.validFrom
? new Date(formData.validFrom).toISOString().split('T')[0]
: ''
}
onChange={handleInputChange}
readOnly={isReadOnly}
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Geçerlilik Bitişi</label>
<input
type="date"
name="validTo"
value={
formData.validTo ? new Date(formData.validTo).toISOString().split('T')[0] : ''
}
onChange={handleInputChange}
readOnly={isReadOnly}
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
</div>
</div>
{/* Mali Bilgiler */}
<div className="space-y-3">
<h4 className="text-sm font-medium text-gray-900 border-b pb-1.5">Mali Bilgiler</h4>
<div>
<label className="block text-sm font-medium text-gray-700">Kredi Limiti (TL)</label>
<input
type="number"
name="creditLimit"
value={formData.creditLimit || 0}
onChange={handleInputChange}
readOnly={isReadOnly}
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Mevcut Bakiye (TL)
</label>
<input
type="number"
name="currentBalance"
value={formData.currentBalance || 0}
onChange={handleInputChange}
readOnly={isReadOnly}
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Ödeme Koşulları</label>
<select
name="paymentTerms"
value={formData.paymentTerms || PaymentTerms.Net30}
onChange={handleInputChange}
disabled={isReadOnly}
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
>
{Object.values(PaymentTerms).map((term) => (
<option key={term} value={term}>
{getPaymentTermsText(term)}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">İndirim Oranı (%)</label>
<input
type="number"
name="discountRate"
value={formData.discountRate || 0}
onChange={handleInputChange}
readOnly={isReadOnly}
min="0"
max="100"
step="0.1"
className="mt-1 block w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
</div>
<div>
<label className="flex items-center">
<input
type="checkbox"
name="isActive"
checked={formData.isActive || false}
onChange={handleInputChange}
disabled={isReadOnly}
className="mr-2"
/>
<span className="text-sm font-medium text-gray-700">Aktif</span>
</label>
</div>
</div>
</div>
{/* Özel Koşullar */}
<div className="mt-4">
<h4 className="text-sm font-medium text-gray-900 border-b pb-1.5 mb-2">
Özel Koşullar
</h4>
<textarea
name="specialConditions"
value={formData.specialConditions?.join('\n') || ''}
onChange={(e) => handleSpecialConditionsChange(e.target.value)}
readOnly={isReadOnly}
rows={3}
placeholder="Her satıra bir özel koşul yazın..."
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
</div>
{/* Performans Metrikleri - Sadece görüntüleme modu */}
{mode === 'view' && formData.performanceMetrics && (
<div className="mt-4">
<h4 className="text-sm font-medium text-gray-900 border-b pb-1.5 mb-3 flex items-center">
<FaStar className="mr-2 text-yellow-500" />
Performans Metrikleri
</h4>
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
<div className="text-center">
<div className="text-2xl font-bold text-blue-600">
{formData.performanceMetrics.deliveryPerformance}%
</div>
<div className="text-sm text-gray-600">Teslimat Performansı</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-green-600">
{formData.performanceMetrics.qualityRating}%
</div>
<div className="text-sm text-gray-600">Kalite Değerlendirmesi</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-purple-600">
{formData.performanceMetrics.priceCompetitiveness}%
</div>
<div className="text-sm text-gray-600">Fiyat Rekabeti</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-indigo-600">
{formData.performanceMetrics.responsiveness}%
</div>
<div className="text-sm text-gray-600">Yanıt Hızı</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-red-600">
{formData.performanceMetrics.complianceRating}%
</div>
<div className="text-sm text-gray-600">Uyum Derecesi</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-yellow-600">
{formData.performanceMetrics.overallScore}%
</div>
<div className="text-sm text-gray-600">Genel Puan</div>
</div>
</div>
</div>
)}
{/* Action Buttons */}
<div className="flex justify-end space-x-2 mt-4 pt-3 border-t">
<button
type="button"
onClick={onClose}
className="px-3 py-1.5 border border-gray-300 rounded-md text-sm text-gray-700 hover:bg-gray-50"
>
{mode === 'view' ? 'Kapat' : 'İptal'}
</button>
{mode !== 'view' && (
<button
type="submit"
className="px-3 py-1.5 bg-blue-600 text-white rounded-md text-sm hover:bg-blue-700 flex items-center"
>
<FaSave className="mr-2" />
Kaydet
</button>
)}
</div>
</form>
</div>
</div>
)
}
export default SupplierCardModal