From ce6a3c567d4ef9c2fa1104ed972cc16ff06de89a Mon Sep 17 00:00:00 2001 From: Bojan Mojsilovic Date: Fri, 15 Mar 2024 14:45:19 +0100 Subject: [PATCH] Add reaction pagination and adjust width --- .../ReactionsModal/ReactionsModal.module.scss | 8 +- .../ReactionsModal/ReactionsModal.tsx | 243 +++++++++++------- src/lib/notes.tsx | 4 +- src/translations.ts | 15 ++ 4 files changed, 168 insertions(+), 102 deletions(-) diff --git a/src/components/ReactionsModal/ReactionsModal.module.scss b/src/components/ReactionsModal/ReactionsModal.module.scss index dc12d70..31d712b 100644 --- a/src/components/ReactionsModal/ReactionsModal.module.scss +++ b/src/components/ReactionsModal/ReactionsModal.module.scss @@ -1,6 +1,6 @@ .ReactionsModal { position: fixed; - width: 432px; + width: 632px; color: var(--text-primary); background-color: var(--background-input); border-radius: 8px; @@ -157,7 +157,7 @@ font-size: 16px; font-weight: 700; line-height: 16px; - max-width: 248px; + max-width: 448px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -223,7 +223,7 @@ font-size: 16px; font-weight: 700; line-height: 16px; - max-width: 248px; + max-width: 448px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -279,7 +279,7 @@ font-size: 16px; font-weight: 700; line-height: 16px; - max-width: 248px; + max-width: 448px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/src/components/ReactionsModal/ReactionsModal.tsx b/src/components/ReactionsModal/ReactionsModal.tsx index c360fb7..6530865 100644 --- a/src/components/ReactionsModal/ReactionsModal.tsx +++ b/src/components/ReactionsModal/ReactionsModal.tsx @@ -3,28 +3,21 @@ import { Tabs } from '@kobalte/core'; import { A } from '@solidjs/router'; import { Component, createEffect, createSignal, For, Show } from 'solid-js'; import { createStore } from 'solid-js/store'; -import { style } from 'solid-js/web'; import { APP_ID } from '../../App'; -import { defaultZapOptions, Kind } from '../../constants'; -import { useAccountContext } from '../../contexts/AccountContext'; +import { Kind } from '../../constants'; import { ReactionStats } from '../../contexts/AppContext'; -import { useSettingsContext } from '../../contexts/SettingsContext'; import { hookForDev } from '../../lib/devTools'; import { hexToNpub } from '../../lib/keys'; import { getEventReactions } from '../../lib/notes'; import { truncateNumber } from '../../lib/notifications'; -import { zapNote, zapProfile } from '../../lib/zap'; import { subscribeTo } from '../../sockets'; import { userName } from '../../stores/profile'; -import { toastZapFail, zapCustomOption, actions as tActions, placeholders as tPlaceholders, zapCustomAmount } from '../../translations'; -import { PrimalNote, PrimalUser, ZapOption } from '../../types/primal'; +import { actions as tActions, placeholders as tPlaceholders } from '../../translations'; import { parseBolt11 } from '../../utils'; import Avatar from '../Avatar/Avatar'; -import ButtonPrimary from '../Buttons/ButtonPrimary'; import Loader from '../Loader/Loader'; import Modal from '../Modal/Modal'; -import TextInput from '../TextInput/TextInput'; -import { useToastContext } from '../Toaster/Toaster'; +import Paginator from '../Paginator/Paginator'; import VerificationCheck from '../VerificationCheck/VerificationCheck'; import styles from './ReactionsModal.module.scss'; @@ -44,18 +37,22 @@ const ReactionsModal: Component<{ const [zapList, setZapList] = createStore([]); const [repostList, setRepostList] = createStore([]); - const [isFetching, setIsFetching] = createSignal(false) + const [isFetching, setIsFetching] = createSignal(false); + + let loadedLikes = 0; + let loadedZaps = 0; + let loadedReposts = 0; createEffect(() => { switch (selectedTab()) { case 'likes': - getLikes(); + loadedLikes === 0 && getLikes(); break; case 'zaps': - getZaps(); + loadedZaps === 0 && getZaps(); break; case 'reposts': - getReposts(); + loadedReposts === 0 && getReposts(); break; } }); @@ -69,7 +66,7 @@ const ReactionsModal: Component<{ } }); - const getLikes = () => { + const getLikes = (offset = 0) => { if (!props.noteId) return; const subId = `nr_l_${props.noteId}_${APP_ID}`; @@ -78,7 +75,8 @@ const ReactionsModal: Component<{ const unsub = subscribeTo(subId, (type,_, content) => { if (type === 'EOSE') { - setLikeList(() => [...users]); + setLikeList((likes) => [ ...likes, ...users ]); + loadedLikes = likeList.length; setIsFetching(() => false); unsub(); } @@ -102,10 +100,10 @@ const ReactionsModal: Component<{ }); setIsFetching(() => true); - getEventReactions(props.noteId, Kind.Reaction, subId); + getEventReactions(props.noteId, Kind.Reaction, subId, offset); }; - const getZaps = () => { + const getZaps = (offset = 0) => { if (!props.noteId) return; const subId = `nr_z_${props.noteId}_${APP_ID}`; @@ -120,7 +118,8 @@ const ReactionsModal: Component<{ sender: users[zap.pubkey], }))); - setZapList(() => [ ...zapData ]); + setZapList((zapItems) => [ ...zapItems, ...zapData ]); + loadedZaps = zapList.length; setIsFetching(() => false); unsub(); } @@ -174,10 +173,10 @@ const ReactionsModal: Component<{ }); setIsFetching(() => true); - getEventReactions(props.noteId, Kind.Zap, subId); + getEventReactions(props.noteId, Kind.Zap, subId, offset); }; - const getReposts = () => { + const getReposts = (offset = 0) => { if (!props.noteId) return; const subId = `nr_r_${props.noteId}_${APP_ID}`; @@ -186,7 +185,8 @@ const ReactionsModal: Component<{ const unsub = subscribeTo(subId, (type,_, content) => { if (type === 'EOSE') { - setRepostList(() => [...users]); + setRepostList((reposts) => [...reposts, ...users]); + loadedReposts = repostList.length; setIsFetching(() => false); unsub(); } @@ -210,7 +210,7 @@ const ReactionsModal: Component<{ }); setIsFetching(() => true); - getEventReactions(props.noteId, Kind.Repost, subId); + getEventReactions(props.noteId, Kind.Repost, subId, offset); }; const totalCount = () => props.stats.likes + props.stats.quotes + props.stats.reposts + props.stats.zaps; @@ -259,93 +259,144 @@ const ReactionsModal: Component<{ - } + + {intl.formatMessage(tPlaceholders.noLikeDetails)} + + } > - - {admirer => - -
- -
-
- {userName(admirer)} -
- + {admirer => +
+
+ +
+ + } + + + + { + const len = likeList.length; + if (len === 0) return; + getLikes(len); + }} + isSmall={true} + /> + + + + - } + + {intl.formatMessage(tPlaceholders.noZapDetails)} + + } > - - {zap => - -
-
-
{truncateNumber(zap.amount)}
-
- -
-
-
- {userName(zap.sender)} -
- -
-
- {zap.message} + {zap => + +
+
+
{truncateNumber(zap.amount)}
+
+ +
+
+
+ {userName(zap.sender)}
+
-
- } - +
+ {zap.message} +
+
+ + } + + + + { + const len = zapList.length; + if (len === 0) return; + getZaps(len); + }} + isSmall={true} + /> + + + + - } + + {intl.formatMessage(tPlaceholders.noRepostDetails)} + + } > - - {reposter => - -
- -
-
- {userName(reposter)} -
- + {reposter => +
+
+ +
+ + } + + + + { + const len = repostList.length; + if (len === 0) return; + getReposts(len); + }} + isSmall={true} + /> + + + + diff --git a/src/lib/notes.tsx b/src/lib/notes.tsx index e78edb3..0fa1cd0 100644 --- a/src/lib/notes.tsx +++ b/src/lib/notes.tsx @@ -470,10 +470,10 @@ export const triggerImportEvents = (events: NostrRelaySignedEvent[], subId: stri }; -export const getEventReactions = (eventId: string, kind: number, subid: string) => { +export const getEventReactions = (eventId: string, kind: number, subid: string, offset = 0) => { sendMessage(JSON.stringify([ "REQ", subid, - {cache: ["event_actions", { event_id: eventId, kind, limit: 100 }]}, + {cache: ["event_actions", { event_id: eventId, kind, limit: 20, offset }]}, ])); }; diff --git a/src/translations.ts b/src/translations.ts index e3b891a..9cef1af 100644 --- a/src/translations.ts +++ b/src/translations.ts @@ -982,6 +982,21 @@ export const notifications = { }; export const placeholders = { + noLikeDetails: { + id: 'placeholders.noLikeDetails', + defaultMessage: 'No details for likes found', + description: 'Placeholder when there are no like details in reactions modal', + }, + noZapDetails: { + id: 'placeholders.noZapDetails', + defaultMessage: 'No details for zaps found', + description: 'Placeholder when there are no zap details in reactions modal', + }, + noRepostDetails: { + id: 'placeholders.noRepostDetails', + defaultMessage: 'No details for reposts found', + description: 'Placeholder when there are no repost details in reactions modal', + }, addComment: { id: 'placeholders.addComment', defaultMessage: 'Add a comment...',