car_mms/app/components/customers/CustomerDetailsView.tsx
2025-09-11 14:22:27 +03:00

322 lines
15 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { Link } from "@remix-run/react";
import { Button } from "~/components/ui/Button";
import { Flex } from "~/components/layout/Flex";
import { useSettings } from "~/contexts/SettingsContext";
import type { CustomerWithVehicles } from "~/types/database";
interface CustomerDetailsViewProps {
customer: CustomerWithVehicles;
onEdit: () => void;
onClose: () => void;
}
export function CustomerDetailsView({
customer,
onEdit,
onClose,
}: CustomerDetailsViewProps) {
const { formatDate, formatCurrency } = useSettings();
return (
<div className="space-y-6">
{/* Enhanced Basic Information Section */}
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 p-6 rounded-xl border border-blue-100">
<div className="flex items-center justify-between mb-4">
<h3 className="text-xl font-bold text-gray-900 flex items-center">
<span className="text-blue-600 ml-2">👤</span>
المعلومات الأساسية
</h3>
<span className="text-sm text-gray-500 bg-white px-3 py-1 rounded-full">
العميل #{customer.id}
</span>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div className="bg-white p-4 rounded-lg shadow-sm">
<label className="block text-sm font-medium text-gray-600 mb-1">اسم العميل</label>
<p className="text-lg font-semibold text-gray-900">{customer.name}</p>
</div>
<div className="bg-white p-4 rounded-lg shadow-sm">
<label className="block text-sm font-medium text-gray-600 mb-1">رقم الهاتف</label>
<p className="text-gray-900" dir="ltr">
{customer.phone ? (
<a
href={`tel:${customer.phone}`}
className="text-blue-600 hover:text-blue-800 font-medium"
>
📞 {customer.phone}
</a>
) : (
<span className="text-gray-400">غير محدد</span>
)}
</p>
</div>
<div className="bg-white p-4 rounded-lg shadow-sm">
<label className="block text-sm font-medium text-gray-600 mb-1">البريد الإلكتروني</label>
<p className="text-gray-900" dir="ltr">
{customer.email ? (
<a
href={`mailto:${customer.email}`}
className="text-blue-600 hover:text-blue-800 font-medium"
>
{customer.email}
</a>
) : (
<span className="text-gray-400">غير محدد</span>
)}
</p>
</div>
<div className="bg-white p-4 rounded-lg shadow-sm">
<label className="block text-sm font-medium text-gray-600 mb-1">تاريخ الإنشاء</label>
<p className="text-gray-900">
{formatDate(customer.createdDate)}
</p>
</div>
<div className="bg-white p-4 rounded-lg shadow-sm">
<label className="block text-sm font-medium text-gray-600 mb-1">آخر تحديث</label>
<p className="text-gray-900">
{formatDate(customer.updateDate)}
</p>
</div>
{customer.address && (
<div className="bg-white p-4 rounded-lg shadow-sm md:col-span-2 lg:col-span-1">
<label className="block text-sm font-medium text-gray-600 mb-1">العنوان</label>
<p className="text-gray-900">{customer.address}</p>
</div>
)}
</div>
</div>
{/* Customer Vehicles Section */}
<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">
<Flex justify="between" align="center" className="flex-wrap gap-4">
<div className="flex items-center">
<span className="text-gray-600 text-xl ml-2">🚗</span>
<h3 className="text-lg font-semibold text-gray-900">
مركبات العميل ({customer.vehicles.length})
</h3>
</div>
{customer.vehicles.length > 0 && (
<Link
to={`/vehicles?customerId=${customer.id}`}
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>
)}
</Flex>
</div>
<div className="p-6">
{customer.vehicles.length === 0 ? (
<div className="text-center py-12">
<div className="text-gray-400 text-4xl mb-4">🚗</div>
<h4 className="text-lg font-medium text-gray-900 mb-2">لا توجد مركبات مسجلة</h4>
<p className="text-gray-500 mb-4">لم يتم تسجيل أي مركبات لهذا العميل بعد</p>
<Link
to="/vehicles"
className="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-colors"
>
إضافة مركبة جديدة
</Link>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{customer.vehicles.map((vehicle) => (
<Link
key={vehicle.id}
to={`/vehicles?plateNumber=${encodeURIComponent(vehicle.plateNumber)}`}
target="_blank"
className="block bg-gray-50 rounded-lg p-4 border border-gray-200 hover:border-blue-300 hover:bg-blue-50 transition-all"
>
<div className="flex items-start justify-between mb-3">
<div className="flex-1">
<h4 className="font-semibold text-gray-900 text-lg">
{vehicle.plateNumber}
</h4>
<p className="text-sm text-gray-500">#{vehicle.id}</p>
</div>
<span className="text-xs text-blue-600 bg-blue-100 px-2 py-1 rounded-full">
انقر للعرض
</span>
</div>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-sm text-gray-600">الصانع:</span>
<span className="text-sm font-medium text-gray-900">{vehicle.manufacturer}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-600">الموديل:</span>
<span className="text-sm font-medium text-gray-900">{vehicle.model}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-600">سنة الصنع:</span>
<span className="text-sm font-medium text-gray-900">{vehicle.year}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-600">آخر زيارة:</span>
<span className="text-sm text-gray-900">
{vehicle.lastVisitDate
? formatDate(vehicle.lastVisitDate)
: <span className="text-gray-400">لا توجد زيارات</span>
}
</span>
</div>
</div>
</Link>
))}
</div>
)}
</div>
</div>
{/* Latest Maintenance Visits Section */}
<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">
<Flex justify="between" align="center" className="flex-wrap gap-4">
<div className="flex items-center">
<span className="text-gray-600 text-xl ml-2">🔧</span>
<h3 className="text-lg font-semibold text-gray-900">
آخر زيارات الصيانة ({customer.maintenanceVisits.length > 3 ? '3 من ' + customer.maintenanceVisits.length : customer.maintenanceVisits.length})
</h3>
</div>
{customer.maintenanceVisits.length > 0 && (
<Link
to={`/maintenance-visits?customerId=${customer.id}`}
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>
)}
</Flex>
</div>
<div className="p-6">
{customer.maintenanceVisits.length === 0 ? (
<div className="text-center py-12">
<div className="text-gray-400 text-4xl mb-4">🔧</div>
<h4 className="text-lg font-medium text-gray-900 mb-2">لا توجد زيارات صيانة</h4>
<p className="text-gray-500 mb-4">لم يتم تسجيل أي زيارات صيانة لهذا العميل بعد</p>
<p className="text-sm text-gray-400 mb-4">
ابدأ بتسجيل أول زيارة صيانة لتتبع تاريخ الخدمات المقدمة
</p>
<Link
to="/maintenance-visits"
className="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-green-600 rounded-lg hover:bg-green-700 transition-colors"
>
تسجيل زيارة صيانة جديدة
</Link>
</div>
) : (
<div className="space-y-4">
{customer.maintenanceVisits.slice(0, 3).map((visit) => (
<div
key={visit.id}
className="bg-gray-50 rounded-lg p-4 border border-gray-200 hover:border-green-300 hover:bg-green-50 transition-all"
>
<div className="flex items-start justify-between mb-3">
<div className="flex-1">
<h4 className="font-semibold text-gray-900 text-lg">
{(() => {
try {
const jobs = JSON.parse(visit.maintenanceJobs);
return jobs.length > 1
? `${jobs.length} أعمال صيانة`
: jobs[0]?.job || 'نوع صيانة غير محدد';
} catch {
return 'نوع صيانة غير محدد';
}
})()}
</h4>
<p className="text-sm text-gray-500">زيارة #{visit.id}</p>
</div>
<div className="text-left">
<div className="text-lg font-bold text-green-600">
{formatCurrency(visit.cost)}
</div>
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
visit.paymentStatus === "paid"
? 'bg-green-100 text-green-800'
: visit.paymentStatus === 'pending'
? 'bg-yellow-100 text-yellow-800'
: 'bg-red-100 text-red-800'
}`}>
{visit.paymentStatus === 'paid' ? 'مدفوع' :
visit.paymentStatus === 'pending' ? 'معلق' : 'غير مدفوع'}
</span>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
<div className="flex justify-between">
<span className="text-gray-600">تاريخ الزيارة:</span>
<span className="font-medium text-gray-900">
{formatDate(visit.visitDate)}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-600">المركبة:</span>
<span className="font-medium text-gray-900">
{visit.vehicle?.plateNumber || 'غير محدد'}
</span>
</div>
{visit.description && (
<div className="md:col-span-2">
<span className="text-gray-600">الوصف:</span>
<p className="text-gray-900 mt-1">{visit.description}</p>
</div>
)}
</div>
</div>
))}
{customer.maintenanceVisits.length > 3 && (
<div className="text-center py-4 border-t border-gray-200">
<p className="text-sm text-gray-500 mb-3">
عرض 3 من أصل {customer.maintenanceVisits.length} زيارة صيانة
</p>
<Link
to={`/maintenance-visits?customerId=${customer.id}`}
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>
عرض جميع الزيارات ({customer.maintenanceVisits.length})
</Link>
</div>
)}
</div>
)}
</div>
</div>
{/* Action Buttons */}
<div className="flex flex-col sm:flex-row gap-3 pt-6 border-t border-gray-200">
<Button
onClick={onEdit}
className="bg-blue-600 hover:bg-blue-700 flex-1 sm:flex-none"
>
<span className="ml-2"></span>
تعديل العميل
</Button>
<Button
variant="outline"
onClick={onClose}
className="flex-1 sm:flex-none"
>
إغلاق
</Button>
</div>
</div>
);
}