Files
sasa-maillist/web/index.html
2025-10-13 15:05:42 +00:00

668 lines
30 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mailing List Manager</title>
<link rel="stylesheet" href="static/css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<!-- Login Page -->
<div class="login-page" id="loginPage">
<div class="login-container">
<div class="login-header">
<div class="login-logo">
<i class="fas fa-envelope"></i>
</div>
<h1>Mailing List Manager</h1>
<p>Sign in to manage your mailing lists</p>
</div>
<form class="login-form" id="loginForm">
<!-- Login Error Message -->
<div class="login-error" id="loginError" style="display: none;">
<i class="fas fa-exclamation-circle"></i>
<span id="loginErrorMessage">Invalid username or password</span>
</div>
<div class="form-group">
<label for="username">
<i class="fas fa-user"></i>
Username
</label>
<input type="text" id="username" placeholder="Enter your username" required autocomplete="username">
</div>
<div class="form-group">
<label for="password">
<i class="fas fa-lock"></i>
Password
</label>
<input type="password" id="password" placeholder="Enter your password" required autocomplete="current-password">
</div>
<button type="submit" class="btn btn-primary btn-block" id="loginBtn">
<span>Sign In</span>
<i class="fas fa-arrow-right"></i>
</button>
</form>
<div class="login-footer">
<p class="text-muted text-sm">
<i class="fas fa-shield-alt"></i>
Secure authentication required
</p>
</div>
</div>
</div>
<!-- Header (shown after login) -->
<header class="header" id="mainHeader" style="display: none;">
<div class="container">
<div class="header-content">
<h1 class="logo">
<i class="fas fa-envelope"></i>
Mailing List Manager
</h1>
<div class="auth-section">
<div class="user-info" id="userInfo">
<div class="user-details">
<span class="user-name" id="currentUsername">User</span>
<span class="user-role" id="currentUserRole">role</span>
</div>
<button class="btn btn-secondary" id="logoutBtn">Logout</button>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="main-content" id="mainContent" style="display: none;">
<div class="container">
<!-- Navigation Tabs -->
<nav class="tab-nav" id="tabNav">
<button class="tab-btn active" data-tab="lists">
<i class="fas fa-list"></i>
Mailing Lists
</button>
<button class="tab-btn" data-tab="members">
<i class="fas fa-users"></i>
Members
</button>
<button class="tab-btn" data-tab="users" id="usersTab" style="display: none;">
<i class="fas fa-user-shield"></i>
Users
</button>
</nav>
<!-- Notification Area -->
<div class="notification" id="notification" style="display: none;">
<span class="notification-message" id="notificationMessage"></span>
<button class="notification-close" id="notificationClose">
<i class="fas fa-times"></i>
</button>
</div>
<!-- Mailing Lists Tab -->
<div class="tab-content active" id="lists-tab">
<div class="section-header">
<h2>Mailing Lists</h2>
<button class="btn btn-primary" id="addListBtn">
<i class="fas fa-plus"></i>
Add List
</button>
</div>
<div class="data-table">
<table class="table" id="listsTable">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Description</th>
<th>Members</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="listsTableBody">
<!-- Dynamic content -->
</tbody>
</table>
</div>
</div>
<!-- Members Tab -->
<div class="tab-content" id="members-tab">
<div class="section-header">
<div class="header-content">
<h2>Members</h2>
<div class="header-help">
<i class="fas fa-info-circle"></i>
<span>Click the "Lists" button next to any member to manage their subscriptions</span>
</div>
</div>
<div class="button-group">
<button class="btn btn-primary" id="addMemberBtn">
<i class="fas fa-plus"></i>
Add Member
</button>
<button class="btn btn-secondary" id="showBulkImportBtn">
<i class="fas fa-upload"></i>
Bulk Import CSV
</button>
</div>
</div>
<div class="data-table">
<table class="table" id="membersTable">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Lists</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="membersTableBody">
<!-- Dynamic content -->
</tbody>
</table>
</div>
</div>
<!-- Users Tab (Admin Only) -->
<div class="tab-content" id="users-tab">
<div class="section-header">
<h2>User Management</h2>
<button class="btn btn-primary" id="addUserBtn">
<i class="fas fa-plus"></i>
Add User
</button>
</div>
<div class="data-table">
<table class="table" id="usersTable">
<thead>
<tr>
<th>Username</th>
<th>Role</th>
<th>Created</th>
<th>Last Login</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="usersTableBody">
<!-- Dynamic content -->
</tbody>
</table>
</div>
</div>
</div>
</main>
<!-- Loading Overlay -->
<div class="loading-overlay" id="loadingOverlay" style="display: none;">
<div class="loading-spinner">
<i class="fas fa-spinner fa-spin"></i>
<p>Loading...</p>
</div>
</div>
<!-- Modals -->
<!-- Add/Edit List Modal -->
<div class="modal" id="listModal">
<div class="modal-content">
<div class="modal-header">
<h3 id="listModalTitle">Add Mailing List</h3>
<button class="modal-close" id="listModalClose">
<i class="fas fa-times"></i>
</button>
</div>
<form id="listForm">
<div class="form-group">
<label for="listName">List Name *</label>
<input type="text" id="listName" name="listName" required>
</div>
<div class="form-group">
<label for="listEmail">List Email *</label>
<input type="email" id="listEmail" name="listEmail" required>
</div>
<div class="form-group">
<label for="listDescription">Description</label>
<textarea id="listDescription" name="listDescription" rows="3"></textarea>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="listActive" name="listActive" checked>
<span class="checkmark"></span>
Active
</label>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="listCancelBtn">Cancel</button>
<button type="submit" class="btn btn-primary" id="listSubmitBtn">Save</button>
</div>
</form>
</div>
</div>
<!-- Add/Edit Member Modal -->
<div class="modal" id="memberModal">
<div class="modal-content">
<div class="modal-header">
<h3 id="memberModalTitle">Add Member</h3>
<button class="modal-close" id="memberModalClose">
<i class="fas fa-times"></i>
</button>
</div>
<form id="memberForm">
<div class="form-group">
<label for="memberName">Member Name *</label>
<input type="text" id="memberName" name="memberName" required>
</div>
<div class="form-group">
<label for="memberEmail">Email Address *</label>
<input type="email" id="memberEmail" name="memberEmail" required>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="memberActive" name="memberActive" checked>
<span class="checkmark"></span>
Active
</label>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="memberCancelBtn">Cancel</button>
<button type="submit" class="btn btn-primary" id="memberSubmitBtn">Save</button>
</div>
</form>
</div>
</div>
<!-- Member Subscriptions Modal -->
<div class="modal" id="memberSubscriptionsModal">
<div class="modal-content">
<div class="modal-header">
<h3 id="memberSubscriptionsTitle">Manage Subscriptions</h3>
<button class="modal-close" id="memberSubscriptionsModalClose">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<div class="member-info-banner" id="memberInfoBanner">
<div class="member-avatar">
<i class="fas fa-user"></i>
</div>
<div class="member-details">
<h4 id="memberSubscriptionsName">Member Name</h4>
<p id="memberSubscriptionsEmail">member@example.com</p>
</div>
</div>
<div class="subscriptions-section">
<h5>Mailing List Subscriptions</h5>
<p class="text-muted text-sm">Check the lists this member should be subscribed to:</p>
<div class="subscription-list" id="subscriptionCheckboxList">
<!-- Dynamic content will be inserted here -->
</div>
</div>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="memberSubscriptionsCancelBtn">Cancel</button>
<button type="button" class="btn btn-primary" id="memberSubscriptionsSaveBtn">
<i class="fas fa-save"></i>
Save Changes
</button>
</div>
</div>
</div>
<!-- Add Subscription Modal (Legacy - keeping for bulk operations) -->
<div class="modal" id="subscriptionModal">
<div class="modal-content">
<div class="modal-header">
<h3>Add Subscription</h3>
<button class="modal-close" id="subscriptionModalClose">
<i class="fas fa-times"></i>
</button>
</div>
<form id="subscriptionForm">
<div class="form-group">
<label for="subscriptionList">Mailing List *</label>
<select id="subscriptionList" name="subscriptionList" required>
<option value="">Select a list...</option>
</select>
</div>
<div class="form-group">
<label for="subscriptionMember">Member *</label>
<select id="subscriptionMember" name="subscriptionMember" required>
<option value="">Select a member...</option>
</select>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="subscriptionCancelBtn">Cancel</button>
<button type="submit" class="btn btn-primary">Add Subscription</button>
</div>
</form>
</div>
</div>
<!-- Bulk Import Modal -->
<div class="modal modal-large" id="bulkImportModal">
<div class="modal-content">
<div class="modal-header">
<h3>Bulk Import Members from CSV</h3>
<button class="modal-close" id="bulkImportModalClose">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<!-- Step 1: File Upload -->
<div class="import-step" id="importStep1">
<h4><i class="fas fa-upload"></i> Step 1: Upload CSV File</h4>
<p class="text-muted">Upload a CSV file containing member information. The file must have 'Name' and 'Email' columns.</p>
<div class="file-upload-area" id="fileUploadArea">
<div class="file-upload-content">
<i class="fas fa-cloud-upload-alt"></i>
<p>Click to select a CSV file or drag and drop</p>
<input type="file" id="csvFileInput" accept=".csv" style="display: none;">
</div>
</div>
<div class="file-info" id="fileInfo" style="display: none;">
<div class="file-details">
<i class="fas fa-file-csv"></i>
<span id="fileName">file.csv</span>
<span id="fileSize" class="text-muted">(0 KB)</span>
</div>
<button type="button" class="btn btn-sm btn-secondary" id="removeFileBtn">
<i class="fas fa-times"></i> Remove
</button>
</div>
<div class="csv-format-help">
<h5><i class="fas fa-info-circle"></i> CSV Format</h5>
<p>Your CSV file should look like this:</p>
<div class="code-example">
<code>Name,Email,Delivery,Member since<br>
Ahmed Ajzan,ahmedajzan@doctors.org.uk,,2025-04-06T18:44:26.819454<br>
Alan Bailey,abgower@icloud.com,,2025-04-06T18:44:26.824446</code>
</div>
<p class="text-muted text-sm">Only the 'Name' and 'Email' columns are required. Additional columns will be ignored.</p>
</div>
</div>
<!-- Step 2: Preview -->
<div class="import-step" id="importStep2" style="display: none;">
<h4><i class="fas fa-eye"></i> Step 2: Preview Data</h4>
<p class="text-muted">Review the data that will be imported:</p>
<div class="preview-stats" id="previewStats">
<div class="stat-item">
<span class="stat-value" id="totalRowsCount">0</span>
<span class="stat-label">Total Rows</span>
</div>
<div class="stat-item">
<span class="stat-value" id="validRowsCount">0</span>
<span class="stat-label">Valid Rows</span>
</div>
<div class="stat-item">
<span class="stat-value" id="errorRowsCount">0</span>
<span class="stat-label">Errors</span>
</div>
</div>
<div class="preview-table-container" id="previewTableContainer">
<table class="table table-sm" id="previewTable">
<thead>
<tr>
<th>Row</th>
<th>Name</th>
<th>Email</th>
<th>Status</th>
</tr>
</thead>
<tbody id="previewTableBody">
<!-- Dynamic content -->
</tbody>
</table>
</div>
<div class="error-list" id="errorList" style="display: none;">
<div class="error-header">
<h5><i class="fas fa-exclamation-triangle"></i> Errors Found</h5>
<button type="button" class="btn btn-sm btn-secondary" id="toggleErrorsBtn">
<span id="errorToggleText">Show All</span>
<i class="fas fa-chevron-down" id="errorToggleIcon"></i>
</button>
</div>
<div class="error-summary" id="errorSummary">
<!-- Summary will be shown here -->
</div>
<div class="error-details" id="errorDetails" style="display: none;">
<div class="error-table-container">
<table class="table table-sm" id="errorTable">
<thead>
<tr>
<th>Row</th>
<th>Issue</th>
<th>Name</th>
<th>Email</th>
<th>Raw Data</th>
</tr>
</thead>
<tbody id="errorTableBody">
<!-- Dynamic content -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Step 3: List Selection -->
<div class="import-step" id="importStep3" style="display: none;">
<h4><i class="fas fa-list"></i> Step 3: Select Mailing Lists</h4>
<p class="text-muted">Choose which mailing lists these members should be subscribed to:</p>
<div class="list-selection" id="listSelection">
<!-- Dynamic content -->
</div>
<div class="selection-info">
<p class="text-muted text-sm">
<i class="fas fa-info-circle"></i>
If a member already exists, they will be added to the selected lists (existing subscriptions will be preserved).
</p>
</div>
</div>
<!-- Step 4: Import Results -->
<div class="import-step" id="importStep4" style="display: none;">
<h4><i class="fas fa-check-circle"></i> Step 4: Import Complete</h4>
<div class="import-results" id="importResults">
<div class="result-stats">
<div class="stat-item">
<span class="stat-value" id="processedCount">0</span>
<span class="stat-label">Processed</span>
</div>
<div class="stat-item">
<span class="stat-value" id="createdCount">0</span>
<span class="stat-label">Created</span>
</div>
<div class="stat-item">
<span class="stat-value" id="updatedCount">0</span>
<span class="stat-label">Updated</span>
</div>
<div class="stat-item">
<span class="stat-value" id="subscriptionsCount">0</span>
<span class="stat-label">Subscriptions</span>
</div>
</div>
<div class="result-errors" id="resultErrors" style="display: none;">
<h5><i class="fas fa-exclamation-triangle"></i> Import Errors</h5>
<ul id="resultErrorList">
<!-- Dynamic content -->
</ul>
</div>
</div>
</div>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="bulkImportBackBtn" style="display: none;">
<i class="fas fa-arrow-left"></i> Back
</button>
<button type="button" class="btn btn-secondary" id="bulkImportCancelBtn">Cancel</button>
<button type="button" class="btn btn-primary" id="bulkImportNextBtn" disabled>
Next <i class="fas fa-arrow-right"></i>
</button>
<button type="button" class="btn btn-primary" id="bulkImportBtn" style="display: none;">
<i class="fas fa-upload"></i> Import Members
</button>
<button type="button" class="btn btn-success" id="bulkImportDoneBtn" style="display: none;">
<i class="fas fa-check"></i> Done
</button>
</div>
</div>
</div>
<!-- Add/Edit User Modal -->
<div class="modal" id="userModal">
<div class="modal-content">
<div class="modal-header">
<h3 id="userModalTitle">Add User</h3>
<button class="modal-close" id="userModalClose">
<i class="fas fa-times"></i>
</button>
</div>
<form id="userForm">
<div class="form-group">
<label for="userName">Username *</label>
<input type="text" id="userName" name="userName" required>
</div>
<div class="form-group">
<label for="userPassword">Password *</label>
<input type="password" id="userPassword" name="userPassword" required>
<div class="form-help" id="passwordHelp">
Leave blank to keep current password (when editing)
</div>
</div>
<div class="form-group">
<label for="userRole">Role *</label>
<select id="userRole" name="userRole" required>
<option value="">Select a role...</option>
<option value="administrator">Administrator - Full access including user management</option>
<option value="operator">Operator - Read/write access to lists and members</option>
<option value="read-only">Read-Only - View-only access</option>
</select>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="userActive" name="userActive" checked>
<span class="checkmark"></span>
Active
</label>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="userCancelBtn">Cancel</button>
<button type="submit" class="btn btn-primary" id="userSubmitBtn">Save</button>
</div>
</form>
</div>
</div>
<!-- Bounce History Modal -->
<div class="modal" id="bounceHistoryModal">
<div class="modal-content">
<div class="modal-header">
<h3 id="bounceHistoryTitle">Bounce History</h3>
<button class="modal-close" id="bounceHistoryModalClose">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<div class="member-info-banner" id="bounceHistoryMemberInfo">
<div class="member-avatar">
<i class="fas fa-user"></i>
</div>
<div class="member-details">
<h4 id="bounceHistoryMemberName">Member Name</h4>
<p id="bounceHistoryMemberEmail">member@example.com</p>
</div>
</div>
<div class="bounce-summary">
<div class="bounce-stat">
<i class="fas fa-exclamation-triangle"></i>
<div>
<div class="bounce-stat-label">Total Bounces</div>
<div class="bounce-stat-value" id="bounceTotalCount">0</div>
</div>
</div>
<div class="bounce-stat">
<i class="fas fa-clock"></i>
<div>
<div class="bounce-stat-label">Last Bounce</div>
<div class="bounce-stat-value" id="bounceLastDate">Never</div>
</div>
</div>
<div class="bounce-stat">
<i class="fas fa-info-circle"></i>
<div>
<div class="bounce-stat-label">Status</div>
<div class="bounce-stat-value" id="bounceStatusText">Clean</div>
</div>
</div>
</div>
<div class="bounce-history-section">
<h5>Bounce Events</h5>
<div class="bounce-history-list" id="bounceHistoryList">
<!-- Dynamic content will be inserted here -->
</div>
</div>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="bounceHistoryCloseBtn">Close</button>
<button type="button" class="btn btn-warning" id="bounceHistoryResetBtn" data-requires-write>
<i class="fas fa-redo"></i>
Reset Bounce Status
</button>
</div>
</div>
</div>
<!-- Confirmation Modal -->
<div class="modal" id="confirmModal">
<div class="modal-content">
<div class="modal-header">
<h3>Confirm Action</h3>
<button class="modal-close" id="confirmModalClose">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<p id="confirmMessage">Are you sure you want to perform this action?</p>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="confirmCancelBtn">Cancel</button>
<button type="button" class="btn btn-danger" id="confirmOkBtn">Confirm</button>
</div>
</div>
</div>
<script src="static/js/api.js"></script>
<script src="static/js/app.js"></script>
<script src="static/js/ui.js"></script>
</body>
</html>