Skip to content

Commit 23c98d7

Browse files
committed
fix(nr-web): Fix 5 issues identified by Bugbot
1. HIGH: Fix plus code prefix generation producing malformed location tags - Fixed getPlusCodePrefixes to generate valid prefixes like 'XX000000+' instead of 'XX00000' (missing + character) 2. LOW: Remove unused exported utility functions - Removed hexToNsec, hexToNpub from keys.ts - Removed truncate from utils.ts 3. LOW: Remove unused replyingToEvent store state - Removed state variable and setter that were never read 4. MEDIUM: Fix race condition causing duplicate events when publishing - Added duplicate check in publishEvent before adding to state - Prevents double-adding when relay echoes back before publish resolves 5. MEDIUM: Fix modal state persisting between different locations - Added useEffect to reset content, error, and isSubmitting state when modal opens or location changes
1 parent bc87c9e commit 23c98d7

4 files changed

Lines changed: 25 additions & 36 deletions

File tree

nr-web/src/components/AddNoteModal.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { useState } from "react";
3+
import { useState, useEffect } from "react";
44
import { useNostrStore } from "@/store/nostr";
55
import { createMapNote } from "@/lib/events";
66
import OpenLocationCode from "open-location-code";
@@ -19,6 +19,15 @@ export function AddNoteModal({ isOpen, onClose, location }: AddNoteModalProps) {
1919
const publishEvent = useNostrStore((state) => state.publishEvent);
2020
const privateKey = useNostrStore((state) => state.privateKey);
2121

22+
// Reset state when modal opens or location changes
23+
useEffect(() => {
24+
if (isOpen) {
25+
setContent("");
26+
setError(null);
27+
setIsSubmitting(false);
28+
}
29+
}, [isOpen, location]);
30+
2231
if (!isOpen || !location) return null;
2332

2433
const plusCode = OpenLocationCode.encode(location.lat, location.lng, 10);

nr-web/src/lib/keys.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getPublicKey, nip19 } from "nostr-tools";
2-
import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
2+
import { bytesToHex } from "@noble/hashes/utils";
33
import * as bip39 from "@scure/bip39";
44
import { wordlist } from "@scure/bip39/wordlists/english";
55
import { HDKey } from "@scure/bip32";
@@ -86,17 +86,3 @@ export function importMnemonic(mnemonic: string): {
8686
publicKey,
8787
};
8888
}
89-
90-
/**
91-
* Convert hex private key to nsec
92-
*/
93-
export function hexToNsec(hex: string): string {
94-
return nip19.nsecEncode(hexToBytes(hex));
95-
}
96-
97-
/**
98-
* Convert hex public key to npub
99-
*/
100-
export function hexToNpub(hex: string): string {
101-
return nip19.npubEncode(hex);
102-
}

nr-web/src/lib/utils.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ export function formatDistanceToNow(timestamp: number): string {
6262
/**
6363
* Get plus code prefix tags for an event
6464
* Returns prefixes from 2 characters up to the full code length
65+
*
66+
* Plus codes are formatted as: XXXXXXXX+XX (8 chars, +, 2 chars)
67+
* Prefixes should be: XX000000+, XXXX0000+, XXXXXX00+, XXXXXXXX+, XXXXXXXX+XX
6568
*/
6669
export function getPlusCodePrefixes(plusCode: string): string[] {
6770
const prefixes: string[] = [];
@@ -72,8 +75,11 @@ export function getPlusCodePrefixes(plusCode: string): string[] {
7275
const prefix = cleanCode.slice(0, len);
7376
// Add back the + for proper formatting
7477
if (len <= 8) {
75-
prefixes.push(prefix + "000000+".slice(0, 8 - len + 1));
78+
// Pad with zeros and add + at position 8
79+
const paddedPrefix = prefix + "0".repeat(8 - len) + "+";
80+
prefixes.push(paddedPrefix);
7681
} else {
82+
// For codes longer than 8, format as XXXXXXXX+XX
7783
prefixes.push(
7884
prefix.slice(0, 8) + "+" + prefix.slice(8)
7985
);
@@ -82,11 +88,3 @@ export function getPlusCodePrefixes(plusCode: string): string[] {
8288

8389
return prefixes;
8490
}
85-
86-
/**
87-
* Truncate a string with ellipsis
88-
*/
89-
export function truncate(str: string, maxLength: number): string {
90-
if (str.length <= maxLength) return str;
91-
return str.slice(0, maxLength - 3) + "...";
92-
}

nr-web/src/store/nostr.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ interface NostrState {
3737

3838
// UI State
3939
selectedEvent: Event | null;
40-
replyingToEvent: Event | null;
4140

4241
// Actions
4342
connect: () => Promise<void>;
@@ -61,7 +60,6 @@ interface NostrState {
6160

6261
// UI actions
6362
setSelectedEvent: (event: Event | null) => void;
64-
setReplyingToEvent: (event: Event | null) => void;
6563
}
6664

6765
export const useNostrStore = create<NostrState>()(
@@ -86,7 +84,6 @@ export const useNostrStore = create<NostrState>()(
8684
},
8785
developerMode: false,
8886
selectedEvent: null,
89-
replyingToEvent: null,
9087

9188
// Connect to relay
9289
connect: async () => {
@@ -170,10 +167,13 @@ export const useNostrStore = create<NostrState>()(
170167

171168
await relay.publish(event);
172169

173-
// Add to local state
174-
set((state) => ({
175-
events: [...state.events, event],
176-
}));
170+
// Add to local state only if not already present (avoid race condition with subscription)
171+
set((state) => {
172+
if (state.events.some((e) => e.id === event.id)) {
173+
return state;
174+
}
175+
return { events: [...state.events, event] };
176+
});
177177
},
178178

179179
// Toggle layer visibility
@@ -221,10 +221,6 @@ export const useNostrStore = create<NostrState>()(
221221
setSelectedEvent: (event: Event | null) => {
222222
set({ selectedEvent: event });
223223
},
224-
225-
setReplyingToEvent: (event: Event | null) => {
226-
set({ replyingToEvent: event });
227-
},
228224
}),
229225
{
230226
name: "nostroots-web-storage",

0 commit comments

Comments
 (0)