UNPKG

@dbs-portal/module-tenant-management

Version:

Tenant management and multi-tenancy support module

144 lines 10.9 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /** * TenantAnalytics Component - Comprehensive tenant analytics dashboard */ import React, { useState } from 'react'; import { Card, Row, Col, Statistic, Select, DatePicker, Space, Typography, Alert, Spin, Progress, Table, Tag } from 'antd'; import { UserOutlined, DatabaseOutlined, ApiOutlined, ClockCircleOutlined, RiseOutlined, DollarOutlined, BarChartOutlined } from '@ant-design/icons'; import { format, subDays, subWeeks, subMonths, subYears } from 'date-fns'; import { useTenantAnalytics } from '../hooks'; const { Title, Text } = Typography; const { Option } = Select; const { RangePicker } = DatePicker; export const TenantAnalytics = ({ tenantId, period = 'month', className }) => { const [selectedPeriod, setSelectedPeriod] = useState(period); const [customDateRange, setCustomDateRange] = useState(null); // Fetch analytics data const { data: analytics, isLoading, error } = useTenantAnalytics(tenantId, selectedPeriod); if (isLoading) { return (_jsx(Card, { className: className, children: _jsx(Spin, { size: "large", style: { display: 'block', textAlign: 'center', padding: '50px' } }) })); } if (error || !analytics) { return (_jsx(Card, { className: className, children: _jsx(Alert, { message: "Failed to load analytics", description: error?.message || 'Analytics data not available', type: "error", showIcon: true }) })); } const getPeriodLabel = (period) => { switch (period) { case 'day': return 'Daily'; case 'week': return 'Weekly'; case 'month': return 'Monthly'; case 'year': return 'Yearly'; default: return 'Monthly'; } }; const formatMetricValue = (value, type = 'number') => { switch (type) { case 'bytes': if (value >= 1024 * 1024 * 1024) return `${(value / (1024 * 1024 * 1024)).toFixed(2)} GB`; if (value >= 1024 * 1024) return `${(value / (1024 * 1024)).toFixed(2)} MB`; if (value >= 1024) return `${(value / 1024).toFixed(2)} KB`; return `${value} B`; case 'percentage': return `${value.toFixed(2)}%`; case 'currency': return `$${value.toLocaleString()}`; default: return value.toLocaleString(); } }; const getGrowthColor = (current, previous) => { if (current > previous) return '#52c41a'; if (current < previous) return '#ff4d4f'; return '#1890ff'; }; // Calculate growth rates (simplified - would need historical data) const calculateGrowthRate = (data) => { if (data.length < 2) return 0; const latest = data[data.length - 1]; const previous = data[data.length - 2]; const latestValue = latest?.count || latest?.usage || latest?.amount || 0; const previousValue = previous?.count || previous?.usage || previous?.amount || 0; if (previousValue === 0) return latestValue > 0 ? 100 : 0; return ((latestValue - previousValue) / previousValue) * 100; }; const userGrowthRate = calculateGrowthRate(analytics.metrics.userGrowth); const storageGrowthRate = calculateGrowthRate(analytics.metrics.storageUsage); const apiGrowthRate = calculateGrowthRate(analytics.metrics.apiCalls); // Prepare table data for detailed metrics const detailedMetrics = [ { key: 'users', metric: 'Total Users', current: analytics.summary.totalUsers, growth: userGrowthRate, icon: _jsx(UserOutlined, {}) }, { key: 'active_users', metric: 'Active Users', current: analytics.summary.activeUsers, growth: userGrowthRate * 0.8, // Simplified calculation icon: _jsx(UserOutlined, {}) }, { key: 'storage', metric: 'Storage Used', current: analytics.summary.storageUsed, growth: storageGrowthRate, icon: _jsx(DatabaseOutlined, {}) }, { key: 'api_calls', metric: 'API Calls', current: analytics.summary.totalApiCalls, growth: apiGrowthRate, icon: _jsx(ApiOutlined, {}) } ]; const columns = [ { title: 'Metric', dataIndex: 'metric', key: 'metric', render: (text, record) => (_jsxs(Space, { children: [record.icon, _jsx(Text, { strong: true, children: text })] })) }, { title: 'Current Value', dataIndex: 'current', key: 'current', render: (value, record) => { const type = record.key === 'storage' ? 'bytes' : 'number'; return formatMetricValue(value, type); } }, { title: 'Growth Rate', dataIndex: 'growth', key: 'growth', render: (growth) => (_jsxs(Space, { children: [_jsx(RiseOutlined, { style: { color: getGrowthColor(growth, 0) } }), _jsxs(Text, { style: { color: getGrowthColor(growth, 0) }, children: [growth > 0 ? '+' : '', growth.toFixed(1), "%"] })] })) } ]; return (_jsxs("div", { className: className, children: [_jsx(Card, { children: _jsxs(Row, { justify: "space-between", align: "middle", children: [_jsxs(Col, { children: [_jsxs(Title, { level: 4, style: { margin: 0 }, children: [_jsx(BarChartOutlined, {}), " Tenant Analytics"] }), _jsxs(Text, { type: "secondary", children: [getPeriodLabel(selectedPeriod), " Overview"] })] }), _jsx(Col, { children: _jsxs(Space, { children: [_jsxs(Select, { value: selectedPeriod, onChange: setSelectedPeriod, style: { width: 120 }, children: [_jsx(Option, { value: "day", children: "Daily" }), _jsx(Option, { value: "week", children: "Weekly" }), _jsx(Option, { value: "month", children: "Monthly" }), _jsx(Option, { value: "year", children: "Yearly" })] }), _jsx(RangePicker, { onChange: (dates) => { if (dates && dates[0] && dates[1]) { setCustomDateRange([dates[0].toDate(), dates[1].toDate()]); } else { setCustomDateRange(null); } }, placeholder: ['Start Date', 'End Date'] })] }) })] }) }), _jsxs(Row, { gutter: 16, style: { marginTop: 16 }, children: [_jsx(Col, { span: 6, children: _jsxs(Card, { children: [_jsx(Statistic, { title: "Total Users", value: analytics.summary.totalUsers, prefix: _jsx(UserOutlined, {}), valueStyle: { color: '#1890ff' } }), _jsx(Progress, { percent: Math.min((analytics.summary.activeUsers / analytics.summary.totalUsers) * 100, 100), size: "small", format: () => `${analytics.summary.activeUsers} active` })] }) }), _jsx(Col, { span: 6, children: _jsxs(Card, { children: [_jsx(Statistic, { title: "Storage Used", value: analytics.summary.storageUsed, suffix: "MB", prefix: _jsx(DatabaseOutlined, {}), valueStyle: { color: '#52c41a' } }), _jsx(Text, { type: "secondary", style: { fontSize: '12px' }, children: formatMetricValue(analytics.summary.storageUsed * 1024 * 1024, 'bytes') })] }) }), _jsx(Col, { span: 6, children: _jsxs(Card, { children: [_jsx(Statistic, { title: "API Calls", value: analytics.summary.totalApiCalls, prefix: _jsx(ApiOutlined, {}), valueStyle: { color: '#722ed1' } }), _jsxs(Text, { type: "secondary", style: { fontSize: '12px' }, children: ["Avg: ", analytics.summary.averageResponseTime, "ms response"] })] }) }), _jsx(Col, { span: 6, children: _jsxs(Card, { children: [_jsx(Statistic, { title: "Uptime", value: analytics.summary.uptime, suffix: "%", precision: 2, prefix: _jsx(ClockCircleOutlined, {}), valueStyle: { color: analytics.summary.uptime >= 99 ? '#52c41a' : analytics.summary.uptime >= 95 ? '#faad14' : '#ff4d4f' } }), _jsx(Progress, { percent: analytics.summary.uptime, size: "small", strokeColor: analytics.summary.uptime >= 99 ? '#52c41a' : analytics.summary.uptime >= 95 ? '#faad14' : '#ff4d4f', showInfo: false })] }) })] }), analytics.metrics.revenue && analytics.metrics.revenue.length > 0 && (_jsxs(Card, { style: { marginTop: 16 }, children: [_jsxs(Title, { level: 5, children: [_jsx(DollarOutlined, {}), " Revenue Metrics"] }), _jsxs(Row, { gutter: 16, children: [_jsx(Col, { span: 8, children: _jsx(Statistic, { title: "Total Revenue", value: analytics.metrics.revenue.reduce((sum, item) => sum + item.amount, 0), prefix: _jsx(DollarOutlined, {}), precision: 2, valueStyle: { color: '#52c41a' } }) }), _jsx(Col, { span: 8, children: _jsx(Statistic, { title: "Average per User", value: analytics.summary.totalUsers > 0 ? analytics.metrics.revenue.reduce((sum, item) => sum + item.amount, 0) / analytics.summary.totalUsers : 0, prefix: _jsx(DollarOutlined, {}), precision: 2, valueStyle: { color: '#1890ff' } }) }), _jsx(Col, { span: 8, children: _jsx(Statistic, { title: "Growth Rate", value: calculateGrowthRate(analytics.metrics.revenue), suffix: "%", precision: 1, prefix: _jsx(RiseOutlined, {}), valueStyle: { color: getGrowthColor(calculateGrowthRate(analytics.metrics.revenue), 0) } }) })] })] })), _jsxs(Card, { style: { marginTop: 16 }, children: [_jsx(Title, { level: 5, children: "Detailed Metrics" }), _jsx(Table, { columns: columns, dataSource: detailedMetrics, pagination: false, size: "small" })] }), _jsxs(Card, { style: { marginTop: 16 }, children: [_jsx(Title, { level: 5, children: "Period Summary" }), _jsxs(Row, { gutter: 16, children: [_jsxs(Col, { span: 12, children: [_jsx(Text, { strong: true, children: "Analysis Period: " }), _jsx(Tag, { color: "blue", children: getPeriodLabel(selectedPeriod) })] }), _jsxs(Col, { span: 12, children: [_jsx(Text, { strong: true, children: "Data Points: " }), _jsxs(Text, { children: [analytics.metrics.userGrowth.length, " records"] })] })] }), _jsxs(Row, { gutter: 16, style: { marginTop: 8 }, children: [_jsxs(Col, { span: 12, children: [_jsx(Text, { strong: true, children: "Last Updated: " }), _jsx(Text, { children: format(new Date(), 'PPP p') })] }), _jsxs(Col, { span: 12, children: [_jsx(Text, { strong: true, children: "Tenant ID: " }), _jsx(Text, { code: true, children: tenantId })] })] })] })] })); }; //# sourceMappingURL=TenantAnalytics.js.map