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