Fix save subasset child modal and delete approriate files for those subassets and subassetchildren
Refactor and simply delete and update logic for assets and subassets
update import for url example
add resetImportForm to window from importmanager instead of script.js
update subasset file attachment expand/collapse to before showing the modal
match accepted file types from frontend to backend for manuals
update deleteAssetFileAsync with early return and to work with starting "/" or without
Add new toast manager with stacking toasts with success and error colors and repositioned to top
set button loading to false on subasset form validation
revert index.html change
initialize settings with default and copy over settings to always make sure all properties are included
remove unused async from createWarrantyDashboard function
Summary of Changes
I've successfully added a "Lifetime" column to the import modal that maps to the isLifetime property in the asset warranty object. Here's what was implemented:
1. Frontend Changes (HTML)
Added a new "Lifetime" column mapping row in the import modal (public/index.html)
Positioned it logically after "Warranty Expiration" and before "2nd Warranty Scope"
2. Frontend Changes (JavaScript)
public/managers/import.js:
Added lifetimeColumn to the column selection dropdowns
Added lifetime to the mappings object for form data collection
Added auto-mapping rules for common lifetime column names: ["lifetime", "lifetime warranty", "is lifetime", "islifetime", "permanent"]
Updated the CSV template to include the "Lifetime" column
Added sample data generation for the lifetime column (defaults to false)
Added lifetimeColumn to the reset form function
3. Backend Changes (Server)
server.js:
Added parsing logic for the lifetime column that accepts multiple formats:
true, 1, yes (case-insensitive) → true
Everything else → false
When isLifetime is true, the warranty expiration date is automatically set to null
The isLifetime property is properly set in the warranty object
Key Features
Flexible Input: Accepts true/false, 1/0, yes/no (case-insensitive)
Auto-mapping: Automatically detects common column names for lifetime warranties
Template Generation: Downloads include the Lifetime column with sample data
Data Validation: Properly handles the boolean conversion and warranty logic
The Problem:
Every time you opened a modal (asset or sub-asset), the ModalManager was adding new keyboard event listeners without removing the old ones. This caused:
1st modal open: 1 event listener → Ctrl+Enter works once
2nd modal open: 2 event listeners → Ctrl+Enter triggers twice (creates 2 assets)
3rd modal open: 3 event listeners → Ctrl+Enter triggers 3 times
And so on...
What Remains Intact:
✅ Warranty Notifications - Still sends notifications at 30, 14, 7, and 3 days before expiration
✅ Maintenance Frequency Notifications - Still sends notifications when frequency-based maintenance is due
✅ Maintenance Specific Date Notifications - Still sends 7-day advance and due-date notifications
✅ Duplicate Prevention - Still prevents duplicate notifications using tracking keys
✅ Data Validation - Still validates all maintenance events and dates
✅ Comprehensive Logging - Still provides detailed debug and summary logs
✅ Date Calculation Fix - Still uses the corrected start-of-day date comparison
The problem is that we're comparing the full DateTime (including time) instead of just the date portion. When the cron runs at 12:01 PM on the expiration date, the warranty expiration date (which defaults to midnight) is actually in the past by about 12 hours, resulting in a negative fractional day that gets floored to -1.
🔧 KEY ENHANCEMENTS:
Comprehensive Summary Reporting
Total assets/components checked
Total warranties processed
Success/failure notification counts
Current notification settings display
Robust Error Handling
Individual asset processing wrapped in try-catch
Failed notifications don't stop the entire process
Detailed error logging with context
Enhanced Date Parsing
Uses the same robust parseDate() function as maintenance
Proper timezone handling with TIMEZONE constant
Validation and warning for invalid dates
Safety Mechanisms
Expired warranty detection (1-7 days past expiration)
Asset type differentiation (Asset vs Component)
Consolidated threshold logic for cleaner code
Detailed Debug Logging
Individual warranty check logging
Processing status for each asset/component
Clear identification of notification triggers
CRITICAL ISSUES FIXED
1. TIMEZONE MISMATCH (HIGH RISK) - FIXED
Problem: Dates compared in UTC while cron runs in local timezone → off-by-one day errors
Solution: Implemented robust timezone handling using Luxon DateTime library
2. DATE PARSING FRAGILITY (HIGH RISK) - FIXED
Problem: Basic new Date() parsing could fail silently with invalid dates
Solution: Created comprehensive parseDate() function handling multiple formats with validation
3. DATE CALCULATION ERRORS (MEDIUM-HIGH RISK) - FIXED
Problem: Month arithmetic had edge cases (Jan 31 + 1 month = March 3 instead of Feb 29)
Solution: Implemented addTimePeriod() using Luxon's robust date arithmetic
4. MISSING VALIDATION & ERROR HANDLING - FIXED
Added comprehensive validation for all maintenance event data
Enhanced error handling to prevent system crashes
Added overdue detection as safety net (1-3 days past due notifications)
🛡️ SAFETY MECHANISMS ADDED
Overdue Detection: Catches missed maintenance (server downtime scenarios)
Duplicate Prevention: Tracking system prevents multiple notifications for same event
Data Validation: Invalid events are skipped with logging, don't crash system
Comprehensive Logging: Detailed debugging and summary reports
📊 TEST RESULTS
The comprehensive test suite shows all critical edge cases now work correctly:
✅ Leap year dates (Feb 29)
✅ Month-end arithmetic (Jan 31 + 1 month = Feb 29, not March 3)
✅ Timezone consistency across DST changes
✅ Multiple date formats parsed correctly
✅ Invalid dates handled gracefully
When viewing a main asset, sub-assets were rendered correctly using createSubAssetElement directly, so clicks worked fine
When viewing a sub-asset, sub-sub-assets were rendered using innerHTML, which converted the DOM elements to HTML strings and back to DOM, losing all event listeners
Instead of using innerHTML with HTML strings, I changed the code to:
Create DOM elements properly using document.createElement
Append elements directly using appendChild
The sub-asset editing was failing with a 404 "Sub-asset not found" error because the collectSubAssetFormData() method was incorrectly handling the sub-asset ID. It was trying to get the ID from a form field (document.getElementById('subAssetId')?.value) instead of using the actual existing sub-asset's ID when in edit mode.
The Fix:
I updated the collectSubAssetFormData() method in public/managers/modalManager.js to follow the same pattern as the asset form:
Edit Mode: When this.isEditMode is true and this.currentSubAsset exists, use this.currentSubAsset.id
Create Mode: When creating a new sub-asset, generate a new ID with this.generateId()
Changes Made:
Fixed the ID assignment logic to use this.currentSubAsset.id in edit mode instead of trying to read from a form field
Added debugging logs to help track the ID assignment process
Ensured the same pattern is used as the working asset form