Fetch geocache event from found log's a tag to display treasure name

- Parse the `a` tag (e.g. `37516:pubkey:d-tag`) into AddrCoords
- Fetch the referenced geocache event via useAddrEvent
- Display the geocache's `name` tag as a clickable link (with chest icon)
  that navigates to the geocache's naddr detail page
- Fall back to showing the d-tag identifier if the event can't be fetched

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy
2026-02-17 20:03:28 -06:00
parent 204ceb0486
commit dff9ec4704
+42 -11
View File
@@ -1,6 +1,11 @@
import { useMemo } from 'react';
import { Link } from 'react-router-dom';
import { ShieldCheck } from 'lucide-react';
import { nip19 } from 'nostr-tools';
import { Badge } from '@/components/ui/badge';
import { Skeleton } from '@/components/ui/skeleton';
import { ChestIcon } from '@/components/icons/ChestIcon';
import { useAddrEvent, type AddrCoords } from '@/hooks/useEvent';
import type { NostrEvent } from '@nostrify/nostrify';
function getTag(tags: string[][], name: string): string | undefined {
@@ -11,29 +16,55 @@ function getAllTags(tags: string[][], name: string): string[] {
return tags.filter(([n]) => n === name).map(([, v]) => v);
}
/** Parse the `a` tag from a found log into addressable event coordinates. */
function parseGeocacheAddr(tags: string[][]): AddrCoords | undefined {
const aTag = getTag(tags, 'a');
if (!aTag) return undefined;
const parts = aTag.split(':');
if (parts.length < 3) return undefined;
const [kindStr, pubkey, ...rest] = parts;
const kind = Number(kindStr);
if (!kind || !pubkey) return undefined;
return { kind, pubkey, identifier: rest.join(':') };
}
/** Renders the content of a found log event (kind 7516). */
export function FoundLogContent({ event }: { event: NostrEvent }) {
const text = event.content;
const images = getAllTags(event.tags, 'image');
const hasVerification = !!getTag(event.tags, 'verification');
// Extract geocache name from the `a` tag if available
const geocacheRef = useMemo(() => {
const aTag = getTag(event.tags, 'a');
if (!aTag) return null;
const [, , dTag] = aTag.split(':');
return dTag ?? null;
}, [event.tags]);
const geocacheAddr = useMemo(() => parseGeocacheAddr(event.tags), [event.tags]);
const { data: geocacheEvent, isLoading: geocacheLoading } = useAddrEvent(geocacheAddr);
const geocacheName = geocacheEvent?.tags.find(([n]) => n === 'name')?.[1];
// Build naddr link for the geocache
const geocacheLink = useMemo(() => {
if (!geocacheAddr) return undefined;
return `/${nip19.naddrEncode({ kind: geocacheAddr.kind, pubkey: geocacheAddr.pubkey, identifier: geocacheAddr.identifier })}`;
}, [geocacheAddr]);
return (
<div className="mt-2">
{/* Geocache reference + verified badge */}
{/* Geocache name link + verified badge */}
<div className="flex flex-wrap items-center gap-1.5 mb-2">
{geocacheRef && (
{geocacheLoading ? (
<Skeleton className="h-5 w-32" />
) : geocacheName && geocacheLink ? (
<Link
to={geocacheLink}
className="flex items-center gap-1.5 text-sm font-medium text-primary hover:underline"
onClick={(e) => e.stopPropagation()}
>
<ChestIcon className="size-3.5" />
{geocacheName}
</Link>
) : geocacheAddr ? (
<Badge variant="secondary" className="text-[11px] gap-1 font-medium">
{geocacheRef}
{geocacheAddr.identifier}
</Badge>
)}
) : null}
{hasVerification && (
<Badge variant="secondary" className="text-[11px] gap-1 font-medium text-green-600 dark:text-green-400">
<ShieldCheck className="size-3" />