erp-platform/ui/src/views/supplyChain/components/SupplierCardModal.tsx

412 lines
16 KiB
TypeScript
Raw Normal View History

2025-09-15 09:31:47 +00:00
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";
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.Material,
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"
>
<option value={SupplierCardTypeEnum.Standard}>
Standart
</option>
<option value={SupplierCardTypeEnum.Premium}>Premium</option>
<option value={SupplierCardTypeEnum.Strategic}>
Stratejik
</option>
<option value={SupplierCardTypeEnum.Preferred}>
Tercihli
</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"
>
<option value={PaymentTerms.Net15}>15 Gün Vadeli</option>
<option value={PaymentTerms.Net30}>30 Gün Vadeli</option>
<option value={PaymentTerms.Net45}>45 Gün Vadeli</option>
<option value={PaymentTerms.Net60}>60 Gün Vadeli</option>
<option value={PaymentTerms.Net90}>90 Gün Vadeli</option>
<option value={PaymentTerms.COD}>Kapıda Ödeme</option>
<option value={PaymentTerms.Prepaid}>Peşin</option>
<option value={PaymentTerms.Cash}>Nakit</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;