mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
add loading state to subscriptions view
This commit is contained in:
@@ -68,6 +68,15 @@ const Board = () => {
|
|||||||
|
|
||||||
const stateString = useStateString(subplebbit?.clients);
|
const stateString = useStateString(subplebbit?.clients);
|
||||||
|
|
||||||
|
const { subscribed, subscribe, unsubscribe } = useSubscribe({subplebbitAddress: selectedAddress});
|
||||||
|
|
||||||
|
const [errorMessage, setErrorMessage] = useState(null);
|
||||||
|
const [successMessage] = useState(null);
|
||||||
|
useError(errorMessage, [errorMessage]);
|
||||||
|
useSuccess(successMessage, [successMessage]);
|
||||||
|
|
||||||
|
const [triggerPublishComment, setTriggerPublishComment] = useState(false);
|
||||||
|
|
||||||
const errorString = useMemo(() => {
|
const errorString = useMemo(() => {
|
||||||
if (subplebbit?.state === 'failed') {
|
if (subplebbit?.state === 'failed') {
|
||||||
let errorString = 'Failed fetching board "' + selectedAddress + '".';
|
let errorString = 'Failed fetching board "' + selectedAddress + '".';
|
||||||
@@ -84,15 +93,6 @@ const Board = () => {
|
|||||||
}
|
}
|
||||||
}, [errorString]);
|
}, [errorString]);
|
||||||
|
|
||||||
const { subscribed, subscribe, unsubscribe } = useSubscribe({subplebbitAddress: selectedAddress});
|
|
||||||
|
|
||||||
const [errorMessage, setErrorMessage] = useState(null);
|
|
||||||
const [successMessage] = useState(null);
|
|
||||||
useError(errorMessage, [errorMessage]);
|
|
||||||
useSuccess(successMessage, [successMessage]);
|
|
||||||
|
|
||||||
const [triggerPublishComment, setTriggerPublishComment] = useState(false);
|
|
||||||
|
|
||||||
|
|
||||||
const flattenedRepliesByThread = useMemo(() => {
|
const flattenedRepliesByThread = useMemo(() => {
|
||||||
return selectedFeed.reduce((acc, thread) => {
|
return selectedFeed.reduce((acc, thread) => {
|
||||||
@@ -541,7 +541,7 @@ const Board = () => {
|
|||||||
{subplebbit?.state === "failed" ? (
|
{subplebbit?.state === "failed" ? (
|
||||||
null
|
null
|
||||||
) : (
|
) : (
|
||||||
feed.length > 1 ? (
|
feed.length > 0 ? (
|
||||||
<Virtuoso
|
<Virtuoso
|
||||||
increaseViewportBy={2000}
|
increaseViewportBy={2000}
|
||||||
data={selectedFeed}
|
data={selectedFeed}
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ const Catalog = () => {
|
|||||||
{subplebbit?.state === "failed" ? (
|
{subplebbit?.state === "failed" ? (
|
||||||
null
|
null
|
||||||
) : (
|
) : (
|
||||||
feed.length > 1 ? (
|
feed.length > 0 ? (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
pageStart={0}
|
pageStart={0}
|
||||||
loadMore={tryLoadMore}
|
loadMore={tryLoadMore}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Helmet } from 'react-helmet-async';
|
|||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { Tooltip } from 'react-tooltip';
|
import { Tooltip } from 'react-tooltip';
|
||||||
import { Virtuoso } from 'react-virtuoso';
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
import { useAccount, useAccountComments, useFeed } from '@plebbit/plebbit-react-hooks';
|
import { useAccount, useAccountComments, useFeed, useSubplebbits } from '@plebbit/plebbit-react-hooks';
|
||||||
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils'
|
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils'
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import useGeneralStore from '../../hooks/stores/useGeneralStore';
|
import useGeneralStore from '../../hooks/stores/useGeneralStore';
|
||||||
@@ -23,6 +23,7 @@ import handleImageClick from '../../utils/handleImageClick';
|
|||||||
import handleQuoteClick from '../../utils/handleQuoteClick';
|
import handleQuoteClick from '../../utils/handleQuoteClick';
|
||||||
import handleStyleChange from '../../utils/handleStyleChange';
|
import handleStyleChange from '../../utils/handleStyleChange';
|
||||||
import useError from '../../hooks/useError';
|
import useError from '../../hooks/useError';
|
||||||
|
import useFeedStateString from '../../hooks/useFeedStateString';
|
||||||
import packageJson from '../../../package.json'
|
import packageJson from '../../../package.json'
|
||||||
const {version} = packageJson
|
const {version} = packageJson
|
||||||
|
|
||||||
@@ -45,15 +46,33 @@ const Subscriptions = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [prevScrollPos, setPrevScrollPos] = useState(0);
|
const [prevScrollPos, setPrevScrollPos] = useState(0);
|
||||||
const [visible, setVisible] = useState(true);
|
const [visible, setVisible] = useState(true);
|
||||||
|
|
||||||
|
const [errorMessage, setErrorMessage] = useState(null);
|
||||||
|
useError(errorMessage, [errorMessage]);
|
||||||
|
|
||||||
const { feed, hasMore, loadMore } = useFeed({subplebbitAddresses: account?.subscriptions, sortType: 'new'});
|
const { feed, hasMore, loadMore } = useFeed({subplebbitAddresses: account?.subscriptions, sortType: 'new'});
|
||||||
const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp));
|
const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp));
|
||||||
|
const {subplebbits} = useSubplebbits({subplebbitAddresses: account?.subscriptions, sortType: 'new'});
|
||||||
|
|
||||||
|
const stateString = useFeedStateString(subplebbits);
|
||||||
|
|
||||||
|
const errorString = useMemo(() => {
|
||||||
|
for (const subplebbit of subplebbits) {
|
||||||
|
if (subplebbit?.updatingState !== 'failed') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const subplebbit of subplebbits) {
|
||||||
|
if (subplebbit?.error) {
|
||||||
|
setErrorMessage(`Failed fetching subplebbit: ${subplebbit?.error.toString().slice(0, 300)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [subplebbits])
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedFeed(feed.sort((a, b) => b.timestamp - a.timestamp));
|
setSelectedFeed(feed.sort((a, b) => b.timestamp - a.timestamp));
|
||||||
}, [feed]);
|
}, [feed]);
|
||||||
|
|
||||||
const [errorMessage] = useState(null);
|
|
||||||
useError(errorMessage, [errorMessage]);
|
|
||||||
|
|
||||||
|
|
||||||
const flattenedRepliesByThread = useMemo(() => {
|
const flattenedRepliesByThread = useMemo(() => {
|
||||||
@@ -258,6 +277,13 @@ const Subscriptions = () => {
|
|||||||
<Link to={`/p/subscriptions/catalog`}>Catalog</Link>
|
<Link to={`/p/subscriptions/catalog`}>Catalog</Link>
|
||||||
]
|
]
|
||||||
</div>
|
</div>
|
||||||
|
{feed.length > 0 ? (
|
||||||
|
null
|
||||||
|
) : (
|
||||||
|
<div id="stats" style={{float: "right", marginTop: "5px"}}>
|
||||||
|
<span>{stateString}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div id="catalog-button-mobile">
|
<div id="catalog-button-mobile">
|
||||||
<span className="btn-wrap">
|
<span className="btn-wrap">
|
||||||
<Link to={`/p/subscriptions/catalog`}>Catalog</Link>
|
<Link to={`/p/subscriptions/catalog`}>Catalog</Link>
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { useMemo } from "react"
|
||||||
|
|
||||||
|
const useFeedStateString = (subplebbits) => {
|
||||||
|
const getClientUrls = (regex) => {
|
||||||
|
const clientUrls = new Set()
|
||||||
|
for (const clientType in subplebbits.clients) {
|
||||||
|
for (const clientUrl in subplebbits.clients[clientType]) {
|
||||||
|
const client = subplebbits.clients[clientType][clientUrl]
|
||||||
|
if (client.state.match(regex)) {
|
||||||
|
clientUrls.add(clientUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...clientUrls]
|
||||||
|
}
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
if (!subplebbits) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const states = {}
|
||||||
|
const clientUrls = {}
|
||||||
|
for (const subplebbit of subplebbits) {
|
||||||
|
states[subplebbit?.updatingState] = (states[subplebbit?.updatingState] || 0) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. Resolving 2 addresses from infura.io, fetching 2 IPNS, 1 IPFS from cloudflare-ipfs.com, ipfs.io
|
||||||
|
let stateString = ''
|
||||||
|
if (states['resolving-address']) {
|
||||||
|
stateString += `resolving ${states['resolving-address']} addresses`
|
||||||
|
const clientUrls = getClientUrls(/address/)
|
||||||
|
if (clientUrls.length) {
|
||||||
|
stateString += ` from ${clientUrls.join(', ')}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (states['fetching-ipns'] || states['fetching-ipfs']) {
|
||||||
|
if (stateString) {
|
||||||
|
stateString += ', '
|
||||||
|
}
|
||||||
|
stateString += `fetching `
|
||||||
|
if (states['fetching-ipns']) {
|
||||||
|
stateString += `${states['fetching-ipns']} IPNS`
|
||||||
|
}
|
||||||
|
if (states['fetching-ipfs']) {
|
||||||
|
if (states['fetching-ipns']) {
|
||||||
|
stateString += ', '
|
||||||
|
}
|
||||||
|
stateString += `${states['fetching-ipfs']} IPNS`
|
||||||
|
}
|
||||||
|
const clientUrls = getClientUrls(/ipfs|ipns/)
|
||||||
|
if (clientUrls.length) {
|
||||||
|
stateString += ` from ${clientUrls.join(', ')}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// capitalize first letter
|
||||||
|
stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1)
|
||||||
|
|
||||||
|
// if string is empty, return undefined instead
|
||||||
|
return stateString || undefined
|
||||||
|
}, [subplebbits])
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useFeedStateString
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
import isValidUrl from '../utils/isValidUrl'
|
||||||
|
|
||||||
const useStateString = (clients) => {
|
const useStateString = (clients) => {
|
||||||
const stateString = useMemo(() => {
|
return useMemo(() => {
|
||||||
if (!clients) {
|
if (!clients) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const states = {}
|
const states = {}
|
||||||
for (const clientType in clients) {
|
for (const clientType in clients) {
|
||||||
for (const clientUrl in clients[clientType]) {
|
for (const clientUrl in clients[clientType]) {
|
||||||
@@ -22,7 +24,12 @@ const useStateString = (clients) => {
|
|||||||
let stateString = ''
|
let stateString = ''
|
||||||
for (const state in states) {
|
for (const state in states) {
|
||||||
const clientUrls = states[state]
|
const clientUrls = states[state]
|
||||||
const clientHosts = clientUrls.map(clientUrl => new URL(clientUrl).hostname)
|
const clientHosts = clientUrls.filter(isValidUrl).map(clientUrl => new URL(clientUrl).hostname)
|
||||||
|
|
||||||
|
// if there are no valid hosts, skip this state
|
||||||
|
if (clientHosts.length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// separate 2 different states using ', '
|
// separate 2 different states using ', '
|
||||||
if (stateString) {
|
if (stateString) {
|
||||||
@@ -35,13 +42,16 @@ const useStateString = (clients) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// capitalize first letter
|
// capitalize first letter
|
||||||
stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1)
|
if (stateString) {
|
||||||
|
stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1)
|
||||||
|
|
||||||
|
console.log("first log:", stateString);
|
||||||
|
}
|
||||||
|
|
||||||
// if string is empty, return undefined instead
|
// if string is empty, return undefined instead
|
||||||
return stateString || undefined
|
console.log("second log:", stateString);
|
||||||
|
return stateString === '' ? undefined : stateString
|
||||||
}, [clients])
|
}, [clients])
|
||||||
|
|
||||||
return stateString
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useStateString
|
export default useStateString
|
||||||
Reference in New Issue
Block a user