Phase 3 Multi-Project CRM Implementation:
- Add UnifiedContact model for cross-project contact linking
- Add Organization model with domain-based auto-detection
- Add ActivityTimeline model for comprehensive interaction tracking
- Add SLATracking model for 24-hour response commitment
- Add ResponseTemplate model with variable substitution
- Add CRM controller with 8 API endpoints
- Add Inbox controller for unified communications
- Add CRM dashboard frontend with tabs (Contacts, Orgs, SLA, Templates)
- Add Contact Management interface (Phase 1)
- Add Unified Inbox interface (Phase 2)
- Integrate CRM routes into main API
Critical Bug Fixes:
- Fix newsletter DELETE button (event handler context issue)
- Fix case submission invisible button (invalid CSS class)
- Fix Chart.js CSP violation (add cdn.jsdelivr.net to policy)
- Fix Chart.js SRI integrity hash mismatch
Technical Details:
- Email-based contact deduplication across projects
- Automatic organization linking via email domain
- Cross-project activity timeline aggregation
- SLA breach detection and alerting system
- Template rendering with {placeholder} substitution
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
144 lines
6.1 KiB
HTML
144 lines
6.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>CRM Dashboard | Tractatus Admin</title>
|
|
<link rel="stylesheet" href="/css/tailwind.css?v=0.1.0.1729786000000">
|
|
<link rel="stylesheet" href="/css/tractatus-theme.min.css?v=0.1.0.1729786000000">
|
|
<script defer src="/js/admin/auth-check.js?v=0.1.0.1729786000000"></script>
|
|
</head>
|
|
<body class="bg-gray-50">
|
|
<div id="admin-navbar" data-page-title="CRM Dashboard" data-page-icon="default"></div>
|
|
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
|
|
<!-- Header -->
|
|
<div class="mb-8">
|
|
<h1 class="text-3xl font-bold text-gray-900">Multi-Project CRM</h1>
|
|
<p class="mt-2 text-gray-600">Unified relationship management across all projects</p>
|
|
</div>
|
|
|
|
<!-- Quick Stats -->
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<div class="text-sm font-medium text-gray-500">Total Contacts</div>
|
|
<div class="mt-2 text-3xl font-semibold text-gray-900" id="stat-contacts">-</div>
|
|
<div class="mt-1 text-xs text-gray-500" id="stat-contacts-projects">Across all projects</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<div class="text-sm font-medium text-gray-500">Organizations</div>
|
|
<div class="mt-2 text-3xl font-semibold text-blue-600" id="stat-organizations">-</div>
|
|
<div class="mt-1 text-xs text-gray-500" id="stat-organizations-types">Multiple types</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<div class="text-sm font-medium text-gray-500">SLA Compliance</div>
|
|
<div class="mt-2 text-3xl font-semibold text-green-600" id="stat-sla-compliance">-</div>
|
|
<div class="mt-1 text-xs text-gray-500">Response rate</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<div class="text-sm font-medium text-gray-500">SLA Breaches</div>
|
|
<div class="mt-2 text-3xl font-semibold text-red-600" id="stat-sla-breached">-</div>
|
|
<div class="mt-1 text-xs text-gray-500" id="stat-sla-pending">Pending responses</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SLA Alert Dashboard -->
|
|
<div class="bg-white rounded-lg shadow mb-8" id="sla-alerts-section">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h2 class="text-lg font-semibold text-gray-900">🚨 SLA Alerts</h2>
|
|
</div>
|
|
<div id="sla-alerts-container" class="p-6">
|
|
<!-- Will be populated by JS -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content Tabs -->
|
|
<div class="bg-white rounded-lg shadow">
|
|
<!-- Tab Navigation -->
|
|
<div class="border-b border-gray-200">
|
|
<nav class="flex space-x-8 px-6" aria-label="Tabs">
|
|
<button class="crm-tab active py-4 px-1 border-b-2 font-medium text-sm" data-tab="contacts">
|
|
Contacts
|
|
</button>
|
|
<button class="crm-tab py-4 px-1 border-b-2 font-medium text-sm" data-tab="organizations">
|
|
Organizations
|
|
</button>
|
|
<button class="crm-tab py-4 px-1 border-b-2 font-medium text-sm" data-tab="sla">
|
|
SLA Tracking
|
|
</button>
|
|
<button class="crm-tab py-4 px-1 border-b-2 font-medium text-sm" data-tab="templates">
|
|
Response Templates
|
|
</button>
|
|
</nav>
|
|
</div>
|
|
|
|
<!-- Tab Content -->
|
|
<div class="p-6">
|
|
<!-- Contacts Tab -->
|
|
<div id="tab-contacts" class="crm-tab-content">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-semibold">Unified Contacts</h3>
|
|
<div class="flex gap-2">
|
|
<select id="filter-contact-project" class="border border-gray-300 rounded px-3 py-2 text-sm">
|
|
<option value="">All Projects</option>
|
|
<option value="tractatus">Tractatus</option>
|
|
<option value="family-history">Family History</option>
|
|
<option value="sydigital">SYDigital</option>
|
|
</select>
|
|
<button id="refresh-contacts" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 text-sm">
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="contacts-list" class="space-y-2">
|
|
<!-- Will be populated by JS -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Organizations Tab -->
|
|
<div id="tab-organizations" class="crm-tab-content hidden">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-semibold">Organizations</h3>
|
|
<button id="refresh-organizations" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 text-sm">
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
<div id="organizations-list" class="space-y-2">
|
|
<!-- Will be populated by JS -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SLA Tracking Tab -->
|
|
<div id="tab-sla" class="crm-tab-content hidden">
|
|
<h3 class="text-lg font-semibold mb-4">SLA Performance</h3>
|
|
<div id="sla-details">
|
|
<!-- Will be populated by JS -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Templates Tab -->
|
|
<div id="tab-templates" class="crm-tab-content hidden">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-semibold">Response Templates</h3>
|
|
<select id="filter-template-category" class="border border-gray-300 rounded px-3 py-2 text-sm">
|
|
<option value="">All Categories</option>
|
|
<option value="general">General</option>
|
|
<option value="media">Media</option>
|
|
<option value="technical">Technical</option>
|
|
<option value="partnership">Partnership</option>
|
|
</select>
|
|
</div>
|
|
<div id="templates-list" class="space-y-2">
|
|
<!-- Will be populated by JS -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script src="/js/components/navbar-admin.js?v=0.1.0.1729786000000"></script>
|
|
<script src="/js/admin/crm-dashboard.js?v=0.1.0.1729786000000"></script>
|
|
</body>
|
|
</html>
|