diff --git a/app/property/[id]/PropertyDetail.js b/app/property/[id]/PropertyDetail.js
index b402d77..7d9f950 100644
--- a/app/property/[id]/PropertyDetail.js
+++ b/app/property/[id]/PropertyDetail.js
@@ -179,6 +179,12 @@ export default function PropertyDetailsPage() {
const [bookingError, setBookingError] = useState(null);
const [bookingSuccess, setBookingSuccess] = useState(false);
const [availableRanges, setAvailableRanges] = useState([]);
+ const [bookingStep, setBookingStep] = useState('entry');
+ const [selectedStart, setSelectedStart] = useState(null);
+ const [selectedEnd, setSelectedEnd] = useState(null);
+ const [calendarMonth, setCalendarMonth] = useState(() => new Date().getMonth());
+ const [calendarYear, setCalendarYear] = useState(() => new Date().getFullYear());
+ const [pricingMode, setPricingMode] = useState('daily');
const [favLoading, setFavLoading] = useState(false);
const [avgRating, setAvgRating] = useState(null);
const [showRatingForm, setShowRatingForm] = useState(false);
@@ -202,6 +208,17 @@ export default function PropertyDetailsPage() {
const mapped = mapApiDetail(data);
setProperty(mapped);
if (mapped) fetchAvgRating(mapped.id);
+ if (mapped && mapped.isRent) {
+ try {
+ const propInfoId = mapped._raw?.propertyInformationId || mapped.id;
+ const ranges = await getAvailableDateRanges(propInfoId);
+ if (ranges && Array.isArray(ranges)) {
+ setAvailableRanges(ranges);
+ }
+ } catch (e) {
+ console.warn('Failed to fetch date ranges', e);
+ }
+ }
}
} catch (err) {
console.error('[PropertyDetail] Failed:', err);
@@ -267,6 +284,77 @@ export default function PropertyDetailsPage() {
}
};
+ const MONTHS_AR = ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'];
+ const DAYS_AR = ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'];
+
+ const availableDatesSet = useMemo(() => {
+ const dates = new Set();
+ if (!Array.isArray(availableRanges)) return dates;
+ availableRanges.forEach(r => {
+ const start = new Date(r.startDate || r.start);
+ const end = new Date(r.endDate || r.end);
+ for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
+ dates.add(d.toISOString().split('T')[0]);
+ }
+ });
+ return dates;
+ }, [availableRanges]);
+
+ const isDateAvailable = (dateStr) => availableDatesSet.has(dateStr);
+ const isPastDate = (dateStr) => {
+ const today = new Date();
+ today.setHours(0, 0, 0, 0);
+ return new Date(dateStr) < today;
+ };
+
+ const handleDayClick = (dateStr) => {
+ if (bookingStep === 'entry') {
+ setSelectedStart(dateStr);
+ setSelectedEnd(null);
+ setBookingStep('exit');
+ } else {
+ if (new Date(dateStr) <= new Date(selectedStart)) {
+ setSelectedStart(dateStr);
+ setSelectedEnd(null);
+ setBookingStep('exit');
+ } else {
+ setSelectedEnd(dateStr);
+ setBookingStep('entry');
+ }
+ }
+ };
+
+ const handleBookingConfirm = async () => {
+ if (!AuthService.isAuthenticated()) { setShowLoginDialog(true); return; }
+ if (!selectedStart || !selectedEnd) {
+ setBookingError('يرجى تحديد تاريخ البداية والنهاية');
+ return;
+ }
+ setBookingLoading(true);
+ setBookingError(null);
+ try {
+ const propInfoId = property._raw?.propertyInformationId || property.id;
+ const startDate = new Date(selectedStart + 'T00:00:00.000').toISOString();
+ const endDate = new Date(selectedEnd + 'T00:00:00.000').toISOString();
+ await bookReservation(propInfoId, startDate, endDate);
+ setBookingSuccess(true);
+ toast.success('تم إرسال طلب الحجز بنجاح');
+ } catch (err) {
+ setBookingError(err.message || 'فشل الحجز');
+ } finally {
+ setBookingLoading(false);
+ }
+ };
+
+ const navigateMonth = (delta) => {
+ let month = calendarMonth + delta;
+ let year = calendarYear;
+ if (month < 0) { month = 11; year--; }
+ if (month > 11) { month = 0; year++; }
+ setCalendarMonth(month);
+ setCalendarYear(year);
+ };
+
const handleRatingSuccess = () => {
setShowRatingForm(false);
if (property) fetchAvgRating(property.id);
@@ -304,6 +392,8 @@ export default function PropertyDetailsPage() {
const isFav = isFavorite(property.id);
const isRoomType = property.type === 'room';
const isMostRequested = avgRating !== null && avgRating >= 4.5;
+ const showPricingToggle = property.isRent && property.priceDisplay?.daily > 0 && property.priceDisplay?.monthly > 0;
+ const effectivePricingMode = showPricingToggle ? pricingMode : (property.isRent && property.priceDisplay?.monthly > 0 ? 'monthly' : 'daily');
return (
@@ -702,27 +792,168 @@ export default function PropertyDetailsPage() {
) : (
<>
-
-
-
-
setBookingDates(prev => ({ ...prev, start: e.target.value }))}
- className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-xl focus:ring-2 focus:ring-amber-500" />
+ {/* Pricing Mode Toggle */}
+ {showPricingToggle && (
+
+
+
-
-
-
setBookingDates(prev => ({ ...prev, end: e.target.value }))}
- className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-xl focus:ring-2 focus:ring-amber-500" />
+ )}
+
+ {/* Step Indicator */}
+
+
+
+ تحديد تاريخ البداية
+
+
←
+
+ {/* Calendar */}
+ {effectivePricingMode === 'daily' ? (
+
+
+
+ {MONTHS_AR[calendarMonth]} {calendarYear}
+
+
+
+
+ {DAYS_AR.map((d, i) => (
+
{d}
+ ))}
+
+
+ {(() => {
+ const firstDay = new Date(calendarYear, calendarMonth, 1).getDay();
+ const daysInMonth = new Date(calendarYear, calendarMonth + 1, 0).getDate();
+ const adjustedFirstDay = (firstDay + 1) % 7;
+ const cells = [];
+ for (let i = 0; i < adjustedFirstDay; i++) {
+ cells.push(
);
+ }
+ for (let day = 1; day <= daysInMonth; day++) {
+ const dateStr = `${calendarYear}-${String(calendarMonth + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
+ const past = isPastDate(dateStr);
+ const available = isDateAvailable(dateStr);
+ const isSelStart = dateStr === selectedStart;
+ const isSelEnd = dateStr === selectedEnd;
+ const inRange = selectedStart && selectedEnd && new Date(dateStr) > new Date(selectedStart) && new Date(dateStr) < new Date(selectedEnd);
+ const disabled = past || !available;
+ cells.push(
+
+ );
+ }
+ return
{cells}
;
+ })()}
+
+ ) : (
+
+
+
+ {calendarYear}
+
+
+
+ {MONTHS_AR.map((name, idx) => {
+ const monthStr = `${calendarYear}-${String(idx + 1).padStart(2, '0')}`;
+ const isSelStart = selectedStart && selectedStart.startsWith(monthStr);
+ const isSelEnd = selectedEnd && selectedEnd.startsWith(monthStr);
+ const inRange = selectedStart && selectedEnd && monthStr > selectedStart.substring(0, 7) && monthStr < selectedEnd.substring(0, 7);
+ return (
+
+ );
+ })}
+
+
+ )}
+
+ {/* Summary */}
+ {selectedStart && (
+
+
+ تاريخ البداية
+ {selectedStart}
+
+ {selectedEnd && (
+ <>
+
+ تاريخ النهاية
+ {selectedEnd}
+
+
+
+ {effectivePricingMode === 'daily' ? 'عدد الأيام' : 'عدد الأشهر'}
+
+ {effectivePricingMode === 'daily'
+ ? Math.max(1, Math.round((new Date(selectedEnd) - new Date(selectedStart)) / (1000 * 60 * 60 * 24)) + 1)
+ : (new Date(selectedEnd).getMonth() - new Date(selectedStart).getMonth() + (new Date(selectedEnd).getFullYear() - new Date(selectedStart).getFullYear()) * 12) + 1}
+
+
+
+ المجموع
+
+ {formatCurrency(effectivePricingMode === 'daily'
+ ? Math.max(1, Math.round((new Date(selectedEnd) - new Date(selectedStart)) / (1000 * 60 * 60 * 24)) + 1) * property.priceDisplay.daily
+ : ((new Date(selectedEnd).getMonth() - new Date(selectedStart).getMonth() + (new Date(selectedEnd).getFullYear() - new Date(selectedStart).getFullYear()) * 12) + 1) * property.priceDisplay.monthly)} ل.س
+
+
+ {property.deposit > 0 && (
+
+ تأمين
+ {formatCurrency(property.deposit)} ل.س
+
+ )}
+ >
+ )}
+
+ )}
+
{bookingError && (
{bookingError}
)}
-
>
)}