import { // Activity, BadgeCheck, Video, // Coins, DollarSign, HelpCircle, MessageSquare, Star, TicketCheck, // TrendingUp, Users, UserX, Bell, CreditCard, UsersRound, } from "lucide-react" import spinnerSrc from "../assets/Circular-indeterminate progress indicator.svg" import { Area, AreaChart, CartesianGrid, Cell, Pie, PieChart, ResponsiveContainer, Tooltip, XAxis, YAxis, } from "recharts" import { RevenueTrendCard } from "../components/dashboard/RevenueTrendCard" import { StatCard } from "../components/dashboard/StatCard" import alertSrc from "../assets/Alert.svg" import { Badge } from "../components/ui/badge" import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card" import { cn } from "../lib/utils" import { getTeamMemberById } from "../api/team.api" import { getDashboard } from "../api/analytics.api" import { getSubscriptionPlans } from "../api/subscription-plans.api" import { getRatings } from "../api/courses.api" import { useEffect, useState } from "react" import { AnalyticsTimeRangeFilter } from "../components/analytics/AnalyticsTimeRangeFilter" import { getPrimaryQuestionTypeSummary, getSeriesPeriodLabel, getSubscriptionMetrics, getVideoLessonsSummary, } from "../lib/analytics" import type { DashboardData, DashboardFilters } from "../types/analytics.types" import { formatPlanDuration } from "../lib/subscriptionPlans" import type { SubscriptionPlan } from "../types/subscription.types" import type { Rating } from "../types/course.types" const PIE_COLORS = ["#9E2891", "#FFD23F", "#1DE9B6", "#C26FC0", "#6366F1", "#F97316", "#14B8A6", "#EF4444"] function formatDate(dateStr: string) { const d = new Date(dateStr) return d.toLocaleDateString("en-US", { month: "short", day: "numeric" }) } const DEFAULT_FILTERS: DashboardFilters = { mode: "all_time" } export function DashboardPage() { const [userFirstName, setUserFirstName] = useState("") const [dashboard, setDashboard] = useState(null) const [loading, setLoading] = useState(true) const [activeStatTab, setActiveStatTab] = useState<"primary" | "secondary">("primary") const [appRatings, setAppRatings] = useState([]) const [appRatingsLoading, setAppRatingsLoading] = useState(true) const [filters, setFilters] = useState(DEFAULT_FILTERS) const [subscriptionPlans, setSubscriptionPlans] = useState([]) const [subscriptionPlansLoading, setSubscriptionPlansLoading] = useState(true) useEffect(() => { const fetchUser = async () => { try { const memberId = Number(localStorage.getItem("member_id")) const res = await getTeamMemberById(memberId) const member = res.data.data setUserFirstName(member.first_name) localStorage.setItem("user_first_name", member.first_name) localStorage.setItem("user_last_name", member.last_name) window.dispatchEvent(new Event("user-profile-updated")) } catch (err) { console.error(err) } } fetchUser() }, []) useEffect(() => { const fetchAppRatings = async () => { try { const res = await getRatings({ target_type: "app", target_id: 1, limit: 5 }) setAppRatings(res.data.data) } catch (err) { console.error(err) } finally { setAppRatingsLoading(false) } } fetchAppRatings() }, []) useEffect(() => { const fetchPlans = async () => { setSubscriptionPlansLoading(true) try { const res = await getSubscriptionPlans() setSubscriptionPlans(res.data) } catch (err) { console.error(err) setSubscriptionPlans([]) } finally { setSubscriptionPlansLoading(false) } } fetchPlans() }, []) useEffect(() => { const fetchDashboard = async () => { setLoading(true) try { const res = await getDashboard(filters) setDashboard(res.data) } catch (err) { console.error(err) setDashboard(null) } finally { setLoading(false) } } fetchDashboard() }, [filters]) const registrationData = dashboard?.users.registrations_last_30_days.map((d) => ({ date: formatDate(d.date), count: d.count, })) ?? [] const subscriptionStatusData = dashboard?.subscriptions.by_status.map((s, i) => ({ name: s.label, value: s.count, color: PIE_COLORS[i % PIE_COLORS.length], })) ?? [] const issueStatusData = dashboard?.issues.by_status.map((s, i) => ({ name: s.label, value: s.count, color: PIE_COLORS[i % PIE_COLORS.length], })) ?? [] const seriesPeriodLabel = dashboard ? getSeriesPeriodLabel(dashboard.date_filter) : "Last 30 Days" const subscriptionMetrics = dashboard ? getSubscriptionMetrics(dashboard.subscriptions) : null return (
Dashboard
Welcome, {userFirstName || localStorage.getItem("user_first_name")}
{loading ? (
Loading dashboard…
) : !dashboard ? (
Failed to load dashboard data.
) : ( <> {/* Stat tabs */}
{/* Stat Cards */} {activeStatTab === "primary" && (
0} /> 0} /> 0} /> 0.5} />
)} {/* Secondary Stats */} {activeStatTab === "secondary" && subscriptionMetrics && (
0} /> 0} /> 0 ? "From subscription status breakdown" : "Total minus active" } deltaPositive={subscriptionMetrics.inactive === 0} /> 0} /> 0} />
)} {/* User Registrations Chart */}
User Registrations
{dashboard.users.total_users.toLocaleString()}
+{dashboard.users.new_today} today · +{dashboard.users.new_week} this week
{seriesPeriodLabel}
{/* Subscription / Issue Status Pie */} {subscriptionStatusData.length > 0 ? "Subscription Status" : "Issue Status"} {(subscriptionStatusData.length > 0 ? subscriptionStatusData : issueStatusData).length > 0 ? ( <>
0 ? subscriptionStatusData : issueStatusData} dataKey="value" nameKey="name" innerRadius={55} outerRadius={80} paddingAngle={2} > {(subscriptionStatusData.length > 0 ? subscriptionStatusData : issueStatusData).map( (entry) => ( ), )}
{(subscriptionStatusData.length > 0 ? subscriptionStatusData : issueStatusData).map((s) => (
{s.name}
{s.value.toLocaleString()}
))}
) : (
No data available
)}
{/* Subscription plans (from catalog API) */}
Subscription plans

Available billing plans for learners.

{subscriptionPlansLoading ? (
) : subscriptionPlans.length === 0 ? (
No subscription plans found
) : (
{subscriptionPlans.map((plan) => (

{plan.name}

{plan.is_active ? "Active" : "Inactive"}
{plan.description ? (

{plan.description}

) : null}
Price
{plan.currency}{" "} {Number.isInteger(plan.price) ? plan.price.toLocaleString() : plan.price.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 2, })}
Billing
{formatPlanDuration(plan)}
))}
)}
{/* App Ratings */}
Recent App Reviews
{appRatingsLoading ? (
) : appRatings.length === 0 ? (
No app reviews yet
) : ( <>
{Array.from({ length: 5 }).map((_, i) => ( sum + r.stars, 0) / appRatings.length, ) ? "fill-amber-400 text-amber-400" : "fill-grayScale-200 text-grayScale-200", )} /> ))}
{(appRatings.reduce((sum, r) => sum + r.stars, 0) / appRatings.length).toFixed(1)} ({appRatings.length} {appRatings.length === 1 ? "review" : "reviews"})
{appRatings.map((rating) => (
U{rating.user_id}
User #{rating.user_id} {formatDate(rating.created_at)}
{Array.from({ length: 5 }).map((_, i) => ( ))}
{rating.review && (

{rating.review}

)}
))}
)}
)}
) }