This commit is contained in:
@ -5,8 +5,6 @@ import { usePathname } from "next/navigation";
|
|||||||
import { Home, Building2, Building, CalendarCheck, CalendarDays, ClipboardList, CreditCard, BookOpenCheck } from "lucide-react";
|
import { Home, Building2, Building, CalendarCheck, CalendarDays, ClipboardList, CreditCard, BookOpenCheck } from "lucide-react";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { label } from "framer-motion/client";
|
|
||||||
|
|
||||||
export default function BottomNav({ isOwner, isOwnerOrAgent }) {
|
export default function BottomNav({ isOwner, isOwnerOrAgent }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
@ -52,7 +50,13 @@ export default function BottomNav({ isOwner, isOwnerOrAgent }) {
|
|||||||
pointer-events-auto
|
pointer-events-auto
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-center gap-0.5 sm:gap-1 overflow-hidden ">
|
<div
|
||||||
|
className="flex items-center sm:justify-center gap-0.5 sm:gap-1 overflow-x-auto max-w-full
|
||||||
|
[&::-webkit-scrollbar]:h-1.5
|
||||||
|
[&::-webkit-scrollbar-track]:bg-gray-100
|
||||||
|
[&::-webkit-scrollbar-thumb]:bg-gray-700
|
||||||
|
[&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-gray-700"
|
||||||
|
>
|
||||||
{items.map((it) => {
|
{items.map((it) => {
|
||||||
const Icon = it.icon;
|
const Icon = it.icon;
|
||||||
const active = isActive(it.href);
|
const active = isActive(it.href);
|
||||||
|
|||||||
@ -28,8 +28,6 @@ export default function OtpComponent({ isLoading, setIsLoading, isSuccess, setIs
|
|||||||
if (result?.ok) {
|
if (result?.ok) {
|
||||||
try {
|
try {
|
||||||
await AuthService.cacheCurrentUser(getOwnerByUserId, getCustomerByUserId);
|
await AuthService.cacheCurrentUser(getOwnerByUserId, getCustomerByUserId);
|
||||||
console.log("Decoded:", AuthService.decodeToken());
|
|
||||||
console.log("User:", AuthService.getUser());
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn("Failed to cache user", err);
|
console.warn("Failed to cache user", err);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ const resources = {
|
|||||||
en: {
|
en: {
|
||||||
translation: {
|
translation: {
|
||||||
/*Block*/
|
/*Block*/
|
||||||
|
|
||||||
subject: "Subject",
|
subject: "Subject",
|
||||||
"blocked.fillAllFields": "Please fill in all required fields",
|
"blocked.fillAllFields": "Please fill in all required fields",
|
||||||
"blocked.reportSent": "Message sent successfully",
|
"blocked.reportSent": "Message sent successfully",
|
||||||
@ -1661,13 +1660,15 @@ const resources = {
|
|||||||
"calendar.mockTenant2": "Sara Ahmed",
|
"calendar.mockTenant2": "Sara Ahmed",
|
||||||
"calendar.mockTenant3": "Mohammed Ali",
|
"calendar.mockTenant3": "Mohammed Ali",
|
||||||
"loading":"Loading",
|
"loading":"Loading",
|
||||||
"neaebymosque":"Distance to nearest mosque (km)"
|
"neaebymosque":"Distance to nearest mosque (km)",
|
||||||
|
"commission":"Commission",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ar: {
|
ar: {
|
||||||
translation: {
|
translation: {
|
||||||
"loading":"جار التحميل",
|
"loading":"جار التحميل",
|
||||||
"neaebymosque":"المسافة الى اقرب جامع",
|
"neaebymosque":"المسافة الى اقرب جامع",
|
||||||
|
"commission":"كمسيون",
|
||||||
/* Block*/
|
/* Block*/
|
||||||
"blocked.fillAllFields": "يرجى تعبئة جميع الحقول المطلوبة",
|
"blocked.fillAllFields": "يرجى تعبئة جميع الحقول المطلوبة",
|
||||||
"blocked.reportSent": "تم إرسال الرسالة بنجاح",
|
"blocked.reportSent": "تم إرسال الرسالة بنجاح",
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
export default function Loading() {
|
export default function Loading() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex items-center justify-center p-4" style={{ backgroundColor: "#08172f" }}>
|
<div className="min-h-screen flex items-center justify-center p-4" style={{ backgroundColor: "#0f172a" }}>
|
||||||
<motion.div initial={{ opacity: 0, scale: 0.9 }} animate={{ opacity: 1, scale: 1.3 }} transition={{ duration: 0.4 }} className="text-center flex flex-col items-center justify-center gap-4">
|
<motion.div initial={{ opacity: 0, scale: 0.9 }} animate={{ opacity: 1, scale: 1.3 }} transition={{ duration: 0.4 }} className="text-center flex flex-col items-center justify-center gap-4">
|
||||||
<motion.div
|
<motion.div
|
||||||
animate={{
|
animate={{
|
||||||
scale: [1, 1.06, 1],
|
scale: [1, 1.06, 1],
|
||||||
@ -18,19 +18,19 @@ export default function Loading() {
|
|||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
ease: "easeInOut",
|
ease: "easeInOut",
|
||||||
}}
|
}}
|
||||||
className="relative w-36 h-36 flex items-center justify-center"
|
className="relative w-25 h-36 flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<svg viewBox="0 0 100 100" className="w-full h-full fill-amber-500/10 stroke-amber-500 stroke-[3] drop-shadow-[0_0_12px_rgba(245,158,11,0.2)]" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 100 100" className="w-full h-full fill-amber-500/10 stroke-amber-500 stroke-[4] drop-shadow-[0_0_12px_rgba(245,158,11,0.2)] " xmlns="http://www.w3.org/2000/svg">
|
||||||
<polygon points="50,5 95,27.5 95,72.5 50,95 5,72.5 5,27.5" />
|
<polygon points="50,5 95,27.5 95,72.5 50,95 5,72.5 5,27.5" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<div className="absolute inset-0 flex items-center justify-center p-2 text-center">
|
<div className="absolute inset-0 flex items-center justify-center p-2 text-center">
|
||||||
<span className="text-amber-400 font-bold text-sm tracking-wide select-none">Sweet Home</span>
|
<span className="text-amber-400 font-bold text-[10px] tracking-wide select-none">Sweet Home</span>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
<p className="text-amber-400 text-sm font-bold tracking-wide animate-pulse" suppressHydrationWarning>
|
<p className="text-amber-400 text-sm font-bold tracking-wide animate-pulse" suppressHydrationWarning>
|
||||||
... {t("loading")}
|
{t("loading")}
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -123,6 +123,7 @@ export default function AddPropertyPage() {
|
|||||||
dailyPrice: "",
|
dailyPrice: "",
|
||||||
monthlyPrice: "",
|
monthlyPrice: "",
|
||||||
deposit: "",
|
deposit: "",
|
||||||
|
commission: "",
|
||||||
allowedPaymentPeriod: "",
|
allowedPaymentPeriod: "",
|
||||||
|
|
||||||
city: Governorate.DAMASCUS,
|
city: Governorate.DAMASCUS,
|
||||||
@ -562,6 +563,7 @@ export default function AddPropertyPage() {
|
|||||||
} else if (formData.offerType === "both") {
|
} else if (formData.offerType === "both") {
|
||||||
if (!formData.dailyPrice) newErrors.dailyPrice = t("addProperty.dailyPriceRequired");
|
if (!formData.dailyPrice) newErrors.dailyPrice = t("addProperty.dailyPriceRequired");
|
||||||
if (!formData.monthlyPrice) newErrors.monthlyPrice = t("addProperty.monthlyPriceRequired");
|
if (!formData.monthlyPrice) newErrors.monthlyPrice = t("addProperty.monthlyPriceRequired");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -681,6 +683,7 @@ export default function AddPropertyPage() {
|
|||||||
const isRent = purpose === "rent";
|
const isRent = purpose === "rent";
|
||||||
const details = {
|
const details = {
|
||||||
description: formData.description || "",
|
description: formData.description || "",
|
||||||
|
commission: parseFloat(formData.commission) || 0,
|
||||||
services: selectedServices,
|
services: selectedServices,
|
||||||
serviceDetails: selectedServices.reduce((acc, s) => ({ ...acc, [s]: formData.serviceDetails[s] || "in general" }), {}),
|
serviceDetails: selectedServices.reduce((acc, s) => ({ ...acc, [s]: formData.serviceDetails[s] || "in general" }), {}),
|
||||||
propertyCondition: formData.furnished ? "WithFurniture" : "WithoutFurniture",
|
propertyCondition: formData.furnished ? "WithFurniture" : "WithoutFurniture",
|
||||||
@ -753,9 +756,9 @@ export default function AddPropertyPage() {
|
|||||||
price: parseFloat(formData.salePrice),
|
price: parseFloat(formData.salePrice),
|
||||||
deposit: parseFloat(formData.deposit) || 0,
|
deposit: parseFloat(formData.deposit) || 0,
|
||||||
};
|
};
|
||||||
console.log("ff", payload);
|
|
||||||
const res = await addSaleProperty(payload);
|
const res = await addSaleProperty(payload);
|
||||||
console.log(res);
|
|
||||||
toast.success(t("toast.salePropertySuccess"));
|
toast.success(t("toast.salePropertySuccess"));
|
||||||
} else {
|
} else {
|
||||||
const rentTypeMap = { daily: RentType.DAILY, monthly: RentType.MONTHLY, both: RentType.MONTHLY };
|
const rentTypeMap = { daily: RentType.DAILY, monthly: RentType.MONTHLY, both: RentType.MONTHLY };
|
||||||
@ -773,7 +776,9 @@ export default function AddPropertyPage() {
|
|||||||
type: formData.furnished ? RentPropertyType.FURNISHED : RentPropertyType.UNFURNISHED,
|
type: formData.furnished ? RentPropertyType.FURNISHED : RentPropertyType.UNFURNISHED,
|
||||||
allowedPaymentPeriod: formData.allowedPaymentPeriod || "1.00:00:00",
|
allowedPaymentPeriod: formData.allowedPaymentPeriod || "1.00:00:00",
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await addRentProperty(payload);
|
const res = await addRentProperty(payload);
|
||||||
|
|
||||||
toast.success(t("toast.rentPropertySuccess"));
|
toast.success(t("toast.rentPropertySuccess"));
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -1221,7 +1226,7 @@ export default function AddPropertyPage() {
|
|||||||
{step === 3 && purpose === "sale" && (
|
{step === 3 && purpose === "sale" && (
|
||||||
<motion.div variants={fadeInUp} className="space-y-8">
|
<motion.div variants={fadeInUp} className="space-y-8">
|
||||||
<div className="text-center mb-6">
|
<div className="text-center mb-6">
|
||||||
<div className="w-20 h-20 bg-amber-500 rounded-2xl flex items-center justify-center mx-auto mb-4">
|
<div className="w-20 h-20 bg-amber-400 rounded-2xl flex items-center justify-center mx-auto mb-4">
|
||||||
<DollarSign className="w-10 h-10 text-amber-600" />
|
<DollarSign className="w-10 h-10 text-amber-600" />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-2">{t("addProperty.salePriceTitle")}</h2>
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">{t("addProperty.salePriceTitle")}</h2>
|
||||||
@ -1251,6 +1256,33 @@ export default function AddPropertyPage() {
|
|||||||
placeholder={t("addProperty.salePricePlaceholder")}
|
placeholder={t("addProperty.salePricePlaceholder")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-3">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
{t("commission")} ({currencySymbol})
|
||||||
|
</label>
|
||||||
|
<div className="relative ">
|
||||||
|
<span className="absolute right-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400 font-bold text-sm flex items-center justify-center">{currencySymbol}</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
value={formData.commission || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const val = e.target.value;
|
||||||
|
|
||||||
|
if (val === "" || parseFloat(val) >= 0) {
|
||||||
|
setFormData({ ...formData, commission: val });
|
||||||
|
}
|
||||||
|
(formData.commission);
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (["-", "e", "E", "+"].includes(e.key)) e.preventDefault();
|
||||||
|
}}
|
||||||
|
className="w-full pr-12 pl-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500"
|
||||||
|
placeholder={t("addProperty.depositPlaceholder")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{errors.salePrice && <p className="text-red-500 text-sm mt-1">{errors.salePrice}</p>}
|
{errors.salePrice && <p className="text-red-500 text-sm mt-1">{errors.salePrice}</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1378,6 +1410,33 @@ export default function AddPropertyPage() {
|
|||||||
placeholder={t("addProperty.depositPlaceholder")}
|
placeholder={t("addProperty.depositPlaceholder")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* كمسيون */}
|
||||||
|
<div className="mt-3">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
{t("commission")} ({currencySymbol})
|
||||||
|
</label>
|
||||||
|
<div className="relative ">
|
||||||
|
<span className="absolute right-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400 font-bold text-sm flex items-center justify-center">{currencySymbol}</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
value={formData.commission || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const val = e.target.value;
|
||||||
|
if (val === "" || parseFloat(val) >= 0) {
|
||||||
|
setFormData({ ...formData, commission: val });
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (["-", "e", "E", "+"].includes(e.key)) e.preventDefault();
|
||||||
|
}}
|
||||||
|
className="w-full pr-12 pl-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500"
|
||||||
|
placeholder={t("addProperty.depositPlaceholder")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
@ -1433,6 +1492,30 @@ export default function AddPropertyPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-3">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
{t("commission")} ({currencySymbol})
|
||||||
|
</label>
|
||||||
|
<div className="relative ">
|
||||||
|
<span className="absolute right-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400 font-bold text-sm flex items-center justify-center">{currencySymbol}</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
value={formData.commission || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const val = e.target.value;
|
||||||
|
if (val === "" || parseFloat(val) >= 0) {
|
||||||
|
setFormData({ ...formData, commission: val });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (["-", "e", "E", "+"].includes(e.key)) e.preventDefault();
|
||||||
|
}}
|
||||||
|
className="w-full pr-12 pl-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500"
|
||||||
|
placeholder={t("addProperty.depositPlaceholder")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -1512,6 +1595,30 @@ export default function AddPropertyPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-3">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
{t("commission")} ({currencySymbol})
|
||||||
|
</label>
|
||||||
|
<div className="relative ">
|
||||||
|
<span className="absolute right-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400 font-bold text-sm flex items-center justify-center">{currencySymbol}</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
value={formData.commission || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const val = e.target.value;
|
||||||
|
if (val === "" || parseFloat(val) >= 0) {
|
||||||
|
setFormData({ ...formData, commission: val });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (["-", "e", "E", "+"].includes(e.key)) e.preventDefault();
|
||||||
|
}}
|
||||||
|
className="w-full pr-12 pl-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500"
|
||||||
|
placeholder={t("addProperty.depositPlaceholder")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|||||||
@ -111,7 +111,6 @@ const PropertyCard = ({ property, viewMode = "grid", onLoginRequired, type = "re
|
|||||||
const [favLoading, setFavLoading] = useState(false);
|
const [favLoading, setFavLoading] = useState(false);
|
||||||
const [currentImage, setCurrentImage] = useState(0);
|
const [currentImage, setCurrentImage] = useState(0);
|
||||||
const isFav = checkFavorite(property.id);
|
const isFav = checkFavorite(property.id);
|
||||||
|
|
||||||
const toggleFavorite = async (e) => {
|
const toggleFavorite = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@ -159,6 +159,7 @@ function mapApiDetail(item) {
|
|||||||
const dailyPrice = item.dailyRent || 0;
|
const dailyPrice = item.dailyRent || 0;
|
||||||
const monthlyPrice = item.monthlyRent || 0;
|
const monthlyPrice = item.monthlyRent || 0;
|
||||||
const salePrice = item.price || 0;
|
const salePrice = item.price || 0;
|
||||||
|
const commission = item.commission || 0;
|
||||||
const price = isRent ? monthlyPrice || dailyPrice : salePrice;
|
const price = isRent ? monthlyPrice || dailyPrice : salePrice;
|
||||||
const priceUnit = isRent ? (monthlyPrice ? "monthly" : "daily") : "sale";
|
const priceUnit = isRent ? (monthlyPrice ? "monthly" : "daily") : "sale";
|
||||||
|
|
||||||
@ -244,7 +245,7 @@ function mapApiDetail(item) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PropertyDetailsPage({type}) {
|
export default function PropertyDetailsPage({ type }) {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|
||||||
@ -272,7 +273,7 @@ export default function PropertyDetailsPage({type}) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const id = params.id;
|
const id = params.id;
|
||||||
|
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
@ -280,7 +281,7 @@ export default function PropertyDetailsPage({type}) {
|
|||||||
try {
|
try {
|
||||||
let data = null;
|
let data = null;
|
||||||
try {
|
try {
|
||||||
data = type==="rent"?await getRentProperty(id):(await getSalePropertyById(id)) || (await getSaleProperty(id));
|
data = type === "rent" ? await getRentProperty(id) : (await getSalePropertyById(id)) || (await getSaleProperty(id));
|
||||||
} catch {}
|
} catch {}
|
||||||
if (!data) {
|
if (!data) {
|
||||||
try {
|
try {
|
||||||
@ -427,6 +428,7 @@ export default function PropertyDetailsPage({type}) {
|
|||||||
}
|
}
|
||||||
setBookingLoading(true);
|
setBookingLoading(true);
|
||||||
setBookingError(null);
|
setBookingError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const propInfoId = property._raw?.propertyInformationId || property.id;
|
const propInfoId = property._raw?.propertyInformationId || property.id;
|
||||||
const startDate = new Date(selectedStart + "T00:00:00.000").toISOString();
|
const startDate = new Date(selectedStart + "T00:00:00.000").toISOString();
|
||||||
@ -528,8 +530,8 @@ export default function PropertyDetailsPage({type}) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="absolute bottom-4 right-4 flex gap-2 z-10">
|
<div className="absolute bottom-4 right-4 flex gap-2 z-10">
|
||||||
<span className="bg-black/70 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">{t("propertyStatus." + property.statusLabel)}</span>
|
<span className="bg-gray-100 text-black px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">{t("propertyStatus." + property.statusLabel)}</span>
|
||||||
<span className="bg-black/70 text-white px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">{t("buildingType." + property.typeLabel)}</span>
|
<span className="bg-gray-100 text-black px-3 py-1 rounded-full text-sm font-medium backdrop-blur-sm">{t("buildingType." + property.typeLabel)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute bottom-4 left-4 bg-black/70 text-white px-3 py-1 rounded-full text-xs backdrop-blur-sm z-10">
|
<div className="absolute bottom-4 left-4 bg-black/70 text-white px-3 py-1 rounded-full text-xs backdrop-blur-sm z-10">
|
||||||
{currentImage + 1} / {property.images.length || 1}
|
{currentImage + 1} / {property.images.length || 1}
|
||||||
@ -607,13 +609,27 @@ export default function PropertyDetailsPage({type}) {
|
|||||||
<span className="font-medium">{t("depositLabel")}</span> {formatCurrency(property.deposit)} {t("syp")}
|
<span className="font-medium">{t("depositLabel")}</span> {formatCurrency(property.deposit)} {t("syp")}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{property.details.commission > 0 && (
|
||||||
|
<div className="text-sm text-gray-500">
|
||||||
|
<span className="font-medium">{t("commission")}</span> {formatCurrency(property.details.commission)} {t("syp")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<>
|
||||||
<span className="text-2xl font-bold text-blue-600">{formatCurrency(property.price)}</span>
|
<div>
|
||||||
<span className="text-gray-500 mr-1">{t("syp")}</span>
|
<span className="text-2xl font-bold text-blue-600">{formatCurrency(property.price)}</span>
|
||||||
<span className="text-sm text-gray-400 mr-2">{t("forSale")}</span>
|
<span className="text-gray-500 mr-1">{t("syp")}</span>
|
||||||
</div>
|
<span className="text-sm text-gray-400 mr-2">{t("forSale")}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="text-2xl font-bold text-blue-600">{formatCurrency(property.details.commission)}</span>
|
||||||
|
<span className="text-gray-500 mr-1">{t("syp")}</span>
|
||||||
|
<span className="text-sm text-gray-400 mr-2">{t("commission")}</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -865,7 +881,7 @@ export default function PropertyDetailsPage({type}) {
|
|||||||
{key === "University" && <GraduationCap className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />}
|
{key === "University" && <GraduationCap className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />}
|
||||||
{key === "Park" && <TreePine className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />}
|
{key === "Park" && <TreePine className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />}
|
||||||
{key === "Mall" && <Building className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />}
|
{key === "Mall" && <Building className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />}
|
||||||
{!["School", "Hospital", "Restaurant", "University", "Park", "Mall","Mosque"].includes(key) && <MapPin className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />}
|
{!["School", "Hospital", "Restaurant", "University", "Park", "Mall", "Mosque"].includes(key) && <MapPin className="w-3.5 h-3.5 text-amber-500 flex-shrink-0" />}
|
||||||
<div>
|
<div>
|
||||||
<div className="text-xs font-medium text-gray-900">{t(proxKey(key))}</div>
|
<div className="text-xs font-medium text-gray-900">{t(proxKey(key))}</div>
|
||||||
<div className="text-[10px] text-gray-500">
|
<div className="text-[10px] text-gray-500">
|
||||||
@ -1049,7 +1065,6 @@ export default function PropertyDetailsPage({type}) {
|
|||||||
)}
|
)}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -82,7 +82,7 @@ export async function generateMetadata({ params, searchParams }) {
|
|||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
const { type } = await searchParams;
|
const { type } = await searchParams;
|
||||||
|
|
||||||
console.log("Property type:", type);
|
|
||||||
|
|
||||||
const raw = await fetchPropertyForMeta(id, type);
|
const raw = await fetchPropertyForMeta(id, type);
|
||||||
|
|
||||||
|
|||||||
@ -68,7 +68,6 @@ export default function TenantRegisterPage() {
|
|||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const res = await addCustomer(payload, null, null);
|
const res = await addCustomer(payload, null, null);
|
||||||
console.log(res);
|
|
||||||
if (res.status === 200 || res.ok) {
|
if (res.status === 200 || res.ok) {
|
||||||
const apiMessage = res.message || res.data?.message || res.data[0]?.message;
|
const apiMessage = res.message || res.data?.message || res.data[0]?.message;
|
||||||
toast.success(apiMessage || t("register.accountCreated"), { duration: 4000 });
|
toast.success(apiMessage || t("register.accountCreated"), { duration: 4000 });
|
||||||
|
|||||||
Reference in New Issue
Block a user