Reply to article

This commit is contained in:
Bojan Mojsilovic 2024-06-05 12:16:38 +02:00
parent 5b5afea786
commit ebdda42433
5 changed files with 51 additions and 29 deletions

View File

@ -16,7 +16,7 @@ import styles from './BookmarkNote.module.scss';
import { saveBookmarks } from '../../lib/localStore'; import { saveBookmarks } from '../../lib/localStore';
import { importEvents, triggerImportEvents } from '../../lib/notes'; import { importEvents, triggerImportEvents } from '../../lib/notes';
const BookmarkArticle: Component<{ note: PrimalArticle, large?: boolean }> = (props) => { const BookmarkArticle: Component<{ note: PrimalArticle | undefined, large?: boolean }> = (props) => {
const account = useAccountContext(); const account = useAccountContext();
const app = useAppContext(); const app = useAppContext();
const intl = useIntl(); const intl = useIntl();
@ -24,8 +24,13 @@ const BookmarkArticle: Component<{ note: PrimalArticle, large?: boolean }> = (pr
const [isBookmarked, setIsBookmarked] = createSignal(false); const [isBookmarked, setIsBookmarked] = createSignal(false);
const [bookmarkInProgress, setBookmarkInProgress] = createSignal(false); const [bookmarkInProgress, setBookmarkInProgress] = createSignal(false);
createEffect(() => { createEffect(() => {
setIsBookmarked(() => account?.bookmarks.includes(props.note?.id) || false); const note = props.note;
if (note) {
setIsBookmarked(() => account?.bookmarks.includes(note.id) || false);
}
}) })
const updateBookmarks = async (bookmarkTags: string[][]) => { const updateBookmarks = async (bookmarkTags: string[][]) => {
@ -47,7 +52,7 @@ const BookmarkArticle: Component<{ note: PrimalArticle, large?: boolean }> = (pr
}; };
const addBookmark = async (bookmarkTags: string[][]) => { const addBookmark = async (bookmarkTags: string[][]) => {
if (account && !bookmarkTags.find(b => b[0] === 'e' && b[1] === props.note.id)) { if (account && props.note && !bookmarkTags.find(b => b[0] === 'e' && b[1] === props.note?.id)) {
const bookmarksToAdd = [...bookmarkTags, ['e', props.note.id]]; const bookmarksToAdd = [...bookmarkTags, ['e', props.note.id]];
if (bookmarksToAdd.length < 2) { if (bookmarksToAdd.length < 2) {
@ -73,8 +78,8 @@ const BookmarkArticle: Component<{ note: PrimalArticle, large?: boolean }> = (pr
} }
const removeBookmark = async (bookmarks: string[][]) => { const removeBookmark = async (bookmarks: string[][]) => {
if (account && bookmarks.find(b => b[0] === 'e' && b[1] === props.note.id)) { if (account && bookmarks.find(b => b[0] === 'e' && b[1] === props.note?.id)) {
const bookmarksToAdd = bookmarks.filter(b => b[0] !== 'e' || b[1] !== props.note.id); const bookmarksToAdd = bookmarks.filter(b => b[0] !== 'e' || b[1] !== props.note?.id);
if (bookmarksToAdd.length < 1) { if (bookmarksToAdd.length < 1) {
logWarning('BOOKMARK ISSUE: ', `before_bookmark_${APP_ID}`); logWarning('BOOKMARK ISSUE: ', `before_bookmark_${APP_ID}`);

View File

@ -13,7 +13,7 @@ import { getUserProfiles } from "../../../lib/profile";
import { subscribeTo } from "../../../sockets"; import { subscribeTo } from "../../../sockets";
import { convertToNotes, referencesToTags } from "../../../stores/note"; import { convertToNotes, referencesToTags } from "../../../stores/note";
import { convertToUser, nip05Verification, truncateNpub, userName } from "../../../stores/profile"; import { convertToUser, nip05Verification, truncateNpub, userName } from "../../../stores/profile";
import { EmojiOption, FeedPage, NostrMentionContent, NostrNoteContent, NostrStatsContent, NostrUserContent, PrimalNote, PrimalUser, SendNoteResult } from "../../../types/primal"; import { EmojiOption, FeedPage, NostrMentionContent, NostrNoteContent, NostrStatsContent, NostrUserContent, PrimalArticle, PrimalNote, PrimalUser, SendNoteResult } from "../../../types/primal";
import { debounce, getScreenCordinates, isVisibleInContainer, uuidv4 } from "../../../utils"; import { debounce, getScreenCordinates, isVisibleInContainer, uuidv4 } from "../../../utils";
import Avatar from "../../Avatar/Avatar"; import Avatar from "../../Avatar/Avatar";
import EmbeddedNote from "../../EmbeddedNote/EmbeddedNote"; import EmbeddedNote from "../../EmbeddedNote/EmbeddedNote";
@ -52,7 +52,7 @@ type AutoSizedTextArea = HTMLTextAreaElement & { _baseScrollHeight: number };
const EditBox: Component<{ const EditBox: Component<{
id?: string, id?: string,
replyToNote?: PrimalNote, replyToNote?: PrimalNote | PrimalArticle,
onClose?: () => void, onClose?: () => void,
onSuccess?: (note: SendNoteResult) => void, onSuccess?: (note: SendNoteResult) => void,
open?: boolean, open?: boolean,
@ -587,8 +587,8 @@ const EditBox: Component<{
createEffect(() => { createEffect(() => {
if (props.open) { if (props.open) {
const draft = readNoteDraft(account?.publicKey, props.replyToNote?.post.noteId); const draft = readNoteDraft(account?.publicKey, props.replyToNote?.noteId);
const draftUserRefs = readNoteDraftUserRefs(account?.publicKey, props.replyToNote?.post.noteId); const draftUserRefs = readNoteDraftUserRefs(account?.publicKey, props.replyToNote?.noteId);
setUserRefs(reconcile(draftUserRefs)); setUserRefs(reconcile(draftUserRefs));
@ -618,8 +618,8 @@ const EditBox: Component<{
if (message().length === 0) return; if (message().length === 0) return;
// save draft just in case there is an unintended interuption // save draft just in case there is an unintended interuption
saveNoteDraft(account?.publicKey, message(), props.replyToNote?.post.noteId); saveNoteDraft(account?.publicKey, message(), props.replyToNote?.noteId);
saveNoteDraftUserRefs(account?.publicKey, userRefs, props.replyToNote?.post.noteId); saveNoteDraftUserRefs(account?.publicKey, userRefs, props.replyToNote?.noteId);
}); });
const onEscape = (e: KeyboardEvent) => { const onEscape = (e: KeyboardEvent) => {
@ -667,8 +667,8 @@ const EditBox: Component<{
return; return;
} }
saveNoteDraft(account?.publicKey, '', props.replyToNote?.post.noteId); saveNoteDraft(account?.publicKey, '', props.replyToNote?.noteId);
saveNoteDraftUserRefs(account?.publicKey, {}, props.replyToNote?.post.noteId); saveNoteDraftUserRefs(account?.publicKey, {}, props.replyToNote?.noteId);
clearEditor(); clearEditor();
}; };
@ -680,8 +680,8 @@ const EditBox: Component<{
}; };
const persistNote = (note: string) => { const persistNote = (note: string) => {
saveNoteDraft(account?.publicKey, note, props.replyToNote?.post.noteId); saveNoteDraft(account?.publicKey, note, props.replyToNote?.noteId);
saveNoteDraftUserRefs(account?.publicKey, userRefs, props.replyToNote?.post.noteId); saveNoteDraftUserRefs(account?.publicKey, userRefs, props.replyToNote?.noteId);
clearEditor(); clearEditor();
}; };
@ -721,10 +721,10 @@ const EditBox: Component<{
const rep = props.replyToNote; const rep = props.replyToNote;
if (rep) { if (rep) {
let rootTag = rep.post.tags.find(t => t[0] === 'e' && t[3] === 'root'); let rootTag = rep.msg.tags.find(t => t[0] === 'e' && t[3] === 'root');
const rHints = (rep.post.relayHints && rep.post.relayHints[rep.post.id]) ? const rHints = (rep.relayHints && rep.relayHints[rep.id]) ?
rep.post.relayHints[rep.post.id] : rep.relayHints[rep.id] :
''; '';
// If the note has a root tag, that meens it is not a root note itself // If the note has a root tag, that meens it is not a root note itself
@ -735,26 +735,26 @@ const EditBox: Component<{
v, v,
); );
tags.push([...tagWithHint]); tags.push([...tagWithHint]);
tags.push(['e', rep.post.id, rHints, 'reply']); tags.push(['e', rep.id, rHints, 'reply']);
} }
// Otherwise, add the note as the root tag for this reply // Otherwise, add the note as the root tag for this reply
else { else {
tags.push([ tags.push([
'e', 'e',
rep.post.id, rep.id,
rHints, rHints,
'root', 'root',
]); ]);
} }
// Copy all `p` tags from the note we are repling to // Copy all `p` tags from the note we are repling to
const repPeople = rep.post.tags.filter(t => t[0] === 'p'); const repPeople = rep.msg.tags.filter(t => t[0] === 'p');
tags = [...tags, ...(unwrap(repPeople))]; tags = [...tags, ...(unwrap(repPeople))];
// If the author of the note is missing, add them // If the author of the note is missing, add them
if (!tags.find(t => t[0] === 'p' && t[1] === rep.post.pubkey)) { if (!tags.find(t => t[0] === 'p' && t[1] === rep.pubkey)) {
tags.push(['p', rep.post.pubkey]); tags.push(['p', rep.pubkey]);
} }
} }
@ -772,7 +772,7 @@ const EditBox: Component<{
toast?.sendSuccess(intl.formatMessage(tToast.publishNoteSuccess)); toast?.sendSuccess(intl.formatMessage(tToast.publishNoteSuccess));
props.onSuccess && props.onSuccess({ success, reasons, note }); props.onSuccess && props.onSuccess({ success, reasons, note });
setIsPostingInProgress(false); setIsPostingInProgress(false);
saveNoteDraft(account.publicKey, '', rep?.post.noteId) saveNoteDraft(account.publicKey, '', rep?.noteId)
clearEditor(); clearEditor();
} }
unsub(); unsub();
@ -1046,7 +1046,7 @@ const EditBox: Component<{
// // setNoteRefs((refs) => ({ // // setNoteRefs((refs) => ({
// // ...refs, // // ...refs,
// // [newNote.post.noteId]: newNote // // [newNote.noteId]: newNote
// // })); // // }));
subUserRef(hex); subUserRef(hex);
@ -1107,10 +1107,10 @@ const EditBox: Component<{
setNoteRefs((refs) => ({ setNoteRefs((refs) => ({
...refs, ...refs,
[newNote.post.noteId]: newNote [newNote.noteId]: newNote
})); }));
subNoteRef(newNote.post.noteId); subNoteRef(newNote.noteId);
unsub(); unsub();
return; return;

View File

@ -12,7 +12,7 @@ import { SolidMarkdown } from "solid-markdown";
import styles from './Longform.module.scss'; import styles from './Longform.module.scss';
import Loader from "../components/Loader/Loader"; import Loader from "../components/Loader/Loader";
import { FeedPage, NostrEventContent, NostrMentionContent, NostrNoteActionsContent, NostrNoteContent, NostrStatsContent, NostrUserContent, NoteActions, PrimalArticle, PrimalNote, PrimalUser, TopZap, ZapOption } from "../types/primal"; import { FeedPage, NostrEventContent, NostrMentionContent, NostrNoteActionsContent, NostrNoteContent, NostrStatsContent, NostrUserContent, NoteActions, PrimalArticle, PrimalNote, PrimalUser, SendNoteResult, TopZap, ZapOption } from "../types/primal";
import { getUserProfileInfo, getUserProfiles } from "../lib/profile"; import { getUserProfileInfo, getUserProfiles } from "../lib/profile";
import { convertToUser, nip05Verification, userName } from "../stores/profile"; import { convertToUser, nip05Verification, userName } from "../stores/profile";
import Avatar from "../components/Avatar/Avatar"; import Avatar from "../components/Avatar/Avatar";
@ -46,6 +46,8 @@ import Wormhole from "../components/Wormhole/Wormhole";
import Search from "../components/Search/Search"; import Search from "../components/Search/Search";
import ArticleSidebar from "../components/HomeSidebar/ArticleSidebar"; import ArticleSidebar from "../components/HomeSidebar/ArticleSidebar";
import ReplyToNote from "../components/ReplyToNote/ReplyToNote"; import ReplyToNote from "../components/ReplyToNote/ReplyToNote";
import { sanitize } from "dompurify";
import { fetchNotes } from "../handleNotes";
export type LongFormData = { export type LongFormData = {
title: string, title: string,
@ -777,6 +779,17 @@ const Longform: Component< { naddr: string } > = (props) => {
); );
} }
const onReplyPosted = async (result: SendNoteResult) => {
const { success, note } = result;
if (!success || !note || !account) return;
const replies = await fetchNotes(account.publicKey, [note.id], `reads_reply_${APP_ID}`);
updateStore('replies', (reps) => [ ...replies, ...reps]);
};
return ( return (
<> <>
<Wormhole <Wormhole
@ -897,7 +910,7 @@ const Longform: Component< { naddr: string } > = (props) => {
<Show when={store.article}> <Show when={store.article}>
<ReplyToNote <ReplyToNote
note={store.article} note={store.article}
onNotePosted={() => {}} onNotePosted={onReplyPosted}
/> />
</Show> </Show>

View File

@ -370,6 +370,7 @@ export const convertToNotes: ConvertToNotes = (page, topZaps) => {
pubkey: msg.pubkey, pubkey: msg.pubkey,
topZaps: [ ...tz ], topZaps: [ ...tz ],
content: sanitize(msg.content), content: sanitize(msg.content),
relayHints: page.relayHints,
}; };
}); });
} }
@ -486,6 +487,7 @@ export const convertToArticles: ConvertToArticles = (page, topZaps) => {
score: stat?.score || 0, score: stat?.score || 0,
score24h: stat?.score24h || 0, score24h: stat?.score24h || 0,
satszapped: stat?.satszapped || 0, satszapped: stat?.satszapped || 0,
relayHints: page.relayHints,
}; };
msg.tags.forEach(tag => { msg.tags.forEach(tag => {

View File

@ -502,6 +502,7 @@ export type PrimalNote = {
tags: string[][], tags: string[][],
topZaps: TopZap[], topZaps: TopZap[],
content: string, content: string,
relayHints?: Record<string, string>,
}; };
@ -534,6 +535,7 @@ export type PrimalArticle = {
score24h: number, score24h: number,
satszapped: number, satszapped: number,
client?: string, client?: string,
relayHints?: Record<string, string>,
}; };
export type PrimalFeed = { export type PrimalFeed = {