Signed-off-by: boris <boris@borishub.co.uk>
This commit is contained in:
boris
2025-04-20 16:49:23 +01:00
parent 709596eea2
commit 78508a7cbd
29 changed files with 2623 additions and 2956 deletions

View File

@@ -17,40 +17,49 @@ function initialiseFacilityData(data, force = false) {
}
// Store the data in sessionStorage for persistence
sessionStorage.setItem('facilityData', JSON.stringify(data));
// Ensure table exists
const table = document.querySelector('#facilityTable');
if (!table) {
console.error('Table not found in DOM. Available elements:',
Array.from(document.querySelectorAll('table')).map(t => t.id || 'no-id'));
throw new Error('Facility table not found in DOM');
}
// Clear existing table content
const tbody = table.querySelector('tbody');
if (tbody) {
tbody.innerHTML = '';
} else {
console.warn('No tbody found in table, creating one');
const newTbody = document.createElement('tbody');
table.appendChild(newTbody);
}
// Initialize filteredData with all data
filteredData = data;
// Calculate total pages
totalPages = Math.ceil(filteredData.length / itemsPerPage);
// Set current page to 1
currentPage = 1;
// Update table with paginated data
updateTableWithPagination();
// Check if we're on the map page
const isMapPage = window.location.pathname.includes('map.php');
if (!isMapPage) {
// Only try to initialize table if we're not on the map page
const table = document.querySelector('#facilityTable');
if (!table) {
console.error('Table not found in DOM. Available elements:',
Array.from(document.querySelectorAll('table')).map(t => t.id || 'no-id'));
throw new Error('Facility table not found in DOM');
}
// Clear existing table content
const tbody = table.querySelector('tbody');
if (tbody) {
tbody.innerHTML = '';
} else {
console.warn('No tbody found in table, creating one');
const newTbody = document.createElement('tbody');
table.appendChild(newTbody);
}
// Set up table controls (sorting and filtering)
setupTableControls();
// Initialize filteredData with all data
filteredData = data;
// Calculate total pages
totalPages = Math.ceil(filteredData.length / itemsPerPage);
// Set current page to 1
currentPage = 1;
// Update table with paginated data
updateTable();
// Set up table controls (sorting and filtering)
setupTableControls();
}
// Mark as initialized
isInitialized = true;
} catch (error) {
error_log('Error initialising facility data:', error);
console.error('Error initialising facility data:', error);
// Don't throw error if we're on map page, as table errors are expected
if (!window.location.pathname.includes('map.php')) {
throw error;
}
}
}
@@ -68,6 +77,10 @@ function renderFacilityTable(data) {
// Clear existing table content
tbody.innerHTML = '';
// Check if user is admin
const userIsAdmin = isAdmin();
console.log('renderFacilityTable - userIsAdmin:', userIsAdmin);
// Render each row
data.forEach((facility, index) => {
if (!facility) return;
@@ -82,9 +95,22 @@ function renderFacilityTable(data) {
// Create category badge with color based on category
const categoryClass = getCategoryColorClass(facility.category);
row.innerHTML = `
<td class="d-none">${escapeHtml(facility.id)}</td>
<td class="fw-medium align-middle" style="width: 15%;">
// Start building the row HTML
let rowHtml = '';
// Only show ID column for admins
if (userIsAdmin) {
console.log('Adding ID column for facility:', facility.id);
rowHtml += `
<td class="fw-medium align-middle text-center" style="width: 40px;">
${escapeHtml(facility.id)}
</td>
`;
}
// Add the rest of the columns
rowHtml += `
<td class="fw-medium align-middle" style="${userIsAdmin ? 'width: 15%;' : 'width: 17%;'}">
<div class="d-flex align-items-center h-100">
<div class="facility-icon me-2 rounded-circle bg-light d-flex align-items-center justify-content-center" style="width: 28px; height: 28px; min-width: 28px;">
<i class="${getFacilityIcon(facility.category)} text-${categoryClass}"></i>
@@ -92,14 +118,14 @@ function renderFacilityTable(data) {
<span class="text-truncate" style="max-width: calc(100% - 35px);">${escapeHtml(facility.title)}</span>
</div>
</td>
<td class="text-center align-middle" style="width: 10%;">
<td class="text-center align-middle" style="${userIsAdmin ? 'width: 10%;' : 'width: 11%;'}">
<div class="d-flex align-items-center justify-content-center h-100">
<span class="badge bg-${categoryClass} bg-opacity-10 text-${categoryClass} px-2 py-1 rounded-pill">
${escapeHtml(facility.category)}
</span>
</div>
</td>
<td class="align-middle" style="width: 25%;">
<td class="align-middle" style="${userIsAdmin ? 'width: 25%;' : 'width: 27%;'}">
<div class="description-container d-flex flex-column justify-content-center">
<div class="cell-content" data-full-text="${escapeHtml(facility.description)}">
${escapeHtml(facility.description)}
@@ -118,16 +144,15 @@ function renderFacilityTable(data) {
</div>
</div>
</td>
<td class="small fw-medium text-center align-middle" style="width: 8%;" hidden>${escapeHtml(facility.postcode)}</td>
<td class="small text-nowrap text-center align-middle" style="width: 12%;">
<td class="small text-nowrap text-center align-middle" style="${userIsAdmin ? 'width: 12%;' : 'width: 12%;'}">
<span class="badge bg-light text-dark border">
${escapeHtml(coordinates)}
</span>
</td>
<td class="small text-center align-middle" style="width: 8%;">${escapeHtml(facility.contributor)}</td>
<td class="text-center align-middle" style="width: 10%;">
<td class="text-center align-middle" style="${userIsAdmin ? 'width: 10%;' : 'width: 5%;'}">
<div class="d-flex justify-content-center gap-1">
${isAdmin() ? `
${userIsAdmin ? `
<button type="button" class="btn btn-sm btn-outline-primary update-btn rounded-circle d-flex align-items-center justify-content-center" style="width: 30px; height: 30px;" data-bs-toggle="modal" data-bs-target="#updateModal" data-facility-id="${facility.id}" title="Edit">
<span class="bi bi-pen-fill"></span>
</button>
@@ -141,15 +166,17 @@ function renderFacilityTable(data) {
</div>
</td>
`;
row.innerHTML = rowHtml;
tbody.appendChild(row);
});
// If no data, show a message
if (data.length === 0) {
const emptyRow = document.createElement('tr');
const colSpan = userIsAdmin ? 8 : 7; // Adjust colspan based on number of columns
emptyRow.innerHTML = `
<td colspan="9" class="text-center py-4 text-muted">
<td colspan="${colSpan}" class="text-center py-4 text-muted">
<div class="d-flex flex-column align-items-center">
<span class="bi bi-inbox fs-2 mb-2"></span>
<p class="mb-0">No facilities found</p>
@@ -204,10 +231,15 @@ function formatAddress(facility) {
* @returns {boolean} True if user is admin, false otherwise
*/
function isAdmin() {
console.log('Checking admin status...');
// Check if auth service is available and has user data
if (window.auth && window.auth.getUser()) {
const authUser = window.auth.getUser();
if (simpleAuth && simpleAuth.getUser()) {
const authUser = simpleAuth.getUser();
console.log('Auth service user data:', authUser);
console.log('Auth service accessLevel:', authUser.accessLevel);
console.log('Auth service isAdmin check:', authUser.accessLevel === 1 || authUser.accessLevel === 0);
if (authUser && (authUser.accessLevel === 1 || authUser.accessLevel === 0)) {
console.log('User is admin according to auth service');
return true;
@@ -217,17 +249,26 @@ function isAdmin() {
// Fallback to localStorage
const user = JSON.parse(localStorage.getItem('user') || '{}');
console.log('Checking admin status from localStorage:', user);
const isAdminUser = user && (user.accessLevel === 1 || user.accessLevel === 0);
console.log('Is admin according to localStorage:', isAdminUser);
console.log('localStorage accessLevel:', user.accessLevel);
console.log('localStorage isAdmin check:', user.accessLevel === 1 || user.accessLevel === 0);
const isAdminUser = user && (user.accessLevel === 1 || user.accessLevel === 0);
console.log('Final isAdmin result:', isAdminUser);
return isAdminUser;
}
/**
* Checks if the current user is authenticated
* (helper function) Checks if the current user is authenticated
* @returns {boolean} True if authenticated, false otherwise
*/
function isAuthenticated() {
// Check if auth service is available
if (simpleAuth) {
return simpleAuth.isAuthenticated();
}
// Fallback to localStorage
const token = localStorage.getItem('token');
return !!token;
}
@@ -395,8 +436,8 @@ function setupFormHandlers() {
// Set the contributor to the current user's username
formData.set('contCreate', JSON.parse(localStorage.getItem('user'))?.username);
try {
// Use authFetch instead of regular fetch
const response = await window.authFetch('/facilitycontroller.php', {
// Use simpleAuth.fetchAuth for authenticated requests
const response = await simpleAuth.fetchAuth('/facilitycontroller.php', {
method: 'POST',
body: formData
});
@@ -493,8 +534,8 @@ function setupFormHandlers() {
}
try {
// Use authFetch instead of regular fetch
const response = await window.authFetch('/facilitycontroller.php', {
// Use simpleAuth.fetchAuth for authenticated requests
const response = await simpleAuth.fetchAuth('/facilitycontroller.php', {
method: 'POST',
body: serverFormData
});
@@ -582,19 +623,19 @@ function setupFormHandlers() {
try {
// Check if token is valid
if (!window.auth) {
if (!simpleAuth) {
throw new Error('Auth service not available');
}
// Validate token with server before proceeding
console.log('Validating token with server...');
const isValid = await window.auth.validateToken();
const isValid = await simpleAuth.validateToken();
if (!isValid) {
throw new Error('Authentication token is invalid or expired');
}
// Get token after validation to ensure it's fresh
const token = window.auth.getToken();
const token = simpleAuth.getToken();
console.log('Using token for delete request:', token);
if (!token) {
@@ -602,16 +643,16 @@ function setupFormHandlers() {
}
// Decode token to check payload
if (window.auth.parseJwt) {
const payload = window.auth.parseJwt(token);
if (simpleAuth.parseJwt) {
const payload = simpleAuth.parseJwt(token);
console.log('Token payload:', payload);
console.log('Access level:', payload.accessLevel);
console.log('Is admin check:', payload.accessLevel === 0 || payload.accessLevel === 1);
}
// Use direct fetch with manual token inclusion
// Use simpleAuth.fetchAuth for authenticated requests
console.log('Sending delete request to server...');
const response = await fetch('/facilitycontroller.php', {
const response = await simpleAuth.fetchAuth('/facilitycontroller.php', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
@@ -1112,86 +1153,5 @@ function getCategoryColorClass(category) {
return 'secondary';
}
/**
* Sets up expandable content for a table row
* @param {HTMLElement} row - The table row element
*/
function setupExpandableContent(row) {
// Setup description expansion
const descriptionContent = row.querySelector('.cell-content');
const toggleBtn = row.querySelector('.toggle-content-btn');
if (descriptionContent) {
// Make description expandable on click
descriptionContent.addEventListener('click', function() {
this.classList.toggle('expanded');
// Update button text if it exists
if (toggleBtn) {
toggleBtn.querySelector('small').textContent =
this.classList.contains('expanded') ? 'Show less' : 'Show more';
}
// Ensure proper alignment when expanded
const container = this.closest('.description-container');
if (container) {
if (this.classList.contains('expanded')) {
container.classList.remove('justify-content-center');
container.classList.add('justify-content-start');
} else {
container.classList.remove('justify-content-start');
container.classList.add('justify-content-center');
}
}
});
// Setup toggle button if it exists
if (toggleBtn) {
toggleBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const content = this.closest('.description-container').querySelector('.cell-content');
content.classList.toggle('expanded');
this.querySelector('small').textContent =
content.classList.contains('expanded') ? 'Show less' : 'Show more';
// Ensure proper alignment when expanded
const container = content.closest('.description-container');
if (container) {
if (content.classList.contains('expanded')) {
container.classList.remove('justify-content-center');
container.classList.add('justify-content-start');
} else {
container.classList.remove('justify-content-start');
container.classList.add('justify-content-center');
}
}
});
}
}
// Setup address expansion
const addressContent = row.querySelector('.address-content');
if (addressContent) {
addressContent.addEventListener('click', function() {
this.classList.toggle('expanded');
// Ensure proper alignment when expanded
const container = this.closest('.d-flex');
if (container) {
if (this.classList.contains('expanded')) {
container.classList.remove('align-items-center');
container.classList.add('align-items-start');
} else {
container.classList.remove('align-items-start');
container.classList.add('align-items-center');
}
}
});
}
}
// Export the initialization function
window.initializeFacilityData = initialiseFacilityData;