// src/components/sheikh/SheikhSessionRequests.tsx import { useState, useEffect, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; import { toast, Toaster } from 'sonner'; // إضافة import sonner import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '../ui/card'; import { Button } from '../ui/button'; import { Badge } from '../ui/badge'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '../ui/table'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '../ui/dialog'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs'; import { CheckCircle2, XCircle, Clock, Calendar, User, DollarSign, MessageSquare, Loader2, Eye, RefreshCw, Video, CreditCard, AlertCircle, } from 'lucide-react'; import { Alert, AlertDescription } from '../ui/alert'; import { Separator } from '../ui/separator'; import { Textarea } from '../ui/textarea'; import { useLanguage } from '../../lib/languageContext'; import { translations } from '../../lib/translations'; // استيراد API import { fetchSheikhSessions, acceptSessionRequest, rejectSessionRequest, SessionDto, SessionStatus, formatTimeTo12Hour, isAuthenticated, } from '../../lib/api/bookingApi'; export function SheikhSessionRequests() { const { language } = useLanguage(); const t = translations[language].sheikhSessions || { title: 'Session Requests', pendingRequests: 'Pending Requests', acceptedSessions: 'Accepted Sessions', completedSessions: 'Completed Sessions', rejectedSessions: 'Rejected Sessions', noPending: 'No pending requests', noSessions: 'No sessions found', accept: 'Accept', reject: 'Reject', confirmAccept: 'Confirm Acceptance', confirmReject: 'Confirm Rejection', acceptMessage: 'Are you sure you want to accept this session request?', rejectMessage: 'Are you sure you want to reject this session request?', reasonRequired: 'Please provide a reason for rejection', enterRejectionReason: 'Enter reason for rejection...', acceptSuccess: 'Session accepted successfully!', rejectSuccess: 'Session rejected successfully!', student: 'Student', dateTime: 'Date & Time', amount: 'Amount', notes: 'Notes', status: 'Status', actions: 'Actions', refresh: 'Refresh', scheduleMeeting: 'Schedule Meeting', meetingScheduled: 'Meeting Scheduled', paymentStatus: 'Payment Status', paid: 'Paid', pending: 'Pending', }; const navigate = useNavigate(); const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedSession, setSelectedSession] = useState(null); const [acceptDialogOpen, setAcceptDialogOpen] = useState(false); const [rejectDialogOpen, setRejectDialogOpen] = useState(false); const [rejectionReason, setRejectionReason] = useState(''); const [submitting, setSubmitting] = useState(false); const [activeTab, setActiveTab] = useState('REQUESTED'); // التحقق من المصادقة useEffect(() => { if (!isAuthenticated()) { navigate('/auth/signin'); } }, [navigate]); const hasLoadedOnce = useRef(false); // جلب الجلسات const loadSessions = async () => { if (!hasLoadedOnce.current) { setLoading(true); } setError(null); try { const data = await fetchSheikhSessions(); setSessions(data || []); } catch (err) { console.error('Failed to load sessions:', err); setError(language === 'ar' ? 'فشل تحميل الجلسات. يرجى المحاولة مرة أخرى.' : 'Failed to load sessions. Please try again.'); } finally { setLoading(false); hasLoadedOnce.current = true; } }; useEffect(() => { loadSessions(); }, []); // تصفية الجلسات حسب الحالة const filteredSessions = sessions.filter(s => s.sessionStatus === activeTab); // الجلسات المعلقة (REQUESTED) - الأهم const pendingSessions = sessions.filter(s => s.sessionStatus === 'REQUESTED'); // قبول الجلسة const handleAccept = async () => { if (!selectedSession) return; const sessionId = selectedSession.sessionId; // إغلاق الديالوج فوراً وتغيير التبويب لتوفير تجربة مستخدم فورية (0ms) setAcceptDialogOpen(false); setActiveTab('TOPAY'); // تحديث الحالة محلياً بشكل فوري setSessions(prev => prev.map(s => s.sessionId === sessionId ? { ...s, sessionStatus: 'TOPAY' } : s ) ); const promise = acceptSessionRequest(sessionId); toast.promise(promise, { loading: language === 'ar' ? 'جاري قبول الجلسة...' : 'Accepting session...', success: t.acceptSuccess, error: language === 'ar' ? 'فشل قبول الجلسة.' : 'Failed to accept session.', }); setSubmitting(true); try { const result = await promise; if (!result) throw new Error('Failed to accept'); } catch (err) { console.error('Failed to accept session:', err); // إعادة تحميل الجلسات في حال الفشل للتراجع عن التغيير المتفائل loadSessions(); } finally { setSubmitting(false); setSelectedSession(null); } }; // رفض الجلسة const handleReject = async () => { if (!selectedSession) return; const sessionId = selectedSession.sessionId; // إغلاق الديالوج فوراً setRejectDialogOpen(false); // تحديث الحالة محلياً بشكل فوري setSessions(prev => prev.map(s => s.sessionId === sessionId ? { ...s, sessionStatus: 'CANCELLED' } : s ) ); const promise = rejectSessionRequest(sessionId); toast.promise(promise, { loading: language === 'ar' ? 'جاري رفض الجلسة...' : 'Rejecting session...', success: t.rejectSuccess, error: language === 'ar' ? 'فشل رفض الجلسة.' : 'Failed to reject session.', }); setSubmitting(true); try { const result = await promise; if (!result) throw new Error('Failed to reject'); } catch (err) { console.error('Failed to reject session:', err); // إعادة تحميل الجلسات للتراجع عن التغيير المتفائل loadSessions(); } finally { setSubmitting(false); setSelectedSession(null); setRejectionReason(''); } }; // الحصول على لون وشكل الحالة const getStatusBadge = (status: SessionStatus) => { switch (status) { case 'REQUESTED': return {language === 'ar' ? 'في انتظار الموافقة' : 'Pending'} ; case 'SCHEDULED': return {language === 'ar' ? 'مجدولة' : 'Scheduled'} ; case 'TOPAY': return {language === 'ar' ? 'في انتظار الدفع' : 'To Pay'} ; case 'ON_GOING': return ; case 'COMPLETED': return {language === 'ar' ? 'مكتملة' : 'Completed'} ; case 'CANCELLED': return {language === 'ar' ? 'ملغية' : 'Cancelled'} ; case 'MISSED': return {language === 'ar' ? 'فاتت' : 'Missed'} ; default: return {status}; } }; // تنسيق التاريخ والوقت const formatDateTime = (dateTimeStr: string) => { const date = new Date(dateTimeStr); return { date: date.toLocaleDateString(language === 'ar' ? 'ar-EG' : 'en-US'), time: formatTimeTo12Hour(date.toLocaleTimeString()), full: `${date.toLocaleDateString(language === 'ar' ? 'ar-EG' : 'en-US')} - ${formatTimeTo12Hour(date.toLocaleTimeString())}`, }; }; // جدول الجلسات const SessionsTable = ({ sessionsList, showActions = true }: { sessionsList: SessionDto[], showActions?: boolean }) => { if (sessionsList.length === 0) { return (
{activeTab === 'REQUESTED' ? t.noPending : t.noSessions}
); } return (
{t.student} {t.dateTime} {t.amount} {t.paymentStatus} {t.status} {showActions && {t.actions}} {sessionsList.map((session) => { const dateTime = formatDateTime(session.scheduledStart); return ( {session.studentName} {dateTime.full} ${session.price} {session.paymentStatus === 'PAID' ? t.paid : t.pending} {getStatusBadge(session.sessionStatus)} {showActions && session.sessionStatus === 'REQUESTED' && (
)} {showActions && session.sessionStatus === 'TOPAY' && ( )}
); })}
); }; return (
{/* إضافة Toaster component */} {/* Header */}

{t.title}

{language === 'ar' ? `لديك ${pendingSessions.length} طلبات جلسات في انتظار الموافقة` : `You have ${pendingSessions.length} pending session requests`}

{/* Error Message */} {error && ( {error} )} {/* Tabs */} setActiveTab(v as SessionStatus)}> {language === 'ar' ? 'قيد الانتظار' : 'Pending'} {pendingSessions.length > 0 && ` (${pendingSessions.length})`} {language === 'ar' ? 'في انتظار الدفع' : 'To Pay'} {language === 'ar' ? 'مكتملة' : 'Completed'} {language === 'ar' ? 'ملغية' : 'Cancelled'} {t.pendingRequests} {language === 'ar' ? 'قم بقبول أو رفض طلبات الجلسات من الطلاب' : 'Accept or reject session requests from students'} {t.acceptedSessions} {language === 'ar' ? 'الجلسات التي تم قبولها وفي انتظار الدفع' : 'Sessions that have been accepted and awaiting payment'} {t.completedSessions} {t.rejectedSessions} {/* Accept Dialog */} {t.confirmAccept} {t.acceptMessage} {selectedSession && (
{t.student}: {selectedSession.studentName}
{t.dateTime}: {formatDateTime(selectedSession.scheduledStart).full}
{t.amount}: ${selectedSession.price}
{selectedSession.sessionDescription && (
{t.notes}:

{selectedSession.sessionDescription}

)}
)}
{/* Reject Dialog */} {t.confirmReject} {t.rejectMessage}