// New method:
navigateToProperty(slug) {
window.location.href = `/property/${slug}`
}
// Footer filter link handler:
document.querySelectorAll('.footer-links a[data-filter]').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault()
const filter = e.target.dataset.filter
window.location.href = `/#catalog`
sessionStorage.setItem('pendingFilter', filter)
})
})
// In init(), check for pending filter:
const pendingFilter = sessionStorage.getItem('pendingFilter')
if (pendingFilter) {
sessionStorage.removeItem('pendingFilter')
setTimeout(() => this.setFilter(pendingFilter), 500)
}
```
#### 3. **public/js/property.js** β Breadcrumb & Similar Properties Navigation
**Current State**: `property.js` loads property by slug, renders gallery, features, utilities, similar properties. Similar properties link to `property.html` (static). Breadcrumb is hardcoded.
**Changes Required**:
- Update `renderSimilarProperties()` to use dynamic slugs (already uses `prop.slug`)
- Add `updateBreadcrumb()` method to set dynamic breadcrumb from property data
- Add "Back to catalog" button with scroll-to-catalog behavior
- Wire share buttons with dynamic URLs
```javascript
// New method:
updateBreadcrumb() {
const items = document.querySelectorAll('.breadcrumb-item a, .breadcrumb-item.active')
if (items.length >= 4 && this.property) {
items[2].textContent = this.getTypeLabel(this.property.type)
items[3].textContent = this.property.title
}
}
// Call in updatePage():
this.updateBreadcrumb()
// Update share methods to use dynamic data:
shareProperty() {
const url = window.location.href
const title = this.property?.title || 'Property'
if (navigator.share) {
navigator.share({ title, url })
} else {
navigator.clipboard.writeText(url)
this.showNotification('Enlace copiado', 'success')
}
}
```
#### 4. **public/js/api.js** β Add Missing Endpoints
**Current State**: Has `getProperties`, `getProperty`, `getFeaturedProperties`, `createLead`, `getLeads`, `getTestimonials`, `getFAQ`, `getServices`, `getSettings`, `trackEvent`, `getCities`.
**Changes Required**:
- Add `getSitemap()` method for sitemap generation
- Add `getNavigationData()` method for consistent nav across pages
```javascript
// New methods:
static async getSitemap() {
const response = await fetch('/api/sitemap')
return response.json()
}
static async getNavigationData(lang = 'es') {
const [cities, featured] = await Promise.all([
this.getCities(),
this.getFeaturedProperties(lang)
])
return { cities: cities.data, featured: featured.data }
}
```
#### 5. **public/property.html** β Consistent Navigation & Breadcrumb
**Current State**: Navbar links point to `index.html` and `index.html#section`. Breadcrumb is static. Similar property cards link to `property.html` (no slug).
**Changes Required**:
- Update all navbar links to use proper paths
- Make breadcrumb dynamic via JS (see property.js changes)
- Update similar property card links to use `prop.slug`
- Add `data-property-id` meta tag for analytics
```html
```
#### 6. **src/server/index.ts** β Sitemap & Navigation API
**Current State**: Has all property/lead/content endpoints. No sitemap endpoint.
**Changes Required**:
- Add `GET /api/sitemap` endpoint returning XML sitemap
- Add `GET /sitemap.xml` static route or dynamic generation
```typescript
// New endpoint:
app.get('/api/sitemap', (c) => {
const properties = db.query('SELECT slug, updated_at FROM properties WHERE published_at IS NOT NULL AND status = ?').all('active')
let xml = `
https://tenerifeprop.com/
${new Date().toISOString()}
1.0
https://tenerifeprop.com/#catalog
0.8
`
properties.forEach((p: any) => {
xml += `
https://tenerifeprop.com/property/${p.slug}
${p.updated_at}
0.7
`
})
xml += '\n'
c.header('Content-Type', 'application/xml')
return c.body(xml)
})
```
#### 7. **Mobile Navigation** β Responsive Improvements
**Current State**: Bootstrap navbar with collapse. Language switcher in navbar. No mobile-specific optimizations for property cards.
**Changes Required**:
- Add mobile bottom navigation bar for property detail page
- Ensure map is usable on mobile (touch-friendly)
- Add swipe navigation for property gallery (already exists in property.js)
- Add "sticky CTA" on mobile property pages
```html
```
### Data Flow
```
User clicks property card (index.html)
β window.location.href = '/property/{slug}'
β property.html loads
β property.js init()
β getPropertySlug() from URL
β API.getProperty(slug, lang)
β Backend: SELECT * FROM properties WHERE slug = ?
β Backend: views_count++
β Response: { success: true, data: { ...property, title, description } }
β updatePage() renders all sections
β loadSimilarProperties() β API.getProperties({ type, city, limit: 3 })
β renderSimilarProperties() with links back to /property/{slug}
```
### API Contracts
| Method | Endpoint | Input | Output |
|--------|----------|-------|--------|
| GET | `/api/properties` | `?type=&city=&minPrice=&maxPrice=&lang=&limit=&offset=` | `{ success, data: Property[], total }` |
| GET | `/api/properties/:slug` | `?lang=` | `{ success, data: Property }` |
| GET | `/api/properties/featured` | `?lang=` | `{ success, data: Property[] }` |
| GET | `/api/sitemap` | - | XML sitemap |
| GET | `/api/cities` | - | `{ success, data: string[] }` |
| POST | `/api/analytics/event` | `{ type, session_id, ...data }` | 200 OK |
**Property Response Shape** (from `/api/properties/:slug`):
```json
{
"success": true,
"data": {
"id": "prop-001",
"slug": "terreno-urbano-adeje",
"title": "Terreno Urbano en Adeje",
"description": "...",
"city": "Adeje",
"zone": "Costa Adeje",
"address": "Avda. de la ConstituciΓ³n",
"price": 385000,
"area": 2500,
"type": "urban",
"images": "[{\"url\":\"...\",\"alt\":\"...\"}]",
"lat": 28.1227,
"lng": -16.6942,
"water": "available",
"electricity": "available",
"road": "asphalt",
"is_featured": 1,
"is_exclusive": 1,
"views_count": 42
}
}
```
### Implementation Checklist
- [ ] **1. Property Card Navigation**
- [ ] Add `data-property-slug` to card root in `renderPropertyCard()` (app.js)
- [ ] Add click handler on map popup β navigate to property (app.js)
- [ ] Wire hero floating cards to specific property slugs (index.html)
- [ ] Wire footer property links to catalog with type filter (index.html + app.js)
- [ ] **2. API Data Integration**
- [ ] Add `getSitemap()` method (api.js)
- [ ] Add `getNavigationData()` method (api.js)
- [ ] Add `/api/sitemap` endpoint returning XML (server/index.ts)
- [ ] **3. Consistent Site Navigation**
- [ ] Update breadcrumb to be dynamic on property page (property.js)
- [ ] Ensure navbar links are consistent across all pages (index.html, property.html)
- [ ] Add "Back to catalog" link on property page
- [ ] **4. User Workflow (B2B Client Journey)**
- [ ] Add pending filter persistence via sessionStorage (app.js)
- [ ] Track property view events with `trackEvent()` (already exists, verify)
- [ ] Add lead form pre-fill with property context (property.js)
- [ ] **5. Site Map Implementation**
- [ ] Create `/api/sitemap` XML endpoint (server/index.ts)
- [ ] Add `
` to index.html ``
- [ ] Include all published properties + main pages
- [ ] **6. Data Connectivity**
- [ ] Verify similar properties use correct slugs (property.js)
- [ ] Verify share buttons use dynamic URLs (property.js)
- [ ] Add `data-property-id` meta tag to property.html
- [ ] **7. Site Consistency**
- [ ] Unify CSS variables across index.html and property.html (already consistent)
- [ ] Ensure footer is identical across pages
- [ ] Verify language switcher works on all pages
- [ ] **8. Mobile Navigation**
- [ ] Add mobile bottom navigation bar to property.html
- [ ] Verify map is touch-friendly on mobile
- [ ] Verify gallery swipe works (already exists)
- [ ] Add responsive CSS for mobile bottom nav
### Technical Debt Notes
1. **Duplicate HTML**: `index.html` contains a nested/wrapper HTML structure (lines 1-15 are a wrapper DOCTYPE). Should be cleaned up but not blocking.
2. **Inline translations**: Both `index.html` and `property.html` embed full translation objects inline. Should be consolidated into external JSON files loaded via `api.js` or `i18n.js`.
3. **Static property.html**: The property page HTML contains hardcoded content that gets overwritten by JS. Consider using a minimal template skeleton.
4. **No server-side routing**: Property pages use client-side URL matching (`/property/:slug`). The server serves `property.html` for all paths. Consider adding proper routing if SEO becomes critical.
5. **Mixed JS patterns**: `app.js` uses vanilla class pattern, `property.html` inline script uses jQuery. Should standardize on one approach.
6. **Missing error states**: No 404 page for invalid property slugs. `property.js` calls `showError()` but replaces entire `
` content.
---
Status: designed
@SDETEngineer ready for test creation
@lead-developer ready for implementation