2030 lines
74 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel - BNKops Influence Campaign Tool</title>
<link rel="icon" href="data:,">
<link rel="stylesheet" href="css/styles.css">
<style>
.admin-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.admin-header {
background: #2c3e50;
color: white;
padding: 2rem 0;
margin-bottom: 2rem;
text-align: center;
}
.admin-nav {
display: flex;
background: #34495e;
border-radius: 8px;
overflow: hidden;
margin-bottom: 2rem;
}
.nav-btn {
flex: 1;
padding: 1rem;
background: none;
border: none;
color: white;
cursor: pointer;
transition: background-color 0.3s;
}
.nav-btn:hover {
background: #2196f3;
}
.nav-btn.active {
background: #2196f3;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-row {
display: flex;
gap: 1rem;
align-items: flex-end;
}
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
.checkbox-group {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.5rem;
margin-top: 0.5rem;
}
.checkbox-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.campaign-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.campaign-card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 0;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
}
.campaign-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.campaign-card.highlighted {
border: 2px solid #ffd700;
box-shadow: 0 0 15px rgba(255, 215, 0, 0.3);
}
.campaign-highlight-badge {
position: absolute;
top: 10px;
right: 10px;
background: #ffd700;
color: #333;
padding: 0.3rem 0.8rem;
border-radius: 20px;
font-size: 0.85rem;
font-weight: bold;
z-index: 10;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.campaign-card-cover {
background-size: cover;
background-position: center;
min-height: 180px;
position: relative;
display: flex;
align-items: flex-end;
}
.campaign-card-cover-overlay {
background: linear-gradient(to top, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0.4) 60%, transparent 100%);
width: 100%;
padding: 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.campaign-card-cover-overlay h3 {
margin: 0;
color: white;
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
}
.campaign-card > .campaign-meta,
.campaign-card > .campaign-actions {
padding: 1.5rem;
}
.campaign-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding: 1.5rem;
}
.campaign-header h3 {
margin: 0;
color: #2c3e50;
}
.status-badge {
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: bold;
text-transform: uppercase;
}
.status-draft {
background: #f39c12;
color: white;
}
.status-active {
background: #27ae60;
color: white;
}
.status-paused {
background: #e74c3c;
color: white;
}
.status-archived {
background: #95a5a6;
color: white;
}
.campaign-meta {
color: #666;
font-size: 0.9rem;
margin-bottom: 1rem;
}
.campaign-meta p {
margin: 0.25rem 0;
}
.campaign-actions {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.btn {
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
text-decoration: none;
display: inline-block;
font-size: 0.9rem;
transition: background-color 0.3s;
}
.btn-primary {
background: #2196f3;
color: white;
}
.btn-secondary {
background: #95a5a6;
color: white;
}
.btn-danger {
background: #e74c3c;
color: white;
}
.btn:hover {
opacity: 0.9;
}
.empty-state {
text-align: center;
padding: 3rem;
color: #666;
}
.loading {
text-align: center;
padding: 2rem;
}
.spinner {
border: 4px solid #f3f3f3;
border-radius: 50%;
border-top: 4px solid #2196f3;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 1rem;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.hidden {
display: none !important;
}
.message-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
}
.message-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
}
.analytics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.analytics-stat {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 8px;
text-align: center;
}
.analytics-stat h3 {
font-size: 2rem;
margin: 0 0 0.5rem 0;
color: #2196f3;
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background: white;
padding: 2rem;
border-radius: 8px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid #eee;
}
.modal-close {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
}
/* Enhanced Form Styling */
.form-group label {
display: block;
font-weight: 600;
color: #2c3e50;
margin-bottom: 0.5rem;
font-size: 0.95rem;
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 0.75rem;
border: 2px solid #e0e6ed;
border-radius: 8px;
font-size: 0.95rem;
transition: border-color 0.3s, box-shadow 0.3s;
background: #f8f9fa;
}
.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
outline: none;
border-color: #2196f3;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
background: white;
}
/* Enhanced Status Select */
.status-select {
position: relative;
}
.status-select select {
appearance: none;
background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
color: white;
font-weight: 600;
padding: 1rem 3rem 1rem 1rem;
font-size: 1rem;
border: none;
cursor: pointer;
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
.status-select select option {
background: white;
color: #2c3e50;
font-weight: 500;
padding: 0.75rem;
text-shadow: none;
}
.status-select select option:hover,
.status-select select option:checked {
background: #2196f3;
color: white;
}
.status-select::after {
content: '▼';
position: absolute;
right: 1rem;
top: 50%;
transform: translateY(-50%);
color: white;
pointer-events: none;
font-size: 0.8rem;
}
.status-select select:focus {
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.3);
}
/* Enhanced Checkbox Styling */
.checkbox-group {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 12px;
border: 2px solid #e9ecef;
margin-top: 0.5rem;
}
.checkbox-item {
background: white;
padding: 1rem;
border-radius: 8px;
border: 2px solid #e9ecef;
margin-bottom: 0.75rem;
transition: all 0.3s;
cursor: pointer;
}
.checkbox-item:hover {
border-color: #2196f3;
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(52, 152, 219, 0.15);
}
.checkbox-item input[type="checkbox"] {
width: auto;
margin-right: 0.75rem;
transform: scale(1.2);
accent-color: #2196f3;
}
.checkbox-item label {
margin: 0;
font-weight: 500;
color: #495057;
cursor: pointer;
flex: 1;
}
.checkbox-item:has(input:checked) {
background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%);
border-color: #2196f3;
}
.checkbox-item:has(input:checked) label {
color: #2c3e50;
font-weight: 600;
}
/* Enhanced Form Grid */
.form-grid {
background: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
margin-bottom: 2rem;
}
/* Section Headers */
.section-header {
color: #2c3e50;
font-size: 1.1rem;
font-weight: 600;
margin: 2rem 0 1rem 0;
padding-bottom: 0.5rem;
border-bottom: 2px solid #e9ecef;
}
/* Enhanced Buttons */
.btn {
padding: 1rem 2rem;
border: none;
border-radius: 8px;
cursor: pointer;
text-decoration: none;
display: inline-block;
font-size: 1rem;
font-weight: 600;
transition: all 0.3s;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.btn-primary {
background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
color: white;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn-secondary:hover {
background: #5a6268;
transform: translateY(-1px);
}
/* User Management Styles */
.users-list {
display: grid;
gap: 1rem;
}
.user-card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 1.5rem;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.user-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.user-info h4 {
margin: 0 0 0.25rem 0;
color: #2c3e50;
}
.user-info p {
margin: 0;
color: #666;
font-size: 0.9rem;
}
.user-badges {
display: flex;
gap: 0.5rem;
align-items: center;
}
.user-badge {
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: bold;
text-transform: uppercase;
}
.user-badge.admin {
background: #e74c3c;
color: white;
}
.user-badge.user {
background: #2196f3;
color: white;
}
.user-badge.temp {
background: #f39c12;
color: white;
}
.user-badge.expired {
background: #95a5a6;
color: white;
}
.user-actions {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.btn-small {
padding: 0.5rem 1rem;
font-size: 0.8rem;
}
/* Campaign Selector Dropdown Styles */
.campaign-selector {
margin-bottom: 2rem;
background: #f8f9fa;
padding: 1.5rem;
border-radius: 12px;
border: 2px solid #e9ecef;
}
.campaign-selector label {
display: block;
font-weight: 600;
color: #2c3e50;
margin-bottom: 0.75rem;
font-size: 1rem;
}
.search-dropdown {
position: relative;
width: 100%;
}
.search-dropdown input {
width: 100%;
padding: 0.75rem 2.5rem 0.75rem 0.75rem;
border: 2px solid #e0e6ed;
border-radius: 8px;
font-size: 0.95rem;
background: white;
transition: border-color 0.3s, box-shadow 0.3s;
}
.search-dropdown input:focus {
outline: none;
border-color: #2196f3;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
.dropdown-arrow {
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-50%);
color: #666;
pointer-events: none;
font-size: 0.8rem;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 2px solid #e0e6ed;
border-top: none;
border-radius: 0 0 8px 8px;
max-height: 200px;
overflow-y: auto;
z-index: 1000;
display: none;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.dropdown-menu.show {
display: block;
}
.dropdown-item {
padding: 0.75rem;
cursor: pointer;
border-bottom: 1px solid #f1f3f4;
transition: background-color 0.2s;
}
.dropdown-item:hover {
background: #f8f9fa;
}
.dropdown-item.selected {
background: #e3f2fd;
color: #1976d2;
font-weight: 600;
}
.dropdown-item:last-child {
border-bottom: none;
}
.dropdown-item.no-results {
color: #666;
font-style: italic;
cursor: default;
}
.dropdown-item.no-results:hover {
background: white;
}
/* Response moderation styles */
.response-card {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.response-card.pending {
border-left: 4px solid #f39c12;
}
.response-card.approved {
border-left: 4px solid #27ae60;
}
.response-card.rejected {
border-left: 4px solid #e74c3c;
}
.response-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1rem;
}
.response-meta {
color: #666;
font-size: 0.9rem;
margin-bottom: 1rem;
}
.response-meta p {
margin: 0.25rem 0;
}
.response-content {
background: #f8f9fa;
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
}
.response-content h4 {
margin: 0 0 0.5rem 0;
color: #2c3e50;
font-size: 1rem;
}
.response-content p {
margin: 0;
color: #444;
line-height: 1.5;
}
.response-actions {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.response-screenshot {
max-width: 200px;
margin-top: 0.5rem;
border-radius: 4px;
cursor: pointer;
}
.response-screenshot:hover {
opacity: 0.8;
}
/* Custom Recipients Styles */
.recipient-card {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
margin-bottom: 0.75rem;
display: flex;
justify-content: space-between;
align-items: flex-start;
transition: box-shadow 0.2s;
}
.recipient-card:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.recipient-info {
flex: 1;
}
.recipient-info h5 {
margin: 0 0 0.25rem 0;
color: #2c3e50;
font-size: 1rem;
}
.recipient-info .recipient-email {
color: #2196f3;
font-size: 0.9rem;
margin-bottom: 0.25rem;
}
.recipient-info .recipient-meta {
color: #666;
font-size: 0.85rem;
margin: 0.25rem 0;
}
.recipient-actions {
display: flex;
gap: 0.5rem;
margin-left: 1rem;
}
.btn-icon {
padding: 0.5rem;
background: none;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
transition: all 0.2s;
}
.btn-icon:hover {
background: #f8f9fa;
transform: scale(1.1);
}
.btn-icon.edit:hover {
border-color: #2196f3;
color: #2196f3;
}
.btn-icon.delete:hover {
border-color: #e74c3c;
color: #e74c3c;
}
/* Bulk Import Modal */
.bulk-import-help {
background: #e3f2fd;
padding: 1rem;
border-radius: 8px;
margin-bottom: 1rem;
font-size: 0.9rem;
}
.bulk-import-help h4 {
margin: 0 0 0.5rem 0;
color: #1976d2;
}
.bulk-import-help code {
background: white;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-family: monospace;
}
@media (max-width: 768px) {
.admin-nav {
flex-direction: column;
}
.form-grid {
grid-template-columns: 1fr;
}
.campaign-actions {
justify-content: center;
}
.user-header {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
.user-actions {
justify-content: center;
}
}
/* Dark mode overrides for admin panel */
[data-theme="dark"] .admin-container {
background-color: var(--page-bg-color, #121212);
}
[data-theme="dark"] .admin-nav {
background: #252525;
}
[data-theme="dark"] .campaign-card {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .campaign-card-body h3 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .form-group label {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .form-group input,
[data-theme="dark"] .form-group select,
[data-theme="dark"] .form-group textarea {
background-color: #252525;
color: var(--text-color, rgba(255, 255, 255, 0.87));
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .section-header h2 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .users-table {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .users-table th {
background: #252525;
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .users-table td {
color: var(--text-color, rgba(255, 255, 255, 0.87));
border-bottom-color: var(--card-border-color, #333);
}
[data-theme="dark"] .users-table tr:hover {
background: #252525;
}
[data-theme="dark"] .form-card {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .form-card h3 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .checkbox-item label {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .responses-list {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .response-item {
border-bottom-color: var(--card-border-color, #333);
}
[data-theme="dark"] .response-item:hover {
background: #252525;
}
[data-theme="dark"] #sync-status-display {
background: var(--card-bg-color, #1e1e1e) !important;
}
[data-theme="dark"] #sync-status-display > div > div {
background: #252525 !important;
border-color: var(--card-border-color, #333) !important;
}
[data-theme="dark"] #sync-status-display strong {
color: var(--text-color, rgba(255, 255, 255, 0.87)) !important;
}
/* ==========================================
Comprehensive Dark Mode for Admin Panel
========================================== */
/* Admin utility classes */
.admin-card {
background: white;
}
.admin-text-muted {
color: #666;
}
[data-theme="dark"] .admin-card {
background: var(--card-bg-color, #1e1e1e);
}
[data-theme="dark"] .admin-text-muted {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
/* Checkbox group container */
[data-theme="dark"] .checkbox-group {
background: #252525;
border-color: var(--card-border-color, #333);
}
/* Checkbox items - the cards inside checkbox group */
[data-theme="dark"] .checkbox-item {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .checkbox-item:hover {
border-color: var(--md-primary-fg-color, #2196f3);
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.2);
}
[data-theme="dark"] .checkbox-item label {
color: var(--text-color, rgba(255, 255, 255, 0.87)) !important;
}
[data-theme="dark"] .checkbox-item:has(input:checked) {
background: linear-gradient(135deg, rgba(33, 150, 243, 0.15) 0%, rgba(100, 181, 246, 0.15) 100%);
border-color: var(--md-primary-fg-color, #2196f3);
}
[data-theme="dark"] .checkbox-item:has(input:checked) label {
color: var(--md-primary-fg-color-light, #42a5f5) !important;
}
/* Form grid container */
[data-theme="dark"] .form-grid {
background: var(--card-bg-color, #1e1e1e);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
/* Campaign selector dropdown */
[data-theme="dark"] .campaign-selector {
background: #252525;
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .campaign-selector label {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Search dropdown */
[data-theme="dark"] .search-dropdown input {
background: var(--card-bg-color, #1e1e1e);
color: var(--text-color, rgba(255, 255, 255, 0.87));
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .search-dropdown input::placeholder {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
[data-theme="dark"] .dropdown-menu {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .dropdown-item {
color: var(--text-color, rgba(255, 255, 255, 0.87));
border-bottom-color: var(--card-border-color, #333);
}
[data-theme="dark"] .dropdown-item:hover {
background: #252525;
}
[data-theme="dark"] .dropdown-item.selected {
background: rgba(33, 150, 243, 0.2);
color: var(--md-primary-fg-color-light, #42a5f5);
}
/* Section headers */
[data-theme="dark"] .section-header {
color: var(--text-color, rgba(255, 255, 255, 0.87));
border-bottom-color: var(--card-border-color, #333);
}
/* Tab content headings */
[data-theme="dark"] .tab-content h2 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Campaign header inside cards */
[data-theme="dark"] .campaign-header h3 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Campaign meta text */
[data-theme="dark"] .campaign-meta {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
/* User cards */
[data-theme="dark"] .user-card {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .user-info h4 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .user-info p {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
/* Response cards */
[data-theme="dark"] .response-card {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .response-meta {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
[data-theme="dark"] .response-content {
background: #252525;
}
[data-theme="dark"] .response-content h4 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .response-content p {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
/* Recipient cards */
[data-theme="dark"] .recipient-card {
background: var(--card-bg-color, #1e1e1e);
border-color: var(--card-border-color, #333);
}
[data-theme="dark"] .recipient-info h5 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
[data-theme="dark"] .recipient-info .recipient-meta {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
/* Add recipient form */
[data-theme="dark"] #add-recipient-form {
background: #252525;
}
[data-theme="dark"] #add-recipient-form h4 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Recipients list header */
[data-theme="dark"] #recipients-list-container h4 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Custom recipients section description */
[data-theme="dark"] #edit-custom-recipients-section p {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6)) !important;
}
/* Modal content */
[data-theme="dark"] .modal-content {
background: var(--card-bg-color, #1e1e1e);
}
[data-theme="dark"] .modal-header {
border-bottom-color: var(--card-border-color, #333);
}
[data-theme="dark"] .modal-header h3 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Bulk import help box */
[data-theme="dark"] .bulk-import-help {
background: rgba(33, 150, 243, 0.15);
}
[data-theme="dark"] .bulk-import-help h4 {
color: var(--md-primary-fg-color-light, #42a5f5);
}
[data-theme="dark"] .bulk-import-help code {
background: #252525;
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Listmonk/Email Sync tab */
[data-theme="dark"] #listmonk-tab > div[style*="background: white"],
[data-theme="dark"] #listmonk-tab > div[style*="background-color: white"] {
background: var(--card-bg-color, #1e1e1e) !important;
}
[data-theme="dark"] #listmonk-stats-section {
background: var(--card-bg-color, #1e1e1e) !important;
}
[data-theme="dark"] #listmonk-stats-section p {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
/* Sync buttons container */
[data-theme="dark"] .sync-buttons + div[style*="background"] {
background: var(--card-bg-color, #1e1e1e) !important;
}
/* Analytics stat boxes */
[data-theme="dark"] .analytics-stat {
background: #252525;
}
[data-theme="dark"] .analytics-stat h3 {
color: var(--md-primary-fg-color, #2196f3);
}
/* Empty state */
[data-theme="dark"] .empty-state {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
/* Loading text */
[data-theme="dark"] .loading p {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
/* Email body formatting tips box */
[data-theme="dark"] div[style*="background: #e3f2fd"] {
background: rgba(33, 150, 243, 0.15) !important;
}
[data-theme="dark"] div[style*="background: #e3f2fd"] strong {
color: var(--md-primary-fg-color-light, #42a5f5) !important;
}
[data-theme="dark"] div[style*="background: #e3f2fd"] li,
[data-theme="dark"] div[style*="background: #e3f2fd"] code {
color: var(--text-color, rgba(255, 255, 255, 0.87)) !important;
}
/* Cover photo hint text */
[data-theme="dark"] small[style*="color: #666"] {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6)) !important;
}
/* Status select dropdown */
[data-theme="dark"] .status-select select option {
background: var(--card-bg-color, #1e1e1e);
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Button icon borders */
[data-theme="dark"] .btn-icon {
border-color: var(--card-border-color, #333);
color: var(--text-muted-color, rgba(255, 255, 255, 0.6));
}
[data-theme="dark"] .btn-icon:hover {
background: #252525;
}
/* Message success/error boxes */
[data-theme="dark"] .message-success {
background: rgba(39, 174, 96, 0.15);
border-color: rgba(39, 174, 96, 0.3);
color: #4ade80;
}
[data-theme="dark"] .message-error {
background: rgba(231, 76, 60, 0.15);
border-color: rgba(231, 76, 60, 0.3);
color: #f87171;
}
/* Filter selects in Response Moderation */
[data-theme="dark"] #admin-campaign-filter,
[data-theme="dark"] #admin-response-status {
background: var(--card-bg-color, #1e1e1e);
color: var(--text-color, rgba(255, 255, 255, 0.87));
border-color: var(--card-border-color, #333);
}
/* Inline styles overrides using important */
[data-theme="dark"] [style*="color: #666"],
[data-theme="dark"] [style*="color:#666"] {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6)) !important;
}
[data-theme="dark"] [style*="color: #2c3e50"],
[data-theme="dark"] [style*="color:#2c3e50"] {
color: var(--text-color, rgba(255, 255, 255, 0.87)) !important;
}
[data-theme="dark"] [style*="color: #444"],
[data-theme="dark"] [style*="color:#444"] {
color: var(--text-color, rgba(255, 255, 255, 0.87)) !important;
}
/* Form row labels */
[data-theme="dark"] .form-row h2 {
color: var(--text-color, rgba(255, 255, 255, 0.87));
}
/* Sync progress section */
[data-theme="dark"] #sync-progress > div[style*="background: #f8f9fa"] {
background: #252525 !important;
}
[data-theme="dark"] #sync-results {
background: rgba(33, 150, 243, 0.15) !important;
border-left-color: var(--md-primary-fg-color, #2196f3) !important;
}
/* Advanced options white box */
[data-theme="dark"] #listmonk-tab div[style*="background: white; padding: 1.5rem"] {
background: var(--card-bg-color, #1e1e1e) !important;
}
/* Note text in listmonk section */
[data-theme="dark"] #listmonk-tab p[style*="color: #666"] {
color: var(--text-muted-color, rgba(255, 255, 255, 0.6)) !important;
}
</style>
</head>
<body>
<div class="admin-header">
<div class="admin-container">
<h1>Campaign Admin Panel</h1>
<p>Manage your influence campaigns</p>
</div>
</div>
<div class="admin-container">
<!-- Navigation -->
<nav class="admin-nav">
<button class="nav-btn active" data-tab="campaigns">Campaigns</button>
<button class="nav-btn" data-tab="create">Create Campaign</button>
<button class="nav-btn" data-tab="edit">Edit Campaign</button>
<button class="nav-btn" data-tab="responses">Response Moderation</button>
<button class="nav-btn" data-tab="users">User Management</button>
<button class="nav-btn" data-tab="listmonk">📧 Email Sync</button>
</nav>
<!-- Success/Error Messages -->
<div id="message-container" class="hidden"></div>
<!-- Campaigns Tab -->
<div id="campaigns-tab" class="tab-content active">
<div class="form-row" style="align-items: center; margin-bottom: 2rem;">
<h2 style="margin: 0;">Active Campaigns</h2>
</div>
<div id="campaigns-loading" class="loading hidden">
<div class="spinner"></div>
<p>Loading campaigns...</p>
</div>
<div id="campaigns-list" class="campaign-grid">
<!-- Campaigns will be loaded here -->
</div>
</div>
<!-- Create Campaign Tab -->
<div id="create-tab" class="tab-content">
<h2>Create New Campaign</h2>
<!-- Campaign Search Dropdown -->
<div class="campaign-selector">
<label for="create-campaign-selector">Select existing campaign as template (optional):</label>
<div class="search-dropdown">
<input type="text" id="create-campaign-selector" placeholder="Search campaigns..." autocomplete="off">
<div class="dropdown-arrow"></div>
<div class="dropdown-menu" id="create-dropdown-menu">
<div class="dropdown-item" data-campaign-id="new">Create New Campaign</div>
<!-- Campaign options will be populated here -->
</div>
</div>
</div>
<form id="create-campaign-form">
<div class="form-grid">
<div class="form-group">
<label for="create-title">Campaign Title *</label>
<input type="text" id="create-title" name="title" required
placeholder="Save Alberta Parks">
</div>
<div class="form-group status-select">
<label for="create-status">Campaign Status</label>
<select id="create-status" name="status">
<option value="draft">📝 Draft</option>
<option value="active">🚀 Active</option>
<option value="paused">⏸️ Paused</option>
<option value="archived">📦 Archived</option>
</select>
</div>
<div class="form-group">
<label for="create-description">Description</label>
<textarea id="create-description" name="description" rows="3"
placeholder="A brief description of the campaign"></textarea>
</div>
</div>
<div class="form-group">
<label for="create-email-subject">Email Subject *</label>
<input type="text" id="create-email-subject" name="email_subject" required
placeholder="Protect Alberta's Provincial Parks">
</div>
<div class="form-group">
<label for="create-email-body">Email Body *</label>
<textarea id="create-email-body" name="email_body" rows="8" required
placeholder="Dear [Representative Name],
I am writing as your constituent to express my concern about...
Sincerely,
[Your Name]"></textarea>
<div style="background: #e3f2fd; padding: 1rem; border-radius: 8px; margin-top: 0.75rem; font-size: 0.9rem;">
<strong style="color: #1565c0;">Dynamic Variables:</strong>
<ul style="margin: 0.5rem 0 0 1.5rem; padding: 0; color: #444;">
<li><code>[Representative Name]</code> - Replaced with the recipient's actual name</li>
<li><code>[Your Name]</code> - Replaced with the sender's name</li>
<li><code>[Your Postal Code]</code> - Replaced with the sender's postal code</li>
</ul>
<strong style="color: #1565c0; display: block; margin-top: 0.75rem;">Formatting Tips:</strong>
<ul style="margin: 0.5rem 0 0 1.5rem; padding: 0; color: #444;">
<li>Start a line with <code>-</code> or <code>*</code> for bullet points</li>
<li>Start a line with <code>1.</code> or <code>2.</code> for numbered lists</li>
<li>Use blank lines to separate paragraphs</li>
</ul>
</div>
</div>
<div class="form-group">
<label for="create-call-to-action">Call to Action</label>
<textarea id="create-call-to-action" name="call_to_action" rows="3"
placeholder="Join thousands of Albertans in protecting our provincial parks. Send an email to your representatives today!"></textarea>
</div>
<div class="form-group">
<label for="create-cover-photo">🖼️ Cover Photo</label>
<input type="file" id="create-cover-photo" name="cover_photo" accept="image/jpeg,image/jpg,image/png,image/gif,image/webp">
<small style="color: #666; font-size: 0.9em;">Upload a cover image for your campaign (max 5MB, jpeg/jpg/png/gif/webp)</small>
</div>
<div class="section-header">⚙️ Campaign Settings</div>
<div class="form-group">
<div class="checkbox-group">
<div class="checkbox-item">
<input type="checkbox" id="create-allow-smtp" name="allow_smtp_email" checked>
<label for="create-allow-smtp">📧 Allow SMTP Email Sending</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-allow-mailto" name="allow_mailto_link" checked>
<label for="create-allow-mailto">🔗 Allow Mailto Links</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-collect-info" name="collect_user_info" checked>
<label for="create-collect-info">👤 Collect User Information</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-show-count" name="show_email_count" checked>
<label for="create-show-count">📊 Show Email Count</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-allow-editing" name="allow_email_editing">
<label for="create-allow-editing">✏️ Allow Email Editing</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-allow-custom-recipients" name="allow_custom_recipients">
<label for="create-allow-custom-recipients">📧 Allow Custom Recipients</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-show-response-wall" name="show_response_wall">
<label for="create-show-response-wall">💬 Show Response Wall Button</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-highlight-campaign" name="highlight_campaign">
<label for="create-highlight-campaign">⭐ Highlight on Homepage (replaces postal code search)</label>
</div>
</div>
</div>
<!-- Custom Recipients Management Section (hidden by default) -->
<div id="create-custom-recipients-section" class="section-header" style="display: none;">
<div class="section-header">📧 Manage Custom Recipients</div>
<p style="color: #666; font-size: 0.9rem; margin-bottom: 1rem;">
Add specific people or organizations to target with this campaign.
<strong>Note:</strong> Custom recipients can only be added after the campaign is created.
</p>
</div>
<div class="section-header">🏛️ Target Government Levels</div>
<div class="form-group">
<div class="checkbox-group">
<div class="checkbox-item">
<input type="checkbox" id="create-federal" name="target_government_levels" value="Federal" checked>
<label for="create-federal">🍁 Federal (MPs)</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-provincial" name="target_government_levels" value="Provincial" checked>
<label for="create-provincial">🏛️ Provincial (MLAs)</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-municipal" name="target_government_levels" value="Municipal" checked>
<label for="create-municipal">🏙️ Municipal (Mayors, Councillors)</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="create-school" name="target_government_levels" value="School Board">
<label for="create-school">🎓 School Board</label>
</div>
</div>
</div>
<div class="form-row">
<button type="submit" class="btn btn-primary">Create Campaign</button>
<button type="button" class="btn btn-secondary" data-action="cancel-create">Cancel</button>
</div>
</form>
</div>
<!-- Edit Campaign Tab -->
<div id="edit-tab" class="tab-content">
<h2>Edit Campaign</h2>
<!-- Campaign Search Dropdown -->
<div class="campaign-selector">
<label for="edit-campaign-selector">Select campaign to edit:</label>
<div class="search-dropdown">
<input type="text" id="edit-campaign-selector" placeholder="Search campaigns..." autocomplete="off">
<div class="dropdown-arrow"></div>
<div class="dropdown-menu" id="edit-dropdown-menu">
<div class="dropdown-item" data-campaign-id="">Select a campaign to edit...</div>
<!-- Campaign options will be populated here -->
</div>
</div>
</div>
<form id="edit-campaign-form">
<div class="form-grid">
<div class="form-group">
<label for="edit-title">Campaign Title *</label>
<input type="text" id="edit-title" name="title" required>
</div>
<div class="form-group">
<label for="edit-status">Status</label>
<select id="edit-status" name="status">
<option value="draft">Draft</option>
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="archived">Archived</option>
</select>
</div>
</div>
<div class="form-group">
<label for="edit-description">Description</label>
<textarea id="edit-description" name="description" rows="3"></textarea>
</div>
<div class="form-group">
<label for="edit-email-subject">Email Subject *</label>
<input type="text" id="edit-email-subject" name="email_subject" required>
</div>
<div class="form-group">
<label for="edit-email-body">Email Body *</label>
<textarea id="edit-email-body" name="email_body" rows="8" required></textarea>
<div style="background: #e3f2fd; padding: 1rem; border-radius: 8px; margin-top: 0.75rem; font-size: 0.9rem;">
<strong style="color: #1565c0;">Dynamic Variables:</strong>
<ul style="margin: 0.5rem 0 0 1.5rem; padding: 0; color: #444;">
<li><code>[Representative Name]</code> - Replaced with the recipient's actual name</li>
<li><code>[Your Name]</code> - Replaced with the sender's name</li>
<li><code>[Your Postal Code]</code> - Replaced with the sender's postal code</li>
</ul>
<strong style="color: #1565c0; display: block; margin-top: 0.75rem;">Formatting Tips:</strong>
<ul style="margin: 0.5rem 0 0 1.5rem; padding: 0; color: #444;">
<li>Start a line with <code>-</code> or <code>*</code> for bullet points</li>
<li>Start a line with <code>1.</code> or <code>2.</code> for numbered lists</li>
<li>Use blank lines to separate paragraphs</li>
</ul>
</div>
</div>
<div class="form-group">
<label for="edit-call-to-action">Call to Action</label>
<textarea id="edit-call-to-action" name="call_to_action" rows="3"></textarea>
</div>
<div class="form-group">
<label for="edit-cover-photo">🖼️ Cover Photo</label>
<div id="current-cover-photo" style="margin-bottom: 0.5rem;"></div>
<input type="file" id="edit-cover-photo" name="cover_photo" accept="image/jpeg,image/jpg,image/png,image/gif,image/webp">
<small style="color: #666; font-size: 0.9em;">Upload a new cover image (max 5MB, jpeg/jpg/png/gif/webp) or leave empty to keep current</small>
</div>
<div class="form-group">
<label>Campaign Settings</label>
<div class="checkbox-group">
<div class="checkbox-item">
<input type="checkbox" id="edit-allow-smtp" name="allow_smtp_email">
<label for="edit-allow-smtp">Allow SMTP Email Sending</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-allow-mailto" name="allow_mailto_link">
<label for="edit-allow-mailto">Allow Mailto Links</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-collect-info" name="collect_user_info">
<label for="edit-collect-info">Collect User Information</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-show-count" name="show_email_count">
<label for="edit-show-count">Show Email Count</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-allow-editing" name="allow_email_editing">
<label for="edit-allow-editing">✏️ Allow Email Editing</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-allow-custom-recipients" name="allow_custom_recipients">
<label for="edit-allow-custom-recipients">📧 Allow Custom Recipients</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-show-response-wall" name="show_response_wall">
<label for="edit-show-response-wall">💬 Show Response Wall Button</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-highlight-campaign" name="highlight_campaign">
<label for="edit-highlight-campaign">⭐ Highlight on Homepage (replaces postal code search)</label>
</div>
</div>
</div>
<div class="form-group">
<label>Target Government Levels</label>
<div class="checkbox-group">
<div class="checkbox-item">
<input type="checkbox" id="edit-federal" name="target_government_levels" value="Federal">
<label for="edit-federal">Federal (MPs)</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-provincial" name="target_government_levels" value="Provincial">
<label for="edit-provincial">Provincial (MLAs)</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-municipal" name="target_government_levels" value="Municipal">
<label for="edit-municipal">Municipal (Mayors, Councillors)</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="edit-school" name="target_government_levels" value="School Board">
<label for="edit-school">School Board</label>
</div>
</div>
</div>
<div class="form-row">
<button type="submit" class="btn btn-primary">Update Campaign</button>
<button type="button" class="btn btn-secondary" data-action="cancel-edit">Cancel</button>
</div>
</form>
<!-- Custom Recipients Management Section (Outside the form to avoid nested forms) -->
<div id="edit-custom-recipients-section" style="display: none; margin-top: 2rem;">
<div class="section-header">📧 Manage Custom Recipients</div>
<p style="color: #666; font-size: 0.9rem; margin-bottom: 1rem;">
Add specific people or organizations to target with this campaign instead of (or in addition to) elected representatives.
</p>
<!-- Add Single Recipient Form -->
<form id="add-recipient-form" class="form-grid" style="background: #f8f9fa; padding: 1.5rem; border-radius: 8px; margin-bottom: 1rem;">
<h4 style="grid-column: 1 / -1; margin-top: 0;">Add New Recipient</h4>
<div class="form-group">
<label for="recipient-name">Recipient Name *</label>
<input type="text" id="recipient-name" name="recipient_name" placeholder="John Smith" required>
</div>
<div class="form-group">
<label for="recipient-email">Email Address *</label>
<input type="email" id="recipient-email" name="recipient_email" placeholder="john.smith@example.com" required>
</div>
<div class="form-group">
<label for="recipient-title">Title/Position</label>
<input type="text" id="recipient-title" name="recipient_title" placeholder="CEO, Director, etc.">
</div>
<div class="form-group">
<label for="recipient-organization">Organization</label>
<input type="text" id="recipient-organization" name="recipient_organization" placeholder="Company or Organization Name">
</div>
<div class="form-group" style="grid-column: 1 / -1;">
<label for="recipient-notes">Notes (optional)</label>
<textarea id="recipient-notes" name="notes" rows="2" placeholder="Internal notes about this recipient..."></textarea>
</div>
<div class="form-row" style="grid-column: 1 / -1; margin: 0;">
<button type="submit" class="btn btn-primary">
Add Recipient
</button>
<button type="button" id="bulk-import-recipients-btn" class="btn btn-secondary">
📥 Bulk Import (CSV)
</button>
</div>
</form>
<!-- Recipients List -->
<div id="recipients-list-container">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
<h4 style="margin: 0;">Current Recipients</h4>
<button type="button" id="clear-all-recipients-btn" class="btn btn-danger btn-small">
🗑️ Clear All
</button>
</div>
<div id="recipients-list">
<!-- Recipients will be loaded here dynamically -->
</div>
</div>
</div>
</div>
<!-- Response Moderation Tab -->
<div id="responses-tab" class="tab-content">
<h2>Response Moderation</h2>
<div style="display: flex; gap: 1rem; margin-bottom: 2rem; flex-wrap: wrap;">
<div class="campaign-selector" style="flex: 1; min-width: 300px; margin: 0;">
<label for="admin-campaign-filter">Filter by Campaign:</label>
<select id="admin-campaign-filter" style="width: 100%; padding: 0.75rem; border: 2px solid #e0e6ed; border-radius: 8px;">
<option value="">All Campaigns</option>
</select>
</div>
<div class="campaign-selector" style="flex: 1; min-width: 200px; margin: 0;">
<label for="admin-response-status">Filter by Status:</label>
<select id="admin-response-status" style="width: 100%; padding: 0.75rem; border: 2px solid #e0e6ed; border-radius: 8px;">
<option value="all">All Statuses</option>
<option value="pending" selected>Pending</option>
<option value="approved">Approved</option>
<option value="rejected">Rejected</option>
</select>
</div>
</div>
<div id="responses-loading" class="loading hidden">
<div class="spinner"></div>
<p>Loading responses...</p>
</div>
<div id="admin-responses-container">
<!-- Responses will be loaded here -->
</div>
</div>
<!-- User Management Tab -->
<div id="users-tab" class="tab-content">
<div class="form-row" style="align-items: center; margin-bottom: 2rem;">
<h2 style="margin: 0;">User Management</h2>
<button class="btn btn-primary" data-action="create-user">Add New User</button>
</div>
<div id="users-loading" class="loading hidden">
<div class="spinner"></div>
<p>Loading users...</p>
</div>
<div id="users-list" class="users-list">
<!-- Users will be loaded here -->
</div>
</div>
<!-- Listmonk Email Sync Tab -->
<div id="listmonk-tab" class="tab-content">
<div class="form-row" style="align-items: center; margin-bottom: 2rem;">
<h2 style="margin: 0;">📧 Email List Synchronization</h2>
<button class="btn btn-secondary" id="refresh-status-btn" onclick="refreshListmonkStatus()">🔄 Refresh Status</button>
</div>
<div class="section-header">📊 Sync Status</div>
<div id="sync-status-display" style="background: #f8f9fa; padding: 1.5rem; border-radius: 8px; margin-bottom: 2rem;">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem; margin-bottom: 1rem;">
<div style="background: white; padding: 1rem; border-radius: 8px; border: 2px solid #e9ecef;">
<strong style="color: #2c3e50; display: block; margin-bottom: 0.5rem;">Connection Status:</strong>
<span id="connection-status" style="font-size: 1.1rem;">⏳ Checking...</span>
</div>
<div style="background: white; padding: 1rem; border-radius: 8px; border: 2px solid #e9ecef;">
<strong style="color: #2c3e50; display: block; margin-bottom: 0.5rem;">Auto-Sync:</strong>
<span id="autosync-status" style="font-size: 1.1rem;">⏳ Checking...</span>
</div>
</div>
<div id="last-error" style="display: none; background: #f8d7da; color: #721c24; padding: 1rem; border-radius: 8px; border: 1px solid #f5c6cb;">
<!-- Error message will be displayed here -->
</div>
</div>
<div class="section-header">🚀 Sync Actions</div>
<div class="admin-card" style="padding: 1.5rem; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); margin-bottom: 2rem;">
<p class="admin-text-muted" style="margin-bottom: 1.5rem;">Sync campaign participants and custom recipients to Listmonk email lists for targeted email campaigns.</p>
<div class="sync-buttons" style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.5rem;">
<button class="btn btn-primary" id="sync-participants-btn" onclick="syncToListmonk('participants')">
👥 Sync Campaign Participants
</button>
<button class="btn btn-primary" id="sync-recipients-btn" onclick="syncToListmonk('recipients')">
📋 Sync Custom Recipients
</button>
<button class="btn btn-primary" id="sync-all-btn" onclick="syncToListmonk('all')">
🔄 Sync All
</button>
</div>
<div id="sync-progress" style="display: none; margin-top: 1.5rem;">
<div style="background: #f8f9fa; border-radius: 8px; overflow: hidden; height: 30px; margin-bottom: 1rem;">
<div id="sync-progress-bar" style="background: linear-gradient(90deg, #2196f3 0%, #1976d2 100%); height: 100%; width: 0%; transition: width 0.3s; display: flex; align-items: center; justify-content: center; color: white; font-weight: 600; font-size: 0.85rem;">
</div>
</div>
<div id="sync-results" style="background: #e3f2fd; padding: 1rem; border-radius: 8px; border-left: 4px solid #2196f3;">
<!-- Sync results will be displayed here -->
</div>
</div>
</div>
<div class="section-header">⚙️ Advanced Options</div>
<div class="admin-card" style="padding: 1.5rem; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); margin-bottom: 2rem;">
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
<button class="btn btn-secondary" id="test-connection-btn" onclick="testListmonkConnection()">
🔌 Test Connection
</button>
<button class="btn btn-secondary" id="reinitialize-lists-btn" onclick="reinitializeListmonk()" style="background: #f39c12;">
⚠️ Reinitialize Lists
</button>
</div>
<p class="admin-text-muted" style="margin-top: 1rem; font-size: 0.9rem;">
<strong>Note:</strong> Reinitializing lists will recreate all email list structures. Use only if lists are corrupted or missing.
</p>
</div>
<div class="section-header">📈 Email List Statistics</div>
<div id="listmonk-stats-section" class="admin-card" style="padding: 1.5rem; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.05);">
<div class="stats-list">
<p class="admin-text-muted" style="text-align: center;">Loading statistics...</p>
</div>
</div>
</div>
</div>
<!-- User Modal -->
<div id="user-modal" class="modal-overlay hidden">
<div class="modal-content">
<div class="modal-header">
<h3 id="user-modal-title">Add New User</h3>
<button class="modal-close" data-action="close-user-modal">&times;</button>
</div>
<form id="user-form">
<div class="form-group">
<label for="user-email">Email Address *</label>
<input type="email" id="user-email" name="email" required>
</div>
<div class="form-group">
<label for="user-password">Password *</label>
<input type="password" id="user-password" name="password" required autocomplete="new-password">
</div>
<div class="form-group">
<label for="user-name">Full Name</label>
<input type="text" id="user-name" name="name">
</div>
<div class="form-group">
<label for="user-phone">Phone Number</label>
<input type="tel" id="user-phone" name="phone">
</div>
<div class="form-group">
<label for="user-type">User Type</label>
<select id="user-type" name="userType">
<option value="user">Standard User</option>
<option value="admin">Administrator</option>
<option value="temp">Temporary User</option>
</select>
</div>
<div class="form-group" id="temp-user-options" style="display: none;">
<label for="user-expire-days">Expiration (Days)</label>
<input type="number" id="user-expire-days" name="expireDays" min="1" max="365" value="30">
</div>
<div class="checkbox-item">
<input type="checkbox" id="user-admin" name="isAdmin">
<label for="user-admin">Grant Administrator Access</label>
</div>
<div class="form-row">
<button type="submit" class="btn btn-primary">Create User</button>
<button type="button" class="btn btn-secondary" data-action="close-user-modal">Cancel</button>
</div>
</form>
</div>
</div>
<!-- Email Broadcast Modal -->
<div id="email-modal" class="modal-overlay hidden">
<div class="modal-content">
<div class="modal-header">
<h3>Send Email to All Users</h3>
<button class="modal-close" data-action="close-email-modal">&times;</button>
</div>
<form id="email-form">
<div class="form-group">
<label for="email-subject">Subject *</label>
<input type="text" id="email-subject" name="subject" required>
</div>
<div class="form-group">
<label for="email-content">Message *</label>
<textarea id="email-content" name="content" rows="8" required
placeholder="Your message to all users..."></textarea>
</div>
<div class="form-row">
<button type="submit" class="btn btn-primary">Send Email</button>
<button type="button" class="btn btn-secondary" data-action="close-email-modal">Cancel</button>
</div>
</form>
</div>
</div>
<!-- Bulk Import Recipients Modal -->
<div id="bulk-import-modal" class="modal-overlay hidden">
<div class="modal-content">
<div class="modal-header">
<h3>Bulk Import Recipients</h3>
<button class="modal-close" data-action="close-bulk-import-modal">&times;</button>
</div>
<div class="bulk-import-help">
<h4>📋 CSV Format</h4>
<p>Upload or paste CSV data with the following columns:</p>
<code>recipient_name,recipient_email,recipient_title,recipient_organization,notes</code>
<p style="margin-top: 0.5rem;"><strong>Example:</strong></p>
<code style="display: block; white-space: pre; font-size: 0.85rem;">John Smith,john@example.com,CEO,Acme Corp,Important contact
Jane Doe,jane@example.com,Director,Example Inc,</code>
</div>
<form id="bulk-import-form">
<div class="form-group">
<label for="bulk-csv-file">Upload CSV File</label>
<input type="file" id="bulk-csv-file" accept=".csv,text/csv">
</div>
<div style="text-align: center; margin: 1rem 0; color: #666;">
<strong>- OR -</strong>
</div>
<div class="form-group">
<label for="bulk-csv-text">Paste CSV Data</label>
<textarea id="bulk-csv-text" rows="8" placeholder="Paste your CSV data here..."></textarea>
</div>
<div class="form-row">
<button type="submit" class="btn btn-primary">Import Recipients</button>
<button type="button" class="btn btn-secondary" data-action="close-bulk-import-modal">Cancel</button>
</div>
</form>
<div id="bulk-import-results" class="hidden" style="margin-top: 1rem;">
<!-- Results will be shown here -->
</div>
</div>
</div>
<!-- Theme Toggle Button -->
<button class="theme-toggle" id="theme-toggle-btn" aria-label="Toggle dark mode">
<svg class="sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0 .39-.39.39-1.03 0-1.41l-1.06-1.06zm1.06-10.96c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"/>
</svg>
<svg class="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/>
</svg>
</button>
<!-- Theme Toggle Script -->
<script>
// Load saved theme preference immediately
(function() {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
document.documentElement.setAttribute('data-theme', savedTheme);
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-theme', 'dark');
}
})();
// Add event listener for theme toggle button
document.addEventListener('DOMContentLoaded', function() {
const themeToggleBtn = document.getElementById('theme-toggle-btn');
if (themeToggleBtn) {
themeToggleBtn.addEventListener('click', function() {
const html = document.documentElement;
const currentTheme = html.getAttribute('data-theme');
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
html.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
});
}
});
</script>
<script src="js/api-client.js"></script>
<script src="js/auth.js"></script>
<script src="js/custom-recipients.js"></script>
<script src="js/listmonk-admin.js"></script>
<script src="js/admin.js"></script>
</body>
</html>