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) => {
{t('addProperty.locationAndImagesSubtitle')}