diff --git a/app/i18n/config.js b/app/i18n/config.js index 852e335..fc1dbc4 100644 --- a/app/i18n/config.js +++ b/app/i18n/config.js @@ -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 ─── */ diff --git a/app/owner/properties/add/page.js b/app/owner/properties/add/page.js index 341602a..357b4d3 100644 --- a/app/owner/properties/add/page.js +++ b/app/owner/properties/add/page.js @@ -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) => {
+ {isUploadingImages && ( +
+ + {t('addProperty.uploadingImagesMessage') || 'جاري رفع الصور... يرجى الانتظار'} +
+ )}
{

{t('addProperty.locationAndImagesSubtitle')}

-
+
@@ -1782,7 +1829,7 @@ const handleMarkerDragEnd = async (lat, lng) => {