Replace broken Location dropdown with Place (city) dropdown + Location Facility text input. Add /api/places endpoint. Add place/location_text filter params to /api/assets. Add functional_location to work orders API and frontend.
This commit is contained in:
+51
-34
@@ -1367,11 +1367,15 @@
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex:1">
|
||||
<div class="fp-label">Location</div>
|
||||
<select id="filterLocation" class="input-field" onchange="onFilterChange()">
|
||||
<option value="">All locations</option>
|
||||
<div class="fp-label">Place / City</div>
|
||||
<select id="filterPlace" class="input-field" onchange="onFilterChange()">
|
||||
<option value="">All places</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex:1">
|
||||
<div class="fp-label">Location Facility</div>
|
||||
<input id="filterLocationText" type="text" class="input-field" placeholder="Building, area..." oninput="onFilterChange()" style="font-size:12px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-row">
|
||||
<div style="flex:1">
|
||||
@@ -1878,6 +1882,12 @@
|
||||
|
||||
<!-- Filter panel (collapsible) -->
|
||||
<div class="filter-panel" id="woFilterPanel">
|
||||
<div class="fp-row">
|
||||
<div style="flex:1">
|
||||
<div class="fp-label">Location / Facility</div>
|
||||
<input id="woFilterLocation" type="text" class="input-field" placeholder="City, pavilion, area..." oninput="onWOFilterChange()" style="font-size:12px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-row">
|
||||
<div style="flex:1">
|
||||
<div class="fp-label">Status</div>
|
||||
@@ -4153,7 +4163,7 @@
|
||||
|
||||
// ── Filter state ──────────────────────────────────────────────────────
|
||||
let assetFilters = { category: null, status: null, make: null, disney_park: null, disney_group: null, disney_filter: null, q: '',
|
||||
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
||||
customer_id: null, location_id: null, assigned_to: null, branch: null, place: null, location_text: null };
|
||||
let noDexFilterActive = false;
|
||||
let assetOffset = 0;
|
||||
const ASSET_PAGE_SIZE = 2000;
|
||||
@@ -4196,6 +4206,15 @@
|
||||
var custSel = document.getElementById('filterCustomer');
|
||||
custSel.innerHTML = '<option value="">All customers</option>' +
|
||||
customers.map(function(c) { return '<option value="' + c.id + '">' + esc(c.name) + '</option>'; }).join('');
|
||||
|
||||
// Load places
|
||||
try {
|
||||
var places = await api('/api/places');
|
||||
var placeSel = document.getElementById('filterPlace');
|
||||
if (placeSel) placeSel.innerHTML = '<option value="">All places</option>' +
|
||||
places.map(function(p) { return '<option value="' + esc(p) + '">' + esc(p) + '</option>'; }).join('');
|
||||
} catch(e) {}
|
||||
|
||||
// Load users for assigned_to filter
|
||||
var users = await api('/api/users');
|
||||
var assnSel = document.getElementById('filterAssignedTo');
|
||||
@@ -4238,7 +4257,8 @@
|
||||
var disneyFilterEl = document.getElementById('filterDisneyFilter');
|
||||
var parkEl = document.getElementById('filterDisneyPark');
|
||||
var custEl = document.getElementById('filterCustomer');
|
||||
var locEl = document.getElementById('filterLocation');
|
||||
var placeEl = document.getElementById('filterPlace');
|
||||
var locTextEl = document.getElementById('filterLocationText');
|
||||
|
||||
var assnEl = document.getElementById('filterAssignedTo');
|
||||
var branchEl = document.getElementById('filterBranch');
|
||||
@@ -4254,7 +4274,6 @@
|
||||
} else {
|
||||
var parkVal = parkEl.value;
|
||||
if (parkVal && parkVal.startsWith('group:')) {
|
||||
// Grouped park category
|
||||
assetFilters.disney_group = parkVal.replace('group:', '');
|
||||
assetFilters.disney_park = null;
|
||||
assetFilters.disney_filter = null;
|
||||
@@ -4269,38 +4288,20 @@
|
||||
}
|
||||
}
|
||||
assetFilters.customer_id = custEl.value || null;
|
||||
assetFilters.place = placeEl ? placeEl.value || null : null;
|
||||
assetFilters.location_text = locTextEl ? locTextEl.value.trim() || null : null;
|
||||
|
||||
assetFilters.assigned_to = assnEl.value || null;
|
||||
assetFilters.branch = branchEl.value || null;
|
||||
|
||||
var prevCust = locEl.dataset.customerId;
|
||||
if (custEl.value !== prevCust) {
|
||||
locEl.innerHTML = '<option value="">All locations</option>';
|
||||
locEl.disabled = true;
|
||||
assetFilters.location_id = null;
|
||||
if (custEl.value) {
|
||||
loadLocationsForCustomer(custEl.value);
|
||||
}
|
||||
} else {
|
||||
assetFilters.location_id = locEl.value || null;
|
||||
}
|
||||
locEl.dataset.customerId = custEl.value;
|
||||
// Clear old location_id since we replaced it
|
||||
assetFilters.location_id = null;
|
||||
|
||||
assetOffset = 0;
|
||||
renderActiveFilterTags();
|
||||
_loadAssets();
|
||||
}
|
||||
|
||||
async function loadLocationsForCustomer(customerId) {
|
||||
try {
|
||||
var locations = await api('/api/locations?customer_id=' + customerId);
|
||||
var locEl = document.getElementById('filterLocation');
|
||||
locEl.innerHTML = '<option value="">All locations</option>' +
|
||||
locations.map(function(l) { return '<option value="' + l.id + '">' + esc(l.name) + '</option>'; }).join('');
|
||||
locEl.disabled = false;
|
||||
} catch (e) { showToast('Failed to load locations', true); }
|
||||
}
|
||||
|
||||
function getActiveFilterCount() {
|
||||
var count = 0;
|
||||
if (assetFilters.category) count++;
|
||||
@@ -4310,6 +4311,8 @@
|
||||
if (assetFilters.disney_group) count++;
|
||||
if (assetFilters.disney_filter) count++;
|
||||
if (assetFilters.customer_id) count++;
|
||||
if (assetFilters.place) count++;
|
||||
if (assetFilters.location_text) count++;
|
||||
if (assetFilters.location_id) count++;
|
||||
if (assetFilters.assigned_to) count++;
|
||||
if (assetFilters.branch) count++;
|
||||
@@ -4340,8 +4343,10 @@
|
||||
if (assetFilters.customer_id) {
|
||||
var custSel = document.getElementById('filterCustomer');
|
||||
var txt = custSel.options[custSel.selectedIndex] ? custSel.options[custSel.selectedIndex].text : 'Customer';
|
||||
tags.push({key:'customer_id', label:'\uD83C\uDFE2 ' + txt});
|
||||
tags.push({key:'customer_id', label:'🏢 ' + txt});
|
||||
}
|
||||
if (assetFilters.place) tags.push({key:'place', label:'📍 ' + assetFilters.place});
|
||||
if (assetFilters.location_text) tags.push({key:'location_text', label:'🏗️ ' + assetFilters.location_text});
|
||||
if (assetFilters.location_id) {
|
||||
var locSel = document.getElementById('filterLocation');
|
||||
var txt = locSel.options[locSel.selectedIndex] ? locSel.options[locSel.selectedIndex].text : 'Location';
|
||||
@@ -4385,10 +4390,14 @@
|
||||
assetFilters.disney_filter = null;
|
||||
} else if (key === 'customer_id') {
|
||||
document.getElementById('filterCustomer').value = '';
|
||||
document.getElementById('filterLocation').innerHTML = '<option value="">All locations</option>';
|
||||
document.getElementById('filterLocation').disabled = true;
|
||||
assetFilters.customer_id = null;
|
||||
assetFilters.location_id = null;
|
||||
} else if (key === 'place') {
|
||||
document.getElementById('filterPlace').value = '';
|
||||
assetFilters.place = null;
|
||||
} else if (key === 'location_text') {
|
||||
document.getElementById('filterLocationText').value = '';
|
||||
assetFilters.location_text = null;
|
||||
} else if (key === 'location_id') {
|
||||
document.getElementById('filterLocation').value = '';
|
||||
assetFilters.location_id = null;
|
||||
@@ -4410,7 +4419,7 @@
|
||||
|
||||
function clearAllFilters() {
|
||||
assetFilters = { category: null, status: null, make: null, disney_park: null, disney_group: null, disney_filter: null, q: '',
|
||||
customer_id: null, location_id: null, assigned_to: null, branch: null };
|
||||
customer_id: null, location_id: null, assigned_to: null, branch: null, place: null, location_text: null };
|
||||
document.getElementById('assetSearch').value = '';
|
||||
document.getElementById('clearSearch').style.display = 'none';
|
||||
document.getElementById('filterCategory').value = '';
|
||||
@@ -4418,8 +4427,8 @@
|
||||
document.getElementById('filterDisneyPark').value = '';
|
||||
document.getElementById('filterDisneyFilter').value = '';
|
||||
document.getElementById('filterCustomer').value = '';
|
||||
document.getElementById('filterLocation').innerHTML = '<option value="">All locations</option>';
|
||||
document.getElementById('filterLocation').disabled = true;
|
||||
if (document.getElementById('filterPlace')) document.getElementById('filterPlace').value = '';
|
||||
if (document.getElementById('filterLocationText')) document.getElementById('filterLocationText').value = '';
|
||||
|
||||
document.getElementById('filterAssignedTo').value = '';
|
||||
document.getElementById('filterBranch').value = '';
|
||||
@@ -4582,11 +4591,13 @@
|
||||
var techEl = document.getElementById('woFilterTech');
|
||||
var priorityEl = document.getElementById('woFilterPriority');
|
||||
var typeEl = document.getElementById('woFilterType');
|
||||
var locEl = document.getElementById('woFilterLocation');
|
||||
|
||||
woFilters.status = statusEl.value || null;
|
||||
woFilters.tech = techEl.value || null;
|
||||
woFilters.priority = priorityEl.value || null;
|
||||
woFilters.work_type = typeEl.value || null;
|
||||
woFilters.location = locEl ? locEl.value.trim() || null : null;
|
||||
|
||||
renderWOActiveFilterTags();
|
||||
woOffset = 0;
|
||||
@@ -4600,6 +4611,7 @@
|
||||
if (woFilters.tech) count++;
|
||||
if (woFilters.priority) count++;
|
||||
if (woFilters.work_type) count++;
|
||||
if (woFilters.location) count++;
|
||||
if (woFilters.date_range && woFilters.date_range !== 'today' && woFilters.date_range !== 'all') count++;
|
||||
if (woFilters.date_from) count++;
|
||||
if (woFilters.date_to) count++;
|
||||
@@ -4624,6 +4636,7 @@
|
||||
if (woFilters.tech) tags.push({key:'tech', label:'👤 ' + woFilters.tech});
|
||||
if (woFilters.priority) tags.push({key:'priority', label:'🏷️ ' + woFilters.priority});
|
||||
if (woFilters.work_type) tags.push({key:'work_type', label:'🔧 ' + woFilters.work_type});
|
||||
if (woFilters.location) tags.push({key:'location', label:'📍 ' + woFilters.location});
|
||||
if (woFilters.date_range === 'today') tags.push({key:'date_range', label:'📅 Today'});
|
||||
else if (woFilters.date_range === 'week') tags.push({key:'date_range', label:'📅 This Week'});
|
||||
else if (woFilters.date_range === 'month') tags.push({key:'date_range', label:'📅 This Month'});
|
||||
@@ -4753,6 +4766,7 @@
|
||||
// Filters
|
||||
if (woFilters.status) params.set('status', woFilters.status);
|
||||
if (woFilters.tech) params.set('tech', woFilters.tech);
|
||||
if (woFilters.location) params.set('location', woFilters.location);
|
||||
|
||||
params.set('limit', String(WO_PAGE_SIZE));
|
||||
params.set('offset', String(woOffset));
|
||||
@@ -4804,6 +4818,7 @@
|
||||
(accountName ? '<div class="wo-account">' + esc(accountName) + '</div>' : '') +
|
||||
'<div class="wo-meta">' +
|
||||
(dateStr ? '<span>📅 ' + esc(dateStr) + '</span>' : '') +
|
||||
(w.functional_location ? '<span>📍 ' + esc(w.functional_location) + '</span>' : '') +
|
||||
(w.territory ? '<span>🏢 ' + esc(w.territory) + '</span>' : '') +
|
||||
(techStr ? '<span>' + esc(techStr) + '</span>' : '') +
|
||||
(cityStr ? '<span>📍 ' + esc(cityStr) + '</span>' : '') +
|
||||
@@ -5051,6 +5066,8 @@
|
||||
if (assetFilters.disney_filter) params.set('disney_filter', assetFilters.disney_filter);
|
||||
if (assetFilters.q) params.set('q', assetFilters.q);
|
||||
if (assetFilters.customer_id) params.set('customer_id', assetFilters.customer_id);
|
||||
if (assetFilters.place) params.set('place', assetFilters.place);
|
||||
if (assetFilters.location_text) params.set('location_text', assetFilters.location_text);
|
||||
if (assetFilters.location_id) params.set('location_id', assetFilters.location_id);
|
||||
if (assetFilters.assigned_to) params.set('assigned_to', assetFilters.assigned_to);
|
||||
if (assetFilters.branch) params.set('branch', assetFilters.branch);
|
||||
|
||||
Reference in New Issue
Block a user