304 lines
13 KiB
TypeScript
304 lines
13 KiB
TypeScript
import { Link } from "@remix-run/react";
|
||
import { useSettings } from "~/contexts/SettingsContext";
|
||
import type { MaintenanceVisitWithRelations } from "~/types/database";
|
||
|
||
interface MaintenanceVisitDetailsViewProps {
|
||
visit: MaintenanceVisitWithRelations;
|
||
}
|
||
|
||
export function MaintenanceVisitDetailsView({ visit }: MaintenanceVisitDetailsViewProps) {
|
||
const { formatCurrency, formatDate, formatNumber } = useSettings();
|
||
const getPaymentStatusColor = (status: string) => {
|
||
switch (status) {
|
||
case 'paid':
|
||
return 'bg-green-100 text-green-800 border-green-200';
|
||
case 'pending':
|
||
return 'bg-yellow-100 text-yellow-800 border-yellow-200';
|
||
case 'partial':
|
||
return 'bg-blue-100 text-blue-800 border-blue-200';
|
||
case 'cancelled':
|
||
return 'bg-red-100 text-red-800 border-red-200';
|
||
default:
|
||
return 'bg-gray-100 text-gray-800 border-gray-200';
|
||
}
|
||
};
|
||
|
||
const getPaymentStatusLabel = (status: string) => {
|
||
switch (status) {
|
||
case 'paid': return 'مدفوع';
|
||
case 'pending': return 'معلق';
|
||
case 'partial': return 'مدفوع جزئياً';
|
||
case 'cancelled': return 'ملغي';
|
||
default: return status;
|
||
}
|
||
};
|
||
|
||
const getDelayLabel = (months: number) => {
|
||
const delayOptions = [
|
||
{ value: 1, label: 'شهر واحد' },
|
||
{ value: 2, label: 'شهرين' },
|
||
{ value: 3, label: '3 أشهر' },
|
||
{ value: 4, label: '4 أشهر' },
|
||
{ value: 6, label: '6 أشهر' },
|
||
{ value: 12, label: 'سنة واحدة' },
|
||
];
|
||
const option = delayOptions.find(opt => opt.value === months);
|
||
return option ? option.label : `${months} أشهر`;
|
||
};
|
||
|
||
return (
|
||
<div className="space-y-8">
|
||
{/* Header Section */}
|
||
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-xl p-6 border border-blue-100">
|
||
<div className="flex items-center justify-between mb-4">
|
||
<div className="flex items-center">
|
||
<span className="text-3xl ml-3">🔧</span>
|
||
<div>
|
||
<h2 className="text-2xl font-bold text-gray-900">
|
||
زيارة صيانة #{visit.id}
|
||
</h2>
|
||
<p className="text-gray-600 mt-1">
|
||
{formatDate(visit.visitDate)}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div className="text-right">
|
||
<div className="text-3xl font-bold text-blue-600 mb-1">
|
||
{formatCurrency(visit.cost)}
|
||
</div>
|
||
<span className={`inline-flex px-3 py-1 text-sm font-semibold rounded-full border ${getPaymentStatusColor(visit.paymentStatus)}`}>
|
||
{getPaymentStatusLabel(visit.paymentStatus)}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Main Details Grid */}
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||
{/* Visit Information */}
|
||
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
|
||
<div className="bg-gray-50 px-6 py-4 border-b border-gray-200">
|
||
<h3 className="text-lg font-semibold text-gray-900 flex items-center">
|
||
<span className="text-gray-600 text-xl ml-2">📋</span>
|
||
تفاصيل الزيارة
|
||
</h3>
|
||
</div>
|
||
<div className="p-6 space-y-4">
|
||
<div className="bg-blue-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-3">أعمال الصيانة المنجزة</label>
|
||
<div className="space-y-3">
|
||
{(() => {
|
||
try {
|
||
const jobs = JSON.parse(visit.maintenanceJobs);
|
||
return jobs.map((job: any, index: number) => (
|
||
<div key={index} className="bg-white p-3 rounded-lg border border-blue-200">
|
||
<div className="flex items-start justify-between">
|
||
<div className="flex-1">
|
||
<p className="font-semibold text-gray-900 mb-1">{job.job}</p>
|
||
{job.notes && (
|
||
<p className="text-sm text-gray-600">{job.notes}</p>
|
||
)}
|
||
</div>
|
||
<span className="inline-flex items-center px-2 py-1 text-xs font-medium bg-blue-100 text-blue-800 rounded-full">
|
||
#{index + 1}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
));
|
||
} catch {
|
||
return (
|
||
<div className="bg-white p-3 rounded-lg border border-blue-200">
|
||
<p className="text-gray-900">لا توجد تفاصيل أعمال الصيانة</p>
|
||
</div>
|
||
);
|
||
}
|
||
})()}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="bg-gray-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">عداد الكيلومترات</label>
|
||
<p className="text-gray-900 font-mono text-lg">
|
||
{formatNumber(visit.kilometers)} كم
|
||
</p>
|
||
</div>
|
||
<div className="bg-gray-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">الزيارة التالية بعد</label>
|
||
<p className="text-gray-900 font-medium">
|
||
{getDelayLabel(visit.nextVisitDelay)}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-gray-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-2">وصف الأعمال المنجزة</label>
|
||
<div className="bg-white rounded-lg p-4 border">
|
||
<p className="text-gray-900 whitespace-pre-wrap leading-relaxed">
|
||
{visit.description}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Vehicle & Customer Information */}
|
||
<div className="space-y-6">
|
||
{/* Vehicle Info */}
|
||
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
|
||
<div className="bg-gray-50 px-6 py-4 border-b border-gray-200">
|
||
<h3 className="text-lg font-semibold text-gray-900 flex items-center">
|
||
<span className="text-gray-600 text-xl ml-2">🚗</span>
|
||
معلومات المركبة
|
||
</h3>
|
||
</div>
|
||
<div className="p-6">
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="bg-green-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">رقم اللوحة</label>
|
||
<p className="text-xl font-bold text-gray-900 font-mono">
|
||
{visit.vehicle.plateNumber}
|
||
</p>
|
||
</div>
|
||
<div className="bg-green-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">السنة</label>
|
||
<p className="text-lg font-semibold text-gray-900">
|
||
{visit.vehicle.year}
|
||
</p>
|
||
</div>
|
||
<div className="bg-green-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">الشركة المصنعة</label>
|
||
<p className="text-gray-900 font-medium">
|
||
{visit.vehicle.manufacturer}
|
||
</p>
|
||
</div>
|
||
<div className="bg-green-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">الموديل</label>
|
||
<p className="text-gray-900 font-medium">
|
||
{visit.vehicle.model}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Customer Info */}
|
||
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
|
||
<div className="bg-gray-50 px-6 py-4 border-b border-gray-200">
|
||
<h3 className="text-lg font-semibold text-gray-900 flex items-center">
|
||
<span className="text-gray-600 text-xl ml-2">👤</span>
|
||
معلومات العميل
|
||
</h3>
|
||
</div>
|
||
<div className="p-6">
|
||
<div className="space-y-4">
|
||
<div className="bg-blue-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">اسم العميل</label>
|
||
<p className="text-lg font-semibold text-gray-900">
|
||
{visit.customer.name}
|
||
</p>
|
||
</div>
|
||
|
||
{(visit.customer.phone || visit.customer.email) && (
|
||
<div className="grid grid-cols-1 gap-4">
|
||
{visit.customer.phone && (
|
||
<div className="bg-blue-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">رقم الهاتف</label>
|
||
<a
|
||
href={`tel:${visit.customer.phone}`}
|
||
className="text-blue-600 hover:text-blue-800 font-mono font-medium"
|
||
dir="ltr"
|
||
>
|
||
📞 {visit.customer.phone}
|
||
</a>
|
||
</div>
|
||
)}
|
||
|
||
{visit.customer.email && (
|
||
<div className="bg-blue-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">البريد الإلكتروني</label>
|
||
<a
|
||
href={`mailto:${visit.customer.email}`}
|
||
className="text-blue-600 hover:text-blue-800 font-medium"
|
||
dir="ltr"
|
||
>
|
||
✉️ {visit.customer.email}
|
||
</a>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{visit.customer.address && (
|
||
<div className="bg-blue-50 p-4 rounded-lg">
|
||
<label className="block text-sm font-medium text-gray-600 mb-1">العنوان</label>
|
||
<p className="text-gray-900">
|
||
{visit.customer.address}
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Income Information */}
|
||
{visit.income && visit.income.length > 0 && (
|
||
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
|
||
<div className="bg-gray-50 px-6 py-4 border-b border-gray-200">
|
||
<h3 className="text-lg font-semibold text-gray-900 flex items-center">
|
||
<span className="text-gray-600 text-xl ml-2">💰</span>
|
||
سجل الدخل
|
||
</h3>
|
||
</div>
|
||
<div className="p-6">
|
||
<div className="space-y-3">
|
||
{visit.income.map((income) => (
|
||
<div key={income.id} className="flex justify-between items-center bg-green-50 p-4 rounded-lg">
|
||
<div>
|
||
<p className="text-sm text-gray-600">تاريخ الدخل</p>
|
||
<p className="font-medium text-gray-900">
|
||
{formatDate(income.incomeDate)}
|
||
</p>
|
||
</div>
|
||
<div className="text-right">
|
||
<p className="text-sm text-gray-600">المبلغ</p>
|
||
<p className="text-xl font-bold text-green-600 font-mono">
|
||
{formatCurrency(income.amount)}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Action Buttons */}
|
||
<div className="flex flex-wrap gap-3 pt-6 border-t border-gray-200">
|
||
<Link
|
||
to={`/vehicles?search=${encodeURIComponent(visit.vehicle.plateNumber)}`}
|
||
className="inline-flex items-center px-4 py-2 text-sm font-medium text-blue-600 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 transition-colors"
|
||
>
|
||
<span className="ml-2">🚗</span>
|
||
عرض تفاصيل المركبة
|
||
</Link>
|
||
<Link
|
||
to={`/customers?search=${encodeURIComponent(visit.customer.name)}`}
|
||
className="inline-flex items-center px-4 py-2 text-sm font-medium text-green-600 bg-green-50 border border-green-200 rounded-lg hover:bg-green-100 transition-colors"
|
||
>
|
||
<span className="ml-2">👤</span>
|
||
عرض تفاصيل العميل
|
||
</Link>
|
||
<Link
|
||
to={`/maintenance-visits?vehicleId=${visit.vehicle.id}`}
|
||
className="inline-flex items-center px-4 py-2 text-sm font-medium text-purple-600 bg-purple-50 border border-purple-200 rounded-lg hover:bg-purple-100 transition-colors"
|
||
>
|
||
<span className="ml-2">📋</span>
|
||
جميع زيارات هذه المركبة
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
);
|
||
} |