dld_backend/public/js/rents.js
2025-11-04 13:17:18 +05:30

591 lines
28 KiB
JavaScript

// Rents page logic moved to external file to satisfy CSP (no inline scripts or handlers)
const API_BASE = '/api';
// Area dropdown values for rents
const areas = [
'al mamzer', 'jabal ali first', 'al nahda second', 'burj khalifa',
'al merkadh', 'dubai investment park second', 'al yelayiss 2',
'dubai investment park first', 'al yelayiss 1', 'al jadaf',
'al nahda first', 'al suq al kabeer', 'mirdif', 'business bay',
'madinat hind 4', 'al thanyah third',
'al qusais industrial fourth', 'al qusais industrial fifth',
'al warqa first', 'muhaisanah fourth', 'al qusais second',
'al karama', 'al hudaiba', 'madinat dubai almelaheyah',
'al safouh second', 'al qusais first', 'wadi al amardi', 'al rega',
'wadi al safa 5', 'marsa dubai',
'hadaeq sheikh mohammed bin rashid', 'me\'aisem first',
'ras al khor industrial third', 'al qusais industrial first',
'al murqabat', 'wadi al safa 6', 'naif', 'nad al shiba third',
'al saffa first', 'um suqaim third', 'al khairan first',
'madinat al mataar', 'saih shuaib 2', 'mankhool',
'al thanyah fifth', 'al hebiah fourth', 'trade center second',
'al warsan first', 'nadd hessa', 'port saeed',
'trade center first', 'al wasl', 'jumeirah first',
'al goze industrial second', 'nad al shiba first', 'al muteena',
'al barsha first', 'jabal ali industrial first', 'palm jumeirah',
'al raffa', 'margham', 'al barshaa south third', 'al satwa',
'al khawaneej second', 'al bada', 'al hamriya', 'al thanyah first',
'al barsha south fourth', 'um hurair second', 'al baraha',
'ras al khor industrial second', 'al goze industrial first',
'al hebiah fifth', 'jumeirah second', 'al mararr',
'wadi al safa 3', 'um suqaim second', 'hor al anz', 'al kheeran',
'wadi al safa 2', 'hor al anz east', 'al manara', 'eyal nasser',
'al yufrah 1', 'al khawaneej first', 'hatta', 'warsan fourth',
'um ramool', 'al goze fourth', 'al goze third',
'al goze industrial third', 'al barsha south fifth',
'al hebiah sixth', 'saih shuaib 3', 'al goze first', 'abu hail',
'al hebiah third', 'al hebiah second', 'rega al buteen',
'al goze industrial fourth', 'nad al hamar', 'al jafliya',
'al barshaa south second', 'al qusais industrial second',
'oud metha', 'um suqaim first', 'jabal ali', 'jumeirah third',
'lehbab second', 'al dhagaya', 'al lusaily', 'hessyan first',
'al khabeesi', 'wadi al safa 7', 'al hebiah first',
'al thanayah fourth', 'al ras', 'muhaisanah second',
'muhaisanah first', 'al-cornich', 'al mizhar third',
'al rashidiya', 'cornich deira', 'lehbab first', 'um al sheif',
'al garhoud', 'al yufrah 2', 'al yufrah 3', 'al saffa second',
'madinat hind 1', 'al sabkha', 'ras al khor industrial first',
'al buteen', 'jabal ali industrial second', 'al safouh first',
'al aweer first', 'al eyas', 'al mizhar first',
'al qusais industrial third', 'um hurair first', 'al kifaf',
'zaabeel first', 'al waheda', 'zaabeel second', 'ghadeer al tair',
'al twar first', 'grayteesah', 'al warsan third', 'al ttay',
'nad al shiba second', 'al barsha second', 'al athbah',
'al warqa fourth'
];
// Projects list from rents
const projects = [
'starz tower by danube', 'azizi feirouz i',
'candace acacia hotel apartments', 'burj al nujoom',
'azizi riviera 35', 'shams townhouses', 'reem-mira community ph 1',
'schon business park', 'damac hills (2) - albizia',
'reem - mira oasis community', 'trident grand', 'collective 2.0',
'lakeside', 'marina vista', 'madinat jumeriah living - phase 2',
'creek beach - surf', 'creek beach - bayshore',
'creek beach - sunset', 'creek beach - breeze',
'creek beach - vida residences', 'creek beach - orchid',
'creek beach - savanna-cedar-mangrove',
'creek beach - canopy - moor', 'creek beach - summer',
'creek beach - grove', 'creek beach - rosewater',
'creek beach - lotus', 'azizi riviera 46', 'sahara meadows2',
'palace beach residence', 'blue wave', 'new dubai gate1',
'elite 4 sports residence', 'binghatti canal', 'azizi riviera 4',
'liva', 'una', 'azizi park avenue', 'la residence 4 at the lotus',
'damac towers by paramount', 'la residence 3 at the lotus',
'damac hills (2) - viridis', 'vera tower', 'maple iii',
'the lakes deema 2', 'harbour gate', 'luma22', 'sunset gardens b',
'reem-mira community ph5', 'canal front residences cf1 & cf2',
'westburry tower', 'arabian ranches lll - june', 'remraam',
'remraam - al ramth 2', 'remraam - al ramth',
'living legends phase 5', 'damac hills (2) - pacifica',
'qpoint liwan-plot r054', 'qline (qpoint phaseii) 3c-lw-r-054',
'hds business centre', 'jumeirah business centre 4',
'gold crest views2', 'le grand chateau', 'the spirit',
'the valley - orania', 'latifa tower',
'serenia residences the palm', 'mag218', 'empire heights',
'the fields at d11 - mbrmc', 'equiti arcade', 'al jawhara tower',
'mudon views', 'sondos orchid', 'sky courts',
'the pulse beachfront 2', 'damac hills - rochester',
'glitz residence 3', 'burj vista', 'grand boulevard', 'sidra',
'the regent', 'the valley - eden', 'collective', 'iris bay',
'stallion tower', 'sondos zinnia', 'damac heights',
'the polo residence',
'mohammed bin rashid al maktoum city- district one, phase 1',
'the grand', 'maple 2', 'al habtoor city', 'al habtoor tower',
'ajmal sarah', 'the haven', 'elite ii sports residence',
'arabian gate', 'hayat boulevard', 'prime gardens', 'coopet',
'azizi riviera 41', 'the apricot', 'executive bay a',
'executive bay b', 'elite 10 sports residence', 'mag 5 boulevard',
'the court',
'mohammed bin rashid al maktoum city-district one phase ii villas',
'manhattan', 'panorama', 'badra phase 1',
'mirdif hills- nasayem avenue', 'jannat', 'midtown - mesk',
'midtown - afnan', 'midtown - dania', 'midtown - noor',
'azizi riviera 20', 'trillionaire residences by binghatti',
'boris becker business tower', 'rukan', 'opalz by danube',
'oakley square residences', 'royale residence1', 'diamond views 3',
'ag tower', 'the address dubai opera', 'burj park v', 'il primo',
'grande', 'act one | act two', 'the mansion', 'burj park iii',
'opera grand', 'the st. regis residences, downtown dubai',
'm burj', 'the residence | burj khalifa', 'burj khalifa towers',
'sharena residence 1', 'sherena residence', 'burj royale',
'azizi riviera 33', 'the vybe', 'damac hills (2) - victoria 2',
'emirates living - springs 2', 'arabella 2 - townhouses at mudon',
'binghatti onyx', 'escan marina tower', 'fawad azizi residence',
'azizi riviera 17', 'the hills', 'park ridge', 'peninsula one',
'emirates garden 1 (lavender - gardenia - rose)',
'port de la mer - la voile',
'terhab hotel & towers at jumeirah village triangle', 'la rosa 3',
'confident lancaster', 'elite 8 sports residence',
'silicon gates 4', 'reem - mira oasis community phase 3',
'port de la mer - la cote', 'atrium gold towers',
'alduaa marina tower', 'jumeirah living marina gate',
'urban oasis', 'd1', 'palazzo versace', 'azizi riviera 39',
'fair view residency', 'regina', 'i - rise tower', 'time 1',
'sobha hartland - the crest', '17 icon bay', 'rukan 3', 'it plaza',
'dd stand point', 'axis silver', 'maha townhouses',
'damac hills (2) - claret', 'qpoint liwan-plot r071',
'no.17, no.18a,no.18b and no.19 citywalk residential',
'elysee iii by pantheon', 'royale garden residence',
'park heights i', 'azizi riviera 22', 'the pad', 'hockey tower',
'saba tower 3', 'citadel tower', 'new dubai gate2',
'azure residence', 'rasha 2', 'azizi riviera 67',
'damac hills (2) - mimosa', 'mudon al ranim 2',
'sobha hartland waves', 'emirates living - springs 7',
'the bridge', 'sapphire residence', 'azizi riviera 63',
'bay square', 'laguna tower', 'glitz residence 1',
'axis residences 3', '15 northside', 'santevill', 'syann park1',
'jadeel -madinat jumeirah living', 'qpoint liwan-plot r068',
'jasmine lane', 'the onyx',
'mohammed bin rashid al maktoum city , district one phase iii , residences 20',
'rigel', 'elash', 'parkside', 'international city emarati',
'donna towers', 'emirates living - springs 12', 'al furjan',
'the crescent', 'gold crest executive', 'uniestate prime tower',
'al khail heights', 'fairmont palm residence',
'emirates living - springs 10', 'damac hills (2) - centaury',
'upside living', 'lawnsi', 'tanaro', 'mag 22',
'palace residences - dubai creek harbour', 'smart heights',
'binghatti avenue', 'vincitore benessere', 'suberbia',
'alef noon residence', 'damac hills (2) - amargo',
'green community west- extension- phase iii', 'town central',
'celestia', 'celia residence', 'merano tower', 'sami q tower',
'living legends phase 3', 'town square zahra', 'dezire residences',
'harbour residences', 'aykon city 2', 'aykon city', 'aykon city 3',
'binghatti emerald', 'plaza residences', 'the lakes ghadeer',
'the binary by omniyat', 'stadium point', 'b2b tower',
'the pulse townhouses', 'elite residence', 'palma residence',
'uniestate supreme residence', 'ghalia', 'the concourse',
'farhad azizi residence', 'silver tower', 'marquis signature',
'creekside 18', 'sandoval lane', 'miraclz tower', 'orion building',
'mayfair residency', 'dunes village', 'the dubai creek residences',
'asayel at madinat jumeirah living', 'ontario tower',
'damac hills - carson', 'global golf residence 2', 'lake view',
'damac hills (2) - avencia', 'azizi shaista residence',
'jumeirah business centre 5', 'the haven residences',
'avenue residence three', 'serena resedence',
'lawnz residence by danube', 'azizi riviera 45', 'park islands',
'villa lantana 1', 'the terraces', '1 residences', 'fahad 2',
'au tower', 'prive by damac', 'the valley - talia', 'ac3', 'mudon',
'marina residence', 'reem townhouses', 'orra marina',
'ellington beach house', 'q - zone (qpoint - phase iii) mu007',
'qpoint liwan- plot mu007', 'aura', 'binghatti tulip',
'downtown views ii', 'mada\'in',
'mohammed bin rashid al maktoum city , district one phase iii , residences 30',
'matex tower', 'mag 318', 'mag eye phase 1', 'jewelz residence',
'the ivy', 'palace estates', 'tiara residence', 'la vista 05',
'reem - mira oasis community phase 2', 'mulberry at park heights',
'greenview 3', 'royale residence2', 'binghatti venus',
'green valley tower', 'ocean heights', 'one za\'abeel', 'maple',
'westwood grande ii by imtiaz', 'grandeur residences',
'creek edge', 'rawda apartments', 'azizi riviera 43',
'silicon gate 1', 'emirates living - springs 5',
'azizi riviera 61', 'la riviera azure', 'lake central',
'the matrix', 'lagoon views at district one',
'emirates living - springs 11', 'the pulse boulevard apartments',
'dubai marina mall', 'reva residences',
'jumeirah business centre 6', 'me do re', 'signature livings',
'vida residence downtown dubai', 'windsor manor', 'amaranta 2',
'madina tower', 'creek rise', 'azizi riviera 27',
'jumeirah business centre2', 'urbana ii', 'avenue residence 2',
'damac hills (2) - coursetia', 'town square jenna and warda',
'arabian ranches iii - sun', 'azizi riviera 3', 'harbour views',
'the signature', 'centrium tower', 'binghatti corner',
'premiers twin tower', 'mag 5', 'bloom towers', 'the point',
'continental tower', 'clayton residency', 'global green view ii',
'binghatti orchid', 'dunes tower', 'reef residence',
'azizi riviera 25', 'hera tower', 'lakeside residence',
'manam prime', 'trafalgar central', 'elite sports residence',
'dd boulevard central', 'the pulse residence', 'zada tower',
'blue bay', 'warsan village - b & c',
'mohammad aqil ali & ahmad ali alzarooni', 'peninsula five',
'sulafa tower', 'the concourse 2', 'tower 108', 'cadi4',
'dusk by binghatti', 'ariyana', 'zumurud dubai marina',
'joya verde residences dubai', 'wilton terraces',
'avenue residence1', 'elite 6 sports residence',
'diamond views 1- villas b', 'myka residence',
'vida residences dubai marina', 'hamilton residency',
'madison residency', 'the royal atlantis,resort and residences',
'ariana park', 'belgravia iii', 'j&g plexs', 'alandalus townhouse',
'golf ville', 'majestine', 'creek palace', 'jumeirah gate',
'silicon avenue', 'noor townhouses', 'golf tower',
'damac hills (2) - amazonia',
'the address residence fountain views ii',
'the address residence fountain views iii', 'boulevard point',
'vida dubai mall', 'the address residence-fountain views',
'luxury family residence ii', 'iris crystal', 'montrose', 'mirar',
'29 boulevard', 'azizi riviera 12', 'azizi samia residence',
'dm marina plaza', 'golf views', 'la visita 02', 'the autograph',
'canal views', 'bloom heights', 'la rive', 'la vista 04',
'rukan residence', 'qpoint liwan-plot mu002', 'lake terrace',
'damac hills (2) - avencia-2', 'burj crown',
'uniestate sports tower', 'cappadocia', 'riah towers',
'yaass tower', 'townhouses at jumeirah islands',
'damac hills (2) - aquilegia',
'mohammed bin rashid al maktoum city , district one phase iii , residences 24',
'oberoi centre', 'elite 5 sports residence',
'the sterling east house', 'sol avenue', 'forte',
'arabian ranches iii - spring', 'daytona house', 'the palm tower',
'hamza tower', 'oxford boulevard', 'the pulse- beachfront',
'sobha creek vistas reserve', 'pearl house i by imtiaz',
'silicon information technology tower', 'binghatti mirage',
'al ferdows', 'damac hills (2) - victoria', 'torch tower',
'azizi riviera 11',
'no.20, no.21a, no.21b and no.22 citywalk residential',
'las casas',
'mohammed bin rashid al maktoum city , district one phase iii , residences 1',
'azizi riviera 9', 'burlington tower',
'damac hills - golf promenade', 'al waleed garden 2',
'residences du port, dubai marina, autograph collection residences',
'damac hills - brookfield-3', 'damac hills - artesia',
'qpoint liwan-plot r010', 'qline (qpoint phase ii) r010',
'sobha hartland waves grande', 'al andalus phase 2',
'alandalus building e', 'alandalus building g', 'alandalus',
'alandalus building d', 'champions tower1', 'park lane tower',
'the paragon by igo', 'vancouver', 'sidra tower', 'elan',
'mohammed bin rashid al maktoum city , district one phase iii , residences 18',
'solitaire cascades', 'bay central west & central towers',
'q-zone (qpoint - phase iii), mu005&6', 'qpoint liwan-plot mu005',
'qpointliwan-plot mu006', 'damac hills (2) - aster',
'qpoint liwan-plot r055',
'no.1, no.2a, no.2b, no.3a and 3b citywalk residential',
'marquise square tower', 'silver star tower',
'emirates living - springs 3',
'mohammed bin rashid al maktoum city , district one phase iii , residences 13',
'churchill tower', 'park horizon', 'binghatti crescent',
'la rosa 5', 'sobha hartland one park avenue', 'la violeta 2',
'villanova amaranta 4', 'beach vista', 'spica', 'water\'s edge',
'beach isle', 'park field', 'azizi riviera 13', 'liv marina',
'crystal tower', 'diamond views 4', 'gardenia 3', 'aura by grovy',
'mbl residence', 'cayan tower', 'claren 1', 'equiti apartments',
'la-riviera apartments', 'arabian & spainsh tower (phase 2)',
'canal residence west 2', 'elite business bay residence',
'palladium', 'the vortex tower', 'the valley-nara',
'belgravia heights i', 'creek crescent', 'jumeirah park 7b&c',
'condor classic', 'samana golf avenue', 'ellington house',
'arabian ranches lll - caya', 'safi townhouses', 'the wings',
'olivz residence', 'al jawzaa', 'prive residence',
'damac hills (2) - zinnia', 'town square hayat',
'the opus by omniyat', 'maria tower', 'naseem townhouses',
'downtown views', 'blvd heights', 'sol bay',
'damac hills - golf vista', 'urbana iii', 'indigo tower',
'azizi riviera 23', 'the pulse beachfront 3', 'apex atrium',
'creek gate', 'azizi riviera 7', 'concept 7 residences',
'silicon heights', 'the pulse residence park',
'platinum by vision', 'paramount tower hotel & residences',
'azizi riviera 2', 'tenora', 'binghatti creek',
'villanova amaranta 3', 'armada towers', 'town square safi',
'crystal residence', 'harmony', 'oia residence',
'casa flores and eden apartments', 'azizi riviera 14',
'clover bay', 'binghatti heights', 'gardenia livings',
'damac hills-park residences 1', 'arabian ranches iii - joy',
'silverene', 'elite downtown residence', 'profile residence',
'the anwa by omniyat', 'prime tower', 'damac hills (2) - vardon',
'shamal waves', 'tiffany towers', 'topaz residences 2',
'qpoint liwan-plot r069', 'azizi riviera 26', 'pearls by vision',
'azizi riviera 47', 'azizi riviera 42', 'azizi gardens',
'imperial', 'reem-mira community ph 4', 'azizi aura residences',
'prime business avenue',
'lincoln park(west side & lincoln park - b)',
'mohammed bin rashid al maktoum city district one- c villas',
'wavez residence', '51@business bay', 'arabian ranches lll - ruba',
'living legends phase 7', 'elz residence', 'burj views'
];
function populateAreas() {
const areaSelect = document.getElementById('area_name');
areas.forEach(area => {
const option = document.createElement('option');
option.value = area;
option.textContent = area.charAt(0).toUpperCase() + area.slice(1).replace(/\b\w/g, l => l.toUpperCase());
areaSelect.appendChild(option);
});
}
function loadProjects() {
const projectSelect = document.getElementById('project');
const sortedProjects = projects.slice().sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
sortedProjects.forEach(project => {
const option = document.createElement('option');
option.value = project;
option.textContent = project.length > 70 ? project.substring(0, 70) + '...' : project;
projectSelect.appendChild(option);
});
}
function showLoading(show) {
document.getElementById('loading').style.display = show ? 'block' : 'none';
}
function showError(message) {
const errorDiv = document.getElementById('error');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
}
function hideError() {
document.getElementById('error').style.display = 'none';
}
function showResults() {
document.getElementById('resultsSection').style.display = 'block';
}
function hideResults() {
document.getElementById('resultsSection').style.display = 'none';
}
function formatDate(dateString) {
if (!dateString) return 'N/A';
const date = new Date(dateString);
return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
}
function formatNumber(num, decimals = 0) {
if (num === null || num === undefined) return 'N/A';
return parseFloat(num).toLocaleString('en-US', { maximumFractionDigits: decimals });
}
function formatCurrency(amount) {
if (!amount) return 'N/A';
return 'AED ' + parseFloat(amount).toLocaleString('en-US', { maximumFractionDigits: 0 });
}
let currentPage = 1;
let lastPaging = { total: 0, page: null, page_size: 30, total_pages: 1, has_next: false, has_prev: false };
async function searchRents(pageOverride) {
const formData = new FormData(document.getElementById('filtersForm'));
const params = new URLSearchParams();
const area_name = formData.get('area_name');
const property_type = formData.get('property_type');
const size_min = formData.get('size_min');
const size_max = formData.get('size_max');
const rooms = formData.get('rooms');
const project = formData.get('project');
const pageSize = formData.get('page_size') || '30';
const page = pageOverride != null ? pageOverride : (formData.get('page') || currentPage || 1);
if (area_name) params.append('area_name', area_name);
if (property_type && property_type !== 'all') params.append('property_type', property_type);
if (size_min && !isNaN(parseFloat(size_min))) params.append('size_min', size_min);
if (size_max && !isNaN(parseFloat(size_max))) params.append('size_max', size_max);
if (rooms && rooms !== 'all') params.append('rooms', rooms);
if (project && project !== 'all') params.append('project', project);
// pagination params
if (page) params.append('page', page);
if (pageSize) params.append('page_size', pageSize);
showLoading(true);
hideError();
hideResults();
try {
const response = await fetch(`${API_BASE}/rents/recent?${params.toString()}`);
const data = await response.json();
if (data.success) {
currentPage = data.data.page || 1;
lastPaging = {
total: data.data.total ?? data.data.count,
page: data.data.page,
page_size: data.data.page_size ?? parseInt(pageSize,10),
total_pages: data.data.total_pages ?? 1,
has_next: !!data.data.has_next,
has_prev: !!data.data.has_prev
};
displayResults(data.data);
} else {
showError(data.message || 'Failed to fetch rents');
}
} catch (error) {
showError('Network error: ' + error.message);
} finally {
showLoading(false);
}
}
function displayResults(data) {
const { rents, count, total, page, page_size, total_pages, has_next, has_prev } = data;
const tbody = document.getElementById('rentsBody');
const resultsCount = document.getElementById('resultsCount');
const showing = count;
const grandTotal = total ?? count;
resultsCount.textContent = `Showing ${showing} of ${grandTotal} rents`;
const pageInfo = document.getElementById('pageInfo');
if (pageInfo) {
if (page && total_pages) {
pageInfo.textContent = `Page ${page} of ${total_pages}`;
} else {
pageInfo.textContent = '';
}
}
const prevBtn = document.getElementById('prevPage');
const nextBtn = document.getElementById('nextPage');
if (prevBtn) prevBtn.disabled = !(has_prev);
if (nextBtn) nextBtn.disabled = !(has_next);
if (rents.length === 0) {
const colCount = document.querySelectorAll('#rentsTable thead th').length;
tbody.innerHTML = (
'<tr>' +
`<td colspan="${colCount}" class="no-results">` +
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">' +
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>' +
'</svg>' +
'<div>No rents found matching your filters</div>' +
'</td>' +
'</tr>'
);
showResults();
return;
}
tbody.innerHTML = rents.map(r => (
'<tr>' +
`<td>${r.rent_id ?? 'N/A'}</td>` +
`<td>${formatDate(r.registration_date)}</td>` +
`<td>${formatDate(r.start_date)}</td>` +
`<td>${formatDate(r.end_date)}</td>` +
`<td>${r.version_en ?? 'N/A'}</td>` +
`<td>${r.area_en ?? 'N/A'}</td>` +
`<td>${formatCurrency(r.contract_amount)}</td>` +
`<td>${formatCurrency(r.annual_amount)}</td>` +
`<td>${r.is_free_hold_en ?? 'N/A'}</td>` +
`<td>${formatNumber(r.actual_area)}</td>` +
`<td>${r.prop_type_en ?? 'N/A'}</td>` +
`<td>${r.prop_sub_type_en ?? 'N/A'}</td>` +
`<td>${r.rooms != null ? formatNumber(r.rooms, 1) : 'N/A'}</td>` +
`<td>${r.usage_en ?? 'N/A'}</td>` +
`<td>${r.nearest_metro_en ?? 'N/A'}</td>` +
`<td>${r.nearest_mall_en ?? 'N/A'}</td>` +
`<td>${r.nearest_landmark_en ?? 'N/A'}</td>` +
`<td>${r.parking != null ? formatNumber(r.parking, 1) : 'N/A'}</td>` +
`<td>${r.total_properties ?? '0'}</td>` +
`<td>${r.master_project_en ?? 'N/A'}</td>` +
`<td>${r.project_en ?? 'N/A'}</td>` +
`<td>${formatDate(r.created_at)}</td>` +
`<td>${formatDate(r.updated_at)}</td>` +
'</tr>'
)).join('');
showResults();
}
function resetFilters() {
document.getElementById('filtersForm').reset();
document.getElementById('size_min').value = '';
document.getElementById('size_max').value = '';
document.getElementById('sizeValue').textContent = 'All Sizes';
hideResults();
hideError();
}
document.addEventListener('DOMContentLoaded', () => {
populateAreas();
loadProjects();
const sizeMinHidden = document.getElementById('size_min');
const sizeMaxHidden = document.getElementById('size_max');
const sizeMinRange = document.getElementById('size_min_range');
const sizeMaxRange = document.getElementById('size_max_range');
const sizeFill = document.getElementById('sizeFill');
const sizeValue = document.getElementById('sizeValue');
const MIN_VAL = parseFloat(sizeMinRange.min);
const MAX_VAL = parseFloat(sizeMinRange.max);
const STEP = parseFloat(sizeMinRange.step) || 100;
function updateSizeLabel() {
const min = parseFloat(sizeMinRange.value);
const max = parseFloat(sizeMaxRange.value);
const hasMin = !isNaN(min);
const hasMax = !isNaN(max);
if (!hasMin && !hasMax) {
sizeValue.textContent = 'All Sizes';
} else if (hasMin && hasMax) {
sizeValue.textContent = `${min.toLocaleString('en-US')} - ${max.toLocaleString('en-US')} sq.ft`;
} else if (hasMin) {
sizeValue.textContent = `${min.toLocaleString('en-US')} sq.ft`;
} else {
sizeValue.textContent = `${max.toLocaleString('en-US')} sq.ft`;
}
// Persist only when different from full range
sizeMinHidden.value = (min > MIN_VAL) ? min : '';
sizeMaxHidden.value = (max < MAX_VAL) ? max : '';
// Update fill track
const left = ((Math.max(MIN_VAL, Math.min(min, max)) - MIN_VAL) / (MAX_VAL - MIN_VAL)) * 100;
const right = ((Math.max(MIN_VAL, Math.max(min, max)) - MIN_VAL) / (MAX_VAL - MIN_VAL)) * 100;
sizeFill.style.left = `${left}%`;
sizeFill.style.width = `${Math.max(0, right - left)}%`;
}
function clampRanges() {
if (parseFloat(sizeMinRange.value) > parseFloat(sizeMaxRange.value) - STEP) {
sizeMinRange.value = (parseFloat(sizeMaxRange.value) - STEP).toString();
}
if (parseFloat(sizeMaxRange.value) < parseFloat(sizeMinRange.value) + STEP) {
sizeMaxRange.value = (parseFloat(sizeMinRange.value) + STEP).toString();
}
}
sizeMinRange.addEventListener('input', () => { clampRanges(); updateSizeLabel(); });
sizeMaxRange.addEventListener('input', () => { clampRanges(); updateSizeLabel(); });
// Ensure both handles are draggable when overlapping by toggling z-index on interaction
function bringMinToFront() {
sizeMinRange.style.zIndex = '6';
sizeMaxRange.style.zIndex = '5';
}
function bringMaxToFront() {
sizeMinRange.style.zIndex = '5';
sizeMaxRange.style.zIndex = '6';
}
['mousedown','pointerdown','touchstart'].forEach(evt => {
sizeMinRange.addEventListener(evt, bringMinToFront, { passive: true });
sizeMaxRange.addEventListener(evt, bringMaxToFront, { passive: true });
});
// Initialize
sizeMinRange.value = MIN_VAL;
sizeMaxRange.value = MAX_VAL;
updateSizeLabel();
document.getElementById('filtersForm').addEventListener('submit', async (e) => {
e.preventDefault();
currentPage = 1;
const pageInput = document.getElementById('page');
if (pageInput) pageInput.value = '1';
await searchRents(1);
});
const resetBtn = document.getElementById('resetBtn');
if (resetBtn) {
resetBtn.addEventListener('click', resetFilters);
}
// pagination buttons
const prevBtn = document.getElementById('prevPage');
const nextBtn = document.getElementById('nextPage');
if (prevBtn) {
prevBtn.addEventListener('click', async () => {
if (lastPaging.has_prev && currentPage > 1) {
currentPage -= 1;
const pageInput2 = document.getElementById('page');
if (pageInput2) pageInput2.value = String(currentPage);
await searchRents(currentPage);
}
});
}
if (nextBtn) {
nextBtn.addEventListener('click', async () => {
if (lastPaging.has_next) {
currentPage += 1;
const pageInput3 = document.getElementById('page');
if (pageInput3) pageInput3.value = String(currentPage);
await searchRents(currentPage);
}
});
}
});