profile: show following, contact-list changes and contact events
- added following count in profile header - added contact-list changes events - added new raw event detail view to visulaize event metadata and raw contentpull/81/head
parent
027c61e00f
commit
5039b3dece
@ -0,0 +1,96 @@
|
||||
import {Event, nip19} from 'nostr-tools';
|
||||
import {elem} from './utils/dom';
|
||||
import {dateTime} from './utils/time';
|
||||
import {isPTag, sortByCreatedAt} from './events';
|
||||
import {getViewContent} from './view';
|
||||
import {getMetadata} from './profiles';
|
||||
|
||||
const contactHistoryMap: {
|
||||
[pubkey: string]: Event[]
|
||||
} = {};
|
||||
|
||||
const updateFollowing = (evt: Event) => {
|
||||
const following = getViewContent().querySelector(`[data-following="${evt.pubkey}"]`);
|
||||
if (following) {
|
||||
const count = evt.tags.filter(isPTag).length;
|
||||
const anchor = elem('a', {
|
||||
data: {following: evt.pubkey},
|
||||
href: `/${evt.id}`,
|
||||
title: dateTime.format(new Date(evt.created_at * 1000)),
|
||||
}, `following ${count}`);
|
||||
following.replaceWith(anchor);
|
||||
}
|
||||
};
|
||||
|
||||
export const setContactList = (evt: Event) => {
|
||||
let contactHistory = contactHistoryMap[evt.pubkey];
|
||||
if (!contactHistory) {
|
||||
contactHistoryMap[evt.pubkey] = [evt];
|
||||
updateFollowing(evt);
|
||||
return;
|
||||
}
|
||||
if (contactHistory.find(({id}) => id === evt.id)) {
|
||||
return;
|
||||
}
|
||||
contactHistory.push(evt);
|
||||
contactHistory.sort(sortByCreatedAt);
|
||||
updateFollowing(contactHistory[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* findChanges
|
||||
* returns added and removed contacts list of P tags, ignores any tag other than 'p'
|
||||
*/
|
||||
const findChanges = (current: Event, previous: Event) => {
|
||||
const previousContacts = previous.tags.join('\n'); // filter for p tags first?
|
||||
const currentContacts = current.tags.join('\n');
|
||||
const addedContacts = current.tags.filter(([tag, pubkey]) => tag === 'p' && !previousContacts.includes(pubkey));
|
||||
const removedContacts = previous.tags.filter(([tag, pubkey]) => tag === 'p' && !currentContacts.includes(pubkey));
|
||||
return [addedContacts, removedContacts];
|
||||
};
|
||||
|
||||
export const updateContactList = (evt: Event) => {
|
||||
const contactHistory = contactHistoryMap[evt.pubkey];
|
||||
if (contactHistory.length === 1) {
|
||||
return [contactHistory[0].tags.filter(isPTag)];
|
||||
}
|
||||
const pos = contactHistory.findIndex(({id}) => id === evt.id);
|
||||
if (evt.id === contactHistory.at(-1)?.id) { // oldest known contact-list update
|
||||
// update existing contact entries
|
||||
contactHistory
|
||||
.slice(0, -1)
|
||||
.forEach((entry, i) => {
|
||||
const previous = contactHistory[i + 1];
|
||||
const [added, removed] = findChanges(entry, previous);
|
||||
const contactNote = getViewContent().querySelector(`[data-contacts="${entry.id}"]`);
|
||||
const updated = getContactUpdateMessage(added, removed);
|
||||
contactNote?.replaceChildren(...updated);
|
||||
});
|
||||
return [evt.tags.filter(isPTag)];
|
||||
}
|
||||
return findChanges(evt, contactHistory[pos + 1]);
|
||||
};
|
||||
|
||||
export const getContactUpdateMessage = (
|
||||
addedList: string[][],
|
||||
removedList: string[][],
|
||||
) => {
|
||||
const content = [];
|
||||
// console.log(addedContacts)
|
||||
if (addedList.length && addedList[0]) {
|
||||
const pubkey = addedList[0][1];
|
||||
const {userName} = getMetadata(pubkey);
|
||||
const npub = nip19.npubEncode(pubkey);
|
||||
content.push(
|
||||
'follows ',
|
||||
elem('a', {href: `/${npub}`, data: {profile: pubkey}}, userName),
|
||||
);
|
||||
}
|
||||
if (addedList.length > 1) {
|
||||
content.push(` (+ ${addedList.length - 1} others)`);
|
||||
}
|
||||
if (removedList?.length > 0) {
|
||||
content.push(elem('small', {}, ` and unfollowed ${removedList.length}`));
|
||||
}
|
||||
return content;
|
||||
};
|
Loading…
Reference in New Issue