diff --git a/apps/web-dashboard/src/app/settings/page.tsx b/apps/web-dashboard/src/app/settings/page.tsx new file mode 100644 index 0000000..0a6d3fd --- /dev/null +++ b/apps/web-dashboard/src/app/settings/page.tsx @@ -0,0 +1,75 @@ +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Settings } from "lucide-react"; + +export default function SettingsPage() { + return ( +
+
+ +
+

Settings

+

Platform configuration and preferences.

+
+
+ +
+ + + API Configuration + Configure the API server connection. + + +
+ + +
+
+ + +
+ +
+
+ + + + IMSI Configuration + Mobile Country Code and Mobile Network Code settings. + + +
+
+ + +
+
+ + +
+
+ +
+
+ + + + ES2+ SM-DP+ Configuration + eSIM profile server connection settings. + + +
+ + +
+
+ + +
+ +
+
+
+
+ ); +} diff --git a/apps/web-dashboard/src/app/subscribers/page.tsx b/apps/web-dashboard/src/app/subscribers/page.tsx new file mode 100644 index 0000000..63ba8a2 --- /dev/null +++ b/apps/web-dashboard/src/app/subscribers/page.tsx @@ -0,0 +1,94 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { UserPlus, Search, Download } from "lucide-react"; + +const subscribers = [ + { id: 1, name: "Alice Martin", msisdn: "+33612345678", imsi: "208930000000001", email: "alice@example.com", status: "active" as const, balance: 45.0, plan: "Premium 5G" }, + { id: 2, name: "Bob Dupont", msisdn: "+33698765432", imsi: "208930000000002", email: "bob@example.com", status: "active" as const, balance: 12.5, plan: "Basic LTE" }, + { id: 3, name: "Claire Moreau", msisdn: "+33678901234", imsi: "208930000000003", email: "claire@example.com", status: "provisioning" as const, balance: 0.0, plan: "Premium 5G" }, + { id: 4, name: "David Leroy", msisdn: "+33667890123", imsi: "208930000000004", email: "david@example.com", status: "suspended" as const, balance: -2.3, plan: "Standard" }, + { id: 5, name: "Emma Petit", msisdn: "+33656789012", imsi: "208930000000005", email: "emma@example.com", status: "active" as const, balance: 78.9, plan: "Premium 5G" }, + { id: 6, name: "François Blanc", msisdn: "+33645678901", imsi: "208930000000006", email: "francois@example.com", status: "active" as const, balance: 25.0, plan: "Standard" }, + { id: 7, name: "Gabrielle Roux", msisdn: "+33634567890", imsi: "208930000000007", email: "gabrielle@example.com", status: "terminated" as const, balance: 0.0, plan: "Basic LTE" }, + { id: 8, name: "Henri Faure", msisdn: "+33623456789", imsi: "208930000000008", email: "henri@example.com", status: "active" as const, balance: 156.2, plan: "Enterprise" }, +]; + +const statusVariant = (s: string) => + s === "active" ? "success" : s === "suspended" ? "warning" : s === "terminated" ? "destructive" : "secondary"; + +export default function SubscribersPage() { + return ( +
+
+
+

Subscribers

+

Manage subscriber accounts and profiles.

+
+
+ + +
+
+ + + + All Subscribers +
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + + {subscribers.map((sub) => ( + + + + + + + + + + ))} + +
NameMSISDNIMSIPlanBalanceStatusActions
+
+

{sub.name}

+

{sub.email}

+
+
{sub.msisdn}{sub.imsi}{sub.plan} + + €{sub.balance.toFixed(2)} + + + {sub.status} + + +
+
+
+
+
+ ); +} diff --git a/apps/web-dashboard/src/app/usage/page.tsx b/apps/web-dashboard/src/app/usage/page.tsx new file mode 100644 index 0000000..3b52bd0 --- /dev/null +++ b/apps/web-dashboard/src/app/usage/page.tsx @@ -0,0 +1,78 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { StatCard } from "@/components/stat-card"; +import { Activity, HardDrive, Phone, MessageSquare } from "lucide-react"; + +const usageEvents = [ + { id: 1, imsi: "208930000000001", type: "DATA", volume: "1.2 GB", cost: "€2.40", time: "2 min ago" }, + { id: 2, imsi: "208930000000002", type: "VOICE", volume: "15 min", cost: "€0.75", time: "5 min ago" }, + { id: 3, imsi: "208930000000005", type: "SMS", volume: "3 msgs", cost: "€0.30", time: "12 min ago" }, + { id: 4, imsi: "208930000000001", type: "DATA", volume: "450 MB", cost: "€0.90", time: "18 min ago" }, + { id: 5, imsi: "208930000000008", type: "DATA", volume: "2.8 GB", cost: "€5.60", time: "25 min ago" }, + { id: 6, imsi: "208930000000006", type: "VOICE", volume: "42 min", cost: "€2.10", time: "30 min ago" }, + { id: 7, imsi: "208930000000002", type: "DATA", volume: "780 MB", cost: "€1.56", time: "45 min ago" }, + { id: 8, imsi: "208930000000005", type: "SMS", volume: "1 msg", cost: "€0.10", time: "1 hr ago" }, +]; + +const typeIcon = (t: string) => { + if (t === "DATA") return HardDrive; + if (t === "VOICE") return Phone; + return MessageSquare; +}; + +export default function UsagePage() { + return ( +
+
+

Usage & Billing

+

Monitor real-time usage and billing metrics.

+
+ +
+ + + + +
+ + + + Recent Usage Events + + +
+ + + + + + + + + + + + {usageEvents.map((evt) => { + const Icon = typeIcon(evt.type); + return ( + + + + + + + + ); + })} + +
TypeIMSIVolumeCostTime
+
+ + {evt.type} +
+
{evt.imsi}{evt.volume}{evt.cost}{evt.time}
+
+
+
+
+ ); +} diff --git a/apps/web-dashboard/src/components/sidebar.tsx b/apps/web-dashboard/src/components/sidebar.tsx new file mode 100644 index 0000000..892de9c --- /dev/null +++ b/apps/web-dashboard/src/components/sidebar.tsx @@ -0,0 +1,62 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { + Users, + LayoutDashboard, + Activity, + CreditCard, + Shield, + Settings, + Radio, + HeartPulse, +} from "lucide-react"; +import { cn } from "@/lib/utils"; + +const navItems = [ + { href: "/", label: "Dashboard", icon: LayoutDashboard }, + { href: "/subscribers", label: "Subscribers", icon: Users }, + { href: "/usage", label: "Usage & Billing", icon: Activity }, + { href: "/payments", label: "Payments", icon: CreditCard }, + { href: "/esim", label: "eSIM Profiles", icon: Radio }, + { href: "/health", label: "System Health", icon: HeartPulse }, + { href: "/chaos", label: "Chaos Engineering", icon: Shield }, + { href: "/settings", label: "Settings", icon: Settings }, +]; + +export function Sidebar() { + const pathname = usePathname(); + + return ( + + ); +} diff --git a/apps/web-dashboard/src/components/stat-card.tsx b/apps/web-dashboard/src/components/stat-card.tsx new file mode 100644 index 0000000..5e60301 --- /dev/null +++ b/apps/web-dashboard/src/components/stat-card.tsx @@ -0,0 +1,36 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { type LucideIcon } from "lucide-react"; +import { cn } from "@/lib/utils"; + +interface StatCardProps { + title: string; + value: string | number; + description?: string; + icon: LucideIcon; + trend?: { value: number; positive: boolean }; + className?: string; +} + +export function StatCard({ title, value, description, icon: Icon, trend, className }: StatCardProps) { + return ( + + + {title} + + + +
{value}
+ {(description || trend) && ( +

+ {trend && ( + + {trend.positive ? "+" : ""}{trend.value}%{" "} + + )} + {description} +

+ )} +
+
+ ); +}