Update mappers for flat API response + enrich with property info
All checks were successful
Build frontend / build (push) Successful in 38s
All checks were successful
Build frontend / build (push) Successful in 38s
- api.js: getRentProperties/getSaleProperties now fetch PropertyInformation for each property's propInfoId (when Properties/Get endpoint is fixed) - Updated all 3 mapApiProperty functions to handle flat response format (no nested propertyInformation) - uses defaults for missing fields - Status/type mapping checks both flat and nested fields
This commit is contained in:
27
app/page.js
27
app/page.js
@ -31,46 +31,47 @@ import Image from 'next/image';
|
|||||||
import { getRentProperties, getSaleProperties } from './utils/api';
|
import { getRentProperties, getSaleProperties } from './utils/api';
|
||||||
|
|
||||||
// Map API property data to the format the UI expects
|
// Map API property data to the format the UI expects
|
||||||
|
// API returns { propInfoId, deposit, monthlyRent, dailyRent, rating, ... }
|
||||||
|
// If propertyInformation is nested, use it; otherwise use flat response with defaults
|
||||||
function mapApiProperty(item, index) {
|
function mapApiProperty(item, index) {
|
||||||
const info = item.propertyInformation || item;
|
const info = item.propertyInformation || {};
|
||||||
const isRent = item.monthlyRent !== undefined || item.dailyRent !== undefined;
|
const hasNestedInfo = !!item.propertyInformation;
|
||||||
|
|
||||||
// Determine price display
|
|
||||||
const dailyPrice = item.dailyRent ?? item.monthlyRent ?? item.price ?? 0;
|
const dailyPrice = item.dailyRent ?? item.monthlyRent ?? item.price ?? 0;
|
||||||
const monthlyPrice = item.monthlyRent ?? 0;
|
const monthlyPrice = item.monthlyRent ?? 0;
|
||||||
|
|
||||||
// Map building type integer to string
|
// BuildingType: 0=Apartment, 1=Villa, 2=House
|
||||||
const buildingTypeMap = { 0: 'apartment', 1: 'villa', 2: 'house' };
|
const buildingTypeMap = { 0: 'apartment', 1: 'villa', 2: 'house' };
|
||||||
const propType = buildingTypeMap[info.buildingType] || 'apartment';
|
const propType = buildingTypeMap[info.buildingType] ?? buildingTypeMap[item.type] ?? 'apartment';
|
||||||
|
|
||||||
// Map property status integer to string
|
// Status: 0=Available, 1=Booked, 2=Maintenance
|
||||||
const statusMap = { 0: 'available', 1: 'booked', 2: 'maintenance' };
|
const statusMap = { 0: 'available', 1: 'booked', 2: 'maintenance' };
|
||||||
const status = statusMap[info.status] || 'available';
|
const status = statusMap[info.status] ?? statusMap[item.status] ?? 'available';
|
||||||
|
|
||||||
// Extract features as string array
|
|
||||||
const features = [];
|
const features = [];
|
||||||
if (item.isSmokeAllow) features.push('يسمح بالتدخين');
|
if (item.isSmokeAllow) features.push('يسمح بالتدخين');
|
||||||
if (item.isVisitorAllow) features.push('يسمح بالزوار');
|
if (item.isVisitorAllow) features.push('يسمح بالزوار');
|
||||||
if (item.specializedFor) features.push('متخصص');
|
if (item.specializedFor) features.push('متخصص');
|
||||||
if (info.numberOfRooms) features.push(`${info.numberOfRooms} غرف`);
|
if (info.numberOfBedRooms) features.push(`${info.numberOfBedRooms} غرف نوم`);
|
||||||
if (info.numberOfBathRooms) features.push(`${info.numberOfBathRooms} حمامات`);
|
if (info.numberOfBathRooms) features.push(`${info.numberOfBathRooms} حمامات`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: item.id ?? index + 1,
|
id: item.id ?? index + 1,
|
||||||
title: info.address || info.description?.substring(0, 40) || 'عقار',
|
propInfoId: item.propInfoId,
|
||||||
|
title: info.address || `عقار #${item.id || index + 1}`,
|
||||||
description: info.description || '',
|
description: info.description || '',
|
||||||
type: propType,
|
type: propType,
|
||||||
price: dailyPrice,
|
price: dailyPrice,
|
||||||
priceUSD: dailyPrice,
|
priceUSD: dailyPrice,
|
||||||
priceUnit: 'daily',
|
priceUnit: 'daily',
|
||||||
location: {
|
location: {
|
||||||
city: extractCity(info.address),
|
city: extractCity(info.address) || 'دمشق',
|
||||||
district: info.address || '',
|
district: info.address || '',
|
||||||
address: info.address || '',
|
address: info.address || '',
|
||||||
lat: parseFloat(info.cordsX) || 0,
|
lat: parseFloat(info.cordsX) || 0,
|
||||||
lng: parseFloat(info.cordsY) || 0,
|
lng: parseFloat(info.cordsY) || 0,
|
||||||
},
|
},
|
||||||
bedrooms: info.numberOfBedRooms || info.numberOfRooms || 0,
|
bedrooms: info.numberOfBedRooms || 0,
|
||||||
bathrooms: info.numberOfBathRooms || 0,
|
bathrooms: info.numberOfBathRooms || 0,
|
||||||
area: info.space || 0,
|
area: info.space || 0,
|
||||||
features,
|
features,
|
||||||
@ -94,7 +95,7 @@ function extractCity(address) {
|
|||||||
for (const city of cities) {
|
for (const city of cities) {
|
||||||
if (address.includes(city)) return city;
|
if (address.includes(city)) return city;
|
||||||
}
|
}
|
||||||
return address.split(' ').pop() || '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback dummy data
|
// Fallback dummy data
|
||||||
|
|||||||
@ -35,35 +35,37 @@ import { getRentProperties, getSaleProperties } from '../utils/api';
|
|||||||
|
|
||||||
// Map API data to UI format
|
// Map API data to UI format
|
||||||
function mapApiProperty(item, index) {
|
function mapApiProperty(item, index) {
|
||||||
const info = item.propertyInformation || item;
|
const info = item.propertyInformation || {};
|
||||||
|
const hasNestedInfo = !!item.propertyInformation;
|
||||||
|
|
||||||
const dailyPrice = item.dailyRent ?? item.monthlyRent ?? item.price ?? 0;
|
const dailyPrice = item.dailyRent ?? item.monthlyRent ?? item.price ?? 0;
|
||||||
const monthlyPrice = item.monthlyRent ?? 0;
|
const monthlyPrice = item.monthlyRent ?? 0;
|
||||||
|
|
||||||
const buildingTypeMap = { 0: 'apartment', 1: 'villa', 2: 'house' };
|
const buildingTypeMap = { 0: 'apartment', 1: 'villa', 2: 'house' };
|
||||||
const propType = buildingTypeMap[info.buildingType] || 'apartment';
|
const propType = buildingTypeMap[info.buildingType] ?? buildingTypeMap[item.type] ?? 'apartment';
|
||||||
|
|
||||||
const statusMap = { 0: 'available', 1: 'booked', 2: 'maintenance' };
|
const statusMap = { 0: 'available', 1: 'booked', 2: 'maintenance' };
|
||||||
const status = statusMap[info.status] || 'available';
|
const status = statusMap[info.status] ?? statusMap[item.status] ?? 'available';
|
||||||
|
|
||||||
const features = [];
|
const features = [];
|
||||||
if (item.isSmokeAllow) features.push('يسمح بالتدخين');
|
if (item.isSmokeAllow) features.push('يسمح بالتدخين');
|
||||||
if (item.isVisitorAllow) features.push('يسمح بالزوار');
|
if (item.isVisitorAllow) features.push('يسمح بالزوار');
|
||||||
if (info.numberOfRooms) features.push(`${info.numberOfRooms} غرف`);
|
if (item.specializedFor) features.push('متخصص');
|
||||||
|
if (info.numberOfBedRooms) features.push(`${info.numberOfBedRooms} غرف نوم`);
|
||||||
if (info.numberOfBathRooms) features.push(`${info.numberOfBathRooms} حمامات`);
|
if (info.numberOfBathRooms) features.push(`${info.numberOfBathRooms} حمامات`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: item.id ?? index + 1,
|
id: item.id ?? index + 1,
|
||||||
title: info.address || info.description?.substring(0, 40) || 'عقار',
|
title: info.address || `عقار #${item.id || index + 1}`,
|
||||||
description: info.description || '',
|
description: info.description || '',
|
||||||
type: propType,
|
type: propType,
|
||||||
price: dailyPrice,
|
price: dailyPrice,
|
||||||
priceUnit: 'daily',
|
priceUnit: 'daily',
|
||||||
location: {
|
location: {
|
||||||
city: extractCity(info.address),
|
city: extractCity(info.address) || 'دمشق',
|
||||||
district: info.address || '',
|
district: info.address || '',
|
||||||
},
|
},
|
||||||
bedrooms: info.numberOfBedRooms || info.numberOfRooms || 0,
|
bedrooms: info.numberOfBedRooms || 0,
|
||||||
bathrooms: info.numberOfBathRooms || 0,
|
bathrooms: info.numberOfBathRooms || 0,
|
||||||
area: info.space || 0,
|
area: info.space || 0,
|
||||||
features,
|
features,
|
||||||
|
|||||||
@ -48,47 +48,47 @@ import { getRentProperty, getSaleProperty, bookReservation, checkAvailability }
|
|||||||
function mapApiDetail(item) {
|
function mapApiDetail(item) {
|
||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
|
|
||||||
const info = item.propertyInformation || item;
|
const info = item.propertyInformation || {};
|
||||||
const isRent = item.monthlyRent !== undefined || item.dailyRent !== undefined;
|
const hasNestedInfo = !!item.propertyInformation;
|
||||||
|
|
||||||
const dailyPrice = item.dailyRent ?? item.monthlyRent ?? item.price ?? 0;
|
const dailyPrice = item.dailyRent ?? item.monthlyRent ?? item.price ?? 0;
|
||||||
const monthlyPrice = item.monthlyRent ?? 0;
|
const monthlyPrice = item.monthlyRent ?? 0;
|
||||||
|
|
||||||
const buildingTypeMap = { 0: 'apartment', 1: 'villa', 2: 'house' };
|
const buildingTypeMap = { 0: 'apartment', 1: 'villa', 2: 'house' };
|
||||||
const propType = buildingTypeMap[info.buildingType] || 'apartment';
|
const propType = buildingTypeMap[info.buildingType] ?? buildingTypeMap[item.type] ?? 'apartment';
|
||||||
|
|
||||||
const statusMap = { 0: 'available', 1: 'booked', 2: 'maintenance' };
|
const statusMap = { 0: 'available', 1: 'booked', 2: 'maintenance' };
|
||||||
const status = statusMap[info.status] || 'available';
|
const status = statusMap[info.status] ?? statusMap[item.status] ?? 'available';
|
||||||
|
|
||||||
// Build features array
|
|
||||||
const features = [];
|
const features = [];
|
||||||
if (item.isSmokeAllow) features.push({ name: 'يسمح بالتدخين', available: true, description: '' });
|
if (item.isSmokeAllow) features.push({ name: 'يسمح بالتدخين', available: true, description: '' });
|
||||||
if (item.isVisitorAllow) features.push({ name: 'يسمح بالزوار', available: true, description: '' });
|
if (item.isVisitorAllow) features.push({ name: 'يسمح بالزوار', available: true, description: '' });
|
||||||
if (item.specializedFor) features.push({ name: 'متخصص', available: true, description: '' });
|
if (item.specializedFor) features.push({ name: 'متخصص', available: true, description: '' });
|
||||||
|
if (info.numberOfBedRooms) features.push({ name: 'غرف النوم', available: true, description: `${info.numberOfBedRooms} غرف` });
|
||||||
|
if (info.numberOfBathRooms) features.push({ name: 'الحمامات', available: true, description: `${info.numberOfBathRooms} حمامات` });
|
||||||
|
if (info.space) features.push({ name: 'المساحة', available: true, description: `${info.space} م²` });
|
||||||
|
|
||||||
const typeLabels = { 0: 'شقة', 1: 'فيلا', 2: 'بيت' };
|
const typeLabels = { 0: 'شقة', 1: 'فيلا', 2: 'بيت' };
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: info.address || info.description?.substring(0, 50) || `عقار #${item.id}`,
|
title: info.address || `عقار #${item.id}`,
|
||||||
description: info.description || '',
|
description: info.description || 'عقار سكني مميز في موقع استراتيجي.',
|
||||||
type: propType,
|
type: propType,
|
||||||
price: dailyPrice,
|
price: dailyPrice,
|
||||||
priceUnit: isRent ? 'daily' : 'sale',
|
priceUnit: 'daily',
|
||||||
location: {
|
location: {
|
||||||
city: extractCity(info.address),
|
city: extractCity(info.address) || 'دمشق',
|
||||||
district: info.address || '',
|
district: info.address || '',
|
||||||
address: info.address || '',
|
address: info.address || '',
|
||||||
lat: parseFloat(info.cordsX) || 0,
|
lat: parseFloat(info.cordsX) || 0,
|
||||||
lng: parseFloat(info.cordsY) || 0,
|
lng: parseFloat(info.cordsY) || 0,
|
||||||
},
|
},
|
||||||
bedrooms: info.numberOfBedRooms || info.numberOfRooms || 0,
|
bedrooms: info.numberOfBedRooms || 0,
|
||||||
bathrooms: info.numberOfBathRooms || 0,
|
bathrooms: info.numberOfBathRooms || 0,
|
||||||
area: info.space || 0,
|
area: info.space || 0,
|
||||||
features: features.length > 0 ? features : [
|
features: features.length > 0 ? features : [
|
||||||
{ name: 'غرف نوم', available: true, description: `${info.numberOfBedRooms || 0} غرف` },
|
{ name: 'متاح للإيجار', available: true, description: '' },
|
||||||
{ name: 'حمامات', available: true, description: `${info.numberOfBathRooms || 0} حمامات` },
|
|
||||||
{ name: 'المساحة', available: true, description: `${info.space || 0} م²` },
|
|
||||||
],
|
],
|
||||||
images: ['/property-placeholder.jpg', '/villa1.jpg', '/villa2.jpg'],
|
images: ['/property-placeholder.jpg', '/villa1.jpg', '/villa2.jpg'],
|
||||||
status,
|
status,
|
||||||
|
|||||||
@ -37,11 +37,39 @@ async function apiFetch(endpoint, options = {}) {
|
|||||||
// ─── Rent Properties ───
|
// ─── Rent Properties ───
|
||||||
|
|
||||||
export async function getRentProperties() {
|
export async function getRentProperties() {
|
||||||
return apiFetch('/RentProperties/GetRentProperties');
|
const rentList = await apiFetch('/RentProperties/GetRentProperties');
|
||||||
|
if (!Array.isArray(rentList) || rentList.length === 0) return rentList;
|
||||||
|
|
||||||
|
// Fetch property info for each rent property's propInfoId
|
||||||
|
const enriched = await Promise.all(
|
||||||
|
rentList.map(async (item) => {
|
||||||
|
try {
|
||||||
|
const propInfo = await apiFetch(`/Properties/Get/${item.propInfoId}`);
|
||||||
|
return { ...item, propertyInformation: propInfo };
|
||||||
|
} catch {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return enriched;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRentProperty(id) {
|
export async function getRentProperty(id) {
|
||||||
return apiFetch(`/RentProperties/GetRentProperties?id=${id}`);
|
const item = await apiFetch(`/RentProperties/GetRentProperties?id=${id}`);
|
||||||
|
if (!item) return item;
|
||||||
|
|
||||||
|
// If it's an array (all results), pick the matching one
|
||||||
|
const property = Array.isArray(item) ? item.find(p => p.id == id) || item[0] : item;
|
||||||
|
|
||||||
|
if (property?.propInfoId) {
|
||||||
|
try {
|
||||||
|
const propInfo = await apiFetch(`/Properties/Get/${property.propInfoId}`);
|
||||||
|
return { ...property, propertyInformation: propInfo };
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRentPropertyLocations(params = {}) {
|
export async function getRentPropertyLocations(params = {}) {
|
||||||
@ -55,11 +83,35 @@ export async function getRentPropertyLocations(params = {}) {
|
|||||||
// ─── Sale Properties ───
|
// ─── Sale Properties ───
|
||||||
|
|
||||||
export async function getSaleProperties() {
|
export async function getSaleProperties() {
|
||||||
return apiFetch('/SaleProperties/GetSaleProperties');
|
const saleList = await apiFetch('/SaleProperties/GetSaleProperties');
|
||||||
|
if (!Array.isArray(saleList) || saleList.length === 0) return saleList;
|
||||||
|
|
||||||
|
const enriched = await Promise.all(
|
||||||
|
saleList.map(async (item) => {
|
||||||
|
try {
|
||||||
|
const propInfo = await apiFetch(`/Properties/Get/${item.propInfoId}`);
|
||||||
|
return { ...item, propertyInformation: propInfo };
|
||||||
|
} catch {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return enriched;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSaleProperty(id) {
|
export async function getSaleProperty(id) {
|
||||||
return apiFetch(`/SaleProperties/GetSaleProperties?id=${id}`);
|
const item = await apiFetch(`/SaleProperties/GetSaleProperties?id=${id}`);
|
||||||
|
const property = Array.isArray(item) ? item.find(p => p.id == id) || item[0] : item;
|
||||||
|
|
||||||
|
if (property?.propInfoId) {
|
||||||
|
try {
|
||||||
|
const propInfo = await apiFetch(`/Properties/Get/${property.propInfoId}`);
|
||||||
|
return { ...property, propertyInformation: propInfo };
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Properties (generic) ───
|
// ─── Properties (generic) ───
|
||||||
|
|||||||
Reference in New Issue
Block a user