mirror of
https://github.com/PrimalHQ/primal-web-app.git
synced 2024-10-01 17:31:13 +00:00
Add reaction pagination and adjust width
This commit is contained in:
parent
6bf10e83a1
commit
ce6a3c567d
@ -1,6 +1,6 @@
|
|||||||
.ReactionsModal {
|
.ReactionsModal {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 432px;
|
width: 632px;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
background-color: var(--background-input);
|
background-color: var(--background-input);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -157,7 +157,7 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
max-width: 248px;
|
max-width: 448px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -223,7 +223,7 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
max-width: 248px;
|
max-width: 448px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -279,7 +279,7 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
max-width: 248px;
|
max-width: 448px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -3,28 +3,21 @@ import { Tabs } from '@kobalte/core';
|
|||||||
import { A } from '@solidjs/router';
|
import { A } from '@solidjs/router';
|
||||||
import { Component, createEffect, createSignal, For, Show } from 'solid-js';
|
import { Component, createEffect, createSignal, For, Show } from 'solid-js';
|
||||||
import { createStore } from 'solid-js/store';
|
import { createStore } from 'solid-js/store';
|
||||||
import { style } from 'solid-js/web';
|
|
||||||
import { APP_ID } from '../../App';
|
import { APP_ID } from '../../App';
|
||||||
import { defaultZapOptions, Kind } from '../../constants';
|
import { Kind } from '../../constants';
|
||||||
import { useAccountContext } from '../../contexts/AccountContext';
|
|
||||||
import { ReactionStats } from '../../contexts/AppContext';
|
import { ReactionStats } from '../../contexts/AppContext';
|
||||||
import { useSettingsContext } from '../../contexts/SettingsContext';
|
|
||||||
import { hookForDev } from '../../lib/devTools';
|
import { hookForDev } from '../../lib/devTools';
|
||||||
import { hexToNpub } from '../../lib/keys';
|
import { hexToNpub } from '../../lib/keys';
|
||||||
import { getEventReactions } from '../../lib/notes';
|
import { getEventReactions } from '../../lib/notes';
|
||||||
import { truncateNumber } from '../../lib/notifications';
|
import { truncateNumber } from '../../lib/notifications';
|
||||||
import { zapNote, zapProfile } from '../../lib/zap';
|
|
||||||
import { subscribeTo } from '../../sockets';
|
import { subscribeTo } from '../../sockets';
|
||||||
import { userName } from '../../stores/profile';
|
import { userName } from '../../stores/profile';
|
||||||
import { toastZapFail, zapCustomOption, actions as tActions, placeholders as tPlaceholders, zapCustomAmount } from '../../translations';
|
import { actions as tActions, placeholders as tPlaceholders } from '../../translations';
|
||||||
import { PrimalNote, PrimalUser, ZapOption } from '../../types/primal';
|
|
||||||
import { parseBolt11 } from '../../utils';
|
import { parseBolt11 } from '../../utils';
|
||||||
import Avatar from '../Avatar/Avatar';
|
import Avatar from '../Avatar/Avatar';
|
||||||
import ButtonPrimary from '../Buttons/ButtonPrimary';
|
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
import Modal from '../Modal/Modal';
|
import Modal from '../Modal/Modal';
|
||||||
import TextInput from '../TextInput/TextInput';
|
import Paginator from '../Paginator/Paginator';
|
||||||
import { useToastContext } from '../Toaster/Toaster';
|
|
||||||
import VerificationCheck from '../VerificationCheck/VerificationCheck';
|
import VerificationCheck from '../VerificationCheck/VerificationCheck';
|
||||||
|
|
||||||
import styles from './ReactionsModal.module.scss';
|
import styles from './ReactionsModal.module.scss';
|
||||||
@ -44,18 +37,22 @@ const ReactionsModal: Component<{
|
|||||||
const [zapList, setZapList] = createStore<any[]>([]);
|
const [zapList, setZapList] = createStore<any[]>([]);
|
||||||
const [repostList, setRepostList] = createStore<any[]>([]);
|
const [repostList, setRepostList] = createStore<any[]>([]);
|
||||||
|
|
||||||
const [isFetching, setIsFetching] = createSignal(false)
|
const [isFetching, setIsFetching] = createSignal(false);
|
||||||
|
|
||||||
|
let loadedLikes = 0;
|
||||||
|
let loadedZaps = 0;
|
||||||
|
let loadedReposts = 0;
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
switch (selectedTab()) {
|
switch (selectedTab()) {
|
||||||
case 'likes':
|
case 'likes':
|
||||||
getLikes();
|
loadedLikes === 0 && getLikes();
|
||||||
break;
|
break;
|
||||||
case 'zaps':
|
case 'zaps':
|
||||||
getZaps();
|
loadedZaps === 0 && getZaps();
|
||||||
break;
|
break;
|
||||||
case 'reposts':
|
case 'reposts':
|
||||||
getReposts();
|
loadedReposts === 0 && getReposts();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -69,7 +66,7 @@ const ReactionsModal: Component<{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getLikes = () => {
|
const getLikes = (offset = 0) => {
|
||||||
if (!props.noteId) return;
|
if (!props.noteId) return;
|
||||||
|
|
||||||
const subId = `nr_l_${props.noteId}_${APP_ID}`;
|
const subId = `nr_l_${props.noteId}_${APP_ID}`;
|
||||||
@ -78,7 +75,8 @@ const ReactionsModal: Component<{
|
|||||||
|
|
||||||
const unsub = subscribeTo(subId, (type,_, content) => {
|
const unsub = subscribeTo(subId, (type,_, content) => {
|
||||||
if (type === 'EOSE') {
|
if (type === 'EOSE') {
|
||||||
setLikeList(() => [...users]);
|
setLikeList((likes) => [ ...likes, ...users ]);
|
||||||
|
loadedLikes = likeList.length;
|
||||||
setIsFetching(() => false);
|
setIsFetching(() => false);
|
||||||
unsub();
|
unsub();
|
||||||
}
|
}
|
||||||
@ -102,10 +100,10 @@ const ReactionsModal: Component<{
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsFetching(() => true);
|
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;
|
if (!props.noteId) return;
|
||||||
|
|
||||||
const subId = `nr_z_${props.noteId}_${APP_ID}`;
|
const subId = `nr_z_${props.noteId}_${APP_ID}`;
|
||||||
@ -120,7 +118,8 @@ const ReactionsModal: Component<{
|
|||||||
sender: users[zap.pubkey],
|
sender: users[zap.pubkey],
|
||||||
})));
|
})));
|
||||||
|
|
||||||
setZapList(() => [ ...zapData ]);
|
setZapList((zapItems) => [ ...zapItems, ...zapData ]);
|
||||||
|
loadedZaps = zapList.length;
|
||||||
setIsFetching(() => false);
|
setIsFetching(() => false);
|
||||||
unsub();
|
unsub();
|
||||||
}
|
}
|
||||||
@ -174,10 +173,10 @@ const ReactionsModal: Component<{
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsFetching(() => true);
|
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;
|
if (!props.noteId) return;
|
||||||
|
|
||||||
const subId = `nr_r_${props.noteId}_${APP_ID}`;
|
const subId = `nr_r_${props.noteId}_${APP_ID}`;
|
||||||
@ -186,7 +185,8 @@ const ReactionsModal: Component<{
|
|||||||
|
|
||||||
const unsub = subscribeTo(subId, (type,_, content) => {
|
const unsub = subscribeTo(subId, (type,_, content) => {
|
||||||
if (type === 'EOSE') {
|
if (type === 'EOSE') {
|
||||||
setRepostList(() => [...users]);
|
setRepostList((reposts) => [...reposts, ...users]);
|
||||||
|
loadedReposts = repostList.length;
|
||||||
setIsFetching(() => false);
|
setIsFetching(() => false);
|
||||||
unsub();
|
unsub();
|
||||||
}
|
}
|
||||||
@ -210,7 +210,7 @@ const ReactionsModal: Component<{
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsFetching(() => true);
|
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;
|
const totalCount = () => props.stats.likes + props.stats.quotes + props.stats.reposts + props.stats.zaps;
|
||||||
@ -259,12 +259,13 @@ const ReactionsModal: Component<{
|
|||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
|
|
||||||
<Tabs.Content class={styles.tabContent} value={'likes'}>
|
<Tabs.Content class={styles.tabContent} value={'likes'}>
|
||||||
<Show
|
|
||||||
when={!isFetching()}
|
|
||||||
fallback={<Loader />}
|
|
||||||
>
|
|
||||||
<For
|
<For
|
||||||
each={likeList}
|
each={likeList}
|
||||||
|
fallback={
|
||||||
|
<Show when={!isFetching()}>
|
||||||
|
{intl.formatMessage(tPlaceholders.noLikeDetails)}
|
||||||
|
</Show>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{admirer =>
|
{admirer =>
|
||||||
<A
|
<A
|
||||||
@ -283,16 +284,33 @@ const ReactionsModal: Component<{
|
|||||||
</A>
|
</A>
|
||||||
}
|
}
|
||||||
</For>
|
</For>
|
||||||
|
|
||||||
|
<Show when={likeList.length < props.stats.likes}>
|
||||||
|
<Paginator
|
||||||
|
loadNextPage={() => {
|
||||||
|
const len = likeList.length;
|
||||||
|
if (len === 0) return;
|
||||||
|
getLikes(len);
|
||||||
|
}}
|
||||||
|
isSmall={true}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show
|
||||||
|
when={isFetching()}
|
||||||
|
>
|
||||||
|
<Loader />
|
||||||
</Show>
|
</Show>
|
||||||
</Tabs.Content>
|
</Tabs.Content>
|
||||||
|
|
||||||
<Tabs.Content class={styles.tabContent} value={'zaps'}>
|
<Tabs.Content class={styles.tabContent} value={'zaps'}>
|
||||||
<Show
|
|
||||||
when={!isFetching()}
|
|
||||||
fallback={<Loader />}
|
|
||||||
>
|
|
||||||
<For
|
<For
|
||||||
each={zapList}
|
each={zapList}
|
||||||
|
fallback={
|
||||||
|
<Show when={!isFetching()}>
|
||||||
|
{intl.formatMessage(tPlaceholders.noZapDetails)}
|
||||||
|
</Show>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{zap =>
|
{zap =>
|
||||||
<A
|
<A
|
||||||
@ -319,15 +337,32 @@ const ReactionsModal: Component<{
|
|||||||
</A>
|
</A>
|
||||||
}
|
}
|
||||||
</For>
|
</For>
|
||||||
|
|
||||||
|
<Show when={zapList.length < props.stats.zaps}>
|
||||||
|
<Paginator
|
||||||
|
loadNextPage={() => {
|
||||||
|
const len = zapList.length;
|
||||||
|
if (len === 0) return;
|
||||||
|
getZaps(len);
|
||||||
|
}}
|
||||||
|
isSmall={true}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show
|
||||||
|
when={isFetching()}
|
||||||
|
>
|
||||||
|
<Loader />
|
||||||
</Show>
|
</Show>
|
||||||
</Tabs.Content>
|
</Tabs.Content>
|
||||||
<Tabs.Content class={styles.tabContent} value={'reposts'}>
|
<Tabs.Content class={styles.tabContent} value={'reposts'}>
|
||||||
<Show
|
|
||||||
when={!isFetching()}
|
|
||||||
fallback={<Loader />}
|
|
||||||
>
|
|
||||||
<For
|
<For
|
||||||
each={repostList}
|
each={repostList}
|
||||||
|
fallback={
|
||||||
|
<Show when={!isFetching()}>
|
||||||
|
{intl.formatMessage(tPlaceholders.noRepostDetails)}
|
||||||
|
</Show>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{reposter =>
|
{reposter =>
|
||||||
<A
|
<A
|
||||||
@ -346,6 +381,22 @@ const ReactionsModal: Component<{
|
|||||||
</A>
|
</A>
|
||||||
}
|
}
|
||||||
</For>
|
</For>
|
||||||
|
|
||||||
|
<Show when={repostList.length < props.stats.reposts}>
|
||||||
|
<Paginator
|
||||||
|
loadNextPage={() => {
|
||||||
|
const len = repostList.length;
|
||||||
|
if (len === 0) return;
|
||||||
|
getReposts(len);
|
||||||
|
}}
|
||||||
|
isSmall={true}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show
|
||||||
|
when={isFetching()}
|
||||||
|
>
|
||||||
|
<Loader />
|
||||||
</Show>
|
</Show>
|
||||||
</Tabs.Content>
|
</Tabs.Content>
|
||||||
<Tabs.Content class={styles.tabContent} value={'quotes'}>
|
<Tabs.Content class={styles.tabContent} value={'quotes'}>
|
||||||
|
@ -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([
|
sendMessage(JSON.stringify([
|
||||||
"REQ",
|
"REQ",
|
||||||
subid,
|
subid,
|
||||||
{cache: ["event_actions", { event_id: eventId, kind, limit: 100 }]},
|
{cache: ["event_actions", { event_id: eventId, kind, limit: 20, offset }]},
|
||||||
]));
|
]));
|
||||||
};
|
};
|
||||||
|
@ -982,6 +982,21 @@ export const notifications = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const placeholders = {
|
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: {
|
addComment: {
|
||||||
id: 'placeholders.addComment',
|
id: 'placeholders.addComment',
|
||||||
defaultMessage: 'Add a comment...',
|
defaultMessage: 'Add a comment...',
|
||||||
|
Loading…
Reference in New Issue
Block a user