diff --git a/src/components/ReqViewer.tsx b/src/components/ReqViewer.tsx
index 8c8e903..efa46d3 100644
--- a/src/components/ReqViewer.tsx
+++ b/src/components/ReqViewer.tsx
@@ -704,6 +704,16 @@ export default function ReqViewer({
[interestListEvent],
);
+ // Compute interest list status for UI feedback
+ const interestListStatus = useMemo(() => {
+ if (!needsInterestList) return null;
+ if (!accountPubkey) return null; // Account required error handles this
+ if (interestListEvent === undefined) return "loading";
+ if (interestListEvent === null) return "not-found";
+ if (hashtags.length === 0) return "empty";
+ return "ok";
+ }, [needsInterestList, accountPubkey, interestListEvent, hashtags.length]);
+
// Resolve $me, $contacts, and $hashtags aliases (memoized to prevent unnecessary object creation)
const resolvedFilter = useMemo(
() =>
@@ -1285,6 +1295,28 @@ export default function ReqViewer({
)}
+ {/* Interest List Warning Banner */}
+ {interestListStatus === "not-found" && (
+
+
+
+ No interest list found (kind 10015).{" "}
+ $hashtags{" "}
+ ignored.
+
+
+ )}
+ {interestListStatus === "empty" && (
+
+
+
+ Interest list has no hashtags.{" "}
+ $hashtags{" "}
+ ignored.
+
+
+ )}
+
{/* Account Required Error */}
{(needsAccount || needsInterestList) && !accountPubkey && (
diff --git a/src/lib/nostr-utils.test.ts b/src/lib/nostr-utils.test.ts
index 6983ed1..ac3e933 100644
--- a/src/lib/nostr-utils.test.ts
+++ b/src/lib/nostr-utils.test.ts
@@ -428,13 +428,24 @@ describe("resolveFilterAliases", () => {
expect(result["#t"]).not.toContain("$hashtags");
});
- it("should handle $hashtags with empty hashtag list", () => {
+ it("should remove #t from filter when $hashtags resolves to empty", () => {
const filter: NostrFilter = { "#t": ["$hashtags"] };
const result = resolveFilterAliases(filter, undefined, [], {
hashtags: [],
});
- expect(result["#t"]).toEqual([]);
+ // Empty #t should be removed from filter entirely
+ expect(result["#t"]).toBeUndefined();
+ });
+
+ it("should preserve other hashtags when $hashtags resolves to empty", () => {
+ const filter: NostrFilter = { "#t": ["$hashtags", "nostr", "bitcoin"] };
+ const result = resolveFilterAliases(filter, undefined, [], {
+ hashtags: [],
+ });
+
+ // Other hashtags should be preserved
+ expect(result["#t"]).toEqual(["nostr", "bitcoin"]);
});
it("should preserve other hashtags when resolving $hashtags", () => {
@@ -520,7 +531,8 @@ describe("resolveFilterAliases", () => {
const result = resolveFilterAliases(filter, accountPubkey, []);
expect(result.authors).toEqual([accountPubkey]);
- expect(result["#t"]).toEqual([]); // Empty when no hashtags provided
+ // Empty #t should be removed from filter entirely
+ expect(result["#t"]).toBeUndefined();
});
});
diff --git a/src/lib/nostr-utils.ts b/src/lib/nostr-utils.ts
index 163e191..d7df37b 100644
--- a/src/lib/nostr-utils.ts
+++ b/src/lib/nostr-utils.ts
@@ -236,7 +236,14 @@ export function resolveFilterAliases(
}
// Deduplicate
- resolved["#t"] = Array.from(new Set(resolvedTTags));
+ const deduped = Array.from(new Set(resolvedTTags));
+
+ // If result is empty, remove #t from filter entirely to avoid unusable query
+ if (deduped.length === 0) {
+ delete resolved["#t"];
+ } else {
+ resolved["#t"] = deduped;
+ }
}
return resolved;