"use client";
import { useState, useEffect, useMemo } from "react";
import { motion } from "framer-motion";
import { useRouter } from "next/navigation";
import { useTranslation } from "react-i18next";
import { Calendar, User, Mail, Phone, CheckCircle, XCircle, Clock, MapPin, Bed, Bath, Square, CalendarDays, ChevronLeft, ChevronRight, Eye, Loader2, Search } from "lucide-react";
import toast, { Toaster } from "react-hot-toast";
import { getMyRentListings, getOwnerReservationRequests } from "@/app/utils/api";
import useAuth from "@/app/hooks/useAuth";
import Loading from "@/app/loading";
const OwnerBookingCalendar = ({ property, onDateSelect, selectedDates }) => {
const { t } = useTranslation();
const [currentMonth, setCurrentMonth] = useState(new Date());
const [hoverDate, setHoverDate] = useState(null);
const daysInMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 0).getDate();
const firstDayOfMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth(), 1).getDay();
const monthNames = [t("january"), t("february"), t("march"), t("april"), t("may"), t("june"), t("july"), t("august"), t("september"), t("october"), t("november"), t("december")];
const dayNames = [t("dayFull.sunday"), t("dayFull.monday"), t("dayFull.tuesday"), t("dayFull.wednesday"), t("dayFull.thursday"), t("dayFull.friday"), t("dayFull.saturday")];
const isDateBooked = (date) => {
if (!property?.bookings || !Array.isArray(property.bookings)) return false;
return property.bookings.some((booking) => {
const start = new Date(booking.startDate);
const end = new Date(booking.endDate);
return date >= start && date <= end;
});
};
const isDateSelected = (date) => {
if (!selectedDates) return false;
const dateStr = date.toISOString().split("T")[0];
return dateStr === selectedDates.start || dateStr === selectedDates.end;
};
const isInRange = (date) => {
if (!selectedDates?.start || !selectedDates?.end) return false;
const dateStr = date.toISOString().split("T")[0];
return dateStr > selectedDates.start && dateStr < selectedDates.end;
};
const handleDateClick = (date) => {
if (isDateBooked(date)) return;
onDateSelect?.(date);
};
const renderDays = () => {
const days = [];
const totalDays = daysInMonth + firstDayOfMonth;
for (let i = 0; i < totalDays; i++) {
if (i < firstDayOfMonth) {
days.push(
);
} else {
const dayNumber = i - firstDayOfMonth + 1;
const date = new Date(currentMonth.getFullYear(), currentMonth.getMonth(), dayNumber);
const isBooked = isDateBooked(date);
const isSelected = isDateSelected(date);
const inRange = isInRange(date);
const isToday = date.toDateString() === new Date().toDateString();
days.push(
,
);
}
}
return days;
};
return (
{monthNames[currentMonth.getMonth()]} {currentMonth.getFullYear()}
{dayNames.map((name, i) => (
{name}
))}
{renderDays()}
);
};
const BookingCard = ({ booking, onViewDetails }) => {
const { t } = useTranslation();
const formatCurrency = (amount) => {
return (amount || 0).toLocaleString() + " " + t("syp");
};
const getStatusBadge = (status) => {
const statusConfig = {
pending: { label: t("pending"), color: "bg-yellow-100 text-yellow-800", icon: Clock },
confirmed: { label: t("confirmed"), color: "bg-green-100 text-green-800", icon: CheckCircle },
cancelled: { label: t("cancelled"), color: "bg-red-100 text-red-800", icon: XCircle },
completed: { label: t("completed"), color: "bg-gray-100 text-gray-800", icon: CheckCircle },
};
const config = statusConfig[status] || statusConfig.pending;
const Icon = config.icon;
return (
{config.label}
);
};
return (
{booking.propertyTitle}
{getStatusBadge(booking.status)}
{booking.location}
{formatCurrency(booking.dailyRent)}
{t("dailyRent")}
{booking.propertyDetails?.bedrooms} {t("rooms")}
{booking.propertyDetails?.bathrooms} {t("baths")}
{booking.propertyDetails?.area} {t("sqm")}
{booking.tenantName && (
{booking.tenantName}
{booking.tenantPhone && (
{booking.tenantPhone}
)}
{booking.tenantEmail && (
{booking.tenantEmail}
)}
)}
{t("monthlyRent")}
{formatCurrency(booking.monthlyRent)}
{t("deposit")}
{formatCurrency(booking.deposit)}
);
};
const BookingDetailsModal = ({ booking, isOpen, onClose }) => {
const { t } = useTranslation();
if (!isOpen || !booking) return null;
const formatCurrency = (amount) => {
return (amount || 0).toLocaleString() + " " + t("syp");
};
return (
e.stopPropagation()}
>
{t("bookingDetails")}
# {booking.id}
{booking.images && booking.images.length > 0 && (
{booking.images.map((img, idx) => (

))}
)}
{t("propertyInfo")}
{t("location")}: {booking.location}
{t("description")}: {booking.parsedDetails?.description || "-"}
{booking.propertyDetails?.bedrooms} {t("rooms")}
{booking.propertyDetails?.bathrooms} {t("bathrooms")}
{booking.propertyDetails?.salons} {t("salons")}
{booking.propertyDetails?.area} {t("sqm")}
{t("financialInfo")}
{t("dailyRent")}
{formatCurrency(booking.dailyRent)}
{t("monthlyRent")}
{formatCurrency(booking.monthlyRent)}
{t("deposit")}
{formatCurrency(booking.deposit)}
{booking.parsedDetails?.services && (
{t("services")}
{booking.parsedDetails.services.map((srv, i) => (
{srv}
))}
)}
);
};
export default function OwnerBookingsPage() {
const { t, i18n } = useTranslation();
const router = useRouter();
const { name, isOwner } = useAuth();
const [bookings, setBookings] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [selectedBooking, setSelectedBooking] = useState(null);
const [filterStatus, setFilterStatus] = useState("all");
const [searchTerm, setSearchTerm] = useState("");
const [dateRange, setDateRange] = useState({ start: "", end: "" });
const [showCalendar, setShowCalendar] = useState(false);
const isRtl = i18n.language === "ar";
useEffect(() => {
if (isOwner) {
fetchData();
} else {
router.push("/auth/choose-role");
}
}, [isOwner, router]);
const fetchData = async () => {
try {
const response = await getOwnerReservationRequests();
let rawData = response;
if (response && response.data) {
rawData = response.data;
}
// تحويل البيانات إلى مصفوفة وتصفية العناصر الفارغة (null أو undefined)
const rawList = Array.isArray(rawData) ? rawData : rawData ? [rawData] : [];
const list = rawList.filter(Boolean);
const mappedBookings = list.map((item) => {
let parsedDetails = {};
try {
if (item?.propertyInformation?.detailsJSON) {
parsedDetails = JSON.parse(item.propertyInformation.detailsJSON);
}
} catch (e) {
console.error("Error parsing detailsJSON", e);
}
const statusMap = {
0: "pending",
1: "confirmed",
2: "completed",
3: "cancelled",
};
const statusKey = statusMap[item?.propertyInformation?.status] || "pending";
return {
id: item?.id,
dailyRent: item?.dailyRent,
monthlyRent: item?.monthlyRent,
deposit: item?.deposit,
createdAt: item?.createdAt,
startDate: item?.createdAt?.split("T")[0],
status: statusKey,
propertyTitle: parsedDetails.description || `${t("property")} #${item?.id}`,
location: item?.propertyInformation?.address || "",
images: item?.propertyInformation?.images || [],
propertyDetails: {
bedrooms: item?.propertyInformation?.numberOfBedRooms || 0,
bathrooms: item?.propertyInformation?.numberOfBathRooms || 0,
salons: item?.propertyInformation?.numberOfSalons || 0,
area: item?.propertyInformation?.space || 0,
},
parsedDetails,
tenantName: item?.tenantName || null,
tenantPhone: item?.tenantPhone || null,
tenantEmail: item?.tenantEmail || null,
};
});
setBookings(mappedBookings);
} catch (error) {
console.error("Error loading listings:", error);
setBookings([]);
} finally {
setIsLoading(false);
}
};
const filteredBookings = useMemo(() => {
return bookings.filter((booking) => {
const matchesStatus = filterStatus === "all" || booking.status === filterStatus;
const matchesSearch =
!searchTerm ||
booking.tenantName?.toLowerCase().includes(searchTerm.toLowerCase()) ||
booking.propertyTitle?.toLowerCase().includes(searchTerm.toLowerCase()) ||
booking.location?.toLowerCase().includes(searchTerm.toLowerCase()) ||
String(booking.id).includes(searchTerm);
const bookingDate = new Date(booking.startDate || booking.createdAt);
const matchesStart = !dateRange.start || bookingDate >= new Date(dateRange.start);
const matchesEnd = !dateRange.end || bookingDate <= new Date(dateRange.end);
return matchesStatus && matchesSearch && matchesStart && matchesEnd;
});
}, [bookings, filterStatus, searchTerm, dateRange]);
const statusCounts = useMemo(() => {
return {
all: bookings.length,
pending: bookings.filter((b) => b.status === "pending").length,
confirmed: bookings.filter((b) => b.status === "confirmed").length,
completed: bookings.filter((b) => b.status === "completed").length,
cancelled: bookings.filter((b) => b.status === "cancelled").length,
};
}, [bookings]);
if (isLoading) {
return (
);
}
return (
setSelectedBooking(null)} />
{t("myBookings")}
{t("welcomeBookings", { name: name, count: bookings.length })}
{[
{ id: "all", label: "allBookings", count: statusCounts.all, color: "text-gray-900", active: "border-gray-900 bg-gray-50" },
{ id: "pending", label: "pending", count: statusCounts.pending, color: "text-yellow-600", active: "border-yellow-500 bg-yellow-50" },
{ id: "confirmed", label: "confirmed", count: statusCounts.confirmed, color: "text-green-600", active: "border-green-500 bg-green-50" },
{ id: "completed", label: "completed", count: statusCounts.completed, color: "text-gray-600", active: "border-gray-500 bg-gray-50" },
{ id: "cancelled", label: "cancelled", count: statusCounts.cancelled, color: "text-red-600", active: "border-red-500 bg-red-50" },
].map((item, index) => (
setFilterStatus(item.id)}
>
{item.count}
{t(item.label)}
))}
{showCalendar && (
)}
{filteredBookings.length === 0 ? (
{t("noBookings")}
{filterStatus !== "all" || searchTerm || dateRange.start || dateRange.end ? t("noBookingsInCategory") : t("noBookingsReceived")}
{(filterStatus !== "all" || searchTerm || dateRange.start || dateRange.end) && (
)}
) : (
{filteredBookings.map((booking) => (
))}
)}
);
}