import React, { useState, useEffect, useCallback } from "react";
import { useAppSelector, useAppDispatch } from "../hooks";
import { PacketRenderer } from "./packets/PacketRenderer";
import { StreamControl } from "./StreamControl";
import { Trash2, RefreshCw, Archive, Radio } from "lucide-react";
import { clearPackets, toggleStreamPause } from "../store/slices/packetSlice";
import { Packet } from "../lib/types";
import { Separator } from "./Separator";
// Number of packets to show per page
const PACKETS_PER_PAGE = 10;
export const PacketList: React.FC = () => {
const { packets, bufferedPackets, loading, error, streamPaused } =
useAppSelector((state) => state.packets);
const dispatch = useAppDispatch();
const [currentPage, setCurrentPage] = useState(1);
// Generate a reproducible hash code for a string
const hashString = useCallback((str: string): string => {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // Convert to 32bit integer
}
// Make sure hash is always positive and convert to string
return Math.abs(hash).toString(36);
}, []);
// Create a packet key using data.id and from address
// This should match the key generation logic in the reducer
const createPacketKey = useCallback(
(packet: Packet): string => {
if (packet.data.id !== undefined && packet.data.from !== undefined) {
// Use Meshtastic node ID format (! followed by lowercase hex) and packet ID
const nodeId = `!${packet.data.from.toString(16).toLowerCase()}`;
return `${nodeId}_${packet.data.id}`;
} else {
// Fallback to hash-based key if no ID or from (should be rare)
return `hash_${hashString(JSON.stringify(packet))}`;
}
},
[hashString]
);
// We don't need to track packet keys in state anymore since we use data.id
// and it's deterministic - removing this effect to prevent the infinite loop issue
if (loading) {
return (