Edit owner
All checks were successful
Build frontend / build (push) Successful in 1m9s

This commit is contained in:
Rahaf
2026-07-15 20:03:38 +03:00
parent 038df6397d
commit 747e42dc00
2 changed files with 53 additions and 4 deletions

View File

@ -1239,6 +1239,7 @@ const resources = {
"addProperty.monthlyPriceRequired": "Monthly price is required",
"addProperty.minImagesRequired": "At least 2 images required",
"addProperty.maxImagesError": "Maximum 5 images allowed",
"addProperty.uploadingImagesMessage": "Uploading images, please wait...",
"addProperty.dailyAndMonthly": "Daily & Monthly Rent",
/* ─── Toast Messages ─── */
@ -2900,6 +2901,7 @@ const resources = {
"addProperty.monthlyPriceRequired": "السعر الشهري مطلوب",
"addProperty.minImagesRequired": "يجب رفع صورتين على الأقل",
"addProperty.maxImagesError": "يمكن رفع 5 صور كحد أقصى",
"addProperty.uploadingImagesMessage": "جاري رفع الصور، يرجى الانتظار...",
"addProperty.dailyAndMonthly": "إيجار يومي وشهري",
/* ─── Toast Messages ─── */

View File

@ -174,6 +174,7 @@ export default function AddPropertyPage() {
const [errors, setErrors] = useState({});
const [isLoading, setIsLoading] = useState(false);
const [isUploadingImages, setIsUploadingImages] = useState(false);
const [agreeToTerms, setAgreeToTerms] = useState(false);
const fileInputRef = useRef(null);
@ -602,11 +603,51 @@ const handleMarkerDragEnd = async (lat, lng) => {
window.scrollTo({ top: 0, behavior: 'smooth' });
};
const ensureImagesUploaded = async () => {
if (formData.images.length === 0) {
return [];
}
setIsUploadingImages(true);
const finalPaths = [];
for (let index = 0; index < formData.images.length; index += 1) {
const file = formData.images[index];
const existingPath = uploadedImagePaths[index];
if (existingPath) {
finalPaths.push(existingPath);
continue;
}
try {
const path = await uploadPicture(file);
finalPaths.push(path);
} catch (err) {
console.error('[AddProperty] Image upload failed:', err);
toast.error(`${t('toast.imageUploadFailed')}: ${file.name}`);
setIsUploadingImages(false);
return [];
}
}
setUploadedImagePaths(finalPaths);
setIsUploadingImages(false);
return finalPaths;
};
const handleSubmit = async () => {
if (!validateStep()) return;
setIsLoading(true);
const finalImagePaths = await ensureImagesUploaded();
if (finalImagePaths.length < 2) {
toast.error(t('addProperty.minImagesRequired'));
setIsLoading(false);
return;
}
// Map UI property type to API BuildingType enum
const buildingTypeMap = { apartment: BuildingType.APARTMENT, villa: BuildingType.VILLA, sweet: BuildingType.SWEET, suite: BuildingType.SWEET, room: BuildingType.ROOM, studio: BuildingType.STUDIO, office: BuildingType.OFFICE, farms: BuildingType.FARMS, shop: BuildingType.SHOP, warehouse: BuildingType.WAREHOUSE };
@ -670,14 +711,14 @@ const handleMarkerDragEnd = async (lat, lng) => {
const propInfo = {
cordsX: formData.lat ? String(formData.lat) : '',
cordsY: formData.lng ? String(formData.lng) : '',
images: uploadedImagePaths,
images: finalImagePaths,
address: `${formData.city} - ${formData.district} - ${formData.address}`.trim(),
description: formData.description || '',
numberOfBathRooms: formData.bathrooms || 0,
numberOfRooms: formData.bedrooms || 0,
numberOfBedRooms: formData.bedrooms || 0,
space: parseFloat(formData.space) || 0,
detailsJSON,
detailsJSON: detailsJSON || '{}',
buildingType: buildingTypeMap[formData.propertyType] ?? BuildingType.APARTMENT,
status: 0,
propertyType: formData.furnished ? RentPropertyCondition.WITH_FURNITURE : RentPropertyCondition.WITHOUT_FURNITURE,
@ -738,6 +779,12 @@ const handleMarkerDragEnd = async (lat, lng) => {
<Toaster position="top-center" reverseOrder={false} />
<div className="container mx-auto px-4 max-w-4xl">
{isUploadingImages && (
<div className="mb-4 rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800 flex items-center justify-center gap-2">
<Loader2 className="w-4 h-4 animate-spin" />
<span>{t('addProperty.uploadingImagesMessage') || 'جاري رفع الصور... يرجى الانتظار'}</span>
</div>
)}
<div className="mb-8">
<div className="flex items-center justify-between mb-4">
<Link
@ -1561,7 +1608,7 @@ const handleMarkerDragEnd = async (lat, lng) => {
<p className="text-gray-600">{t('addProperty.locationAndImagesSubtitle')}</p>
</div>
<div className="rounded-3xl border border-amber-100 bg-gradient-to-br from-amber-50 via-white to-orange-50 p-4 sm:p-5 md:p-6 shadow-sm">
<div className="rounded-3xl border border-amber-100 bg-linear-to-br from-amber-50 via-white to-orange-50 p-4 sm:p-5 md:p-6 shadow-sm">
<div className="flex flex-col gap-3 md:flex-row md:items-start md:justify-between mb-5">
<div>
<div className="flex items-center gap-2 text-amber-700 font-semibold mb-1">
@ -1782,7 +1829,7 @@ const handleMarkerDragEnd = async (lat, lng) => {
<button
onClick={handleSubmit}
disabled={isLoading || !agreeToTerms}
className="flex-1 py-3 px-4 bg-gradient-to-r from-amber-500 to-amber-600 text-white rounded-xl font-medium hover:from-amber-600 hover:to-amber-700 transition-all disabled:opacity-50 flex items-center justify-center gap-2"
className="flex-1 py-3 px-4 bg-linear-to-r from-amber-500 to-amber-600 text-white rounded-xl font-medium hover:from-amber-600 hover:to-amber-700 transition-all disabled:opacity-50 flex items-center justify-center gap-2"
>
{isLoading ? (
<>