mirror of
https://github.com/sassanix/Warracker.git
synced 2026-05-13 04:39:08 -05:00
Reverted
Reverted the changes, as performance and core usage was effected
This commit is contained in:
+1
-176
@@ -1,180 +1,5 @@
|
||||
# Changelog
|
||||
## 1.0.3 - 2025-11-07
|
||||
|
||||
### Added
|
||||
- **Modular Entry Orchestrator and Feature Modules**
|
||||
- Added a lean ES module entry orchestrator `index.js` that initializes auth and feature modules after `authStateReady`.
|
||||
- Created feature-specific modules to prepare deconstruction of the monolith while preserving identical behavior:
|
||||
- `warrantyListController.js` (list loading/filtering/rendering controller surface)
|
||||
- `tagManager.js` (tag management: load/render/create/update/delete)
|
||||
- `addWarrantyForm.js` (multi-step add warranty wizard surface)
|
||||
- Wired pages to load the new module entry with `<script type="module" src="./js/index.js"></script>` alongside legacy `script.js` for zero-regression rollout.
|
||||
- _Files: `frontend/js/index.js`, `frontend/js/controllers/warrantyListController.js`, `frontend/js/components/tagManager.js`, `frontend/js/components/addWarrantyForm.js`, `frontend/index.html`, `frontend/about.html`, `frontend/status.html`, `frontend/register.html`, `frontend/reset-password.html`, `frontend/reset-password-request.html`_
|
||||
|
||||
- **Centralized Authentication Service**
|
||||
- New module `authService.js` exposes `initAuth`, `login`, `logout`, `getToken`, `getCurrentUser`, `isAuthenticated`.
|
||||
- Backwards compatibility: attaches a `window.auth` facade so existing code continues to work.
|
||||
- Handles header UI state, user menu/settings dropdown toggling, and dispatches a unified `authStateReady` event.
|
||||
- Robustly hides “Create Account” UI when registration is disabled (with a MutationObserver to keep it hidden after other scripts mutate the DOM).
|
||||
- _Files: `frontend/js/services/authService.js`, `frontend/*.html` (module includes)_
|
||||
|
||||
- **Dedicated API Service**
|
||||
- New `apiService.js` provides a `baseRequest` wrapper that injects the `Authorization` header and normalizes error handling.
|
||||
- Exposes named helpers (e.g., `getWarranties`, `updateWarranty`, `deleteWarranty`, `getStatistics`, `savePreferences`) and a `window.api` shim for non-module scripts.
|
||||
- Safe global `fetch` shim adds the Authorization header for `/api/...` calls when missing.
|
||||
- _Files: `frontend/js/services/apiService.js`, `frontend/*.html` (module includes)_
|
||||
|
||||
- **Central State Management Store**
|
||||
- Introduced a `store.js` module to act as a single source of truth for application data (warranties, filters, loading states), eliminating scattered global variables.
|
||||
- UI updates are now driven by custom events, creating a predictable data flow.
|
||||
- _Files: `frontend/js/store.js`_
|
||||
|
||||
- **Component-Based UI Modules**
|
||||
- Created a suite of new, reusable UI component modules to replace HTML string concatenation. Each is responsible for building a specific part of the UI via safe DOM manipulation.
|
||||
- Modules include: `warrantyCard.js`, `tag.js`, `modals.js`, `editModal.js`, `claims.js`, `notes.js`, `paperless.js`, and `ui.js`.
|
||||
- _Files: `frontend/js/components/*`_
|
||||
|
||||
- **HTML `<template>` for Warranty Cards**
|
||||
- Added a `<template id="warranty-card-template">` to `index.html` to define the warranty card structure, separating markup from rendering logic for improved performance and maintainability.
|
||||
- _Files: `frontend/index.html`_
|
||||
|
||||
### Enhanced
|
||||
- **Dockerfile: simplified static file serving**
|
||||
- Removed build stage; frontend files are now copied directly to `/var/www/html/` for static serving.
|
||||
- No build step required; all frontend assets are served as-is.
|
||||
- _Files: `Dockerfile`_
|
||||
|
||||
- **HTML and asset loading**
|
||||
- Switched all page `<script>` and `<link>` paths to relative paths (e.g., `./script.js`) for static file serving.
|
||||
- Ensured `script.js` is loaded with `defer` across pages to avoid early DOM access issues.
|
||||
- All assets are served directly from the `frontend/` directory without a build step.
|
||||
- _Files: `frontend/*.html`, `frontend/**/*`_
|
||||
|
||||
- **Frontend structure**
|
||||
- Consolidated all frontend files into a single `frontend/` directory for simplified static serving.
|
||||
- _Files: `frontend/settings-styles.css`_
|
||||
|
||||
- **Global State Management Refactor**
|
||||
- Migrated `frontend/script.js` to read/write state exclusively via the centralized `window.store` API.
|
||||
- Replaced direct usages of `warranties`, `currentFilters`, and `allTags` with `store.getWarranties/setWarranties`, `store.getFilters/updateFilter`, and `store.getAllTags/setAllTags`.
|
||||
- Updated filter event listeners, export flow, tag management (create/update/delete), and the filtering/rendering pipeline (`applyFilters`, `renderWarranties`) to consume store-backed data.
|
||||
- `loadTags()` now persists tags to the store and dispatches events to refresh dependent UIs.
|
||||
- Replaced remaining direct reads of removed globals with store getters in `script.js` (e.g., card action handlers, `filterWarranties()`, `openClaimsModal()`, and notes modal handlers). App behavior unchanged; all reads/writes now flow through `window.store`.
|
||||
- _Files: `frontend/script.js`_
|
||||
|
||||
- **Major UI Refactor for Maintainability & Security**
|
||||
- Replaced nearly all `innerHTML` assignments with a robust, component-based rendering approach. This makes the UI easier to debug, maintain, and more secure against XSS vulnerabilities.
|
||||
- **Warranty List:** The main warranty display for grid, list, and table views is now rendered using the `warrantyCard.js` component.
|
||||
- **Edit Modal:** The complex dynamic sections (serial numbers, current document displays for invoices/manuals/photos, and tag selection) are now built with the `editModal.js` component.
|
||||
- **Claims Modal:** The entire claims view, including the header, loading/error states, and claims list, is now rendered by the `claims.js` component.
|
||||
- **Other Modals:** Refactored the rendering logic for the Tag Management, Notes, and Paperless-ngx document browser modals to use their respective new components.
|
||||
- _Files: `frontend/script.js`, `frontend/js/components/*`_
|
||||
|
||||
- **Begin Extraction of UI Event Listeners**
|
||||
- Moved the global UI event initialization (`setupUIEventListeners`) into `warrantyListController.initEventListeners()` as part of the modularization.
|
||||
- Legacy `frontend/script.js` delegates to the controller to attach listeners, maintaining identical behavior during the staged rollout.
|
||||
- _Files: `frontend/js/controllers/warrantyListController.js`, `frontend/script.js`_
|
||||
|
||||
- **Controller-based Filter Pipeline**
|
||||
- Migrated `applyFilters` logic into `warrantyListController.js` to centralize filtering while preserving identical behavior.
|
||||
- Legacy `applyFilters` in `frontend/script.js` now delegates to the controller to avoid duplication.
|
||||
- _Files: `frontend/js/controllers/warrantyListController.js`, `frontend/script.js`_
|
||||
|
||||
- **Filter Dropdowns and Preference Persistence Extraction**
|
||||
- Moved filter dropdown population functions (`populateTagFilter`, `populateVendorFilter`, `populateWarrantyTypeFilter`) and preference persistence (`saveFilterPreferences`, `loadFilterAndSortPreferences`) into `warrantyListController.js`.
|
||||
- Legacy functions in `frontend/script.js` now delegate to the controller, ensuring a single source of truth.
|
||||
- _Files: `frontend/js/controllers/warrantyListController.js`, `frontend/script.js`_
|
||||
|
||||
- **Read-only State Bridges for Module Access**
|
||||
- Exposed read-only getters on `window` for `currentView`, `lastLoadedArchived`, and `lastLoadedIncludesArchived` to allow module code to read legacy flags safely without changing their source of truth.
|
||||
- _Files: `frontend/script.js`_
|
||||
|
||||
- **Delegated List Actions Fallback in Controller**
|
||||
- Added robust delegated handlers in `warrantyListController.initEventListeners()` for `#warrantiesList` (claims, edit, delete, notes, archive/unarchive) that activate only when the legacy initializer is not present, preventing double bindings.
|
||||
- _Files: `frontend/js/controllers/warrantyListController.js`_
|
||||
|
||||
- **Controller-based Data Loader (`loadWarranties`)**
|
||||
- Migrated the full `loadWarranties` flow into `warrantyListController.js` while preserving behavior: authentication check, scope selection (Personal/Global), Archived vs All handling with archived merge, processing via `processWarrantyData`, filter dropdown repopulation, and final render through `applyFilters()`.
|
||||
- Legacy `frontend/script.js` now delegates `loadWarranties` to the controller.
|
||||
- _Files: `frontend/js/controllers/warrantyListController.js`, `frontend/script.js`_
|
||||
|
||||
- **Warranty List Rendering (component-based refactor, public bundle)**
|
||||
- Rewrote `renderWarranties` in `frontend/script.js` to stop concatenating HTML strings and instead delegate card creation to `window.components.createWarrantyCard(warranty, options)`.
|
||||
- Builds `actionsHtml`, `contentHtml`, `statusText/statusClass`, and view-specific root class via helpers; appends tags using `window.components.appendTags`; preserves document links row placement per view.
|
||||
- Uses `DocumentFragment` to batch DOM insertions for performance and `window.components.ui.renderEmptyState` for empty states.
|
||||
- Centralized card action handling with a single delegated listener on `#warrantiesList` for edit, delete, archive/unarchive, claims, and notes.
|
||||
- Updated all call sites to the no-arg `renderWarranties()`; visual output and behavior remain identical across Grid, List, and Table views.
|
||||
- _Files: `frontend/script.js`_
|
||||
|
||||
- **Finalized Legacy Script Delegation**
|
||||
- Completed migration of UI event listeners from `frontend/script.js` (`setupUIEventListeners`) into `warrantyListController.initEventListeners()`:
|
||||
- Filters: `statusFilter`, `tagFilter`, `vendorFilter`, `warrantyTypeFilter`
|
||||
- Sort: `sortBy`
|
||||
- View switchers: `gridViewBtn`, `listViewBtn`, `tableViewBtn`
|
||||
- Actions: `refreshBtn`, `exportBtn`, `importBtn`
|
||||
- Replaced the legacy initializer call site and removed `setupUIEventListeners` from `script.js` (now delegates to the controller).
|
||||
- Delegated modal openings to component layer: `openDeleteModal`/`openArchiveModal` now call `window.components.modals.openDeleteModal/openArchiveModal` which owns DOM updates and visibility.
|
||||
- Moved Edit modal save flow out of legacy script: `saveWarranty` now lives in `frontend/js/components/editModal.js`, uses `apiService.updateWarranty`, and is exposed as `window.components.editModal.saveWarranty`.
|
||||
- Updated Save button wiring: controller binds Save to `editModal.saveWarranty`, preserving `setupSaveWarrantyObserver` wrapping when present.
|
||||
- Consolidated card action delegation: the single `#warrantiesList` delegated listener resides exclusively in the controller; removed the overlapping legacy delegation from `script.js`.
|
||||
- `script.js` is now a thin delegator with identical external behavior.
|
||||
- _Files: `frontend/script.js`, `frontend/js/controllers/warrantyListController.js`, `frontend/js/components/modals.js`, `frontend/js/components/editModal.js`_
|
||||
|
||||
- **Page-Specific Script Modularization (`status.js`)**
|
||||
- Converted `frontend/status.js` from a legacy script into a self-contained ES Module.
|
||||
- Replaced all `fetch` calls with methods from the imported `apiService.js` and all authentication logic with `authService.js`, removing dependencies on the global scope.
|
||||
- The module now initializes itself via a `DOMContentLoaded` listener, making it independent of the legacy `script.js`.
|
||||
- Updated `frontend/status.html` to load `status.js` with `type="module"`, ensuring modern script handling.
|
||||
- _Files: `frontend/status.js`, `frontend/status.html`_
|
||||
|
||||
- **API Service Extension**
|
||||
- Added a generic `apiService.request()` method to handle various API calls, which was utilized in the refactoring of `status.js`.
|
||||
- _Files: `frontend/js/services/apiService.js`_
|
||||
|
||||
|
||||
### Fixed
|
||||
- 404s for non-module assets in production by ensuring all assets are properly referenced with relative paths.
|
||||
- User menu not opening: restored click/close listeners within `authService.js`.
|
||||
- Login page “Create Account” visible while registration disabled: force-hidden with strong CSS and observer.
|
||||
- Status page edit actions blocked by early `document.body.appendChild(...)`: added `defer` to `script.js` includes.
|
||||
- **Thumbnail sizing on initial load (Grid/List/Table)**
|
||||
- Removed inline image sizing in the renderer so thumbnail sizes are now driven by CSS view classes, ensuring correct sizes apply immediately without hard reload or manual view switch.
|
||||
- Applied view preference before first render during data load to guarantee correct view class on first paint.
|
||||
- Tuned responsive CSS for very small screens (≤360px): List view 60×60, Table view 20×20; preserved existing ≤768px sizes.
|
||||
- _Files: `frontend/script.js`, `frontend/style.css`, `frontend/js/controllers/warrantyListController.js`_
|
||||
- **Security:** Mitigated potential cross-site scripting (XSS) vulnerabilities by removing reliance on building the UI with `innerHTML` from dynamic data.
|
||||
- **Performance:** Improved rendering performance by using efficient DOM creation and appending (`<template>` clones, `document.createElement`) instead of causing the browser to re-parse large HTML strings on every update.
|
||||
- **Code Quality:** Drastically reduced code complexity and repetition in `script.js` by delegating UI creation to specialized component modules.
|
||||
- Eliminated 404s for removed stylesheet by deleting the `/styles.css` link in `frontend/about.html` and removing it from the service worker pre-cache (`frontend/sw.js`).
|
||||
- _Files: `frontend/about.html`, `frontend/sw.js`_
|
||||
- Resolved transient `ReferenceError` messages (e.g., `allTags`/`warranties`/`currentFilters` not defined) by completing the store-backed migration in `frontend/script.js`.
|
||||
|
||||
### Removed
|
||||
- Legacy, scattered auth scripts now replaced by `authService.js`:
|
||||
- `frontend/auth.js`, `frontend/auth-new.js`, `frontend/include-auth-new.js`, `frontend/fix-auth-buttons.js`, `frontend/fix-auth-buttons-loader.js`, `frontend/registration-status.js`.
|
||||
- **Global State Variables**
|
||||
- Eliminated global variables like `let warranties = []` and `let currentFilters = {}` from `script.js`, centralizing all state management within `store.js`.
|
||||
- **Hardcoded HTML Strings**
|
||||
- Removed large, multi-line HTML string templates from JavaScript files, which were fragile and difficult to maintain.
|
||||
|
||||
- Frontend duplicate/unused assets removed:
|
||||
- Removed unused stylesheet: `frontend/styles.css`
|
||||
- Removed debug files: `frontend/js/i18n-debug.js`, `frontend/temp-toast-debug.js`
|
||||
|
||||
- Backend cleanup: removed unused `backend/fix_notification_columns.py`.
|
||||
|
||||
### House Cleaning
|
||||
- Deleted generated artifacts not needed in repo: `frontend/dist`, `frontend/node_modules` (frontend is now served statically without build)
|
||||
- Purged Python caches: `backend/**/__pycache__`, stray `.pyc`
|
||||
- Removed old backup: `backend/fix_permissions.sql.bak`
|
||||
- **Code Refinement in `settings-new.js`**
|
||||
- **Settings page refactor — ES Module & event wiring**
|
||||
- Converted `frontend/settings-new.js` into a self-contained ES Module and updated `settings-new.html` to load it with a `<script type="module" src="./settings-new.js"></script>` tag. The module imports `authService` and `apiService` rather than relying on global functions.
|
||||
- Removed inline `onclick` handlers from the Settings HTML (notably the Delete User modal) and rewired UI interactions using `addEventListener` inside the module so handlers are module-scoped instead of being attached to `window`.
|
||||
- Extended `frontend/js/services/apiService.js` with settings/admin endpoints consumed by the module (for example: `getUser`, `getUsers`, `updateUser`, `deleteUser`, `getSiteSettings`, `saveSiteSettings`, `getAuditTrail`, `triggerNotifications`) and preserved the `window.api` shim for backward compatibility.
|
||||
- Fixed a porting-induced syntax/parsing issue (unbalanced brace) and removed a leftover global (`window.currentDeleteUserId`) in favor of a module-scoped `currentDeleteUserId` to avoid leaking state.
|
||||
- The refactored module parses without syntax errors. Runtime smoke tests are planned/encouraged (see next steps) and final decommission of the legacy `script.js` will follow once runtime verification is complete.
|
||||
- _Files: `frontend/settings-new.html`, `frontend/settings-new.js`, `frontend/js/services/apiService.js`_
|
||||
## 1.0.3 - 2025-10-31
|
||||
|
||||
|
||||
## 1.0.2 - 2025-10-30
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ COPY --chown=warracker:warracker backend/migrations/ ./migrations/
|
||||
COPY --chown=warracker:warracker locales/ ./locales/
|
||||
COPY --chown=warracker:warracker locales/ /var/www/html/locales/
|
||||
|
||||
# 4. Frontend (static files, no build step)
|
||||
# 4. Frontend (bundled in one instruction)
|
||||
COPY --chown=warracker:warracker frontend/ /var/www/html/
|
||||
|
||||
# 5. Backend (bundled in one instruction)
|
||||
|
||||
+23
-25
@@ -7,33 +7,31 @@
|
||||
<title data-i18n="about.title">About - Warracker</title>
|
||||
|
||||
<!-- Favicons -->
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./img/favicon-512x512.png">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon-512x512.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<!-- Stylesheets -->
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004"> <!-- Main stylesheet -->
|
||||
<link rel="stylesheet" href="style.css?v=20250119004"> <!-- Main stylesheet -->
|
||||
<link rel="stylesheet" href="styles.css?v=20250119001"> <!-- Additional styles -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css"> <!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="./header-fix.css?v=20250119001"> <!-- Header specific styles -->
|
||||
<link rel="stylesheet" href="header-fix.css?v=20250119001"> <!-- Header specific styles -->
|
||||
<!-- Mobile Header specific styles -->
|
||||
<link rel="stylesheet" href="./mobile-header.css?v=20250119002">
|
||||
<link rel="stylesheet" href="mobile-header.css?v=20250119002">
|
||||
|
||||
<!-- Scripts loaded in head -->
|
||||
<script src="./theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
|
||||
|
||||
<script src="./script.js?v=20250119001" defer></script>
|
||||
<script type="module" src="./js/index.js"></script>
|
||||
<script src="theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<script src="include-auth-new.js?v=20250119001"></script> <!-- Handles auth state display -->
|
||||
<script src="fix-auth-buttons-loader.js?v=20250119001"></script> <!-- Fixes auth button display timing -->
|
||||
<script src="script.js?v=20250119001" defer></script>
|
||||
<!-- i18next Local Scripts -->
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<!-- i18n initialization script -->
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
|
||||
<style>
|
||||
.about-hero {
|
||||
@@ -335,7 +333,7 @@
|
||||
<!-- Hero Section -->
|
||||
<div class="about-hero">
|
||||
<h1><i class="fas fa-shield-alt"></i> Warracker</h1>
|
||||
<div class="version" id="versionDisplay" data-i18n="about.version">Version v1.0.3</div>
|
||||
<div class="version" id="versionDisplay" data-i18n="about.version">Version v1.0.2</div>
|
||||
<p class="description" data-i18n="about.description">
|
||||
A comprehensive warranty management system designed to help you track, organize, and manage all your product warranties in one secure, user-friendly platform.
|
||||
</p>
|
||||
@@ -412,16 +410,16 @@
|
||||
</div>
|
||||
|
||||
<!-- Scripts loaded at the end of body -->
|
||||
|
||||
<script src="auth.js?v=20250119001"></script>
|
||||
|
||||
<!-- Version Checker -->
|
||||
<script src="./version-checker.js?v=20251030001" defer></script> <!-- Version checker script -->
|
||||
<script src="version-checker.js?v=20251030001" defer></script> <!-- Version checker script -->
|
||||
|
||||
<!-- Footer Width Fix -->
|
||||
<script src="./footer-fix.js?v=20251024001"></script>
|
||||
<script src="footer-fix.js?v=20251024001"></script>
|
||||
|
||||
<!-- Footer Content Manager -->
|
||||
<script src="./footer-content.js?v=20250119001"></script>
|
||||
<script src="footer-content.js?v=20250119001"></script>
|
||||
|
||||
<!-- Powered by Warracker Footer -->
|
||||
<footer class="warracker-footer" id="warrackerFooter">
|
||||
@@ -436,7 +434,7 @@
|
||||
// Update version display dynamically
|
||||
const versionDisplay = document.getElementById('versionDisplay');
|
||||
if (versionDisplay && window.i18next) {
|
||||
const currentVersion = '1.0.3'; // This should match version-checker.js
|
||||
const currentVersion = '1.0.2'; // This should match version-checker.js
|
||||
versionDisplay.textContent = window.i18next.t('about.version') + ' v' + currentVersion;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* Authentication functionality for Warracker (New UI)
|
||||
* Handles user login, logout, and authentication state management for the new UI design
|
||||
*/
|
||||
|
||||
// Authentication state
|
||||
let currentUser = null;
|
||||
let authToken = null;
|
||||
|
||||
// Initialize authentication
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
console.log('Initializing auth-new.js for new UI');
|
||||
|
||||
// Initial check of authentication state
|
||||
checkAuthState();
|
||||
|
||||
// Set up periodic check of auth state (every 30 seconds)
|
||||
setInterval(checkAuthState, 30000);
|
||||
|
||||
// Set up logout functionality
|
||||
setupLogout();
|
||||
});
|
||||
|
||||
/**
|
||||
* Set up logout functionality
|
||||
*/
|
||||
function setupLogout() {
|
||||
// Look for logout button in the new UI
|
||||
const logoutButton = document.querySelector('.logout-btn');
|
||||
|
||||
if (logoutButton) {
|
||||
console.log('Found logout button in new UI');
|
||||
|
||||
// Add click event to logout
|
||||
logoutButton.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
logout();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is authenticated and update UI accordingly
|
||||
*/
|
||||
function checkAuthState() {
|
||||
console.log('Checking auth state for new UI');
|
||||
|
||||
// Get auth token from localStorage
|
||||
authToken = localStorage.getItem('auth_token');
|
||||
const userInfo = localStorage.getItem('user_info');
|
||||
|
||||
if (authToken && userInfo) {
|
||||
try {
|
||||
currentUser = JSON.parse(userInfo);
|
||||
updateUIForAuthenticatedUser();
|
||||
validateToken();
|
||||
} catch (error) {
|
||||
console.error('Error parsing user info:', error);
|
||||
clearAuthData();
|
||||
updateUIForUnauthenticatedUser();
|
||||
}
|
||||
} else {
|
||||
updateUIForUnauthenticatedUser();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update UI elements for authenticated user in the new UI
|
||||
*/
|
||||
function updateUIForAuthenticatedUser() {
|
||||
console.log('Updating UI for authenticated user');
|
||||
|
||||
// Find login/register buttons in the new UI based on the screenshot
|
||||
const loginButton = document.querySelector('a[href="login.html"], a.login');
|
||||
const registerButton = document.querySelector('a[href="register.html"], a.register');
|
||||
|
||||
// Hide login/register buttons if they exist
|
||||
if (loginButton) {
|
||||
console.log('Hiding login button');
|
||||
loginButton.style.display = 'none';
|
||||
}
|
||||
|
||||
if (registerButton) {
|
||||
console.log('Hiding register button');
|
||||
registerButton.style.display = 'none';
|
||||
}
|
||||
|
||||
// Show user info if it exists
|
||||
const userDisplay = document.querySelector('.user-display');
|
||||
if (userDisplay && currentUser) {
|
||||
let displayName = currentUser.username || 'User';
|
||||
userDisplay.textContent = displayName;
|
||||
userDisplay.style.display = 'inline-block';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update UI elements for unauthenticated user in the new UI
|
||||
*/
|
||||
function updateUIForUnauthenticatedUser() {
|
||||
console.log('Updating UI for unauthenticated user');
|
||||
|
||||
// Find login/register buttons in the new UI based on the screenshot
|
||||
const loginButton = document.querySelector('a[href="login.html"], a.login');
|
||||
const registerButton = document.querySelector('a[href="register.html"], a.register');
|
||||
|
||||
// Show login/register buttons if they exist
|
||||
if (loginButton) {
|
||||
console.log('Showing login button');
|
||||
loginButton.style.display = 'inline-block';
|
||||
}
|
||||
|
||||
if (registerButton) {
|
||||
console.log('Showing register button');
|
||||
registerButton.style.display = 'inline-block';
|
||||
}
|
||||
|
||||
// Hide user info if it exists
|
||||
const userDisplay = document.querySelector('.user-display');
|
||||
if (userDisplay) {
|
||||
userDisplay.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout user
|
||||
*/
|
||||
async function logout() {
|
||||
try {
|
||||
console.log('Logging out user');
|
||||
|
||||
// Call logout API
|
||||
const response = await fetch('/api/auth/logout', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
// Clear auth data regardless of API response
|
||||
clearAuthData();
|
||||
updateUIForUnauthenticatedUser();
|
||||
|
||||
// Show success message
|
||||
console.log('Logged out successfully');
|
||||
|
||||
// Reload page to refresh UI
|
||||
window.location.reload();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
|
||||
// Still clear auth data even if API call fails
|
||||
clearAuthData();
|
||||
updateUIForUnauthenticatedUser();
|
||||
|
||||
console.log('Logged out with errors');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear authentication data from localStorage
|
||||
*/
|
||||
function clearAuthData() {
|
||||
localStorage.removeItem('auth_token');
|
||||
localStorage.removeItem('user_info');
|
||||
authToken = null;
|
||||
currentUser = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate token with the server
|
||||
*/
|
||||
async function validateToken() {
|
||||
if (!authToken) {
|
||||
clearAuthData();
|
||||
updateUIForUnauthenticatedUser();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Use the full URL to avoid path issues
|
||||
const apiUrl = window.location.origin + '/api/auth/validate-token';
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
console.error('Token validation failed:', errorData.message);
|
||||
throw new Error(errorData.message || 'Invalid token');
|
||||
}
|
||||
|
||||
// Token is valid, update last active time
|
||||
const data = await response.json();
|
||||
if (data.user) {
|
||||
currentUser = data.user;
|
||||
localStorage.setItem('user_info', JSON.stringify(currentUser));
|
||||
updateUIForAuthenticatedUser();
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Token validation error:', error);
|
||||
clearAuthData();
|
||||
updateUIForUnauthenticatedUser();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Export authentication functions for use in other scripts
|
||||
window.authNew = {
|
||||
isAuthenticated: () => !!authToken,
|
||||
getCurrentUser: () => currentUser,
|
||||
getToken: () => authToken,
|
||||
checkAuthState,
|
||||
logout
|
||||
};
|
||||
@@ -4,10 +4,8 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Authenticating...</title>
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004">
|
||||
<script src="./theme-loader.js?v=20250119001"></script>
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
<link rel="stylesheet" href="style.css?v=20250119004">
|
||||
<script src="theme-loader.js?v=20250119001"></script>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
@@ -161,20 +159,20 @@
|
||||
</script>
|
||||
|
||||
<!-- i18next Local Scripts -->
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
|
||||
<!-- i18n Configuration -->
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
|
||||
<script src="./auth-redirect.js?v=20250119001"></script>
|
||||
<script src="auth-redirect.js?v=20250119001"></script>
|
||||
|
||||
<!-- Footer Width Fix -->
|
||||
<script src="./footer-fix.js?v=20251024001"></script>
|
||||
<script src="footer-fix.js?v=20251024001"></script>
|
||||
|
||||
<!-- Footer Content Manager -->
|
||||
<script src="./footer-content.js?v=20250119001"></script>
|
||||
<script src="footer-content.js?v=20250119001"></script>
|
||||
|
||||
<!-- Powered by Warracker Footer -->
|
||||
<footer class="warracker-footer" id="warrackerFooter">
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
/**
|
||||
* Authentication functionality for Warracker
|
||||
* Handles user login, logout, and authentication state management
|
||||
*/
|
||||
|
||||
class AuthManager {
|
||||
constructor() {
|
||||
this.token = null;
|
||||
this.currentUser = null;
|
||||
this.onLogoutCallbacks = [];
|
||||
|
||||
// Initial state load from localStorage
|
||||
this.token = localStorage.getItem('auth_token');
|
||||
const userInfoString = localStorage.getItem('user_info');
|
||||
if (userInfoString) {
|
||||
try {
|
||||
this.currentUser = JSON.parse(userInfoString);
|
||||
} catch (e) {
|
||||
console.error('Auth.js: Corrupt user_info in localStorage. Clearing.');
|
||||
this.currentUser = null;
|
||||
localStorage.removeItem('user_info');
|
||||
// Consider clearing token as well if user_info is corrupt
|
||||
// localStorage.removeItem('auth_token');
|
||||
// this.token = null;
|
||||
}
|
||||
}
|
||||
console.log('[Auth.js] Initial state:', { token: this.token ? 'present' : 'null', currentUser: this.currentUser });
|
||||
}
|
||||
|
||||
isAuthenticated() {
|
||||
// User is authenticated if both token and currentUser (with an id) are present
|
||||
return !!(this.token && this.currentUser && this.currentUser.id);
|
||||
}
|
||||
|
||||
getCurrentUser() {
|
||||
return this.currentUser;
|
||||
}
|
||||
|
||||
getToken() {
|
||||
// Always return the current state of this.token, which should be synced with localStorage
|
||||
return this.token;
|
||||
}
|
||||
|
||||
clearAuthData() {
|
||||
console.log('[Auth.js] Clearing auth data.');
|
||||
localStorage.removeItem('auth_token');
|
||||
localStorage.removeItem('user_info');
|
||||
this.token = null;
|
||||
this.currentUser = null;
|
||||
this.onLogoutCallbacks.forEach(cb => cb());
|
||||
}
|
||||
|
||||
onLogout(callback) {
|
||||
if (typeof callback === 'function') {
|
||||
this.onLogoutCallbacks.push(callback);
|
||||
}
|
||||
}
|
||||
|
||||
async checkAuthState(isInitialLoad = false) {
|
||||
console.log('[Auth.js] checkAuthState called. Initial load:', isInitialLoad);
|
||||
this.token = localStorage.getItem('auth_token'); // Re-read token, might have changed (e.g. by auth-redirect.js)
|
||||
const userInfoString = localStorage.getItem('user_info');
|
||||
|
||||
this.currentUser = null; // Reset before check
|
||||
|
||||
if (userInfoString) {
|
||||
try {
|
||||
this.currentUser = JSON.parse(userInfoString);
|
||||
} catch (e) {
|
||||
console.error('Auth.js: Failed to parse user_info from localStorage during checkAuthState. Clearing auth data.', e);
|
||||
this.clearAuthData(); // Clear potentially corrupt data
|
||||
this.updateUIBasedOnAuthState(); // Update UI to reflect logged-out state
|
||||
return; // Exit early
|
||||
}
|
||||
}
|
||||
|
||||
if (this.token) {
|
||||
// If token exists, try to validate it and fetch/confirm user_info
|
||||
// This is crucial if user_info was missing or to refresh/validate existing user_info
|
||||
console.log('[Auth.js] Token found. Validating and fetching user info...');
|
||||
try {
|
||||
const response = await fetch('/api/auth/validate-token', {
|
||||
headers: { 'Authorization': `Bearer ${this.token}` }
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (data.valid && data.user && data.user.id) {
|
||||
this.currentUser = data.user;
|
||||
localStorage.setItem('user_info', JSON.stringify(this.currentUser)); // Ensure localStorage is up-to-date
|
||||
console.log('[Auth.js] Token validated, user_info updated/confirmed:', this.currentUser);
|
||||
} else {
|
||||
console.warn('[Auth.js] Token validation failed or user data invalid from API. Clearing auth data.');
|
||||
this.clearAuthData();
|
||||
}
|
||||
} else {
|
||||
console.warn(`[Auth.js] Token validation API call failed (status: ${response.status}). Clearing auth data.`);
|
||||
this.clearAuthData();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Auth.js] Error validating token / fetching user info:', error);
|
||||
this.clearAuthData();
|
||||
}
|
||||
} else {
|
||||
// No token, ensure everything is cleared
|
||||
if (this.currentUser) { // If there was user_info but no token, clear user_info
|
||||
console.log('[Auth.js] No token found, but user_info was present. Clearing user_info.');
|
||||
this.clearAuthData();
|
||||
}
|
||||
}
|
||||
|
||||
this.updateUIBasedOnAuthState();
|
||||
}
|
||||
|
||||
updateUIBasedOnAuthState() {
|
||||
const isAuthenticated = this.isAuthenticated();
|
||||
this._updateDOMForAuthState(isAuthenticated, this.currentUser);
|
||||
this.dispatchAuthStateEvent(isAuthenticated, this.currentUser);
|
||||
}
|
||||
|
||||
_updateDOMForAuthState(isAuthenticated, user) {
|
||||
const authContainer = document.getElementById('authContainer');
|
||||
const userMenu = document.getElementById('userMenu');
|
||||
const userDisplayName = document.getElementById('userDisplayName');
|
||||
const userNameMenu = document.getElementById('userName');
|
||||
const userEmailMenu = document.getElementById('userEmail');
|
||||
const logoutMenuItem = document.getElementById('logoutMenuItem');
|
||||
|
||||
// Select all potential login/register buttons more broadly
|
||||
const loginButtons = document.querySelectorAll('a[href="login.html"], .login-btn');
|
||||
const registerButtons = document.querySelectorAll('a[href="register.html"], .register-btn');
|
||||
const genericAuthButtonsContainers = document.querySelectorAll('.auth-buttons');
|
||||
|
||||
|
||||
if (isAuthenticated && user) {
|
||||
console.log('Auth.js: Updating UI for AUTHENTICATED user:', user);
|
||||
if (authContainer) { authContainer.style.display = 'none'; authContainer.style.visibility = 'hidden'; }
|
||||
|
||||
if (userMenu) {
|
||||
userMenu.style.display = 'block'; // Or 'flex' based on CSS
|
||||
userMenu.style.visibility = 'visible';
|
||||
const displayNameText = user.first_name || user.username || 'User';
|
||||
const fullNameText = `${user.first_name || ''} ${user.last_name || ''}`.trim() || user.username || 'User Name';
|
||||
if (userDisplayName) userDisplayName.textContent = displayNameText;
|
||||
if (userNameMenu) userNameMenu.textContent = fullNameText;
|
||||
if (userEmailMenu && user.email) userEmailMenu.textContent = user.email;
|
||||
}
|
||||
loginButtons.forEach(btn => { btn.style.display = 'none'; btn.style.visibility = 'hidden'; });
|
||||
registerButtons.forEach(btn => { btn.style.display = 'none'; btn.style.visibility = 'hidden'; });
|
||||
genericAuthButtonsContainers.forEach(container => {
|
||||
if (container.id !== 'authContainer') { // Avoid double-hiding if authContainer also has .auth-buttons
|
||||
container.style.display = 'none'; container.style.visibility = 'hidden';
|
||||
}
|
||||
});
|
||||
|
||||
if (logoutMenuItem) {
|
||||
logoutMenuItem.style.display = 'flex'; // Assuming it's a flex item
|
||||
// Ensure logout listener is attached (can be done once in constructor or DOMContentLoaded)
|
||||
}
|
||||
} else {
|
||||
console.log('Auth.js: Updating UI for UNAUTHENTICATED user.');
|
||||
if (authContainer) { authContainer.style.display = 'flex'; authContainer.style.visibility = 'visible'; }
|
||||
|
||||
if (userMenu) { userMenu.style.display = 'none'; userMenu.style.visibility = 'hidden'; }
|
||||
|
||||
// Reset user display names if they exist
|
||||
if (userDisplayName) userDisplayName.textContent = 'User';
|
||||
if (userNameMenu) userNameMenu.textContent = 'User Name';
|
||||
if (userEmailMenu) userEmailMenu.textContent = 'user@example.com';
|
||||
|
||||
loginButtons.forEach(btn => { btn.style.display = 'inline-block'; btn.style.visibility = 'visible'; });
|
||||
registerButtons.forEach(btn => { btn.style.display = 'inline-block'; btn.style.visibility = 'visible'; });
|
||||
genericAuthButtonsContainers.forEach(container => {
|
||||
if (container.id !== 'authContainer') {
|
||||
container.style.display = 'flex'; // Or 'block'
|
||||
container.style.visibility = 'visible';
|
||||
}
|
||||
});
|
||||
if (logoutMenuItem) { logoutMenuItem.style.display = 'none'; }
|
||||
}
|
||||
}
|
||||
|
||||
dispatchAuthStateEvent(isAuthenticated, user) {
|
||||
console.log('[Auth.js] Dispatching authStateReady event', { isAuthenticated, user });
|
||||
// Ensure this event is dispatched after the current call stack clears
|
||||
setTimeout(() => {
|
||||
window.dispatchEvent(new CustomEvent('authStateReady', {
|
||||
detail: { isAuthenticated, user }
|
||||
}));
|
||||
}, 0);
|
||||
}
|
||||
|
||||
async login(username, password) {
|
||||
// Assuming showLoading/hideLoading are global or part of another module
|
||||
if (typeof showLoading === 'function') showLoading();
|
||||
try {
|
||||
const response = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username, password })
|
||||
});
|
||||
const data = await response.json();
|
||||
if (response.ok) {
|
||||
this.token = data.token;
|
||||
this.currentUser = data.user;
|
||||
localStorage.setItem('auth_token', this.token);
|
||||
localStorage.setItem('user_info', JSON.stringify(this.currentUser));
|
||||
this.updateUIBasedOnAuthState();
|
||||
return data; // Return data for login.js to handle redirect
|
||||
} else {
|
||||
throw new Error(data.message || 'Login failed');
|
||||
}
|
||||
} catch (error) {
|
||||
this.clearAuthData(); // Ensure state is cleared on login failure
|
||||
this.updateUIBasedOnAuthState();
|
||||
throw error; // Re-throw for login.js to handle
|
||||
} finally {
|
||||
if (typeof hideLoading === 'function') hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
async logout() {
|
||||
if (typeof showLoading === 'function') showLoading();
|
||||
const currentTokenForApiCall = this.token; // Use current token for API call
|
||||
|
||||
this.clearAuthData(); // Clear local state immediately
|
||||
this.updateUIBasedOnAuthState(); // Update UI to logged-out state
|
||||
|
||||
try {
|
||||
if (currentTokenForApiCall) {
|
||||
await fetch('/api/auth/logout', {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${currentTokenForApiCall}` }
|
||||
});
|
||||
console.log('[Auth.js] Logout API call successful.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Auth.js] Logout API call failed, but user is logged out locally.', error);
|
||||
} finally {
|
||||
if (typeof hideLoading === 'function') hideLoading();
|
||||
// Redirect to login page after all operations
|
||||
if (window.location.pathname !== '/login.html') {
|
||||
window.location.href = 'login.html';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addAuthHeader(options = {}) {
|
||||
const token = this.getToken();
|
||||
if (!token) return options;
|
||||
|
||||
const headers = options.headers || {};
|
||||
return { ...options, headers: { ...headers, 'Authorization': `Bearer ${token}`}};
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize and export
|
||||
window.auth = new AuthManager();
|
||||
|
||||
// Initial check on DOMContentLoaded
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
console.log('[Auth.js] DOMContentLoaded - performing initial async auth state check.');
|
||||
await window.auth.checkAuthState(true); // Ensure auth state is processed first
|
||||
|
||||
// Setup user menu toggle
|
||||
const userMenuBtn_original = document.getElementById('userMenuBtn');
|
||||
const userMenuDropdown = document.getElementById('userMenuDropdown');
|
||||
|
||||
if (userMenuBtn_original && userMenuDropdown) {
|
||||
console.log('[Auth.js] Setting up user menu. Button:', userMenuBtn_original, 'Dropdown:', userMenuDropdown);
|
||||
|
||||
// Robust listener attachment: clone the button to remove any prior listeners
|
||||
const userMenuBtn = userMenuBtn_original.cloneNode(true);
|
||||
userMenuBtn_original.parentNode.replaceChild(userMenuBtn, userMenuBtn_original);
|
||||
|
||||
userMenuBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation(); // Prevent click from immediately closing due to document listener
|
||||
console.log('[Auth.js] userMenuBtn clicked - DEBUG INFO:', {
|
||||
userMenuDropdown: !!userMenuDropdown,
|
||||
dropdownClassList: userMenuDropdown ? Array.from(userMenuDropdown.classList) : 'not found',
|
||||
hasActiveClass: userMenuDropdown ? userMenuDropdown.classList.contains('active') : 'dropdown not found',
|
||||
buttonId: userMenuBtn.id,
|
||||
dropdownId: userMenuDropdown ? userMenuDropdown.id : 'not found'
|
||||
});
|
||||
|
||||
userMenuDropdown.classList.toggle('active');
|
||||
|
||||
const isNowActive = userMenuDropdown.classList.contains('active');
|
||||
console.log('[Auth.js] User menu toggled via userMenuBtn. Active:', isNowActive);
|
||||
|
||||
// Add a temporary debug check to see if it gets closed immediately
|
||||
setTimeout(() => {
|
||||
const stillActive = userMenuDropdown.classList.contains('active');
|
||||
console.log('[Auth.js] User menu status after 100ms:', stillActive);
|
||||
if (isNowActive && !stillActive) {
|
||||
console.warn('[Auth.js] User menu was closed immediately! Possible global click interference.');
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
console.log('[Auth.js] User menu click listener attached to userMenuBtn.');
|
||||
} else {
|
||||
console.warn('[Auth.js] User menu button (userMenuBtn) or dropdown (userMenuDropdown) not found. Menu interactivity might be affected.');
|
||||
}
|
||||
|
||||
// Setup settings gear menu toggle (if elements exist on the current page)
|
||||
const settingsBtn_original = document.getElementById('settingsBtn');
|
||||
const settingsMenu = document.getElementById('settingsMenu'); // The dropdown menu itself
|
||||
if (settingsBtn_original && settingsMenu) {
|
||||
const settingsBtn = settingsBtn_original.cloneNode(true);
|
||||
settingsBtn_original.parentNode.replaceChild(settingsBtn, settingsBtn_original);
|
||||
|
||||
settingsBtn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
settingsMenu.classList.toggle('active');
|
||||
console.log('[Auth.js] Settings menu toggled via settingsBtn.');
|
||||
});
|
||||
console.log('[Auth.js] Settings menu click listener attached to settingsBtn.');
|
||||
}
|
||||
|
||||
// Global click listener to close dropdowns - ensure this is added only once
|
||||
if (!window._authJsGlobalClickListenerAdded) {
|
||||
document.addEventListener('click', (e) => {
|
||||
console.log('[Auth.js] Global click detected on:', e.target);
|
||||
|
||||
// Re-fetch elements by ID inside the listener to ensure they are current
|
||||
const currentDropdown = document.getElementById('userMenuDropdown');
|
||||
const currentButton = document.getElementById('userMenuBtn'); // Use the standardized ID
|
||||
|
||||
if (currentDropdown && currentButton && currentDropdown.classList.contains('active')) {
|
||||
console.log('[Auth.js] User menu is active, checking if click is outside...');
|
||||
const isOutsideDropdown = !currentDropdown.contains(e.target);
|
||||
const isOutsideButton = !currentButton.contains(e.target);
|
||||
console.log('[Auth.js] Click outside dropdown:', isOutsideDropdown, 'outside button:', isOutsideButton);
|
||||
|
||||
if (isOutsideDropdown && isOutsideButton) {
|
||||
currentDropdown.classList.remove('active');
|
||||
console.log('[Auth.js] User menu closed by global click.');
|
||||
}
|
||||
}
|
||||
|
||||
const currentSettingsMenu = document.getElementById('settingsMenu');
|
||||
const currentSettingsBtn = document.getElementById('settingsBtn');
|
||||
if (currentSettingsMenu && currentSettingsBtn && currentSettingsMenu.classList.contains('active') &&
|
||||
!currentSettingsMenu.contains(e.target) && !currentSettingsBtn.contains(e.target)) {
|
||||
currentSettingsMenu.classList.remove('active');
|
||||
console.log('[Auth.js] Settings menu closed by global click.');
|
||||
}
|
||||
});
|
||||
window._authJsGlobalClickListenerAdded = true;
|
||||
console.log('[Auth.js] Global click listener for dropdowns added.');
|
||||
}
|
||||
|
||||
// Attach logout listener to logout menu item
|
||||
const logoutMenuItem_original = document.getElementById('logoutMenuItem');
|
||||
if (logoutMenuItem_original) {
|
||||
const logoutMenuItem = logoutMenuItem_original.cloneNode(true); // Ensures fresh listener
|
||||
logoutMenuItem_original.parentNode.replaceChild(logoutMenuItem, logoutMenuItem_original);
|
||||
logoutMenuItem.addEventListener('click', () => {
|
||||
console.log('[Auth.js] Logout menu item clicked.');
|
||||
window.auth.logout();
|
||||
});
|
||||
console.log('[Auth.js] Logout menu item listener attached.');
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Script to load the fix-auth-buttons.js script on all pages
|
||||
* This script should be included in the head of each HTML file
|
||||
*/
|
||||
|
||||
// Log authentication status for debugging
|
||||
console.log('fix-auth-buttons-loader.js is running');
|
||||
console.log('Auth token exists:', !!localStorage.getItem('auth_token'));
|
||||
console.log('User info exists:', !!localStorage.getItem('user_info'));
|
||||
|
||||
// Execute immediately to hide buttons as soon as possible
|
||||
if (localStorage.getItem('auth_token')) {
|
||||
console.log('User is logged in, attempting to hide login/register buttons immediately');
|
||||
|
||||
// Hide auth container if it exists
|
||||
const authContainer = document.getElementById('authContainer');
|
||||
if (authContainer) {
|
||||
console.log('Found authContainer, hiding it');
|
||||
authContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
// Hide individual buttons if they exist
|
||||
const loginButtons = document.querySelectorAll('a[href="login.html"], .login-btn, .auth-btn.login-btn');
|
||||
const registerButtons = document.querySelectorAll('a[href="register.html"], .register-btn, .auth-btn.register-btn');
|
||||
|
||||
console.log('Found login buttons:', loginButtons.length);
|
||||
console.log('Found register buttons:', registerButtons.length);
|
||||
|
||||
loginButtons.forEach(button => button.style.display = 'none');
|
||||
registerButtons.forEach(button => button.style.display = 'none');
|
||||
|
||||
// Show user menu if it exists
|
||||
const userMenu = document.getElementById('userMenu');
|
||||
if (userMenu) {
|
||||
console.log('Found userMenu, showing it');
|
||||
userMenu.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// Create a script element to load the actual fix script
|
||||
const script = document.createElement('script');
|
||||
script.src = 'fix-auth-buttons.js';
|
||||
script.async = true;
|
||||
|
||||
// Add the script to the document
|
||||
document.head.appendChild(script);
|
||||
|
||||
console.log('Added fix-auth-buttons.js script to the page');
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Script to fix the login and register buttons in the new UI
|
||||
* This script specifically targets the buttons shown in the screenshot
|
||||
*/
|
||||
|
||||
// Log execution
|
||||
console.log('fix-auth-buttons.js loaded and executing');
|
||||
|
||||
// Function to check if user is authenticated
|
||||
function isAuthenticated() {
|
||||
const token = localStorage.getItem('auth_token');
|
||||
// console.log('Auth token check:', !!token); // Keep console logs minimal here if auth.js is primary
|
||||
return !!token;
|
||||
}
|
||||
|
||||
// Function to find elements by text content
|
||||
function getElementsByText(selector, text) {
|
||||
const elements = document.querySelectorAll(selector);
|
||||
return Array.prototype.filter.call(elements, element => element.textContent.trim() === text);
|
||||
}
|
||||
|
||||
// Function to hide login and register buttons if user is authenticated
|
||||
function updateAuthButtons() {
|
||||
// console.log('fix-auth-buttons.js: updateAuthButtons executing...'); // Keep console logs minimal here
|
||||
if (isAuthenticated()) {
|
||||
// console.log('fix-auth-buttons.js: User is authenticated, hiding login/register buttons');
|
||||
const loginButtons = document.querySelectorAll('a[href="login.html"], .login-btn, .auth-btn.login-btn');
|
||||
const registerButtons = document.querySelectorAll('a[href="register.html"], .register-btn, .auth-btn.register-btn');
|
||||
const authContainer = document.getElementById('authContainer');
|
||||
const userMenu = document.getElementById('userMenu'); // Ensure this ID is consistent or use userMenuBtn's parent
|
||||
|
||||
loginButtons.forEach(button => { button.style.display = 'none'; button.style.visibility = 'hidden'; });
|
||||
registerButtons.forEach(button => { button.style.display = 'none'; button.style.visibility = 'hidden'; });
|
||||
if (authContainer) { authContainer.style.display = 'none'; authContainer.style.visibility = 'hidden';}
|
||||
if (userMenu) { userMenu.style.display = 'block'; userMenu.style.visibility = 'visible'; }
|
||||
|
||||
const userInfo = localStorage.getItem('user_info');
|
||||
if (userInfo) {
|
||||
try {
|
||||
const user = JSON.parse(userInfo);
|
||||
const displayName = user.first_name || user.username || 'User';
|
||||
const userDisplayName = document.getElementById('userDisplayName');
|
||||
if (userDisplayName) userDisplayName.textContent = displayName;
|
||||
|
||||
const userNameMenu = document.getElementById('userName');
|
||||
if (userNameMenu) {
|
||||
userNameMenu.textContent = `${user.first_name || ''} ${user.last_name || ''}`.trim() || user.username || 'User Name';
|
||||
}
|
||||
const userEmailMenu = document.getElementById('userEmail');
|
||||
if (userEmailMenu && user.email) userEmailMenu.textContent = user.email;
|
||||
} catch (error) { /* console.error('fix-auth-buttons.js: Error parsing user info:', error); */ }
|
||||
}
|
||||
} else {
|
||||
// console.log('fix-auth-buttons.js: User is not authenticated, showing login/register buttons');
|
||||
const loginButtons = document.querySelectorAll('a[href="login.html"], .login-btn, .auth-btn.login-btn');
|
||||
const registerButtons = document.querySelectorAll('a[href="register.html"], .register-btn, .auth-btn.register-btn');
|
||||
const authContainer = document.getElementById('authContainer');
|
||||
const userMenu = document.getElementById('userMenu');
|
||||
|
||||
loginButtons.forEach(button => { button.style.display = 'inline-block'; button.style.visibility = 'visible'; });
|
||||
registerButtons.forEach(button => { button.style.display = 'inline-block'; button.style.visibility = 'visible'; });
|
||||
if (authContainer) { authContainer.style.display = 'flex'; authContainer.style.visibility = 'visible'; }
|
||||
if (userMenu) { userMenu.style.display = 'none'; userMenu.style.visibility = 'hidden'; }
|
||||
}
|
||||
}
|
||||
|
||||
// Run immediately
|
||||
// console.log('Running updateAuthButtons immediately from fix-auth-buttons.js');
|
||||
updateAuthButtons();
|
||||
|
||||
// Update auth buttons when page loads
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// console.log('DOMContentLoaded event triggered in fix-auth-buttons.js, updating auth buttons');
|
||||
updateAuthButtons();
|
||||
// REMOVE: setupUserMenuDropdown();
|
||||
});
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Immediate Authentication State Handler
|
||||
*
|
||||
* This script runs as soon as possible to hide login/register buttons if a user is logged in
|
||||
* It should be included directly in the HTML before any other scripts
|
||||
*/
|
||||
|
||||
console.log('include-auth-new.js: Running immediate auth check');
|
||||
|
||||
// Function to update UI based on auth state (extracted for reuse)
|
||||
function updateAuthUI() {
|
||||
if (localStorage.getItem('auth_token')) {
|
||||
console.log('include-auth-new.js: Updating UI for authenticated user');
|
||||
// Inject CSS to hide auth buttons and show user menu
|
||||
const styleId = 'auth-ui-style';
|
||||
let style = document.getElementById(styleId);
|
||||
if (!style) {
|
||||
style = document.createElement('style');
|
||||
style.id = styleId;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
style.textContent = `
|
||||
#authContainer, .auth-buttons, a[href="login.html"], a[href="register.html"],
|
||||
.login-btn, .register-btn, .auth-btn.login-btn, .auth-btn.register-btn {
|
||||
display: none !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
#userMenu, .user-menu {
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
`;
|
||||
|
||||
// Update user info display elements immediately
|
||||
try {
|
||||
var userInfoStr = localStorage.getItem('user_info');
|
||||
if (userInfoStr) {
|
||||
var userInfo = JSON.parse(userInfoStr);
|
||||
var displayName = userInfo.username || 'User';
|
||||
var userDisplayName = document.getElementById('userDisplayName');
|
||||
if (userDisplayName) userDisplayName.textContent = displayName;
|
||||
var userName = document.getElementById('userName');
|
||||
if (userName) {
|
||||
userName.textContent = (userInfo.first_name || '') + ' ' + (userInfo.last_name || '');
|
||||
if (!userName.textContent.trim()) userName.textContent = userInfo.username || 'User';
|
||||
}
|
||||
var userEmail = document.getElementById('userEmail');
|
||||
if (userEmail && userInfo.email) userEmail.textContent = userInfo.email;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('include-auth-new.js: Error updating user info display:', e);
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log('include-auth-new.js: Updating UI for logged-out user');
|
||||
// Inject CSS to show auth buttons and hide user menu
|
||||
const styleId = 'auth-ui-style';
|
||||
let style = document.getElementById(styleId);
|
||||
if (!style) {
|
||||
style = document.createElement('style');
|
||||
style.id = styleId;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
style.textContent = `
|
||||
#authContainer, .auth-buttons {
|
||||
display: flex !important; /* Use flex for container */
|
||||
visibility: visible !important;
|
||||
}
|
||||
a[href="login.html"], a[href="register.html"],
|
||||
.login-btn, .register-btn, .auth-btn.login-btn, .auth-btn.register-btn {
|
||||
display: inline-block !important; /* Use inline-block for buttons */
|
||||
visibility: visible !important;
|
||||
}
|
||||
#userMenu, .user-menu {
|
||||
display: none !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// Immediately check auth state and update UI
|
||||
updateAuthUI();
|
||||
|
||||
// Listen for changes to localStorage and update UI without reloading
|
||||
window.addEventListener('storage', function(event) {
|
||||
if (event.key === 'auth_token' || event.key === 'user_info') {
|
||||
console.log(`include-auth-new.js: Storage event detected for ${event.key}. Updating UI.`);
|
||||
updateAuthUI(); // Update UI instead of reloading
|
||||
// window.location.reload(); // <-- Keep commented out / Remove permanently
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Script to include the new authentication script in existing HTML files
|
||||
* This script should be included at the end of the body in each HTML file
|
||||
*/
|
||||
|
||||
// Function to load and execute the new authentication script
|
||||
function loadAuthNewScript() {
|
||||
// Create a script element
|
||||
const script = document.createElement('script');
|
||||
script.src = 'auth-new.js';
|
||||
script.async = true;
|
||||
|
||||
// Add the script to the document
|
||||
document.body.appendChild(script);
|
||||
|
||||
console.log('Added auth-new.js script to the page');
|
||||
}
|
||||
|
||||
// Function to check if we're using the new UI
|
||||
function isNewUI() {
|
||||
// Check for elements that are specific to the new UI
|
||||
const loginButton = document.querySelector('a[href="login.html"].auth-btn, a.login');
|
||||
const registerButton = document.querySelector('a[href="register.html"].auth-btn, a.register');
|
||||
|
||||
// If we find these elements, we're using the new UI
|
||||
return !!(loginButton || registerButton);
|
||||
}
|
||||
|
||||
// Load the new authentication script if we're using the new UI
|
||||
if (isNewUI()) {
|
||||
console.log('Detected new UI, loading auth-new.js');
|
||||
loadAuthNewScript();
|
||||
} else {
|
||||
console.log('Using old UI, not loading auth-new.js');
|
||||
}
|
||||
+22
-52
@@ -2,56 +2,45 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Authentication redirect script -->
|
||||
<script src="./auth-redirect.js?v=20250119001" data-protected="true"></script>
|
||||
<script src="auth-redirect.js?v=20250119001" data-protected="true"></script>
|
||||
|
||||
<!-- Include authentication script first to handle login state immediately -->
|
||||
|
||||
<script src="include-auth-new.js?v=20250119001"></script>
|
||||
|
||||
<!-- File utilities script for secure file handling -->
|
||||
<script src="./file-utils.js?v=20250119001"></script>
|
||||
<script src="file-utils.js?v=20250119001"></script>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Warracker - Warranty Tracker</title>
|
||||
<!-- Add standard favicon.ico link -->
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<!-- Replace the old favicon link -->
|
||||
<!-- <link rel="icon" type="image/png" href="img/favicon.png"> -->
|
||||
<!-- Add new favicon links -->
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./img/favicon-512x512.png">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004">
|
||||
<script src="./theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<script type="module" src="./js/store.js"></script>
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
<script type="module" src="./js/components/warrantyCard.js"></script>
|
||||
<script type="module" src="./js/components/tag.js"></script>
|
||||
<script type="module" src="./js/components/editModal.js"></script>
|
||||
<script type="module" src="./js/components/modals.js"></script>
|
||||
<script type="module" src="./js/components/claims.js"></script>
|
||||
<script type="module" src="./js/components/notes.js"></script>
|
||||
<script type="module" src="./js/components/paperless.js"></script>
|
||||
<script type="module" src="./js/components/ui.js"></script>
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon-512x512.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="style.css?v=20250119004">
|
||||
<script src="theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
|
||||
<!-- Font Awesome for icons -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
<!-- Load header fix styles to ensure consistent header styling -->
|
||||
<link rel="stylesheet" href="./header-fix.css?v=20250119001">
|
||||
<link rel="stylesheet" href="header-fix.css?v=20250119001">
|
||||
<!-- Load fix for auth buttons -->
|
||||
|
||||
<script src="fix-auth-buttons-loader.js?v=20250119001"></script>
|
||||
<!-- Mobile Header specific styles -->
|
||||
<link rel="stylesheet" href="./mobile-header.css?v=20250119002">
|
||||
<link rel="stylesheet" href="mobile-header.css?v=20250119002">
|
||||
|
||||
<!-- i18next Local Scripts -->
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
|
||||
<!-- i18n Configuration -->
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
|
||||
<!-- Immediate authentication check script -->
|
||||
<script>
|
||||
@@ -106,7 +95,7 @@
|
||||
</script>
|
||||
|
||||
<!-- Registration status check script -->
|
||||
|
||||
<script src="registration-status.js?v=20250119001"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Header -->
|
||||
@@ -1336,9 +1325,8 @@
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="./script.js?v=20250119002" defer></script>
|
||||
<script type="module" src="./js/index.js"></script>
|
||||
<script src="auth.js?v=20250119001"></script>
|
||||
<script src="script.js?v=20250119002"></script>
|
||||
<script>
|
||||
// Lightweight UI logic for Filter/Sort popovers (no change to core logic)
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
@@ -1647,10 +1635,10 @@
|
||||
</script>
|
||||
|
||||
<!-- Footer Width Fix -->
|
||||
<script src="./footer-fix.js?v=20251024001"></script>
|
||||
<script src="footer-fix.js?v=20251024001"></script>
|
||||
|
||||
<!-- Footer Content Manager -->
|
||||
<script src="./footer-content.js?v=20250119001"></script>
|
||||
<script src="footer-content.js?v=20250119001"></script>
|
||||
|
||||
<!-- Powered by Warracker Footer -->
|
||||
<footer class="warracker-footer" id="warrackerFooter">
|
||||
@@ -1696,23 +1684,5 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Templates (do not affect layout) -->
|
||||
<template id="warranty-card-template">
|
||||
<div class="warranty-card">
|
||||
<div class="product-name-header">
|
||||
<h3 class="warranty-title"></h3>
|
||||
<div class="warranty-actions">
|
||||
<button class="action-btn edit-btn" title="Edit"><i class="fas fa-edit"></i></button>
|
||||
<button class="action-btn delete-btn" title="Delete"><i class="fas fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warranty-content">
|
||||
<div class="warranty-info"></div>
|
||||
</div>
|
||||
<div class="warranty-status-row"><span></span></div>
|
||||
</div>
|
||||
</template>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
||||
|
||||
+15
-17
@@ -1,19 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="./auth-redirect.js?v=20250119001" data-protected="false"></script>
|
||||
<script src="auth-redirect.js?v=20250119001" data-protected="false"></script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title data-i18n="auth.login_title">Login - Warracker</title>
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./img/favicon-512x512.png">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004">
|
||||
<script src="./theme-loader.js?v=20250119001"></script>
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon-512x512.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="style.css?v=20250119004">
|
||||
<script src="theme-loader.js?v=20250119001"></script>
|
||||
<script>
|
||||
// If user is authenticated and has a theme in user_info (from previous sessions), reflect it early
|
||||
try {
|
||||
@@ -24,11 +22,11 @@
|
||||
} catch (_) {}
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
<script src="registration-status.js?v=20250119001"></script>
|
||||
|
||||
</head>
|
||||
<body class="login-page-body">
|
||||
@@ -84,7 +82,7 @@
|
||||
</form>
|
||||
<div id="ssoSection" style="display: none;">
|
||||
<div class="separator"><span>OR</span></div>
|
||||
<a href="./api/oidc/login" id="oidcLoginButton" class="btn btn-secondary btn-block btn-sso" style="text-decoration: none;">
|
||||
<a href="/api/oidc/login" id="oidcLoginButton" class="btn btn-secondary btn-block btn-sso" style="text-decoration: none;">
|
||||
<i class="fab fa-openid" style="margin-right: 8px;"></i> <span>Login with SSO Provider</span>
|
||||
</a>
|
||||
</div>
|
||||
@@ -96,7 +94,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="auth.js?v=20250119001"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Check for OIDC errors in URL parameters and display them
|
||||
|
||||
+20
-23
@@ -2,37 +2,34 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Authentication redirect script -->
|
||||
<script src="./auth-redirect.js?v=20250119001" data-protected="false"></script>
|
||||
<script src="auth-redirect.js?v=20250119001" data-protected="false"></script>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title data-i18n="auth.register">Register - Warracker</title>
|
||||
<!-- Favicons -->
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./img/favicon-512x512.png">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004">
|
||||
<script src="./theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon-512x512.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="style.css?v=20250119004">
|
||||
<script src="theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<!-- Font Awesome for icons -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
<!-- Load header fix styles to ensure consistent header styling -->
|
||||
<link rel="stylesheet" href="./header-fix.css?v=20250119001">
|
||||
<link rel="stylesheet" href="header-fix.css?v=20250119001">
|
||||
<!-- Mobile Header specific styles -->
|
||||
<link rel="stylesheet" href="./mobile-header.css?v=20250119002">
|
||||
<link rel="stylesheet" href="mobile-header.css?v=20250119002">
|
||||
<!-- i18next Local Scripts -->
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<!-- i18n initialization script -->
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
<!-- Load fix for auth buttons -->
|
||||
|
||||
<script src="./script.js?v=20250119001" defer></script>
|
||||
<script type="module" src="./js/index.js"></script>
|
||||
<script src="fix-auth-buttons-loader.js?v=20250119001"></script>
|
||||
<script src="script.js?v=20250119001" defer></script>
|
||||
<style>
|
||||
.auth-container {
|
||||
max-width: 500px;
|
||||
@@ -240,7 +237,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Registration status check script -->
|
||||
|
||||
<script src="registration-status.js?v=20250119001"></script>
|
||||
<script>
|
||||
// Additional handling for the register page
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
@@ -380,7 +377,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Script for authentication -->
|
||||
|
||||
<script src="auth.js?v=20250119001"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const registerForm = document.getElementById('registerForm');
|
||||
@@ -622,10 +619,10 @@
|
||||
</script>
|
||||
|
||||
<!-- Footer Width Fix -->
|
||||
<script src="./footer-fix.js?v=20251024001"></script>
|
||||
<script src="footer-fix.js?v=20251024001"></script>
|
||||
|
||||
<!-- Footer Content Manager -->
|
||||
<script src="./footer-content.js?v=20250119001"></script>
|
||||
<script src="footer-content.js?v=20250119001"></script>
|
||||
|
||||
<!-- Powered by Warracker Footer -->
|
||||
<footer class="warracker-footer" id="warrackerFooter">
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Registration Status Checker
|
||||
*
|
||||
* This script checks if registration is enabled on the site and hides registration buttons/links if disabled.
|
||||
* Include this script in all pages that have registration links or buttons.
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Only check if user is not logged in
|
||||
if (!localStorage.getItem('auth_token')) {
|
||||
checkRegistrationStatus();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if registration is enabled and hide registration elements if disabled
|
||||
*/
|
||||
function checkRegistrationStatus() {
|
||||
fetch('/api/auth/registration-status')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (!data.enabled) {
|
||||
// Hide all registration links and buttons
|
||||
hideRegistrationElements();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error checking registration status:', error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide all registration-related elements on the page
|
||||
*/
|
||||
function hideRegistrationElements() {
|
||||
// Hide elements with specific classes
|
||||
const elements = [
|
||||
'.register-btn', // Main navigation register button
|
||||
'a[href="register.html"]', // Links to register page
|
||||
'a[href="./register.html"]', // Links to register page (relative)
|
||||
'a[href="/register.html"]' // Links to register page (root relative)
|
||||
];
|
||||
|
||||
// Apply to all matching elements
|
||||
elements.forEach(selector => {
|
||||
document.querySelectorAll(selector).forEach(element => {
|
||||
element.style.display = 'none';
|
||||
});
|
||||
});
|
||||
|
||||
// Special case for auth container in the header
|
||||
const authContainer = document.getElementById('authContainer');
|
||||
if (authContainer) {
|
||||
// Check if it has multiple children and at least one is hidden
|
||||
const children = authContainer.children;
|
||||
let visibleCount = 0;
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (children[i].style.display !== 'none') {
|
||||
visibleCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's only one visible child, adjust the container styling
|
||||
if (visibleCount === 1) {
|
||||
authContainer.style.justifyContent = 'flex-end';
|
||||
}
|
||||
}
|
||||
|
||||
// Special case for auth links in login/register pages
|
||||
const authLinks = document.querySelector('.auth-links');
|
||||
if (authLinks) {
|
||||
const links = authLinks.querySelectorAll('a');
|
||||
links.forEach(link => {
|
||||
if (link.textContent === 'Create Account' ||
|
||||
link.href.includes('register.html')) {
|
||||
link.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Add a message about registration being disabled if we're on the login page
|
||||
if (window.location.pathname.includes('login.html')) {
|
||||
const infoMessage = document.createElement('div');
|
||||
infoMessage.className = 'registration-info';
|
||||
infoMessage.innerHTML = '<small>New account registration is currently disabled</small>';
|
||||
infoMessage.style.color = 'var(--text-muted)';
|
||||
infoMessage.style.fontSize = '0.8em';
|
||||
infoMessage.style.marginTop = '10px';
|
||||
authLinks.appendChild(infoMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,31 +5,28 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title data-i18n="auth.reset_password_title">Warracker - Reset Password</title>
|
||||
<!-- Favicons -->
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./img/favicon-512x512.png">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004">
|
||||
<script src="./theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon-512x512.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="style.css?v=20250119004">
|
||||
<script src="theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<!-- Font Awesome for icons -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
<!-- Load header fix styles to ensure consistent header styling -->
|
||||
<link rel="stylesheet" href="./header-fix.css?v=20250119001">
|
||||
<link rel="stylesheet" href="header-fix.css?v=20250119001">
|
||||
<!-- Mobile Header specific styles -->
|
||||
<link rel="stylesheet" href="./mobile-header.css?v=20250119002">
|
||||
<link rel="stylesheet" href="mobile-header.css?v=20250119002">
|
||||
<!-- i18next Local Scripts -->
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<!-- i18n initialization script -->
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
<!-- Load fix for auth buttons -->
|
||||
|
||||
<script src="./script.js?v=20250119001" defer></script>
|
||||
<script type="module" src="./js/index.js"></script>
|
||||
<script src="fix-auth-buttons-loader.js?v=20250119001"></script>
|
||||
<script src="script.js?v=20250119001" defer></script>
|
||||
<style>
|
||||
.auth-container {
|
||||
max-width: 400px;
|
||||
@@ -100,7 +97,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Registration status check script -->
|
||||
|
||||
<script src="registration-status.js?v=20250119001"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Header -->
|
||||
@@ -262,13 +259,13 @@
|
||||
document.addEventListener('DOMContentLoaded', initializeTheme);
|
||||
</script>
|
||||
|
||||
|
||||
<script src="auth.js?v=20250119001"></script>
|
||||
|
||||
<!-- Footer Width Fix -->
|
||||
<script src="./footer-fix.js?v=20251024001"></script>
|
||||
<script src="footer-fix.js?v=20251024001"></script>
|
||||
|
||||
<!-- Footer Content Manager -->
|
||||
<script src="./footer-content.js?v=20250119001"></script>
|
||||
<script src="footer-content.js?v=20250119001"></script>
|
||||
|
||||
<!-- Powered by Warracker Footer -->
|
||||
<footer class="warracker-footer" id="warrackerFooter">
|
||||
|
||||
@@ -5,31 +5,28 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title data-i18n="auth.set_new_password_title">Warracker - Set New Password</title>
|
||||
<!-- Favicons -->
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./img/favicon-512x512.png">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004">
|
||||
<script src="./theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon-512x512.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="style.css?v=20250119004">
|
||||
<script src="theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<!-- Font Awesome for icons -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
<!-- Load header fix styles to ensure consistent header styling -->
|
||||
<link rel="stylesheet" href="./header-fix.css?v=20250119001">
|
||||
<link rel="stylesheet" href="header-fix.css?v=20250119001">
|
||||
<!-- Mobile Header specific styles -->
|
||||
<link rel="stylesheet" href="./mobile-header.css?v=20250119002">
|
||||
<link rel="stylesheet" href="mobile-header.css?v=20250119002">
|
||||
<!-- i18next Local Scripts -->
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<!-- i18n initialization script -->
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
<!-- Load fix for auth buttons -->
|
||||
|
||||
<script src="./script.js?v=20250119001" defer></script>
|
||||
<script type="module" src="./js/index.js"></script>
|
||||
<script src="fix-auth-buttons-loader.js?v=20250119001"></script>
|
||||
<script src="script.js?v=20250119001" defer></script>
|
||||
<style>
|
||||
.auth-container {
|
||||
max-width: 400px;
|
||||
@@ -157,7 +154,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Registration status check script -->
|
||||
|
||||
<script src="registration-status.js?v=20250119001"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Header -->
|
||||
@@ -429,13 +426,13 @@
|
||||
</script>
|
||||
|
||||
<!-- Scripts -->
|
||||
|
||||
<script src="auth.js?v=20250119001"></script>
|
||||
|
||||
<!-- Footer Width Fix -->
|
||||
<script src="./footer-fix.js?v=20251024001"></script>
|
||||
<script src="footer-fix.js?v=20251024001"></script>
|
||||
|
||||
<!-- Footer Content Manager -->
|
||||
<script src="./footer-content.js?v=20250119001"></script>
|
||||
<script src="footer-content.js?v=20250119001"></script>
|
||||
|
||||
<!-- Powered by Warracker Footer -->
|
||||
<footer class="warracker-footer" id="warrackerFooter">
|
||||
|
||||
+1321
-499
File diff suppressed because it is too large
Load Diff
+64
-28
@@ -2,47 +2,48 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Authentication redirect script -->
|
||||
<script src="./auth-redirect.js?v=20250119001" data-protected="true"></script>
|
||||
<script src="auth-redirect.js?v=20250119001" data-protected="true"></script>
|
||||
|
||||
<!-- Include authentication script first to handle login state immediately -->
|
||||
|
||||
<script src="include-auth-new.js?v=20250119001"></script>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Settings - Warracker</title>
|
||||
<!-- Favicons -->
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./img/favicon-512x512.png">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon-512x512.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<!-- Load the main site styles first -->
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004">
|
||||
<link rel="stylesheet" href="style.css?v=20250119004">
|
||||
<!-- Font Awesome for icons -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
<!-- Then load settings-specific styles -->
|
||||
<link rel="stylesheet" href="./settings-styles.css?v=20250119001">
|
||||
<link rel="stylesheet" href="settings-styles.css?v=20250119001">
|
||||
<!-- Apply theme immediately -->
|
||||
<script src="./theme-loader.js?v=20250119001"></script>
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
<script src="theme-loader.js?v=20250119001"></script>
|
||||
<!-- Load header fix styles last to override any conflicting styles -->
|
||||
<link rel="stylesheet" href="./header-fix.css?v=20250119001">
|
||||
<link rel="stylesheet" href="header-fix.css?v=20250119001">
|
||||
<!-- Mobile Header specific styles -->
|
||||
<link rel="stylesheet" href="./mobile-header.css?v=20250119002">
|
||||
<link rel="stylesheet" href="mobile-header.css?v=20250119002">
|
||||
<!-- Load fix for auth buttons -->
|
||||
|
||||
<script src="fix-auth-buttons-loader.js?v=20250119001"></script>
|
||||
|
||||
<!-- i18next Local Scripts -->
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
|
||||
<!-- i18n Configuration -->
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
|
||||
<!-- Temporary debug script -->
|
||||
<script src="js/i18n-debug.js?v=20250119001"></script>
|
||||
|
||||
<!-- Mobile menu logic isolated to avoid collisions on settings -->
|
||||
<script src="./mobile-menu.js?v=20250119002" defer></script>
|
||||
<script src="mobile-menu.js?v=20250119002" defer></script>
|
||||
|
||||
<!-- Immediate authentication check script -->
|
||||
<script>
|
||||
@@ -1076,17 +1077,52 @@
|
||||
<p style="font-size: 0.8em; color: #666;">User ID: <span id="displayUserId"></span></p>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary close-modal">Cancel</button>
|
||||
<button type="button" id="confirmDeleteUserBtn" class="btn btn-danger">Delete</button>
|
||||
<button type="button" id="confirmDeleteUserBtn" class="btn btn-danger" onclick="deleteUser()">Delete</button>
|
||||
</div>
|
||||
<div style="margin-top: 20px; border-top: 1px solid #ddd; padding-top: 10px;">
|
||||
<p><small>If the delete button doesn't work, try these alternatives:</small></p>
|
||||
<ul style="font-size: 0.8em;">
|
||||
<li><a href="#" id="directDeleteLink" style="color: #dc3545;">Alternative 1: Direct function call</a></li>
|
||||
<li><a href="#" id="directAPILink" style="color: #dc3545;">Alternative 2: Direct API call</a></li>
|
||||
<li><a href="#" id="directDeleteLink" style="color: #dc3545;" onclick="deleteUser(); return false;">Alternative 1: Direct function call</a></li>
|
||||
<li><a href="#" id="directAPILink" style="color: #dc3545;" onclick="directDeleteUserAPI(document.getElementById('deleteUserId').value); return false;">Alternative 2: Direct API call</a></li>
|
||||
<li><button type="submit" class="btn btn-sm btn-danger">Alternative 3: Form Submit</button></li>
|
||||
</ul>
|
||||
<div style="margin-top: 10px;">
|
||||
<button type="button" id="emergencyDeleteBtn" class="btn btn-sm btn-danger">Emergency Delete</button>
|
||||
<button type="button" id="emergencyDeleteBtn" class="btn btn-sm btn-danger"
|
||||
onclick="(function() {
|
||||
const userId = document.getElementById('deleteUserId').value || document.getElementById('displayUserId').textContent;
|
||||
if (!userId) {
|
||||
alert('Error: User ID is missing');
|
||||
return;
|
||||
}
|
||||
const token = localStorage.getItem('auth_token');
|
||||
if (!token) {
|
||||
alert('Error: Authentication token is missing');
|
||||
return;
|
||||
}
|
||||
alert('Emergency delete for user ID: ' + userId);
|
||||
fetch('/api/admin/users/' + userId, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + token,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
alert('Response status: ' + response.status);
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
alert('User deleted successfully');
|
||||
document.querySelectorAll('.modal-backdrop').forEach(m => m.style.display = 'none');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Failed to delete user: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Error: ' + error.message);
|
||||
});
|
||||
})(); return false;">
|
||||
Emergency Delete (Inline JS)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1136,14 +1172,14 @@
|
||||
<div id="toastContainer" class="toast-container"></div>
|
||||
|
||||
<!-- Scripts -->
|
||||
|
||||
<script type="module" src="./settings-new.js"></script>
|
||||
<script src="auth.js?v=20250119001"></script>
|
||||
<script src="settings-new.js?v=20250119001"></script>
|
||||
|
||||
<!-- Footer Width Fix -->
|
||||
<script src="./footer-fix.js?v=20251024001"></script>
|
||||
<script src="footer-fix.js?v=20251024001"></script>
|
||||
|
||||
<!-- Footer Content Manager -->
|
||||
<script src="./footer-content.js?v=20250119001"></script>
|
||||
<script src="footer-content.js?v=20250119001"></script>
|
||||
|
||||
<!-- Powered by Warracker Footer -->
|
||||
<footer class="warracker-footer" id="warrackerFooter">
|
||||
|
||||
+24
-28
@@ -2,47 +2,43 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Authentication redirect script -->
|
||||
<script src="./auth-redirect.js?v=20250119001" data-protected="true"></script>
|
||||
<script src="auth-redirect.js?v=20250119001" data-protected="true"></script>
|
||||
|
||||
<!-- Include authentication script first to handle login state immediately -->
|
||||
|
||||
<script src="include-auth-new.js?v=20250119001"></script>
|
||||
|
||||
<!-- File utilities script for secure file handling -->
|
||||
<script src="./file-utils.js?v=20250119001"></script>
|
||||
<script src="file-utils.js?v=20250119001"></script>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title data-i18n="status.title">Status - Warracker</title>
|
||||
<!-- Favicons -->
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./img/favicon-512x512.png">
|
||||
<link rel="manifest" href="./manifest.json">
|
||||
<link rel="stylesheet" href="./style.css?v=20250119004">
|
||||
<script src="./theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<script type="module" src="./js/store.js"></script>
|
||||
<script type="module" src="./js/services/authService.js"></script>
|
||||
<script type="module" src="./js/services/apiService.js"></script>
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon-512x512.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="style.css?v=20250119004">
|
||||
<script src="theme-loader.js?v=20250119001"></script> <!-- Apply theme early -->
|
||||
<!-- Font Awesome for icons -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
|
||||
<!-- Load header fix styles to ensure consistent header styling -->
|
||||
<link rel="stylesheet" href="./header-fix.css?v=20250119001">
|
||||
<link rel="stylesheet" href="header-fix.css?v=20250119001">
|
||||
<!-- Mobile Header specific styles -->
|
||||
<link rel="stylesheet" href="./mobile-header.css?v=20250119002">
|
||||
<link rel="stylesheet" href="mobile-header.css?v=20250119002">
|
||||
<!-- Chart.js for visualizations -->
|
||||
<script src="./chart.js?v=20250119001"></script>
|
||||
<script src="chart.js?v=20250119001"></script>
|
||||
<!-- i18next Local Scripts -->
|
||||
<script src="./js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="./js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18next.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextHttpBackend.min.js?v=20250119001"></script>
|
||||
<script src="js/lib/i18nextBrowserLanguageDetector.min.js?v=20250119001"></script>
|
||||
<!-- i18n initialization script -->
|
||||
<script src="./js/i18n.js?v=20250119001"></script>
|
||||
<script src="js/i18n.js?v=20250119001"></script>
|
||||
<!-- Load fix for auth buttons -->
|
||||
|
||||
<script src="./script.js?v=20250119002" defer></script> <!-- Added script.js -->
|
||||
<script type="module" src="./js/index.js"></script>
|
||||
<script type="module" src="./status.js?v=20250119001"></script> <!-- Status page specific functionality -->
|
||||
<script src="fix-auth-buttons-loader.js?v=20250119001"></script>
|
||||
<script src="script.js?v=20250119002" defer></script> <!-- Added script.js -->
|
||||
<script src="status.js?v=20250119001" defer></script> <!-- Status page specific functionality -->
|
||||
<style>
|
||||
.user-menu {
|
||||
position: relative;
|
||||
@@ -826,14 +822,14 @@
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="module" src="./status.js?v=20250119001"></script>
|
||||
<script src="auth.js?v=20250119001"></script>
|
||||
<script src="status.js?v=20250119001" defer></script>
|
||||
|
||||
<!-- Footer Width Fix -->
|
||||
<script src="./footer-fix.js?v=20251024001"></script>
|
||||
<script src="footer-fix.js?v=20251024001"></script>
|
||||
|
||||
<!-- Footer Content Manager -->
|
||||
<script src="./footer-content.js?v=20250119001"></script>
|
||||
<script src="footer-content.js?v=20250119001"></script>
|
||||
|
||||
<!-- Powered by Warracker Footer -->
|
||||
<footer class="warracker-footer" id="warrackerFooter">
|
||||
|
||||
+38
-19
@@ -1,5 +1,3 @@
|
||||
import apiService from './js/services/apiService.js';
|
||||
import authService from './js/services/authService.js';
|
||||
(function() {
|
||||
// DOM Elements
|
||||
const loadingIndicator = document.getElementById('loadingIndicator');
|
||||
@@ -103,13 +101,17 @@ import authService from './js/services/authService.js';
|
||||
async function fetchStatistics() {
|
||||
try {
|
||||
console.log('Checking authentication status... (status.js IIFE)');
|
||||
if (!authService || !authService.isAuthenticated()) {
|
||||
if (!window.auth || !window.auth.isAuthenticated()) {
|
||||
throw new Error('Authentication required.');
|
||||
}
|
||||
const token = authService.getToken();
|
||||
const token = window.auth.getToken();
|
||||
if (!token) {
|
||||
throw new Error('Authentication token not available.');
|
||||
}
|
||||
const options = {
|
||||
method: 'GET',
|
||||
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json'}
|
||||
};
|
||||
|
||||
// Check saved view scope preference to determine which API endpoint to use
|
||||
const savedScope = loadViewScopePreference();
|
||||
@@ -119,15 +121,17 @@ import authService from './js/services/authService.js';
|
||||
const apiUrl = shouldUseGlobalView ? GLOBAL_STATISTICS_API_URL : STATISTICS_API_URL;
|
||||
console.log('Fetching statistics from:', apiUrl, '(Global view preference:', savedScope, ')');
|
||||
|
||||
const response = shouldUseGlobalView
|
||||
? await apiService.request('/api/statistics/global')
|
||||
: await apiService.request('/api/statistics');
|
||||
const json = await response.json();
|
||||
const response = await fetch(apiUrl, options);
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Failed to fetch statistics: ${response.status} ${errorText}`);
|
||||
}
|
||||
|
||||
// Update isGlobalView to match the loaded data
|
||||
isGlobalView = shouldUseGlobalView;
|
||||
console.log(`[DEBUG] Set isGlobalView to: ${isGlobalView}`);
|
||||
|
||||
return json;
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching statistics (status.js IIFE):', error);
|
||||
throw error;
|
||||
@@ -154,10 +158,13 @@ import authService from './js/services/authService.js';
|
||||
|
||||
try {
|
||||
// Check if global view is enabled for this user
|
||||
const token = authService.getToken();
|
||||
const token = window.auth.getToken();
|
||||
if (!token) return;
|
||||
|
||||
const response = await apiService.request('/api/settings/global-view-status', { method: 'GET' });
|
||||
const response = await fetch('/api/settings/global-view-status', {
|
||||
method: 'GET',
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
@@ -336,8 +343,11 @@ import authService from './js/services/authService.js';
|
||||
|
||||
try {
|
||||
// Check if global view is still available
|
||||
const token = authService.getToken();
|
||||
const response = await apiService.request('/api/settings/global-view-status', { method: 'GET' });
|
||||
const token = window.auth.getToken();
|
||||
const response = await fetch('/api/settings/global-view-status', {
|
||||
method: 'GET',
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
@@ -934,9 +944,14 @@ import authService from './js/services/authService.js';
|
||||
let allWarrantiesForTimeline = [];
|
||||
try {
|
||||
// Try to fetch all warranties for a complete timeline
|
||||
const token = authService && authService.getToken ? authService.getToken() : null;
|
||||
const token = window.auth && window.auth.getToken ? window.auth.getToken() : null;
|
||||
if (token) {
|
||||
const allWarrantiesResponse = await apiService.request('/api/warranties', { method: 'GET' });
|
||||
const allWarrantiesResponse = await fetch('/api/warranties', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (allWarrantiesResponse.ok) {
|
||||
allWarrantiesForTimeline = await allWarrantiesResponse.json();
|
||||
} else {
|
||||
@@ -1017,8 +1032,9 @@ import authService from './js/services/authService.js';
|
||||
|
||||
async function loadUserPreferences() {
|
||||
try {
|
||||
if (!authService || !authService.getToken()) { console.warn('Auth or token not available for prefs in status.js'); return; }
|
||||
const response = await apiService.request('/api/auth/preferences', { method: 'GET' });
|
||||
if (!window.auth || !window.auth.getToken()) { console.warn('Auth or token not available for prefs in status.js'); return; }
|
||||
const token = window.auth.getToken();
|
||||
const response = await fetch('/api/auth/preferences', { headers: { 'Authorization': `Bearer ${token}` } });
|
||||
if (response.ok) {
|
||||
const prefs = await response.json();
|
||||
if (prefs && prefs.expiring_soon_days !== undefined) { // Check for undefined specifically
|
||||
@@ -1072,10 +1088,13 @@ import authService from './js/services/authService.js';
|
||||
// ALWAYS fetch fresh details when editing from the status page to ensure modal has latest data.
|
||||
console.log(`[DEBUG status.js] Edit from status page for warranty ${warrantyId}. ALWAYS fetching fresh details from /api/debug/warranty/:id.`);
|
||||
showLoadingSpinner(); // Show spinner for this specific fetch
|
||||
const token = authService.getToken();
|
||||
const token = localStorage.getItem('auth_token') || (window.auth && window.auth.getToken());
|
||||
if (!token) throw new Error('Authentication token not available for fetching fresh details.');
|
||||
|
||||
const response = await apiService.request(`/api/debug/warranty/${warrantyId}`, { method: 'GET' });
|
||||
const response = await fetch(`/api/debug/warranty/${warrantyId}`, {
|
||||
method: 'GET',
|
||||
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
|
||||
+7
-7
@@ -4827,18 +4827,18 @@ html.dark-mode .warracker-footer a:hover {
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
@media (max-width: 768px) {
|
||||
.grid-view .product-photo-thumbnail img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
.list-view .product-photo-thumbnail img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
.table-view .product-photo-thumbnail img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.product-photo-thumbnail {
|
||||
margin-right: 5px;
|
||||
|
||||
@@ -15,6 +15,7 @@ const urlsToCache = [
|
||||
|
||||
// Stylesheets (versioned)
|
||||
'./style.css?v=20250119004',
|
||||
'./styles.css?v=20250119001',
|
||||
'./settings-styles.css?v=20250119001',
|
||||
'./header-fix.css?v=20250119001',
|
||||
'./mobile-header.css?v=20250119002',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Version checker for Warracker
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const currentVersion = '1.0.3'; // Current version of the application
|
||||
const currentVersion = '1.0.2'; // Current version of the application
|
||||
const updateStatus = document.getElementById('updateStatus');
|
||||
const updateLink = document.getElementById('updateLink');
|
||||
const versionDisplay = document.getElementById('versionDisplay');
|
||||
|
||||
Reference in New Issue
Block a user