mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-07-06 01:42:11 +02:00
Linting and code cleanup for an imitation of order
This commit is contained in:
@@ -1,3 +1,14 @@
|
||||
export { useRepeaterMode, type UseRepeaterModeResult, formatDuration, formatTelemetry, formatNeighbors, formatAcl } from './useRepeaterMode';
|
||||
export {
|
||||
useRepeaterMode,
|
||||
type UseRepeaterModeResult,
|
||||
formatDuration,
|
||||
formatTelemetry,
|
||||
formatNeighbors,
|
||||
formatAcl,
|
||||
} from './useRepeaterMode';
|
||||
export { useUnreadCounts, type UseUnreadCountsResult } from './useUnreadCounts';
|
||||
export { useConversationMessages, type UseConversationMessagesResult, getMessageContentKey } from './useConversationMessages';
|
||||
export {
|
||||
useConversationMessages,
|
||||
type UseConversationMessagesResult,
|
||||
getMessageContentKey,
|
||||
} from './useConversationMessages';
|
||||
|
||||
@@ -34,47 +34,56 @@ export function useConversationMessages(
|
||||
const seenMessageContent = useRef<Set<string>>(new Set());
|
||||
|
||||
// Fetch messages for active conversation
|
||||
const fetchMessages = useCallback(async (showLoading = false) => {
|
||||
if (!activeConversation || activeConversation.type === 'raw') {
|
||||
setMessages([]);
|
||||
setHasOlderMessages(false);
|
||||
return;
|
||||
}
|
||||
const fetchMessages = useCallback(
|
||||
async (showLoading = false) => {
|
||||
if (!activeConversation || activeConversation.type === 'raw') {
|
||||
setMessages([]);
|
||||
setHasOlderMessages(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (showLoading) {
|
||||
setMessagesLoading(true);
|
||||
// Clear messages first so MessageList resets scroll state for new conversation
|
||||
setMessages([]);
|
||||
}
|
||||
try {
|
||||
const data = await api.getMessages({
|
||||
type: activeConversation.type === 'channel' ? 'CHAN' : 'PRIV',
|
||||
conversation_key: activeConversation.id,
|
||||
limit: MESSAGE_PAGE_SIZE,
|
||||
});
|
||||
setMessages(data);
|
||||
// Track seen content for new messages
|
||||
seenMessageContent.current.clear();
|
||||
for (const msg of data) {
|
||||
seenMessageContent.current.add(getMessageContentKey(msg));
|
||||
}
|
||||
// If we got a full page, there might be more
|
||||
setHasOlderMessages(data.length >= MESSAGE_PAGE_SIZE);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch messages:', err);
|
||||
toast.error('Failed to load messages', {
|
||||
description: err instanceof Error ? err.message : 'Check your connection',
|
||||
});
|
||||
} finally {
|
||||
if (showLoading) {
|
||||
setMessagesLoading(false);
|
||||
setMessagesLoading(true);
|
||||
// Clear messages first so MessageList resets scroll state for new conversation
|
||||
setMessages([]);
|
||||
}
|
||||
}
|
||||
}, [activeConversation]);
|
||||
try {
|
||||
const data = await api.getMessages({
|
||||
type: activeConversation.type === 'channel' ? 'CHAN' : 'PRIV',
|
||||
conversation_key: activeConversation.id,
|
||||
limit: MESSAGE_PAGE_SIZE,
|
||||
});
|
||||
setMessages(data);
|
||||
// Track seen content for new messages
|
||||
seenMessageContent.current.clear();
|
||||
for (const msg of data) {
|
||||
seenMessageContent.current.add(getMessageContentKey(msg));
|
||||
}
|
||||
// If we got a full page, there might be more
|
||||
setHasOlderMessages(data.length >= MESSAGE_PAGE_SIZE);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch messages:', err);
|
||||
toast.error('Failed to load messages', {
|
||||
description: err instanceof Error ? err.message : 'Check your connection',
|
||||
});
|
||||
} finally {
|
||||
if (showLoading) {
|
||||
setMessagesLoading(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
[activeConversation]
|
||||
);
|
||||
|
||||
// Fetch older messages (pagination)
|
||||
const fetchOlderMessages = useCallback(async () => {
|
||||
if (!activeConversation || activeConversation.type === 'raw' || loadingOlder || !hasOlderMessages) return;
|
||||
if (
|
||||
!activeConversation ||
|
||||
activeConversation.type === 'raw' ||
|
||||
loadingOlder ||
|
||||
!hasOlderMessages
|
||||
)
|
||||
return;
|
||||
|
||||
setLoadingOlder(true);
|
||||
try {
|
||||
@@ -87,7 +96,7 @@ export function useConversationMessages(
|
||||
|
||||
if (data.length > 0) {
|
||||
// Prepend older messages (they come sorted DESC, so older are at the end)
|
||||
setMessages(prev => [...prev, ...data]);
|
||||
setMessages((prev) => [...prev, ...data]);
|
||||
// Track seen content
|
||||
for (const msg of data) {
|
||||
seenMessageContent.current.add(getMessageContentKey(msg));
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { api } from '../api';
|
||||
import type { Contact, Conversation, Message, TelemetryResponse, NeighborInfo, AclEntry } from '../types';
|
||||
import type {
|
||||
Contact,
|
||||
Conversation,
|
||||
Message,
|
||||
TelemetryResponse,
|
||||
NeighborInfo,
|
||||
AclEntry,
|
||||
} from '../types';
|
||||
import { CONTACT_TYPE_REPEATER } from '../types';
|
||||
|
||||
// Format seconds into human-readable duration (e.g., 1d17h2m, 1h5m, 3m)
|
||||
@@ -121,7 +128,7 @@ export function useRepeaterMode(
|
||||
// Check if active conversation is a repeater
|
||||
const activeContactIsRepeater = useMemo(() => {
|
||||
if (!activeConversation || activeConversation.type !== 'contact') return false;
|
||||
const contact = contacts.find(c => c.public_key === activeConversation.id);
|
||||
const contact = contacts.find((c) => c.public_key === activeConversation.id);
|
||||
return contact?.type === CONTACT_TYPE_REPEATER;
|
||||
}, [activeConversation, contacts]);
|
||||
|
||||
@@ -181,12 +188,7 @@ export function useRepeaterMode(
|
||||
if (!activeContactIsRepeater || !repeaterLoggedIn) return;
|
||||
|
||||
// Show the command as an outgoing message
|
||||
const commandMessage = createLocalMessage(
|
||||
activeConversation.id,
|
||||
`> ${command}`,
|
||||
true,
|
||||
0
|
||||
);
|
||||
const commandMessage = createLocalMessage(activeConversation.id, `> ${command}`, true, 0);
|
||||
setMessages((prev) => [...prev, commandMessage]);
|
||||
|
||||
try {
|
||||
|
||||
@@ -51,19 +51,21 @@ export function useUnreadCounts(
|
||||
// Fetch messages and count unreads for new channels/contacts
|
||||
// Uses server-side last_read_at for consistent read state across devices
|
||||
useEffect(() => {
|
||||
const newChannels = channels.filter(c => !fetchedChannels.current.has(c.key));
|
||||
const newContacts = contacts.filter(c => c.public_key && !fetchedContacts.current.has(c.public_key));
|
||||
const newChannels = channels.filter((c) => !fetchedChannels.current.has(c.key));
|
||||
const newContacts = contacts.filter(
|
||||
(c) => c.public_key && !fetchedContacts.current.has(c.public_key)
|
||||
);
|
||||
|
||||
if (newChannels.length === 0 && newContacts.length === 0) return;
|
||||
|
||||
// Mark as fetched before starting (to avoid duplicate fetches if effect re-runs)
|
||||
newChannels.forEach(c => fetchedChannels.current.add(c.key));
|
||||
newContacts.forEach(c => fetchedContacts.current.add(c.public_key));
|
||||
newChannels.forEach((c) => fetchedChannels.current.add(c.key));
|
||||
newContacts.forEach((c) => fetchedContacts.current.add(c.public_key));
|
||||
|
||||
const fetchAndCountUnreads = async () => {
|
||||
const conversations: Array<{ type: 'PRIV' | 'CHAN'; conversation_key: string }> = [
|
||||
...newChannels.map(c => ({ type: 'CHAN' as const, conversation_key: c.key })),
|
||||
...newContacts.map(c => ({ type: 'PRIV' as const, conversation_key: c.public_key })),
|
||||
...newChannels.map((c) => ({ type: 'CHAN' as const, conversation_key: c.key })),
|
||||
...newContacts.map((c) => ({ type: 'PRIV' as const, conversation_key: c.public_key })),
|
||||
];
|
||||
|
||||
if (conversations.length === 0) return;
|
||||
@@ -82,16 +84,16 @@ export function useUnreadCounts(
|
||||
// Use server-side last_read_at, fallback to 0 if never read
|
||||
const lastRead = channel.last_read_at || 0;
|
||||
|
||||
const unreadMsgs = msgs.filter(m => !m.outgoing && m.received_at > lastRead);
|
||||
const unreadMsgs = msgs.filter((m) => !m.outgoing && m.received_at > lastRead);
|
||||
if (unreadMsgs.length > 0) {
|
||||
newUnreadCounts[key] = unreadMsgs.length;
|
||||
// Check if any unread message mentions the user
|
||||
if (unreadMsgs.some(m => messageContainsMention(m.text, myNameRef.current))) {
|
||||
if (unreadMsgs.some((m) => messageContainsMention(m.text, myNameRef.current))) {
|
||||
newMentions[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const latestTime = Math.max(...msgs.map(m => m.received_at));
|
||||
const latestTime = Math.max(...msgs.map((m) => m.received_at));
|
||||
newLastMessageTimes[key] = latestTime;
|
||||
setLastMessageTime(key, latestTime);
|
||||
}
|
||||
@@ -105,26 +107,26 @@ export function useUnreadCounts(
|
||||
// Use server-side last_read_at, fallback to 0 if never read
|
||||
const lastRead = contact.last_read_at || 0;
|
||||
|
||||
const unreadMsgs = msgs.filter(m => !m.outgoing && m.received_at > lastRead);
|
||||
const unreadMsgs = msgs.filter((m) => !m.outgoing && m.received_at > lastRead);
|
||||
if (unreadMsgs.length > 0) {
|
||||
newUnreadCounts[key] = unreadMsgs.length;
|
||||
// Check if any unread message mentions the user
|
||||
if (unreadMsgs.some(m => messageContainsMention(m.text, myNameRef.current))) {
|
||||
if (unreadMsgs.some((m) => messageContainsMention(m.text, myNameRef.current))) {
|
||||
newMentions[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const latestTime = Math.max(...msgs.map(m => m.received_at));
|
||||
const latestTime = Math.max(...msgs.map((m) => m.received_at));
|
||||
newLastMessageTimes[key] = latestTime;
|
||||
setLastMessageTime(key, latestTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(newUnreadCounts).length > 0) {
|
||||
setUnreadCounts(prev => ({ ...prev, ...newUnreadCounts }));
|
||||
setUnreadCounts((prev) => ({ ...prev, ...newUnreadCounts }));
|
||||
}
|
||||
if (Object.keys(newMentions).length > 0) {
|
||||
setMentions(prev => ({ ...prev, ...newMentions }));
|
||||
setMentions((prev) => ({ ...prev, ...newMentions }));
|
||||
}
|
||||
setLastMessageTimes(getLastMessageTimes());
|
||||
} catch (err) {
|
||||
@@ -138,7 +140,11 @@ export function useUnreadCounts(
|
||||
// Mark conversation as read when user views it
|
||||
// Calls server API to persist read state across devices
|
||||
useEffect(() => {
|
||||
if (activeConversation && activeConversation.type !== 'raw' && activeConversation.type !== 'map') {
|
||||
if (
|
||||
activeConversation &&
|
||||
activeConversation.type !== 'raw' &&
|
||||
activeConversation.type !== 'map'
|
||||
) {
|
||||
const key = getStateKey(
|
||||
activeConversation.type as 'channel' | 'contact',
|
||||
activeConversation.id
|
||||
|
||||
Reference in New Issue
Block a user