This commit is contained in:
@ -91,7 +91,6 @@ export default function NotificationHandler() {
|
||||
|
||||
// This MUST be synchronous from a user gesture
|
||||
const permission = await Notification.requestPermission();
|
||||
console.log("[FCM] Permission result:", permission);
|
||||
|
||||
if (permission === "granted") {
|
||||
await setupFCM();
|
||||
|
||||
@ -84,24 +84,15 @@ export default function LoginPage() {
|
||||
|
||||
try {
|
||||
const loginFn = loginMethod === "email" ? loginWithEmail : loginWithPhone;
|
||||
console.log(
|
||||
"[Login] Attempting login via",
|
||||
loginMethod,
|
||||
":",
|
||||
formData.credential,
|
||||
);
|
||||
|
||||
const result = await loginFn(formData.credential, formData.password);
|
||||
|
||||
console.log("[Login] Response status:", result.status);
|
||||
|
||||
if (result.status === 200) {
|
||||
const token =
|
||||
typeof result.data === "string"
|
||||
? result.data
|
||||
: result.data?.token || result.data?.accessToken;
|
||||
AuthService.addToken(token);
|
||||
console.log("[Login] Token stored");
|
||||
|
||||
// Fetch user profile to get full name
|
||||
const authUser = AuthService.getUser();
|
||||
@ -119,7 +110,6 @@ export default function LoginPage() {
|
||||
email: profile.email || authUser.email,
|
||||
phone: profile.phone || profile.phoneNumber || authUser.phone,
|
||||
});
|
||||
console.log("[Login] User profile cached");
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("[Login] Failed to fetch profile:", err);
|
||||
@ -127,7 +117,6 @@ export default function LoginPage() {
|
||||
}
|
||||
|
||||
const userRole = AuthService.isOwner() ? "owner" : "customer";
|
||||
console.log("[Login] User role:", userRole);
|
||||
|
||||
setIsSuccess(true);
|
||||
toast.success("تم تسجيل الدخول بنجاح!", {
|
||||
@ -138,14 +127,12 @@ export default function LoginPage() {
|
||||
router.push("/");
|
||||
}, 1500);
|
||||
} else if (result.status === 206) {
|
||||
console.log("[Login] 206 — OTP required");
|
||||
const tempToken =
|
||||
typeof result.data === "string"
|
||||
? result.data
|
||||
: result.data?.token || result.data?.accessToken;
|
||||
if (tempToken) {
|
||||
AuthService.addToken(tempToken);
|
||||
console.log("[Login] Temp token stored for OTP");
|
||||
}
|
||||
toast("يرجى إدخال رمز التحقق", {
|
||||
icon: "🔐",
|
||||
@ -159,7 +146,6 @@ export default function LoginPage() {
|
||||
} else {
|
||||
await sendPhoneOTP();
|
||||
}
|
||||
console.log("[Login] OTP sent successfully");
|
||||
} catch (otpErr) {
|
||||
console.warn("[Login] OTP send failed, proceeding anyway:", otpErr);
|
||||
}
|
||||
@ -197,10 +183,8 @@ export default function LoginPage() {
|
||||
|
||||
try {
|
||||
const verifyFn = loginMethod === "email" ? verifyEmail : verifyPhone;
|
||||
console.log("[OTP] Verifying code:", otpCode);
|
||||
|
||||
const result = await verifyFn(otpCode);
|
||||
console.log("[OTP] Verify response status:", result.status);
|
||||
|
||||
if (result.ok) {
|
||||
const finalToken =
|
||||
@ -209,7 +193,6 @@ export default function LoginPage() {
|
||||
: result.data?.token || result.data?.accessToken;
|
||||
if (finalToken && typeof finalToken === "string") {
|
||||
AuthService.addToken(finalToken);
|
||||
console.log("[OTP] Final token stored");
|
||||
}
|
||||
|
||||
setIsSuccess(true);
|
||||
@ -218,7 +201,6 @@ export default function LoginPage() {
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("[OTP] Redirecting to home");
|
||||
router.push("/");
|
||||
}, 1500);
|
||||
} else {
|
||||
@ -235,7 +217,6 @@ export default function LoginPage() {
|
||||
|
||||
const resendOTP = async () => {
|
||||
try {
|
||||
console.log("[OTP] Resending OTP via", loginMethod);
|
||||
if (loginMethod === "email") {
|
||||
await sendEmailOTP();
|
||||
} else {
|
||||
@ -677,7 +658,6 @@ export default function LoginPage() {
|
||||
setStep("login");
|
||||
setOtpCode("");
|
||||
setOtpError("");
|
||||
console.log("[OTP] Going back to login");
|
||||
}}
|
||||
className="text-gray-400 hover:text-white transition-colors"
|
||||
>
|
||||
|
||||
@ -695,7 +695,6 @@ export default function OwnerBookingsPage() {
|
||||
>
|
||||
<OwnerBookingCalendar
|
||||
property={{ bookings }}
|
||||
onDateSelect={(date) => console.log('Date selected:', date)}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
@ -234,7 +234,6 @@ export default function AddPropertyPage() {
|
||||
getCurrencies().then((data) => {
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
setCurrencies(data);
|
||||
console.log('[AddProperty] Currencies loaded:', data);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.warn('[AddProperty] Failed to load currencies:', err);
|
||||
@ -382,7 +381,6 @@ const handleMapClick = async (coords) => {
|
||||
|
||||
const handleImageUpload = async (files) => {
|
||||
const newImages = Array.from(files);
|
||||
console.log('[AddProperty] handleImageUpload called with', newImages.length, 'files');
|
||||
|
||||
if (formData.images.length + newImages.length > 10) {
|
||||
toast.error('يمكنك رفع 10 صور كحد أقصى');
|
||||
@ -416,7 +414,6 @@ const handleMapClick = async (coords) => {
|
||||
try {
|
||||
const path = await uploadPicture(file);
|
||||
setUploadedImagePaths(prev => [...prev, path]);
|
||||
console.log('[AddProperty] Image uploaded:', path);
|
||||
} catch (err) {
|
||||
console.error('[AddProperty] Image upload failed:', err);
|
||||
toast.error('فشل رفع الصورة: ' + file.name);
|
||||
@ -675,9 +672,7 @@ const handleMapClick = async (coords) => {
|
||||
price: parseFloat(formData.salePrice) || 0,
|
||||
currencyId: selectedCurrencyId,
|
||||
};
|
||||
console.log('[AddProperty] Sale payload:', JSON.stringify(payload, null, 2));
|
||||
const res = await addSaleProperty(payload);
|
||||
console.log('[AddProperty] Sale API response:', res);
|
||||
toast.success('تم إضافة عقار للبيع بنجاح!');
|
||||
} else {
|
||||
const rentTypeMap = { daily: RentType.DAILY, monthly: RentType.MONTHLY, both: RentType.MONTHLY };
|
||||
@ -692,9 +687,7 @@ const handleMapClick = async (coords) => {
|
||||
type: formData.furnished ? RentPropertyType.FURNISHED : RentPropertyType.UNFURNISHED,
|
||||
allowedPaymentPeriod: formData.allowedPaymentPeriod || '',
|
||||
};
|
||||
console.log('[AddProperty] Rent payload:', JSON.stringify(payload, null, 2));
|
||||
const res = await addRentProperty(payload);
|
||||
console.log('[AddProperty] Rent API response:', res);
|
||||
toast.success('تم إضافة عقار للإيجار بنجاح!');
|
||||
}
|
||||
setTimeout(() => {
|
||||
|
||||
@ -1191,8 +1191,6 @@ export default function OwnerPropertiesPage() {
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("[OwnerProperties] Fetching listings for user:", userId);
|
||||
|
||||
const [rentData, saleData] = await Promise.allSettled([
|
||||
getMyRentListings(),
|
||||
getMySaleListings(),
|
||||
@ -1215,13 +1213,6 @@ export default function OwnerPropertiesPage() {
|
||||
: []
|
||||
: [];
|
||||
|
||||
console.log(
|
||||
"[OwnerProperties] Rent:",
|
||||
rentList.length,
|
||||
"Sale:",
|
||||
saleList.length,
|
||||
);
|
||||
|
||||
const normalizeServices = (details) => {
|
||||
const rawServices = details.services || {};
|
||||
const serviceList = Array.isArray(rawServices)
|
||||
|
||||
@ -459,9 +459,7 @@ export default function HomePage() {
|
||||
lng: p.location.lng,
|
||||
address: p.location.address
|
||||
}))}
|
||||
onPropertyClick={(property) => {
|
||||
console.log('Property clicked:', property);
|
||||
}}
|
||||
onPropertyClick={() => {}}
|
||||
/>
|
||||
) : (
|
||||
<div className="h-[400px] flex flex-col items-center justify-center bg-gray-50">
|
||||
|
||||
@ -105,7 +105,6 @@
|
||||
// }
|
||||
|
||||
|
||||
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
@ -118,9 +117,108 @@ const ENDPOINTS = {
|
||||
en: '/Configuration/GetENPrivacyPolicy',
|
||||
};
|
||||
|
||||
function tryParseJson(value) {
|
||||
let current = value;
|
||||
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
if (typeof current !== 'string') break;
|
||||
|
||||
const trimmed = current.trim();
|
||||
if (!trimmed) return trimmed;
|
||||
|
||||
try {
|
||||
current = JSON.parse(trimmed);
|
||||
} catch {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
function normalizeItem(item, index) {
|
||||
if (!item || typeof item !== 'object') return null;
|
||||
|
||||
const title =
|
||||
typeof item.title === 'string' ? item.title.trim() : '';
|
||||
const description =
|
||||
typeof item.description === 'string' ? item.description.trim() : '';
|
||||
|
||||
if (!title && !description) return null;
|
||||
|
||||
return {
|
||||
id: index + 1,
|
||||
title,
|
||||
description,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePolicyContent(raw) {
|
||||
const decoded = tryParseJson(raw);
|
||||
|
||||
if (Array.isArray(decoded)) {
|
||||
const items = decoded.map((item, index) => normalizeItem(item, index)).filter(Boolean);
|
||||
return {
|
||||
items,
|
||||
rawText: typeof raw === 'string' ? raw.trim() : '',
|
||||
};
|
||||
}
|
||||
|
||||
if (decoded && typeof decoded === 'object') {
|
||||
const possibleArray = Array.isArray(decoded.items)
|
||||
? decoded.items
|
||||
: Array.isArray(decoded.data)
|
||||
? decoded.data
|
||||
: null;
|
||||
|
||||
if (possibleArray) {
|
||||
const items = possibleArray.map((item, index) => normalizeItem(item, index)).filter(Boolean);
|
||||
return {
|
||||
items,
|
||||
rawText: typeof raw === 'string' ? raw.trim() : '',
|
||||
};
|
||||
}
|
||||
|
||||
const singleItem = normalizeItem(decoded, 0);
|
||||
if (singleItem) {
|
||||
return {
|
||||
items: [singleItem],
|
||||
rawText: typeof raw === 'string' ? raw.trim() : '',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof decoded === 'string') {
|
||||
const cleaned = decoded.replace(/\\r\\n/g, '\n').replace(/\\n/g, '\n').trim();
|
||||
|
||||
const matches = [...cleaned.matchAll(/"title"\s*:\s*"([^"]+)"\s*,\s*"description"\s*:\s*"([^"]+)"/g)];
|
||||
if (matches.length > 0) {
|
||||
return {
|
||||
items: matches.map((match, index) => ({
|
||||
id: index + 1,
|
||||
title: match[1].trim(),
|
||||
description: match[2].trim(),
|
||||
})),
|
||||
rawText: cleaned,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
items: [],
|
||||
rawText: cleaned,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
items: [],
|
||||
rawText: '',
|
||||
};
|
||||
}
|
||||
|
||||
export default function PrivacyPage() {
|
||||
const [language, setLanguage] = useState('ar');
|
||||
const [policyText, setPolicyText] = useState('');
|
||||
const [policyItems, setPolicyItems] = useState([]);
|
||||
const [rawPolicyText, setRawPolicyText] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
@ -146,13 +244,14 @@ export default function PrivacyPage() {
|
||||
}
|
||||
|
||||
const text = await response.text();
|
||||
const normalized = normalizePolicyContent(text);
|
||||
|
||||
console.log('API RESPONSE:', text);
|
||||
|
||||
setPolicyText(text.trim());
|
||||
setPolicyItems(normalized.items);
|
||||
setRawPolicyText(normalized.rawText);
|
||||
} catch (err) {
|
||||
if (err.name !== 'AbortError') {
|
||||
setPolicyText('');
|
||||
if (err?.name !== 'AbortError') {
|
||||
setPolicyItems([]);
|
||||
setRawPolicyText('');
|
||||
setError(
|
||||
language === 'ar'
|
||||
? 'تعذر تحميل النص من الخادم.'
|
||||
@ -207,9 +306,37 @@ export default function PrivacyPage() {
|
||||
)}
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-6 shadow-sm">
|
||||
<div className="whitespace-pre-wrap leading-8 text-gray-800">
|
||||
{policyText}
|
||||
{policyItems.length > 0 ? (
|
||||
<div className="space-y-4">
|
||||
{policyItems.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="rounded-2xl border border-gray-200 bg-gray-50 p-5"
|
||||
>
|
||||
{item.title && (
|
||||
<div className="mb-3 flex items-start gap-3">
|
||||
<div className="mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-amber-100 text-sm font-bold text-amber-700">
|
||||
{item.id}
|
||||
</div>
|
||||
<h3 className="text-base font-bold text-gray-900">
|
||||
{item.title}
|
||||
</h3>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{item.description && (
|
||||
<p className="text-sm leading-8 text-gray-700 whitespace-pre-wrap">
|
||||
{item.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="whitespace-pre-wrap leading-8 text-gray-800">
|
||||
{rawPolicyText}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -616,10 +616,9 @@
|
||||
|
||||
|
||||
// app/register/tenant/page.js
|
||||
|
||||
'use client';
|
||||
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
@ -697,7 +696,6 @@ export default function TenantRegisterPage() {
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
console.log('[CustomerRegister] Submitting customer registration...');
|
||||
|
||||
const payload = {
|
||||
firstName: formData.firstName,
|
||||
@ -714,7 +712,6 @@ export default function TenantRegisterPage() {
|
||||
try {
|
||||
// لا توجد صور للمستأجر
|
||||
const res = await addCustomer(payload, null, null);
|
||||
console.log('[CustomerRegister] addCustomer response:', res);
|
||||
|
||||
if (res.status === 200 || res.ok) {
|
||||
const tempToken = res.data;
|
||||
|
||||
@ -252,9 +252,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
@ -371,7 +368,6 @@ export default function SettingsPage() {
|
||||
throw new Error(responseText || `فشل إرسال البلاغ (HTTP ${res.status})`);
|
||||
}
|
||||
|
||||
console.log('Send report success:', responseText);
|
||||
toast.success(responseText || 'تم إرسال البلاغ بنجاح');
|
||||
setShowReportDialog(false);
|
||||
setReportSubject('');
|
||||
|
||||
Reference in New Issue
Block a user