Files
Warracker/frontend/status.html
sassanix 92ffb07aa1 Add collapsible warranty details, inline editing on Status page, vendor filter/sort; various fixes
### Added
- Collapsible warranty details in the Status page table, showing full warranty info inline.
- Inline warranty editing via "Edit Warranty" button in expanded view.
- Vendor column added to sort options on the main warranty list.
- Vendor filter dropdown added to the main warranty list.

### Changed
- Removed direct product name links from Status page table in favor of inline expansion.
- CSV export now formats dates as YYYY-MM-DD.

### Fixed
- Resolved browser validation error with product URLs in hidden tabs by switching to text input and improving validation logic.
- Edit modal no longer closes on backdrop clicks.
- Migration scripts now support custom `DB_NAME` values by removing hardcoded names.
2025-05-16 15:36:39 -03:00

627 lines
28 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<!-- Authentication redirect script -->
<script src="auth-redirect.js" data-protected="true"></script>
<!-- Include authentication script first to handle login state immediately -->
<script src="include-auth-new.js"></script>
<!-- File utilities script for secure file handling -->
<script src="file-utils.js"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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">
<script src="theme-loader.js"></script> <!-- Apply theme early -->
<!-- Font Awesome for icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Load header fix styles to ensure consistent header styling -->
<link rel="stylesheet" href="header-fix.css">
<!-- Chart.js for visualizations -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Load fix for auth buttons -->
<script src="fix-auth-buttons-loader.js"></script>
<script src="script.js" defer></script> <!-- Added script.js -->
<style>
.user-menu {
position: relative;
margin-left: 15px;
}
.user-btn {
background: none;
border: none;
color: var(--text-color);
cursor: pointer;
display: flex;
align-items: center;
font-size: 0.9rem;
padding: 5px 10px;
border-radius: 20px;
transition: background-color 0.3s;
}
.user-btn:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.dark-mode .user-btn:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.user-btn i {
margin-right: 5px;
}
.user-menu-dropdown {
position: absolute;
top: 100%;
right: 0;
background-color: var(--card-bg);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
width: 200px;
z-index: 1000;
display: none;
padding: 10px 0;
margin-top: 5px;
}
.user-menu-dropdown.active {
display: block;
}
.user-info {
padding: 10px 15px;
border-bottom: 1px solid var(--border-color);
margin-bottom: 5px;
}
.user-name {
font-weight: bold;
margin-bottom: 5px;
}
.user-email {
font-size: 0.8rem;
color: var(--text-muted);
word-break: break-all;
}
.user-menu-item {
padding: 8px 15px;
cursor: pointer;
transition: background-color 0.3s;
display: flex;
align-items: center;
}
.user-menu-item:hover {
background-color: var(--hover-bg);
}
.user-menu-item i {
margin-right: 10px;
width: 16px;
text-align: center;
}
.auth-buttons {
display: flex;
gap: 10px;
margin-left: 15px;
}
.auth-btn {
padding: 5px 15px;
border-radius: 20px;
font-size: 0.9rem;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
}
.auth-btn i {
margin-right: 5px;
}
.login-btn {
background-color: transparent;
border: 1px solid var(--primary-color);
color: var(--primary-color);
}
.login-btn:hover {
background-color: rgba(var(--primary-rgb), 0.1);
}
.register-btn {
background-color: var(--primary-color);
border: 1px solid var(--primary-color);
color: white;
}
.register-btn:hover {
background-color: var(--primary-dark);
}
@media (max-width: 768px) {
.export-btn .export-text {
display: none;
}
}
</style>
<!-- Immediate authentication check script -->
<script>
// Check if user is logged in immediately to hide buttons
(function() {
if (localStorage.getItem('auth_token')) {
// Hide login and register buttons immediately
document.addEventListener('DOMContentLoaded', function() {
console.log('Inline script: User is logged in, hiding login/register buttons');
// Hide auth container
var authContainer = document.getElementById('authContainer');
if (authContainer) {
authContainer.style.display = 'none';
authContainer.style.visibility = 'hidden';
}
// Show user menu
var userMenu = document.getElementById('userMenu');
if (userMenu) {
userMenu.style.display = 'block';
userMenu.style.visibility = 'visible';
}
// Update user info if possible
try {
var userInfo = JSON.parse(localStorage.getItem('user_info'));
if (userInfo) {
var displayName = userInfo.first_name || 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('Error updating user info:', e);
}
}, { once: true });
}
})();
</script>
</head>
<body>
<!-- Header -->
<header>
<div class="container">
<div class="app-title">
<i class="fas fa-shield-alt"></i>
<h1><a href="index.html" style="color: inherit; text-decoration: none; cursor: pointer;">Warracker</a></h1>
</div>
<div class="nav-links">
<a href="index.html" class="nav-link">
<i class="fas fa-home"></i> Home
</a>
<a href="status.html" class="nav-link active">
<i class="fas fa-chart-pie"></i> Status
</a>
</div>
<!-- Group for right-aligned elements -->
<div class="header-right-group">
<div id="authContainer" class="auth-buttons">
<a href="login.html" class="auth-btn login-btn">
<i class="fas fa-sign-in-alt"></i> Login
</a>
<a href="register.html" class="auth-btn register-btn">
<i class="fas fa-user-plus"></i> Register
</a>
</div>
<div id="userMenu" class="user-menu" style="display: none;">
<button id="userBtn" class="user-btn">
<i class="fas fa-user-circle"></i>
<span id="userDisplayName">User</span>
</button>
<div id="userMenuDropdown" class="user-menu-dropdown">
<div class="user-info">
<div id="userName" class="user-name">User Name</div>
<div id="userEmail" class="user-email">user@example.com</div>
</div>
<div class="user-menu-item">
<a href="settings-new.html" style="color: inherit; text-decoration: none; display: block;">
<i class="fas fa-cog"></i> Settings
</a>
</div>
<div class="user-menu-item">
<i class="fas fa-info-circle"></i>
<a href="about.html" style="text-decoration: none; color: inherit;">About</a>
</div>
<div class="user-menu-item" id="logoutMenuItem">
<i class="fas fa-sign-out-alt"></i> Logout
</div>
</div>
</div>
</div> <!-- End header-right-group -->
</div>
</header>
<!-- Main Content -->
<div class="container">
<div class="status-content">
<div class="dashboard-header">
<h2>Warranty Status Dashboard</h2>
<button id="refreshDashboardBtn" class="refresh-btn" title="Refresh dashboard">
<i class="fas fa-sync-alt"></i>
</button>
</div>
<!-- Loading Indicator -->
<div id="loadingIndicator" class="loading-container active">
<div class="loading-spinner"></div>
</div>
<!-- Error Message Container -->
<div id="errorContainer" style="display: none;" class="error-message">
<i class="fas fa-exclamation-circle"></i>
<h3>Error Loading Dashboard</h3>
<p id="errorMessage">There was a problem loading the warranty statistics. Please try refreshing the page.</p>
<p id="errorDetails" class="error-details"></p>
</div>
<!-- Dashboard Content -->
<div id="dashboardContent">
<!-- Summary Cards -->
<div class="status-cards">
<div class="status-card" data-status="active">
<div class="card-icon">
<i class="fas fa-check-circle"></i>
</div>
<div class="card-content">
<h3>Active</h3>
<p class="count" id="activeCount">0</p>
</div>
</div>
<div class="status-card" data-status="expiring">
<div class="card-icon">
<i class="fas fa-exclamation-circle"></i>
</div>
<div class="card-content">
<h3>Expiring Soon</h3>
<p class="count" id="expiringCount">0</p>
</div>
</div>
<div class="status-card" data-status="expired">
<div class="card-icon">
<i class="fas fa-times-circle"></i>
</div>
<div class="card-content">
<h3>Expired</h3>
<p class="count" id="expiredCount">0</p>
</div>
</div>
<div class="status-card" data-status="total">
<div class="card-icon">
<i class="fas fa-shield-alt"></i>
</div>
<div class="card-content">
<h3>Total</h3>
<p class="count" id="totalCount">0</p>
</div>
</div>
</div>
<!-- Charts Section -->
<div class="charts-container">
<div class="chart-card">
<h3>Warranty Status Distribution</h3>
<div class="chart-container">
<canvas id="statusChart"></canvas>
</div>
</div>
<div class="chart-card">
<h3>Expiration Timeline</h3>
<div class="chart-container">
<canvas id="timelineChart"></canvas>
</div>
</div>
</div>
<!-- Recent Expirations -->
<div class="recent-expirations">
<div class="table-header">
<h3>Recently Expired or Expiring Soon</h3>
<div class="table-actions">
<div class="search-box">
<i class="fas fa-search"></i>
<input type="text" id="searchWarranties" placeholder="Search warranties...">
</div>
<div class="filter-options">
<select id="statusFilter" class="filter-select">
<option value="all">All Statuses</option>
<option value="active">Active</option>
<option value="expiring">Expiring Soon</option>
<option value="expired">Expired</option>
</select>
</div>
<button id="exportBtn" class="export-btn" title="Export data">
<i class="fas fa-download"></i> <span class="export-text">Export</span>
</button>
</div>
</div>
<div class="table-responsive">
<table id="recentExpirationsTable">
<thead>
<tr>
<th class="sortable" data-sort="product">Product <i class="fas fa-sort"></i></th>
<th class="sortable" data-sort="purchase">Purchase Date <i class="fas fa-sort"></i></th>
<th class="sortable" data-sort="expiration">Expiration Date <i class="fas fa-sort"></i></th>
<th class="sortable" data-sort="status">Status <i class="fas fa-sort"></i></th>
</tr>
</thead>
<tbody id="recentExpirationsBody">
<!-- Data will be filled by JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Toast Notifications -->
<div class="toast-container" id="toastContainer"></div>
<!-- Edit Warranty Modal -->
<div id="editModal" class="modal-backdrop">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">Edit Warranty</h3>
<button class="close-btn" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body">
<!-- Tab Navigation -->
<div class="edit-tabs-nav">
<button type="button" class="edit-tab-btn active" data-tab="edit-product-info">
<i class="fas fa-box"></i> Product
</button>
<button type="button" class="edit-tab-btn" data-tab="edit-warranty-details">
<i class="fas fa-shield-alt"></i> Warranty
</button>
<button type="button" class="edit-tab-btn" data-tab="edit-documents">
<i class="fas fa-file-alt"></i> Documents
</button>
<button type="button" class="edit-tab-btn" data-tab="edit-tags">
<i class="fas fa-tags"></i> Tags
</button>
</div>
<form id="editWarrantyForm">
<input type="hidden" id="editWarrantyId">
<!-- Product Info Tab -->
<div class="edit-tab-content active" id="edit-product-info">
<div class="form-group">
<label for="editProductName">Product Name</label>
<input type="text" id="editProductName" name="product_name" class="form-control" required>
</div>
<div class="form-group">
<label for="editProductUrl">Product URL (Optional)</label>
<input type="text" id="editProductUrl" name="product_url" class="form-control" placeholder="https://example.com/product">
</div>
<div class="form-group">
<label>Serial Numbers</label>
<div id="editSerialNumbersContainer">
<!-- Serial number inputs will be added dynamically -->
</div>
</div>
<div class="form-group">
<label for="editVendor">Vendor (Optional)</label>
<input type="text" id="editVendor" name="vendor" class="form-control" placeholder="e.g. Amazon, Best Buy, etc.">
</div>
</div>
<!-- Warranty Details Tab -->
<div class="edit-tab-content" id="edit-warranty-details">
<div class="form-group">
<label for="editPurchaseDate">Purchase Date</label>
<input type="date" id="editPurchaseDate" name="purchase_date" class="form-control" required>
</div>
<!-- Add Lifetime Checkbox -->
<div class="form-group">
<label class="lifetime-label">
<input type="checkbox" id="editIsLifetime" name="is_lifetime" value="true">
Lifetime Warranty
</label>
</div>
<!-- End Lifetime Checkbox -->
<div id="editWarrantyDurationFields">
<div class="form-group">
<label for="editWarrantyDurationYears">Warranty Period</label>
<div class="duration-inputs">
<div>
<input type="number" id="editWarrantyDurationYears" name="warranty_duration_years" class="form-control" min="0" max="100" placeholder="Years">
<small>Years</small>
</div>
<div>
<input type="number" id="editWarrantyDurationMonths" name="warranty_duration_months" class="form-control" min="0" max="11" placeholder="Months">
<small>Months</small>
</div>
<div>
<input type="number" id="editWarrantyDurationDays" name="warranty_duration_days" class="form-control" min="0" max="365" placeholder="Days">
<small>Days</small>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="editPurchasePrice">Purchase Price (Optional)</label>
<div class="price-input-wrapper">
<span class="currency-symbol">$</span>
<input type="number" id="editPurchasePrice" name="purchase_price" class="form-control" min="0" step="0.01" placeholder="0.00">
</div>
</div>
<div class="form-group">
<label for="editNotes">Notes (Optional)</label>
<textarea id="editNotes" name="notes" class="form-control" rows="3" placeholder="Add any notes about this warranty..."></textarea>
</div>
</div>
<!-- Documents Tab -->
<div class="edit-tab-content" id="edit-documents">
<div class="form-group">
<label>Invoice/Receipt</label>
<div class="file-input-wrapper">
<label for="editInvoice" class="file-input-label">
<i class="fas fa-upload"></i> Choose File
</label>
<input type="file" id="editInvoice" name="invoice" class="file-input" accept=".pdf,.png,.jpg,.jpeg">
</div>
<div id="editFileName" class="file-name"></div>
<div id="currentInvoice" class="mt-10"></div>
<button type="button" id="deleteInvoiceBtn" class="btn btn-danger btn-sm mt-2" style="display:none;"><i class="fas fa-trash"></i> Delete Invoice</button>
</div>
<div class="form-group">
<label>Product Manual (Optional)</label>
<div class="file-input-wrapper">
<label for="editManual" class="file-input-label">
<i class="fas fa-upload"></i> Choose File
</label>
<input type="file" id="editManual" name="manual" class="file-input" accept=".pdf,.png,.jpg,.jpeg">
</div>
<div id="editManualFileName" class="file-name"></div>
<div id="currentManual" class="mt-10"></div>
<button type="button" id="deleteManualBtn" class="btn btn-danger btn-sm mt-2" style="display:none;"><i class="fas fa-trash"></i> Delete Manual</button>
</div>
<div class="form-group">
<label>Files (ZIP/RAR, Optional)</label>
<div class="file-input-wrapper">
<label for="editOtherDocument" class="file-input-label">
<i class="fas fa-upload"></i> Choose File
</label>
<input type="file" id="editOtherDocument" name="other_document" class="file-input" accept=".zip,.rar">
</div>
<div id="editOtherDocumentFileName" class="file-name"></div>
<div id="currentOtherDocument" class="mt-10"></div>
<button type="button" id="deleteOtherDocumentBtn" class="btn btn-danger btn-sm mt-2" style="display:none;"><i class="fas fa-trash"></i> Delete Files</button>
</div>
</div>
<!-- Tags Tab -->
<div class="edit-tab-content" id="edit-tags">
<div class="form-group">
<label>Add Tags</label>
<p class="text-muted">Tags help you organize and filter your warranties</p>
<div class="tags-container">
<div class="selected-tags" id="editSelectedTags">
<!-- Selected tags will be displayed here -->
</div>
<div class="tags-dropdown">
<input type="text" id="editTagSearch" class="form-control" placeholder="Search or add new tag...">
<div class="tags-list" id="editTagsList">
<!-- Tag options will be populated by JavaScript -->
</div>
</div>
<div class="mt-10">
<button type="button" id="editManageTagsBtn" class="btn btn-secondary btn-sm">
<i class="fas fa-cog"></i> Manage Tags
</button>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-danger" data-dismiss="modal">Cancel</button>
<button id="saveWarrantyBtn" class="btn btn-primary">Save Changes</button>
</div>
</div>
</div>
<!-- Confirm Delete Modal -->
<div id="deleteModal" class="modal-backdrop">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">Confirm Delete</h3>
<button class="close-btn" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body">
<p>Are you sure you want to delete this warranty? This action cannot be undone.</p>
<p><strong>Product:</strong> <span id="deleteProductName"></span></p>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button id="confirmDeleteBtn" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
<!-- Tag Management Modal -->
<div id="tagManagementModal" class="modal-backdrop">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">Manage Tags</h3>
<button class="close-btn" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body">
<form id="newTagForm" class="tag-form">
<input type="text" id="newTagName" class="form-control" placeholder="New tag name" required>
<input type="color" id="newTagColor" value="#808080">
<button type="submit" class="btn btn-primary">Add Tag</button>
</form>
<h4 class="mt-20">Existing Tags</h4>
<div id="existingTags" class="existing-tags">
<!-- Tags will be populated here by JavaScript -->
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
<!-- Loading Spinner -->
<div class="loading-container" id="loadingContainer">
<div class="loading-spinner"></div>
</div>
<script src="auth.js"></script>
<script src="status.js" defer></script>
</body>
</html>