defmodule DaProductAppWeb.AnalyticsLive do use DaProductAppWeb, :live_view alias DaProductApp.TerminalManagement @impl true def mount(_params, _session, socket) do # Subscribe to real-time updates if connected?(socket) do TerminalManagement.subscribe_to_device_updates() end socket = socket |> assign(:page_title, "Analytics & Reporting") |> assign(:current_tab, "overview") |> assign(:date_range, :last_30_days) |> assign(:loading, true) |> assign(:current_page , "anaylytics") |> load_analytics_data() {:ok, socket} end @impl true def handle_params(params, _url, socket) do tab = params["tab"] || "overview" date_range = String.to_atom(params["range"] || "last_30_days") socket = socket |> assign(:current_tab, tab) |> assign(:date_range, date_range) |> load_analytics_data() {:noreply, socket} end @impl true def handle_event("change_tab", %{"tab" => tab}, socket) do {:noreply, push_patch(socket, to: ~p"/analytics?tab=#{tab}&range=#{socket.assigns.date_range}")} end @impl true def handle_event("change_date_range", %{"range" => range}, socket) do date_range = String.to_atom(range) {:noreply, push_patch(socket, to: ~p"/analytics?tab=#{socket.assigns.current_tab}&range=#{range}")} end @impl true def handle_event("export_report", %{"format" => format}, socket) do analytics_data = socket.assigns.analytics_data case TerminalManagement.export_analytics_report(analytics_data, String.to_atom(format)) do {:ok, exported_data} -> # Generate filename with timestamp timestamp = DateTime.utc_now() |> DateTime.to_unix() # Determine content type and push appropriate download event case format do "json" -> filename = "analytics_report_#{timestamp}.json" {:noreply, push_event(socket, "download_file", %{ content: exported_data, filename: filename, type: "application/json" })} "csv" -> filename = "analytics_report_#{timestamp}.csv" {:noreply, push_event(socket, "download_file", %{ content: exported_data, filename: filename, type: "text/csv" })} "pdf" -> filename = "analytics_report_#{timestamp}.html" {:noreply, push_event(socket, "download_file", %{ content: exported_data, filename: filename, type: "text/html" })} _ -> socket = put_flash(socket, :error, "Unsupported format: #{format}") {:noreply, socket} end {:error, reason} -> socket = put_flash(socket, :error, "Export failed: #{reason}") {:noreply, socket} end end @impl true def handle_event("schedule_report", params, socket) do schedule_config = %{ schedule: params["schedule"], recipients: String.split(params["recipients"], ","), format: String.to_atom(params["format"]), filters: %{} } case TerminalManagement.schedule_analytics_report(schedule_config) do %{status: "scheduled"} = result -> socket = put_flash(socket, :info, "Report scheduled successfully (ID: #{result.report_id})") {:noreply, socket} _ -> socket = put_flash(socket, :error, "Failed to schedule report") {:noreply, socket} end end @impl true def handle_event("refresh_analytics", _params, socket) do socket = socket |> assign(:loading, true) |> load_analytics_data() {:noreply, socket} end @impl true def handle_info({:device_update, _device_data}, socket) do # Refresh analytics when device data changes socket = load_analytics_data(socket) {:noreply, socket} end @impl true def handle_info({:monitoring_update, _monitoring_data}, socket) do # Refresh analytics when monitoring data changes socket = load_analytics_data(socket) {:noreply, socket} end defp load_analytics_data(socket) do date_range = socket.assigns[:date_range] || :last_30_days analytics_data = TerminalManagement.generate_device_analytics(date_range, %{ include_utilization: true, include_cost_analysis: true, include_predictions: true, include_location_data: true }) # Load actual device data for geographic mapping devices = TerminalManagement.list_terminals_with_latest_status() # Prepare device data for map with location information map_devices = Enum.map(devices, fn device -> location = TerminalManagement.get_latest_terminal_location(device.id) %{ serial_number: device.serial_number, status: device.status, area: device.area, vendor: device.vendor, model: device.model, lat: parse_float(location.lat), lng: parse_float(location.lng) } end) |> Enum.filter(fn device -> # Only include devices with valid coordinates device.lat != nil and device.lng != nil and is_number(device.lat) and is_number(device.lng) end) socket |> assign(:analytics_data, analytics_data) |> assign(:map_devices, map_devices) |> assign(:loading, false) end # Helper function to parse float values defp parse_float(nil), do: nil defp parse_float(value) when is_number(value), do: value defp parse_float(value) when is_binary(value) do case Float.parse(value) do {float_val, _} -> float_val :error -> nil end end defp parse_float(_), do: nil @impl true def render(assigns) do ~H"""
Comprehensive insights into your device ecosystem
Total Devices
<%= @analytics_data.summary.total_devices %>
+<%= @analytics_data.summary.new_devices %> new devices this period
Active Devices
<%= @analytics_data.summary.active_devices %>
<%= @analytics_data.summary.activation_rate %>% activation rate
Performance Score
<%= @analytics_data.performance.overall_kpis.performance_grade %>
<%= @analytics_data.performance.overall_kpis.reliability_score %>% reliability
Compliance Rate
<%= @analytics_data.compliance.compliance_score %>%
<%= @analytics_data.compliance.device_compliance.non_compliant_devices %> devices need attention
<%= count %>
<%= status %>
<%= @analytics_data.trends.growth_rate %>%
Growth Rate
<%= length(@analytics_data.trends.daily.registrations) %>
Active Days
<%= length(@analytics_data.trends.weekly) %>
Weeks Tracked
Week <%= week_data.week %>
<%= week_data.registrations %> new registrations
<%= @analytics_data.performance.overall_kpis.overall_success_rate %>%
Overall Success Rate
<%= @analytics_data.performance.overall_kpis.operational_efficiency %>%
Operational Efficiency
<%= @analytics_data.performance.overall_kpis.reliability_score %>%
Reliability Score
<%= @analytics_data.performance.overall_kpis.performance_grade %>
Performance Grade
Total Pushes
<%= @analytics_data.performance.parameter_push.total_pushes %>
Success Rate
<%= @analytics_data.performance.parameter_push.success_rate %>%
Avg Response Time
<%= @analytics_data.performance.parameter_push.avg_response_time %>
Most Pushed Parameters:
Total Updates
<%= @analytics_data.performance.ota_updates.total_updates %>
Successful
<%= @analytics_data.performance.ota_updates.successful_updates %>
Pending
<%= @analytics_data.performance.ota_updates.pending_updates %>
Failed
<%= @analytics_data.performance.ota_updates.failed_updates %>
<%= @analytics_data.performance.response_times.avg_response_time %>ms
Average
<%= @analytics_data.performance.response_times.p95_response_time %>ms
95th Percentile
<%= @analytics_data.performance.response_times.p99_response_time %>ms
99th Percentile
<%= @analytics_data.performance.response_times.fastest_response %>ms
Fastest
<%= @analytics_data.performance.response_times.slowest_response %>ms
Slowest
<%= @analytics_data.geographic.coverage_metrics.total_areas_covered %>
Areas Covered
<%= @analytics_data.geographic.coverage_metrics.avg_devices_per_area %>
Avg Devices/Area
<%= @analytics_data.geographic.coverage_metrics.area_coverage_score %>
Coverage Score
<%= area.area %>
<%= area.online_count %>/<%= area.device_count %> online
<%= area.device_count %>
devices
<%= @analytics_data.compliance.compliance_score %>%
Overall Compliance
<%= @analytics_data.compliance.security_metrics.security_score %>%
Security Score
<%= @analytics_data.compliance.update_compliance.update_compliance_rate %>%
Update Compliance
<%= @analytics_data.compliance.update_compliance.devices_requiring_updates %>
Need Updates
<%= @analytics_data.compliance.update_compliance.overdue_updates %>
Overdue
<%= @analytics_data.compliance.update_compliance.update_compliance_rate %>%
Compliance Rate
<%= @analytics_data.compliance.update_compliance.avg_update_delay %>
Avg Delay
<%= @analytics_data.compliance.security_metrics.vulnerabilities_detected %>
Vulnerabilities
<%= @analytics_data.compliance.security_metrics.security_patches_applied %>
Patches Applied
<%= @analytics_data.compliance.security_metrics.encryption_compliance %>%
Encryption Compliance
<%= @analytics_data.compliance.security_metrics.security_score %>
Security Score
Generated: <%= @analytics_data.generated_at |> DateTime.to_string() %>
Date Range: <%= @analytics_data.date_range.start |> DateTime.to_date() %> to <%= @analytics_data.date_range.end |> DateTime.to_date() %>
Total Devices: <%= @analytics_data.summary.total_devices %>
Performance Grade: <%= @analytics_data.performance.overall_kpis.performance_grade %>
Compliance Score: <%= @analytics_data.compliance.compliance_score %>%
Coverage Areas: <%= @analytics_data.geographic.coverage_metrics.total_areas_covered %>