Skip to main content

Overview

Ficha Dubai loads property data from a JSON file (property-5157395.json). The data is normalized by the normalizeProperty() function in app.js to handle different data structures consistently.

Property JSON Structure

The JSON file follows this structure:
{
  "data": {
    "property": {
      "property_uuid": "bbb8185d-2ee3-48a4-ba7f-8fecaba6e549",
      "nid": 49695472717,
      "property_id": "5157395",
      "titulo": "Apartamento en Venta en Las Cabañas, Bello",
      "descripcion": "Apartamento en venta de 79m2...",
      "url_360": "https://apartamento-dubai.vercel.app/?m=bE7cSwnyKad",
      "images": [...],
      "servicios": [...],
      "caracteristicas_propiedad": [...],
      "detalles_propiedad": {...}
    }
  },
  "success": true
}

Top-Level Fields

data.property
object
required
Main property object containing all property information
success
boolean
API response status indicator

Property Object Fields

Basic Information

property_uuid
string
required
Unique identifier for the property
"property_uuid": "bbb8185d-2ee3-48a4-ba7f-8fecaba6e549"
property_id
string
required
Property listing ID
"property_id": "5157395"
titulo
string
required
Property title/headline
"titulo": "Apartamento en Venta en Las Cabañas, Bello"
descripcion
string
required
Detailed property description
"descripcion": "Apartamento en venta de 79m2, con vista exterior..."
url_360
string
URL for 360° virtual tour (optional)
"url_360": "https://apartamento-dubai.vercel.app/?m=bE7cSwnyKad"

Images Array

The images array contains property photos:
"images": [
  {
    "url": "venta-594a5fafcf-1.webp",
    "order": 1,
    "type_img": 1,
    "title": null,
    "comment": null
  },
  {
    "url": "venta-cca6e41506-2.webp",
    "order": 2,
    "type_img": 1,
    "title": null,
    "comment": null
  }
]

Image Object Fields

url
string
required
Image filename or full URL. If it doesn’t start with http, it’s prefixed with images/
order
number
required
Display order (1-based). Images are sorted by this field
type_img
number
Image type identifier (1 = standard photo)
title
string | null
Optional image title
comment
string | null
Optional image description

Services Array

The servicios array contains estimated utility costs:
"servicios": [
  {
    "servicio": "gas",
    "estrato": 3,
    "valor": 25000
  },
  {
    "servicio": "energia",
    "estrato": 3,
    "valor": 100000
  },
  {
    "servicio": "acueducto",
    "estrato": 3,
    "valor": 115000
  },
  {
    "servicio": "internet_tv",
    "estrato": 3,
    "valor": 125000
  }
]

Service Object Fields

servicio
string
required
Service type: gas, energia, acueducto, internet_tv
estrato
number
Socioeconomic stratum (1-6 in Colombia)
valor
number
required
Estimated monthly cost in local currency (COP)

Characteristics Array

The caracteristicas_propiedad array lists property features:
"caracteristicas_propiedad": [
  "Interior",
  "Balcón",
  "Conjunto Cerrado",
  "Instalación de gas"
]
Each item is a simple string. Common values include: “Interior”, “Balcón”, “Conjunto Cerrado”, “Instalación de gas”, “Zona de lavandería”, “Ascensor”

Property Details Object

The detalles_propiedad object contains detailed specifications:
"detalles_propiedad": {
  "area": 79.0,
  "tipo_inmueble": "Apartamento",
  "estrato": "3",
  "conjunto": "Dubai",
  "direccion": "CARRERA 58AA 31-166",
  "precio_venta": 328000000.0,
  "precio_anterior": null,
  "barriocomun": "Las Cabañas",
  "ciudad": "Bello",
  "num_habitaciones": 3,
  "num_ascensores": 0,
  "num_piso": 5,
  "baños": 2,
  "garajes": 0,
  "telefono": "3015637932",
  "correo": "[email protected]",
  "anos_antiguedad": 10,
  "latitud": 6.319948999999999,
  "longitud": -75.565495
}

Required Fields

area
number
required
Private area in square meters
tipo_inmueble
string
required
Property type: “Apartamento”, “Casa”, “Local”, “Oficina”, etc.
precio_venta
number
required
Sale price in local currency (COP)
ciudad
string
required
City name
direccion
string
required
Full street address

Optional Fields

precio_anterior
number | null
Previous price (for showing discounts)
estrato
string
Socioeconomic stratum (1-6)
conjunto
string
Building or complex name
barriocomun
string
Neighborhood name
num_habitaciones
number
Number of bedrooms
baños
number
Number of bathrooms
garajes
number
Number of parking spaces
num_piso
number
Floor number
anos_antiguedad
number
Property age in years
telefono
string
Contact phone number
correo
string
Contact email address
latitud
number
Latitude coordinate for map
longitud
number
Longitude coordinate for map

The normalizeProperty() Function

The normalizeProperty() function in app.js (lines 571-611) transforms the raw JSON into a consistent format:
const normalizeProperty = (raw) => {
  const property = raw?.property || raw?.data?.property || raw;
  const details = property?.detalles_propiedad || {};
  const images = Array.isArray(property?.images)
    ? property.images
        .slice()
        .sort((a, b) => (a.order || 0) - (b.order || 0))
        .map((img) => img.url || img)
    : [];

  return {
    titulo: property?.titulo,
    descripcion: property?.descripcion,
    url_360: property?.url_360,
    images,
    servicios: property?.servicios || [],
    caracteristicas_propiedad: property?.caracteristicas_propiedad || [],
    tipo_inmueble: details?.tipo_inmueble || property?.tipo_inmueble,
    estrato: details?.estrato || property?.estrato,
    conjunto: details?.conjunto || details?.conjunto_edificio || property?.conjunto,
    direccion: details?.direccion || property?.direccion,
    barrio: details?.barriocomun || property?.barrio,
    ciudad: details?.ciudad || property?.ciudad,
    departamento: details?.departamento || property?.departamento,
    precio: details?.precio_venta ?? property?.precio,
    precio_anterior: details?.precio_anterior ?? property?.precio_anterior,
    area_privada: details?.area ?? property?.area_privada,
    area_construida: details?.area_construida ?? property?.area_construida,
    habitaciones: details?.num_habitaciones ?? property?.habitaciones,
    banos: details?.baños ?? details?.banos ?? property?.banos,
    parqueaderos: details?.garajes ?? property?.parqueaderos,
    antiguedad: details?.anos_antiguedad ?? property?.antiguedad,
    telefono: details?.telefono || details?.contacto_zona || property?.telefono,
    correo: details?.correo || property?.correo,
    nombre_contacto: property?.nombre_contacto,
    administracion: details?.last_admin_price ?? property?.administracion,
    latitud: details?.latitud ?? property?.latitud,
    longitud: details?.longitud ?? property?.longitud,
    estado: property?.estado,
  };
};

What It Does

1

Handles Multiple Formats

Accepts data from different API response structures
2

Sorts Images

Automatically sorts images by the order field
3

Flattens Structure

Combines fields from property and detalles_propiedad into a single object
4

Provides Fallbacks

Uses optional chaining (?.) and nullish coalescing (??) for safe access
5

Normalizes Field Names

Maps inconsistent field names to a standard schema

Creating Your Own Property JSON

Minimal Example

Here’s the minimum required structure:
{
  "data": {
    "property": {
      "property_uuid": "unique-id-here",
      "property_id": "12345",
      "titulo": "Beautiful Apartment",
      "descripcion": "A stunning 2-bedroom apartment in the heart of the city.",
      "images": [
        {
          "url": "images/photo1.jpg",
          "order": 1
        }
      ],
      "detalles_propiedad": {
        "area": 85.0,
        "tipo_inmueble": "Apartamento",
        "precio_venta": 350000000,
        "ciudad": "Medellín",
        "direccion": "Calle 10 #20-30",
        "num_habitaciones": 2,
        "baños": 2
      }
    }
  },
  "success": true
}

Complete Example

For a fully-featured listing:
{
  "data": {
    "property": {
      "property_uuid": "abc123-def456-ghi789",
      "property_id": "67890",
      "titulo": "Luxury Penthouse with Ocean View",
      "descripcion": "Experience luxury living in this stunning penthouse with panoramic ocean views, modern finishes, and top-of-the-line appliances.",
      "url_360": "https://example.com/360-tour",
      "images": [
        {
          "url": "images/penthouse-main.jpg",
          "order": 1,
          "type_img": 1,
          "title": "Living Room",
          "comment": "Spacious living area with ocean view"
        },
        {
          "url": "images/penthouse-kitchen.jpg",
          "order": 2,
          "type_img": 1,
          "title": "Kitchen",
          "comment": "Modern kitchen with island"
        }
      ],
      "servicios": [
        {
          "servicio": "gas",
          "estrato": 6,
          "valor": 50000
        },
        {
          "servicio": "energia",
          "estrato": 6,
          "valor": 200000
        }
      ],
      "caracteristicas_propiedad": [
        "Vista al mar",
        "Terraza",
        "Jacuzzi",
        "Smart Home",
        "Gimnasio privado"
      ],
      "detalles_propiedad": {
        "area": 180.0,
        "area_construida": 200.0,
        "tipo_inmueble": "Apartamento",
        "estrato": "6",
        "conjunto": "Ocean View Residences",
        "direccion": "Avenida del Mar 500",
        "precio_venta": 850000000.0,
        "precio_anterior": 950000000.0,
        "barriocomun": "El Poblado",
        "ciudad": "Medellín",
        "num_habitaciones": 3,
        "num_ascensores": 2,
        "num_piso": 15,
        "baños": 3,
        "garajes": 2,
        "telefono": "3001234567",
        "correo": "[email protected]",
        "anos_antiguedad": 2,
        "last_admin_price": 500000,
        "latitud": 6.2476,
        "longitud": -75.5658
      }
    }
  },
  "success": true
}

Loading Property Data

The loadData() function in app.js (lines 665-687) loads property data:
const loadData = async () => {
  // Initialize lightbox
  initLightbox();

  // Check for inline data first
  if (window.PROPERTY_DATA) {
    populatePage(window.PROPERTY_DATA);
    return;
  }

  // Otherwise, fetch from JSON file
  try {
    const response = await fetch("./property-5157395.json");
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    const data = await response.json();
    populatePage(data);
  } catch (error) {
    $("#property-title").textContent = "No se pudo cargar el inmueble";
  }
};

Two Loading Methods

Define property data directly in HTML:
<script>
  window.PROPERTY_DATA = {
    data: {
      property: {
        // Your property data here
      }
    }
  };
</script>
<script src="app.js" defer></script>

Data Validation Tips

Always include an order field in image objects. Images without order may display in unpredictable sequence.
"images": [
  {"url": "photo1.jpg", "order": 1},
  {"url": "photo2.jpg", "order": 2}
]
Prices should be numbers, not strings. Don’t include currency symbols or thousands separators.
// Correct
"precio_venta": 328000000

// Wrong
"precio_venta": "$328,000,000"
Latitude and longitude must be valid decimal numbers:
  • Latitude: -90 to 90
  • Longitude: -180 to 180
"latitud": 6.319949,
"longitud": -75.565495
If including a url_360, ensure it’s a valid, accessible URL.
"url_360": "https://example.com/tour"

Styling Guide

Customize the visual appearance of property listings

Configuration

Configure Tailwind, Analytics, and dependencies

Build docs developers (and LLMs) love