defmodule DaProductAppWeb.DashboardLive do use DaProductAppWeb, :live_view import Logger alias DaProductApp.Users alias DaProductApp.TerminalManagement # on_mount DaProductAppWeb.Live.SetCurrentPage def mount(_params, session, socket) do user_token = session["user_token"] user = user_token && Users.get_user_by_session_token(user_token) current_user = user || nil Logger.debug("Socket Assigns: #{inspect(socket.assigns)}", []) # Correct usage #current_user = Map.get(session, "current_user", nil) stats = TerminalManagement.get_dashboard_statistics() online_rate = TerminalManagement.get_device_online_rate() terminals = TerminalManagement.list_terminals_with_latest_status() chart_data = TerminalManagement.get_chart_data("today") # Phase 3.1: Add real-time monitoring data monitoring_data = TerminalManagement.get_realtime_monitoring_data() # Subscribe to real-time updates if connected?(socket) do TerminalManagement.subscribe_to_device_updates() # Set up periodic updates every 30 seconds Process.send_after(self(), :update_monitoring_data, 30_000) end socket = socket |> assign(:current_user, current_user) |> assign(:show_sidebar, true) # Enable sidebar for dashboard |> assign(:page_title, "Dashboard") # Set the page title |> assign(:current_page, :dashboard) # Set the current page for sidebar highlighting |> assign(:stats, stats) |> assign(:online_rate, online_rate) |> assign(:terminals, terminals) |> assign(:selected_terminal, nil) |> assign(:terminal_logs, []) |> assign(:show_panel, false) |> assign(:chart_data, chart_data) |> assign(:selected_period, "today") # Phase 3.1: Real-time monitoring assigns |> assign(:monitoring_data, monitoring_data) |> assign(:device_health, monitoring_data.device_health) |> assign(:connection_status, monitoring_data.connection_status) |> assign(:performance_metrics, monitoring_data.performance_metrics) |> assign(:alert_summary, monitoring_data.alert_summary) |> assign(:show_monitoring_details, false) {:ok, socket} end def render(assigns) do ~H"""

Real-time Device Monitoring

Live updates every 30 seconds • Last updated: <%= Calendar.strftime(@monitoring_data.last_updated, "%H:%M:%S") %>

<%= @device_health.total %>
Total Devices
<%= @device_health.healthy %>
Healthy
<%= if @alert_summary.total_alerts > 0 do %>
<%= @alert_summary.total_alerts %>
Alerts
<% end %>
<%= @device_health.healthy %>
Healthy Devices
Last 5 minutes
<%= @device_health.warning %>
Warning
5-30 minutes ago
<%= @device_health.critical %>
Critical
30-60 minutes ago
<%= @device_health.offline %>
Offline
Over 1 hour ago
Success Rate
<%= Float.round(@performance_metrics.parameter_push_success_rate, 1) %>%
Parameter Operations
Avg Response
<%= @performance_metrics.avg_response_time_ms %>ms
Last Hour
Uptime
<%= @performance_metrics.uptime_percentage %>%
Last Hour
Connections
<%= @connection_status.current_connections %>
Per Minute
Total Devices
<%= @stats.total_devices %>
Registered devices
New Devices
<%= @stats.new_devices_today %>
Added today
Activated
<%= @stats.activated_devices %>
Active today
Upgrades
<%= @stats.upgrades_today %>
Completed today
App Downloads
<%= @stats.app_downloads_today %>
Downloaded today

Update statistics

■ OTA updates ■ total number of APP downloads

The device is online Rate

<%= @online_rate.online_rate %>%
<%= @online_rate.online_devices %> stand
""" end def handle_event("set_chart_range", %{"range" => range}, socket) do chart_data = TerminalManagement.get_chart_data(range) stats = TerminalManagement.get_dashboard_statistics(range) {:noreply, assign(socket, :chart_data, chart_data) |> assign(:selected_period, range) |> assign(:stats, stats)} end def handle_event("refresh_update_statistics", _params, socket) do # Refresh all statistics and chart data based on the currently selected period stats = TerminalManagement.get_dashboard_statistics(socket.assigns.selected_period) chart_data = TerminalManagement.get_chart_data(socket.assigns.selected_period) online_rate = TerminalManagement.get_device_online_rate() socket = socket |> assign(:stats, stats) |> assign(:chart_data, chart_data) |> assign(:online_rate, online_rate) |> put_flash(:info, "Statistics updated successfully") {:noreply, socket} end # Navigation event handlers for dashboard cards def handle_event("navigate_to_devices", _params, socket) do {:noreply, push_navigate(socket, to: ~p"/terminals")} end def handle_event("navigate_to_new_devices", _params, socket) do # Navigate to terminals page with today's filter {:noreply, push_navigate(socket, to: ~p"/terminals?filter=today")} end def handle_event("navigate_to_activated_devices", _params, socket) do # Navigate to terminals page with active filter {:noreply, push_navigate(socket, to: ~p"/terminals?status=online")} end def handle_event("navigate_to_upgrades", _params, socket) do # Navigate to app upgrade status page {:noreply, push_navigate(socket, to: ~p"/appupgrade/status")} end def handle_event("navigate_to_app_downloads", _params, socket) do # Navigate to app packages page {:noreply, push_navigate(socket, to: ~p"/apppackage")} end # Phase 3.1: Real-time monitoring event handlers def handle_event("refresh_monitoring", _params, socket) do monitoring_data = TerminalManagement.get_realtime_monitoring_data() socket = socket |> assign(:monitoring_data, monitoring_data) |> assign(:device_health, monitoring_data.device_health) |> assign(:connection_status, monitoring_data.connection_status) |> assign(:performance_metrics, monitoring_data.performance_metrics) |> assign(:alert_summary, monitoring_data.alert_summary) {:noreply, socket} end def handle_event("toggle_monitoring_details", _params, socket) do {:noreply, assign(socket, :show_monitoring_details, !socket.assigns.show_monitoring_details)} end # Handle real-time PubSub messages def handle_info({:device_update, device_data}, socket) do # Update specific device in the terminals list updated_terminals = update_terminal_in_list(socket.assigns.terminals, device_data) {:noreply, assign(socket, :terminals, updated_terminals)} end def handle_info({:monitoring_update, monitoring_data}, socket) do socket = socket |> assign(:monitoring_data, monitoring_data) |> assign(:device_health, monitoring_data.device_health) |> assign(:connection_status, monitoring_data.connection_status) |> assign(:performance_metrics, monitoring_data.performance_metrics) |> assign(:alert_summary, monitoring_data.alert_summary) {:noreply, socket} end # Periodic updates def handle_info(:update_monitoring_data, socket) do monitoring_data = TerminalManagement.get_realtime_monitoring_data() socket = socket |> assign(:monitoring_data, monitoring_data) |> assign(:device_health, monitoring_data.device_health) |> assign(:connection_status, monitoring_data.connection_status) |> assign(:performance_metrics, monitoring_data.performance_metrics) |> assign(:alert_summary, monitoring_data.alert_summary) # Schedule next update Process.send_after(self(), :update_monitoring_data, 30_000) {:noreply, socket} end # Helper function to update terminal in list defp update_terminal_in_list(terminals, device_data) do Enum.map(terminals, fn terminal -> if terminal.serial_number == device_data.serial_number do Map.merge(terminal, device_data) else terminal end end) end # Helper function to get period description for UI labels defp period_description("today"), do: "today" defp period_description("week"), do: "this week" defp period_description("month"), do: "this month" end