Display property images from API using full URLs
All checks were successful
Build frontend / build (push) Successful in 1m3s
All checks were successful
Build frontend / build (push) Successful in 1m3s
- All mappers extract images from propertyInformation.images - Paths prefixed with API base URL (http://45.93.137.91/api) - Falls back to placeholder if no images - Updated: main page, properties listing, property detail, owner properties
This commit is contained in:
@ -99,22 +99,21 @@ export default function AddPropertyPage() {
|
|||||||
livingRooms: 1,
|
livingRooms: 1,
|
||||||
|
|
||||||
services: {
|
services: {
|
||||||
electricity: false,
|
[PropertyService.ELECTRICITY]: false,
|
||||||
internet: false,
|
[PropertyService.INTERNET]: false,
|
||||||
heating: false,
|
[PropertyService.HEATING]: false,
|
||||||
water: false,
|
[PropertyService.WATER]: false,
|
||||||
airConditioning: false,
|
[PropertyService.CENTRAL_AIR_CONDITIONING]: false,
|
||||||
parking: false,
|
[PropertyService.PARKING]: false,
|
||||||
elevator: false
|
[PropertyService.ELEVATOR]: false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
serviceDetails: {},
|
||||||
|
|
||||||
terms: {
|
terms: {
|
||||||
noSmoking: false,
|
[PropertyTerm.NO_SMOKING]: false,
|
||||||
noPets: false,
|
[PropertyTerm.NO_ANIMALS]: false,
|
||||||
noParties: false,
|
[PropertyTerm.NO_PARTIES]: false
|
||||||
noAlcohol: false,
|
|
||||||
suitableForChildren: true,
|
|
||||||
suitableForElderly: true
|
|
||||||
},
|
},
|
||||||
|
|
||||||
offerType: 'daily',
|
offerType: 'daily',
|
||||||
@ -831,34 +830,37 @@ const handleMapClick = async (coords) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-bold text-gray-900 mb-4">الخدمات المتوفرة</h3>
|
<h3 className="text-lg font-bold text-gray-900 mb-4">الخدمات المتوفرة <span className="text-red-500">*</span></h3>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
<div className="space-y-3">
|
||||||
{serviceList.map((service) => {
|
{serviceList.map((service) => {
|
||||||
const Icon = service.icon;
|
const Icon = service.icon;
|
||||||
|
const isSelected = formData.services[service.id];
|
||||||
return (
|
return (
|
||||||
<label
|
<div key={service.id} className={`border rounded-xl transition-all ${isSelected ? 'border-amber-500 bg-amber-50' : 'border-gray-200'}`}>
|
||||||
key={service.id}
|
<label className="flex items-center gap-3 p-3 cursor-pointer">
|
||||||
className={`flex items-center gap-2 p-3 border rounded-xl cursor-pointer transition-all ${
|
|
||||||
formData.services[service.id]
|
|
||||||
? 'border-amber-500 bg-amber-50'
|
|
||||||
: 'border-gray-200 hover:border-amber-200 hover:bg-amber-50/50'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={formData.services[service.id]}
|
checked={isSelected}
|
||||||
onChange={() => toggleService(service.id)}
|
onChange={() => toggleService(service.id)}
|
||||||
className="hidden"
|
className="w-4 h-4 text-amber-500 rounded"
|
||||||
/>
|
/>
|
||||||
<Icon className={`w-5 h-5 ${
|
<Icon className={`w-5 h-5 ${isSelected ? 'text-amber-600' : 'text-gray-400'}`} />
|
||||||
formData.services[service.id] ? 'text-amber-600' : 'text-gray-400'
|
<span className={`text-sm font-medium ${isSelected ? 'text-amber-700' : 'text-gray-600'}`}>
|
||||||
}`} />
|
|
||||||
<span className={`text-sm ${
|
|
||||||
formData.services[service.id] ? 'text-amber-700' : 'text-gray-600'
|
|
||||||
}`}>
|
|
||||||
{service.label}
|
{service.label}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
{isSelected && (
|
||||||
|
<div className="px-3 pb-3">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={formData.serviceDetails[service.id] || ''}
|
||||||
|
onChange={(e) => updateServiceDetail(service.id, e.target.value)}
|
||||||
|
className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-amber-500"
|
||||||
|
placeholder="تفاصيل الخدمة (مثال: في جميع الغرف)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -746,7 +746,11 @@ export default function OwnerPropertiesPage() {
|
|||||||
area: info.space || 0,
|
area: info.space || 0,
|
||||||
livingRooms: details.livingRooms || 0,
|
livingRooms: details.livingRooms || 0,
|
||||||
status: { 0: 'available', 1: 'booked', 2: 'maintenance' }[info.status] || 'available',
|
status: { 0: 'available', 1: 'booked', 2: 'maintenance' }[info.status] || 'available',
|
||||||
images: ['/property-placeholder.jpg'],
|
images: (() => {
|
||||||
|
const apiBase = typeof window !== 'undefined' ? (process.env.NEXT_PUBLIC_API_URL || 'http://45.93.137.91/api') : '';
|
||||||
|
const raw = Array.isArray(info.images) ? info.images : [];
|
||||||
|
return raw.length > 0 ? raw.map(img => img.startsWith('http') ? img : `${apiBase}${img}`) : ['/property-placeholder.jpg'];
|
||||||
|
})(),
|
||||||
createdAt: item.createdAt || new Date().toISOString(),
|
createdAt: item.createdAt || new Date().toISOString(),
|
||||||
furnished: details.furnished || false,
|
furnished: details.furnished || false,
|
||||||
description: info.description || '',
|
description: info.description || '',
|
||||||
|
|||||||
@ -51,6 +51,13 @@ function mapApiProperty(item, index) {
|
|||||||
if (info.numberOfBedRooms) features.push(`${info.numberOfBedRooms} غرف نوم`);
|
if (info.numberOfBedRooms) features.push(`${info.numberOfBedRooms} غرف نوم`);
|
||||||
if (info.numberOfBathRooms) features.push(`${info.numberOfBathRooms} حمامات`);
|
if (info.numberOfBathRooms) features.push(`${info.numberOfBathRooms} حمامات`);
|
||||||
|
|
||||||
|
// Extract images from API and build full URLs
|
||||||
|
const apiBase = typeof window !== 'undefined' ? (process.env.NEXT_PUBLIC_API_URL || 'http://45.93.137.91/api') : '';
|
||||||
|
const rawImages = Array.isArray(info.images) ? info.images : [];
|
||||||
|
const images = rawImages.length > 0
|
||||||
|
? rawImages.map(img => img.startsWith('http') ? img : `${apiBase}${img}`)
|
||||||
|
: ['/property-placeholder.jpg'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: item.id ?? index + 1,
|
id: item.id ?? index + 1,
|
||||||
title: info.address || `عقار #${item.id || index + 1}`,
|
title: info.address || `عقار #${item.id || index + 1}`,
|
||||||
@ -70,7 +77,7 @@ function mapApiProperty(item, index) {
|
|||||||
bathrooms: info.numberOfBathRooms || 0,
|
bathrooms: info.numberOfBathRooms || 0,
|
||||||
area: info.space || 0,
|
area: info.space || 0,
|
||||||
features,
|
features,
|
||||||
images: ['/property-placeholder.jpg'],
|
images,
|
||||||
status,
|
status,
|
||||||
rating: item.rating || 4.5,
|
rating: item.rating || 4.5,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
|
|||||||
@ -53,6 +53,13 @@ function mapApiProperty(item, index) {
|
|||||||
if (info.numberOfBedRooms) features.push(`${info.numberOfBedRooms} غرف نوم`);
|
if (info.numberOfBedRooms) features.push(`${info.numberOfBedRooms} غرف نوم`);
|
||||||
if (info.numberOfBathRooms) features.push(`${info.numberOfBathRooms} حمامات`);
|
if (info.numberOfBathRooms) features.push(`${info.numberOfBathRooms} حمامات`);
|
||||||
|
|
||||||
|
// Extract images from API and build full URLs
|
||||||
|
const apiBase = typeof window !== 'undefined' ? (process.env.NEXT_PUBLIC_API_URL || 'http://45.93.137.91/api') : '';
|
||||||
|
const rawImages = Array.isArray(info.images) ? info.images : [];
|
||||||
|
const images = rawImages.length > 0
|
||||||
|
? rawImages.map(img => img.startsWith('http') ? img : `${apiBase}${img}`)
|
||||||
|
: ['/property-placeholder.jpg'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: item.id ?? index + 1,
|
id: item.id ?? index + 1,
|
||||||
title: info.address || `عقار #${item.id || index + 1}`,
|
title: info.address || `عقار #${item.id || index + 1}`,
|
||||||
@ -68,7 +75,7 @@ function mapApiProperty(item, index) {
|
|||||||
bathrooms: info.numberOfBathRooms || 0,
|
bathrooms: info.numberOfBathRooms || 0,
|
||||||
area: info.space || 0,
|
area: info.space || 0,
|
||||||
features,
|
features,
|
||||||
images: ['/property-placeholder.jpg'],
|
images,
|
||||||
status,
|
status,
|
||||||
rating: item.rating || 4.5,
|
rating: item.rating || 4.5,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
|
|||||||
@ -70,6 +70,13 @@ function mapApiDetail(item) {
|
|||||||
|
|
||||||
const typeLabels = { 0: 'شقة', 1: 'فيلا', 2: 'بيت' };
|
const typeLabels = { 0: 'شقة', 1: 'فيلا', 2: 'بيت' };
|
||||||
|
|
||||||
|
// Extract images from API and build full URLs
|
||||||
|
const apiBase = typeof window !== 'undefined' ? (process.env.NEXT_PUBLIC_API_URL || 'http://45.93.137.91/api') : '';
|
||||||
|
const rawImages = Array.isArray(info.images) ? info.images : [];
|
||||||
|
const images = rawImages.length > 0
|
||||||
|
? rawImages.map(img => img.startsWith('http') ? img : `${apiBase}${img}`)
|
||||||
|
: ['/property-placeholder.jpg', '/villa1.jpg', '/villa2.jpg'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: info.address || `عقار #${item.id}`,
|
title: info.address || `عقار #${item.id}`,
|
||||||
@ -90,7 +97,7 @@ function mapApiDetail(item) {
|
|||||||
features: features.length > 0 ? features : [
|
features: features.length > 0 ? features : [
|
||||||
{ name: 'متاح للإيجار', available: true, description: '' },
|
{ name: 'متاح للإيجار', available: true, description: '' },
|
||||||
],
|
],
|
||||||
images: ['/property-placeholder.jpg', '/villa1.jpg', '/villa2.jpg'],
|
images,
|
||||||
status,
|
status,
|
||||||
rating: item.rating || 4.5,
|
rating: item.rating || 4.5,
|
||||||
reviews: 0,
|
reviews: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user