- Created KPIDashboard component with tab navigation (product/acquisition/revenue/report) - Created MixpanelPanel for product KPIs linking to Mixpanel - Created GA4Panel for acquisition KPIs linking to GA4 - Created StripePanel for revenue KPIs linking to Stripe dashboard - Created UnifiedReport with KPI thresholds table and reporting schedule - Added KPI dashboard route (/app/kpi) and sidebar navigation link - Added KPI dashboard CSS styles (metric cards, tabs, table, info cards) - Fixed pre-existing parse errors in Faq.tsx (unescaped apostrophes) - Fixed pre-existing CSS import paths in routes.tsx Co-Authored-By: Paperclip <noreply@paperclip.ing>
97 lines
3.7 KiB
TypeScript
97 lines
3.7 KiB
TypeScript
import { Component } from 'solid-js';
|
|
import { KPI_THRESHOLDS } from '../../lib/analytics/kpi-service';
|
|
|
|
export const UnifiedReport: Component = () => {
|
|
const kpiEntries = Object.entries(KPI_THRESHOLDS) as [string, typeof KPI_THRESHOLDS[keyof typeof KPI_THRESHOLDS]][];
|
|
|
|
return (
|
|
<div class="freno-kpi-panel-content">
|
|
<div class="freno-kpi-panel-header">
|
|
<div>
|
|
<h2>Unified KPI Report</h2>
|
|
<p class="freno-text-muted">Cross-tool KPI summary template</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="freno-kpi-report-template">
|
|
<div class="freno-kpi-info-card">
|
|
<h3>KPI Thresholds Reference</h3>
|
|
<p>All tracked KPIs with their target thresholds and alert levels. This template is designed for weekly/monthly reporting across all analytics tools.</p>
|
|
</div>
|
|
|
|
<table class="freno-kpi-table">
|
|
<thead>
|
|
<tr>
|
|
<th>KPI</th>
|
|
<th>Category</th>
|
|
<th>Warning Threshold</th>
|
|
<th>Critical Threshold</th>
|
|
<th>Direction</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{kpiEntries.map(([key, thresholds]) => (
|
|
<tr>
|
|
<td class="freno-kpi-table-key">{key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())}</td>
|
|
<td>
|
|
<span class="freno-kpi-badge">{getCategory(key)}</span>
|
|
</td>
|
|
<td>{thresholds.warning}{getUnit(key)}</td>
|
|
<td>{thresholds.critical}{getUnit(key)}</td>
|
|
<td>
|
|
<span classList={{ 'freno-text-success': thresholds.direction === 'higher', 'freno-text-error': thresholds.direction === 'lower' }}>
|
|
{thresholds.direction === 'higher' ? '↑ Higher is better' : '↓ Lower is better'}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="freno-kpi-info-card">
|
|
<h3>Reporting Schedule</h3>
|
|
<ul>
|
|
<li><strong>Weekly Report:</strong> Auto-generated every Monday at 9:00 AM</li>
|
|
<li><strong>Monthly Report:</strong> Auto-generated on the 1st of each month</li>
|
|
<li><strong>Alert Thresholds:</strong> Real-time notifications via Slack when KPIs breach warning/critical levels</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="freno-kpi-info-card">
|
|
<h3>External Dashboards</h3>
|
|
<ul>
|
|
<li><a href="https://mixpanel.com" target="_blank" rel="noopener noreferrer">Mixpanel</a> — Product analytics (MAU, retention, funnels, viral coefficient)</li>
|
|
<li><a href="https://analytics.google.com" target="_blank" rel="noopener noreferrer">Google Analytics 4</a> — Web analytics (traffic sources, CAC tracking)</li>
|
|
<li><a href="https://dashboard.stripe.com" target="_blank" rel="noopener noreferrer">Stripe</a> — Revenue tracking (MRR, churn, LTV)</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
function getCategory(key: string): string {
|
|
const productKeys = ['mau', 'paying_users', 'conversion_rate', 'nps', 'viral_coefficient'];
|
|
const acquisitionKeys = ['cac'];
|
|
const revenueKeys = ['mrr', 'churn_rate', 'ltv'];
|
|
if (productKeys.includes(key)) return 'Product';
|
|
if (acquisitionKeys.includes(key)) return 'Acquisition';
|
|
if (revenueKeys.includes(key)) return 'Revenue';
|
|
return 'Other';
|
|
}
|
|
|
|
function getUnit(key: string): string {
|
|
const units: Record<string, string> = {
|
|
cac: ' USD',
|
|
mrr: ' USD',
|
|
ltv: ' USD',
|
|
churn_rate: '%',
|
|
conversion_rate: '%',
|
|
mau: '',
|
|
paying_users: '',
|
|
nps: ' pts',
|
|
viral_coefficient: '',
|
|
};
|
|
return units[key] || '';
|
|
}
|