diff --git a/src/components/follows/FollowsView.tsx b/src/components/follows/FollowsView.tsx
index 1cdc496..1883cf0 100644
--- a/src/components/follows/FollowsView.tsx
+++ b/src/components/follows/FollowsView.tsx
@@ -11,9 +11,11 @@ import { shortenPubkey, profileName } from "../../lib/utils";
function FollowRow({
pubkey,
followsYou,
+ isNew,
}: {
pubkey: string;
followsYou?: boolean;
+ isNew?: boolean;
}) {
const profile = useProfile(pubkey);
const name = profileName(profile, shortenPubkey(pubkey));
@@ -60,6 +62,9 @@ function FollowRow({
{followsYou && (
follows you
)}
+ {isNew && (
+ new
+ )}
@@ -82,12 +87,14 @@ function FollowRow({
export function FollowsView() {
const { followsTab, setFollowsTab } = useUIStore();
const { pubkey, follows } = useUserStore();
- const { clearNewFollowers } = useNotificationsStore();
+ const { newFollowerPubkeys, clearNewFollowers } = useNotificationsStore();
const [followers, setFollowers] = useState([]);
const [followersLoading, setFollowersLoading] = useState(false);
const [followersError, setFollowersError] = useState(null);
const [followersFetched, setFollowersFetched] = useState(false);
+ // Snapshot new follower pubkeys on mount, before clearing
+ const [newPubkeys] = useState(() => new Set(newFollowerPubkeys));
// Clear badge when view opens
useEffect(() => {
@@ -191,8 +198,14 @@ export function FollowsView() {
{!followersLoading && !followersError && followers.length === 0 && followersFetched && (
No followers found yet.
)}
- {followers.map((pk) => (
-
+ {[...followers]
+ .sort((a, b) => {
+ const aNew = newPubkeys.has(a) ? 1 : 0;
+ const bNew = newPubkeys.has(b) ? 1 : 0;
+ return bNew - aNew; // new followers first
+ })
+ .map((pk) => (
+
))}
>
)}
diff --git a/src/lib/notificationPoller.ts b/src/lib/notificationPoller.ts
index 582b449..5bb6a86 100644
--- a/src/lib/notificationPoller.ts
+++ b/src/lib/notificationPoller.ts
@@ -96,7 +96,7 @@ async function pollOnce(pubkey: string) {
for (const e of newFollowers) {
const name = await getProfileName(e.pubkey);
notifyFollower(name).catch(() => {});
- useNotificationsStore.getState().incrementNewFollowers();
+ useNotificationsStore.getState().addNewFollower(e.pubkey);
}
}
} catch { /* non-critical */ }
diff --git a/src/stores/notifications.ts b/src/stores/notifications.ts
index aeab823..90c21d8 100644
--- a/src/stores/notifications.ts
+++ b/src/stores/notifications.ts
@@ -17,6 +17,7 @@ interface NotificationsState {
dmLastSeen: Record;
dmUnreadCount: number;
newFollowersCount: number;
+ newFollowerPubkeys: Set;
loadFromDb: (pubkey: string) => Promise;
fetchNotifications: (pubkey: string) => Promise;
@@ -25,7 +26,7 @@ interface NotificationsState {
isRead: (eventId: string) => boolean;
markDMRead: (partnerPubkey: string) => void;
computeDMUnread: (conversations: Array<{ partnerPubkey: string; lastAt: number }>) => void;
- incrementNewFollowers: () => void;
+ addNewFollower: (pubkey: string) => void;
clearNewFollowers: () => void;
}
@@ -76,6 +77,7 @@ export const useNotificationsStore = create((set, get) => ({
dmLastSeen: loadDMLastSeen(),
dmUnreadCount: 0,
newFollowersCount: 0,
+ newFollowerPubkeys: new Set(),
loadFromDb: async (pubkey: string) => {
const isNewAccount = pubkey !== get().currentPubkey;
@@ -210,6 +212,9 @@ export const useNotificationsStore = create((set, get) => ({
set({ dmUnreadCount });
},
- incrementNewFollowers: () => set((s) => ({ newFollowersCount: s.newFollowersCount + 1 })),
- clearNewFollowers: () => set({ newFollowersCount: 0 }),
+ addNewFollower: (pubkey: string) => set((s) => ({
+ newFollowersCount: s.newFollowersCount + 1,
+ newFollowerPubkeys: new Set([...s.newFollowerPubkeys, pubkey]),
+ })),
+ clearNewFollowers: () => set({ newFollowersCount: 0, newFollowerPubkeys: new Set() }),
}));