Add debug lines for fav click

This commit is contained in:
Jack Kingsman
2026-04-08 16:18:46 -07:00
parent 01c86a486e
commit 8e2e039985
6 changed files with 58 additions and 15 deletions

View File

@@ -207,20 +207,36 @@ export function App() {
const handleToggleFavorite = useCallback(
async (type: 'channel' | 'contact', id: string) => {
const ts = performance.now().toFixed(2);
console.log(
`[fav-debug] handleToggleFavorite called t=${ts} type=${type} id=${id.slice(0, 12)}`
);
// Optimistically toggle the favorite flag
if (type === 'contact') {
setContacts((prev) =>
prev.map((c) => (c.public_key === id ? { ...c, favorite: !c.favorite } : c))
);
setContacts((prev) => {
const match = prev.find((c) => c.public_key === id);
console.log(
`[fav-debug] optimistic contact toggle t=${ts} current=${match?.favorite}${!match?.favorite}`
);
return prev.map((c) => (c.public_key === id ? { ...c, favorite: !c.favorite } : c));
});
} else {
setChannels((prev) =>
prev.map((c) => (c.key === id ? { ...c, favorite: !c.favorite } : c))
);
setChannels((prev) => {
const match = prev.find((c) => c.key === id);
console.log(
`[fav-debug] optimistic channel toggle t=${ts} current=${match?.favorite}${!match?.favorite}`
);
return prev.map((c) => (c.key === id ? { ...c, favorite: !c.favorite } : c));
});
}
try {
await api.toggleFavorite(type, id);
} catch {
console.log(`[fav-debug] firing API request t=${ts}`);
const result = await api.toggleFavorite(type, id);
console.log(`[fav-debug] API response t=${ts}`, result);
} catch (err) {
console.error(`[fav-debug] API error t=${ts}`, err);
// Revert on failure
if (type === 'contact') {
setContacts((prev) =>

View File

@@ -120,7 +120,12 @@ export function ChannelInfoPane({
<button
type="button"
className="text-sm flex items-center gap-2 hover:text-primary transition-colors"
onClick={() => onToggleFavorite('channel', channel.key)}
onClick={(e) => {
console.log(
`[fav-debug] ChannelInfoPane star clicked t=${performance.now().toFixed(2)} detail=${e.detail} isTrusted=${e.isTrusted}`
);
onToggleFavorite('channel', channel.key);
}}
>
{channel.favorite ? (
<>

View File

@@ -351,9 +351,12 @@ export function ChatHeader({
{(conversation.type === 'channel' || conversation.type === 'contact') && (
<button
className="p-1 rounded hover:bg-accent text-lg leading-none transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
onClick={() =>
onToggleFavorite(conversation.type as 'channel' | 'contact', conversation.id)
}
onClick={(e) => {
console.log(
`[fav-debug] star clicked t=${performance.now().toFixed(2)} detail=${e.detail} isTrusted=${e.isTrusted}`
);
onToggleFavorite(conversation.type as 'channel' | 'contact', conversation.id);
}}
title={favoriteTitle}
aria-label={isFav ? 'Remove from favorites' : 'Add to favorites'}
>

View File

@@ -377,7 +377,12 @@ export function ContactInfoPane({
<button
type="button"
className="text-sm flex items-center gap-2 hover:text-primary transition-colors"
onClick={() => onToggleFavorite('contact', contact.public_key)}
onClick={(e) => {
console.log(
`[fav-debug] ContactInfoPane star clicked t=${performance.now().toFixed(2)} detail=${e.detail} isTrusted=${e.isTrusted}`
);
onToggleFavorite('contact', contact.public_key);
}}
title="Favorite contacts stay loaded on the radio for ACK support"
>
{contact.favorite ? (

View File

@@ -266,7 +266,12 @@ export function RepeaterDashboard({
)}
<button
className="p-1 rounded hover:bg-accent text-lg leading-none transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
onClick={() => onToggleFavorite('contact', conversation.id)}
onClick={(e) => {
console.log(
`[fav-debug] RepeaterDashboard star clicked t=${performance.now().toFixed(2)} detail=${e.detail} isTrusted=${e.isTrusted}`
);
onToggleFavorite('contact', conversation.id);
}}
title={
isFav
? 'Remove from favorites. Favorite contacts stay loaded on the radio for ACK support.'

View File

@@ -12,7 +12,16 @@ export function mergeContactIntoList(contacts: Contact[], incoming: Contact): Co
const idx = contacts.findIndex((c) => c.public_key === incoming.public_key);
if (idx >= 0) {
const existing = contacts[idx];
const merged = { ...existing, ...incoming };
// Preserve user-action-only fields that should not be overwritten by
// radio-event-driven WS updates (adverts, path updates, syncs). These
// fields are only changed via explicit user actions (favorite toggle,
// mark-read) or full REST refetches, not via mesh/radio events.
const merged = {
...existing,
...incoming,
favorite: existing.favorite,
last_read_at: existing.last_read_at,
};
const unchanged = (Object.keys(merged) as (keyof Contact)[]).every(
(k) => existing[k] === merged[k]
);