From 8f086e7d3809c6715fc7b15b9330dddc23e44054 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 8 May 2023 18:08:50 +0200 Subject: [PATCH 01/17] update formatState.js --- src/utils/formatState.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/formatState.js b/src/utils/formatState.js index 4218972e..6251a7b2 100644 --- a/src/utils/formatState.js +++ b/src/utils/formatState.js @@ -17,7 +17,7 @@ function formatState(str) { } }); - if (formattedWords.includes("Failed")) { + if (formattedWords[0] === "Failed" || formattedWords[0] === "Succeeded") { return formattedWords.join(" ") + "."; } From fdcb090144cb704ea998a72c835e424c50c5fe9c Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 8 May 2023 18:29:56 +0200 Subject: [PATCH 02/17] add new offline icon --- public/assets/offline.png | Bin 859 -> 1122 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/assets/offline.png b/public/assets/offline.png index a40aa2bb0c843be979468f70180b57f687fcaae8..dd343f6aefe6965cd494106d530fca2b3f4e9e5a 100644 GIT binary patch delta 577 zcmcc3_K0JG3NK5#qpu?a!^VE@KZ&dp^}3jt3?}Zn%$!=0Ie7x3I46)!(>K&J(4Sn% z=u!{jSp{TPq~=7rWag&k6=&w>*%=wx=wp@OQh)&)gnR@pjYtyc8lCfV@{58C5=E0! z?F^xo!NihNCvRj-t8X#;vXy~>G1Sw=F~mafY{*Uc{S_V&z#3DimrQ~D($rRR(<}M;@X(XpGCJqtADQdVMRHse1#Nr8J2P|EKGuuh_eNiz%A(qq{M6ZUXy%k`eKw@*06&pX>GWY+@21s8T7HkJ|fTHP_D*Exc- zpyHTd8>3XPdQzUW=92rHEG-t?EBm z6?tfWll$tIy$`ZJX4c(cI{QO#oza;yyEV#}By+eaO~0=l`{dcbe&vb&=It%(mrs5b q9p5au{D&3W{JJXlO1DS*ck5fvTl1~fs#u-@2s~Z=T-G@yGywp;SoPij delta 361 zcmV-v0ha#a2-^mbBnkm@Qb$4nuFf3kkuiz_0a=l~)04*mFq4-8T7MZ{;RgT!0VqjC zK~y*qt&>d-gFpy{ou;dvp!Hxb-FhCEZe4n@9-v9LQz7#RB7^-iF;d>+0~wo|_{y=| zq?+yt0$Y})R>%3S>$JXMot1K@c%ElT4Z|R@7ie$a_gugFZrYotY2tfL(!{v6$BWt5 zwymvaZyv`HAbNg#F@FOr+6!Qt9ThsXTC-}6ClG{z9~|C}vr7;ZKy&K5sg2KLNew}H zSD0E9KVYw_@m&RWv{$bf!+6?%bKzc8EBh9 Date: Mon, 8 May 2023 18:45:01 +0200 Subject: [PATCH 03/17] improve offline indicators styling --- src/components/styled/Board.styled.jsx | 92 +++++++++++++++----------- src/components/styled/Home.styled.jsx | 5 +- src/components/views/Board.jsx | 15 ++--- src/components/views/Subscriptions.jsx | 31 ++++++--- 4 files changed, 82 insertions(+), 61 deletions(-) diff --git a/src/components/styled/Board.styled.jsx b/src/components/styled/Board.styled.jsx index 50d5ebee..c3981457 100644 --- a/src/components/styled/Board.styled.jsx +++ b/src/components/styled/Board.styled.jsx @@ -30,12 +30,6 @@ export const NavBar = styled.div` #board-nav-mobile { display: none; } - - .offline-nav { - width: 12px; - position: relative; - margin: 2px 2px -2px -2px; - } } @media (max-width: 480px) { @@ -244,13 +238,14 @@ export const Header = styled.div` margin: 5px auto; width: 300px; height: 100px; + + img { + border: none; + width: 300px; + height: 100px; + } } - img { - border: none; - width: 300px; - height: 100px; - } .board-title { font-family: Tahoma, sans-serif; @@ -276,13 +271,14 @@ export const Header = styled.div` margin: 5px auto; width: 300px; height: 100px; + + img { + border: none; + width: 300px; + height: 100px; + } } - img { - border: none; - width: 300px; - height: 100px; - } .board-title { font-family: Tahoma, sans-serif; @@ -307,13 +303,14 @@ export const Header = styled.div` margin: 5px auto; width: 300px; height: 100px; + + img { + border: none; + width: 300px; + height: 100px; + } } - img { - border: none; - width: 300px; - height: 100px; - } .board-title { font-size: 24pt; @@ -336,13 +333,14 @@ export const Header = styled.div` margin: 5px auto; width: 300px; height: 100px; + + img { + border: none; + width: 300px; + height: 100px; + } } - img { - border: none; - width: 300px; - height: 100px; - } .board-title { font-size: 24pt; @@ -366,12 +364,12 @@ export const Header = styled.div` width: 300px; height: 100px; max-width: 100%; - } - img { - border: none; - width: 300px; - height: 100px; + img { + border: none; + width: 300px; + height: 100px; + } } .board-title { @@ -397,13 +395,14 @@ export const Header = styled.div` margin: 5px auto; width: 300px; height: 100px; + + img { + border: none; + width: 300px; + height: 100px; + } } - img { - border: none; - width: 300px; - height: 100px; - } .board-title { font-family: Tahoma, sans-serif; @@ -424,6 +423,12 @@ export const Header = styled.div` return ''; } }} + + .offline { + width: 16px; + position: relative; + margin: 2px 2px -4px 2px; + } `; export const Break = styled.hr` @@ -1626,7 +1631,14 @@ export const BoardForm = styled.div` .offline-sub { width: 13px; margin-right: -5px; - margin-bottom: -2px; + margin-bottom: -3px; + position: relative; + } + + .offline-reply { + width: 13px; + margin-right: 2px; + margin-bottom: -3px; position: relative; } @@ -2981,12 +2993,14 @@ export const BoardForm = styled.div` margin-bottom: 335px; .offline-mobile-sub { - width: 18px; + width: 13px; + margin-top: 3px; margin-right: 5px; } .offline-mobile-sub-reply { - width: 15px; + width: 13px; + margin-top: 3px; } .thread { diff --git a/src/components/styled/Home.styled.jsx b/src/components/styled/Home.styled.jsx index a9d0026a..199d83a9 100644 --- a/src/components/styled/Home.styled.jsx +++ b/src/components/styled/Home.styled.jsx @@ -240,14 +240,11 @@ export const BoardsContent = styled.div` object-fit: cover; } - .board-avatar-container img.offline { - filter: brightness(50%); - } - .offline-indicator { position: absolute; top: 5px; right: 5px; + width: 16px; } .board-text { diff --git a/src/components/views/Board.jsx b/src/components/views/Board.jsx index c3338104..58dd2a43 100644 --- a/src/components/views/Board.jsx +++ b/src/components/views/Board.jsx @@ -370,10 +370,6 @@ const Board = () => { {index === 0 ? null : "\u00a0"} handleClickTitle(subplebbit.title, subplebbit.address)} >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} ))} @@ -428,10 +424,13 @@ const Board = () => {
- <> -
{selectedTitle}
-
p/{selectedAddress}
- +
{selectedTitle}
+
p/{selectedAddress} + +
diff --git a/src/components/views/Subscriptions.jsx b/src/components/views/Subscriptions.jsx index 5587b56c..f5fb2d4d 100644 --- a/src/components/views/Subscriptions.jsx +++ b/src/components/views/Subscriptions.jsx @@ -172,10 +172,6 @@ const Subscriptions = () => { {index === 0 ? null : "\u00a0"} handleClickTitle(subplebbit.title, subplebbit.address)} >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} ))} @@ -523,12 +519,27 @@ const Subscriptions = () => { )}  p/ - {thread.subplebbitAddress.includes(".eth") ? thread.subplebbitAddress : ( - {thread.subplebbitAddress.slice(0, 10) + "(...)"} + {thread.subplebbitAddress.includes(".eth") ? + ( + <> + {thread.subplebbitAddress} + + + ) : ( + <> + {thread.subplebbitAddress.slice(0, 10) + "(...)"} + + )}   From a63ea84fe77070c539860b7c4b9d19ee25b0e357 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 8 May 2023 21:10:42 +0200 Subject: [PATCH 04/17] add offline indicators to SubscriptionsCatalog --- src/components/BoardAvatar.jsx | 2 +- src/components/OfflineIndicator.jsx | 2 +- src/components/styled/Catalog.styled.jsx | 12 ++++++++++ src/components/views/Catalog.jsx | 13 ++++++---- src/components/views/SubscriptionsCatalog.jsx | 24 +++++++++++++------ 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/components/BoardAvatar.jsx b/src/components/BoardAvatar.jsx index 7cbe0f47..8d5a040b 100644 --- a/src/components/BoardAvatar.jsx +++ b/src/components/BoardAvatar.jsx @@ -25,7 +25,7 @@ const BoardAvatar = ({ address }) => { {!isOnline && ( offline )} diff --git a/src/components/OfflineIndicator.jsx b/src/components/OfflineIndicator.jsx index bae408c8..6596c4bf 100644 --- a/src/components/OfflineIndicator.jsx +++ b/src/components/OfflineIndicator.jsx @@ -16,7 +16,7 @@ const OfflineIndicator = ({ address, className, tooltipPlace }) => { alt="offline" src="assets/offline.png" data-tooltip-id="tooltip" - data-tooltip-content="OFFLINE" + data-tooltip-content="Offline" data-tooltip-place={tooltipPlace} /> diff --git a/src/components/styled/Catalog.styled.jsx b/src/components/styled/Catalog.styled.jsx index a066bef6..de5f20d0 100644 --- a/src/components/styled/Catalog.styled.jsx +++ b/src/components/styled/Catalog.styled.jsx @@ -39,6 +39,18 @@ export const Threads = styled.div` text-align: right; } + .offline-icon { + height: 16px; + margin: 2px; + } + + .offline-icon-no-link { + height: 13px; + position: absolute; + margin-left: 13px; + margin-top: -2px; + } + .sticky-icon { background-image: url(assets/sticky.gif); width: 16px; diff --git a/src/components/views/Catalog.jsx b/src/components/views/Catalog.jsx index 8a709fc9..4e5f4241 100644 --- a/src/components/views/Catalog.jsx +++ b/src/components/views/Catalog.jsx @@ -2,6 +2,7 @@ import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react import { Helmet } from 'react-helmet-async'; import InfiniteScroll from 'react-infinite-scroller'; import { Link, useNavigate, useParams } from 'react-router-dom'; +import { Tooltip } from 'react-tooltip'; import { useFeed, usePublishComment, useSubplebbit, useSubscribe } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import useGeneralStore from '../../hooks/stores/useGeneralStore'; @@ -282,10 +283,6 @@ const Catalog = () => { setSelectedAddress(subplebbit.address); }} >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} ))} @@ -342,7 +339,12 @@ const Catalog = () => { <>
{selectedTitle}
-
p/{selectedAddress}
+
p/{selectedAddress} + +
@@ -438,6 +440,7 @@ const Catalog = () => {
+ {feed.length < 1 ? ( diff --git a/src/components/views/SubscriptionsCatalog.jsx b/src/components/views/SubscriptionsCatalog.jsx index d5b99b46..bbfd7694 100644 --- a/src/components/views/SubscriptionsCatalog.jsx +++ b/src/components/views/SubscriptionsCatalog.jsx @@ -2,6 +2,7 @@ import React, { Fragment, useEffect, useState } from 'react'; import { Helmet } from 'react-helmet-async'; import InfiniteScroll from 'react-infinite-scroller'; import { Link, useNavigate } from 'react-router-dom'; +import { Tooltip } from 'react-tooltip'; import { useAccount, useFeed } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import useGeneralStore from '../../hooks/stores/useGeneralStore'; @@ -106,10 +107,6 @@ const SubscriptionsCatalog = () => { setSelectedAddress(subplebbit.address); }} >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} ))} @@ -203,6 +200,7 @@ const SubscriptionsCatalog = () => {
+ {selectedFeed.length < 1 ? ( @@ -254,9 +252,21 @@ const SubscriptionsCatalog = () => { ) : null} ) : null} - {/*
- -
*/} +
+ {thread.link ? ( + // */ + + ) : ( + // */ + + ) } +
R: {thread.replyCount} From 66e90138d0c2335ffa089a51c23cf60f34f982c0 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 9 May 2023 12:59:00 +0200 Subject: [PATCH 05/17] update SettingsModal, add useStateString, fixes --- package.json | 2 +- public/assets/offline.png | Bin 1122 -> 1121 bytes src/components/SettingsModal.jsx | 18 ++++++---- src/hooks/useStateString.js | 47 +++++++++++++++++++++++++ yarn.lock | 57 +++++++++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 src/hooks/useStateString.js diff --git a/package.json b/package.json index 17801e37..d7f8d777 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "@babel/plugin-transform-react-jsx": "7.21.0", "@capacitor/android": "3.6.0", "@capacitor/core": "3.6.0", - "@plebbit/plebbit-react-hooks": "https://github.com/plebbit/plebbit-react-hooks.git#91ea5a494fde74836b085e912f671cc5489ecf09", + "@plebbit/plebbit-react-hooks": "https://github.com/plebbit/plebbit-react-hooks.git#e602eda8080f2b3449388c2d5868d6e6da60c8f6", "@testing-library/dom": "9.0.1", "@testing-library/jest-dom": "5.14.1", "@testing-library/react": "14.0.0", diff --git a/public/assets/offline.png b/public/assets/offline.png index dd343f6aefe6965cd494106d530fca2b3f4e9e5a..2ca2cc936bf999d0a150b26d19975df1c76762ff 100644 GIT binary patch delta 411 zcmV;M0c8H-2;m5j7YY;z1^@s6iG0m4ks*%>6aWAK0CYS~B(b?v0Rb?R4g%wUL7>Z= z00040NklAyG z$%kXV_iP+;O{lL}Plu+Ie>q7&jBMMs0BhSe#QU8LzQhH`&rHfz{6uD1mN!9+;~4gR zCqaqf**qRpY?>ww55w@qn|BR=CMVAGOa|W=FfnzT8Rsbnzw0{BM=r!v*^5zve=<=N z0mlLahq!2A6auni5gz3*U%N00UPTTL4@nQ8u5d`D#W}(`4C#46V4?{2eNUWH#}0R< zr8OZcUCS95wmd!D*+DAIKwbNW9nqgV+hAWa?k#cGm*b;o)Z4J-BjQD8a#2TuVe7`^FsKN_XB~rt@c&R^N|1m002ovPDHLk FV1n@fvl{>a delta 412 zcmV;N0b~B*2;vBk7YY^#1^@s6#I$TXks*%>761SM01o^eM6tP40Rb|T4g%wUgf{fG z00041Nklq)j-j8$$S?3MjI2m3{8+m&RO*`M`E27vAw|9A zBDpyBd(Xxptz3Eea@tjU`L9d@Vr0v*I9OfR&Y#a@@FgxdenwKZ;tiQ;n!W|m_q|)! zl>{Y*XZ3tiv0)fA+;!cZH$NJG42~bikqo{uV0`E{GR{*De$zB5A35hk$Vs0BLq~EeRIH2Bh@i!&o(OB@B z;kMcF_<5e~$P8t3OBJ=-4W9K%8d<`hf=8?Ajo@nWX@1xO&G-?nGR(}oD0ie|2u328 z-z#0@=KhZ(kxw^=gs-QQ>RVrf8K?L<2A_UCxo~-tLI&&WY0000 {
  • - + */}
    • { /> toggleExpanded(1)} - >Profile + >Account +
      + + +
      -
    */} +
    • { onClick={() => toggleExpanded(2)} >Plebbit Options
      - -
      + +
    • diff --git a/src/hooks/useStateString.js b/src/hooks/useStateString.js new file mode 100644 index 00000000..b7f21e15 --- /dev/null +++ b/src/hooks/useStateString.js @@ -0,0 +1,47 @@ +import { useMemo } from 'react' + +const useStateString = (clients) => { + const stateString = useMemo(() => { + if (!clients) { + return + } + const states = {} + for (const clientType in clients) { + for (const clientUrl in clients[clientType]) { + const state = clients[clientType][clientUrl].state + if (state === 'stopped') { + continue + } + if (!states[state]) { + states[state] = [] + } + states[state].push(clientUrl) + } + } + + let stateString = '' + for (const state in states) { + const clientUrls = states[state] + const clientHosts = clientUrls.map(clientUrl => new URL(clientUrl).hostname) + + // separate 2 different states using ', ' + if (stateString) { + stateString += ', ' + } + + // e.g. 'fetching IPFS from cloudflare-ipfs.com, ipfs.io' + const formattedState = state.replaceAll('-', ' ').replace('ipfs', 'IPFS').replace('ipns', 'IPNS') + stateString += `${formattedState} from ${clientHosts.join(', ')}` + } + + // capitalize first letter + stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1) + + // if string is empty, return undefined instead + return stateString || undefined + }, [clients]) + + return stateString +} + +export default useStateString \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 3594950f..a1553cf4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2655,6 +2655,48 @@ ts-custom-error "3.3.1" uuid "9.0.0" +"@plebbit/plebbit-js@https://github.com/plebbit/plebbit-js.git#bcf4ec7ba024fdd7dc0bb2fab76c27c93597dd50": + version "0.0.3" + resolved "https://github.com/plebbit/plebbit-js.git#bcf4ec7ba024fdd7dc0bb2fab76c27c93597dd50" + dependencies: + "@keyv/sqlite" "3.6.2" + "@plebbit/plebbit-logger" "github:plebbit/plebbit-logger" + "@types/node-fetch" "2.6.2" + "@types/proper-lockfile" "4.1.2" + "@types/uuid" "8.3.4" + assert "2.0.0" + async-wait-until "2.0.12" + buffer "6.0.3" + captcha-canvas "3.2.1" + err-code "3.0.1" + ethers "5.7.2" + file-type "16.5.4" + form-data "4.0.0" + hpagent "1.2.0" + ipfs-http-client "56.0.3" + ipfs-only-hash "4.0.0" + is-ipfs "6.0.2" + jose "4.11.0" + js-sha256 "0.9.0" + keyv "4.5.2" + knex "2.3.0" + libp2p-crypto "0.21.2" + limiter "2.1.0" + localforage "1.10.0" + lodash-es "4.17.21" + open-graph-scraper "5.2.3" + p-limit "3.1.0" + peer-id "0.16.0" + proper-lockfile "github:plebbit/node-proper-lockfile" + retry "0.13.1" + safe-stable-stringify "2.4.1" + skia-canvas "1.0.0" + sqlite3 "5.1.2" + tiny-typed-emitter "2.1.0" + tinycache "1.1.2" + ts-custom-error "3.3.1" + uuid "9.0.0" + "@plebbit/plebbit-logger@github:plebbit/plebbit-logger": version "0.0.1" uid "9525ca9539479918931c3b334e8d490d1c87e507" @@ -2683,6 +2725,21 @@ uuid "8.3.2" zustand "4.0.0" +"@plebbit/plebbit-react-hooks@https://github.com/plebbit/plebbit-react-hooks.git#e602eda8080f2b3449388c2d5868d6e6da60c8f6": + version "0.0.1" + resolved "https://github.com/plebbit/plebbit-react-hooks.git#e602eda8080f2b3449388c2d5868d6e6da60c8f6" + dependencies: + "@plebbit/plebbit-js" "https://github.com/plebbit/plebbit-js.git#bcf4ec7ba024fdd7dc0bb2fab76c27c93597dd50" + "@plebbit/plebbit-logger" "https://github.com/plebbit/plebbit-logger.git" + assert "2.0.0" + ethers "5.6.9" + localforage "1.10.0" + lodash.isequal "4.5.0" + memoizee "0.4.15" + quick-lru "5.1.1" + uuid "8.3.2" + zustand "4.0.0" + "@pmmmwh/react-refresh-webpack-plugin@^0.5.3": version "0.5.10" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz#2eba163b8e7dbabb4ce3609ab5e32ab63dda3ef8" From 2aff229997ae8ad196148a043f3f50ae92ff228c Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 9 May 2023 15:58:19 +0200 Subject: [PATCH 06/17] add new loading states --- src/components/views/Board.jsx | 25 ++++++++++---- src/components/views/Catalog.jsx | 28 +++++++++++----- src/components/views/Pending.jsx | 34 ++++++++++++------- src/components/views/Thread.jsx | 28 +++++++++++++--- src/utils/formatState.js | 27 --------------- yarn.lock | 57 -------------------------------- 6 files changed, 82 insertions(+), 117 deletions(-) delete mode 100644 src/utils/formatState.js diff --git a/src/components/views/Board.jsx b/src/components/views/Board.jsx index 58dd2a43..b091bcab 100644 --- a/src/components/views/Board.jsx +++ b/src/components/views/Board.jsx @@ -16,7 +16,6 @@ import PostLoader from '../PostLoader'; import ReplyModal from '../ReplyModal'; import SettingsModal from '../SettingsModal'; import findShortParentCid from '../../utils/findShortParentCid'; -import formatState from '../../utils/formatState'; import getCommentMediaInfo from '../../utils/getCommentMediaInfo'; import getDate from '../../utils/getDate'; import handleAddressClick from '../../utils/handleAddressClick'; @@ -25,6 +24,7 @@ import handleQuoteClick from '../../utils/handleQuoteClick'; import handleStyleChange from '../../utils/handleStyleChange'; import useClickForm from '../../hooks/useClickForm'; import useError from '../../hooks/useError'; +import useStateString from '../../hooks/useStateString'; import useSuccess from '../../hooks/useSuccess'; import packageJson from '../../../package.json' const {version} = packageJson @@ -66,12 +66,23 @@ const Board = () => { const { subplebbitAddress } = useParams(); const subplebbit = useSubplebbit({subplebbitAddress: selectedAddress}); - useEffect(() => { - if (subplebbit.error) { - const errorMessage = formatState(subplebbit.error); - setErrorMessage(errorMessage); + const stateString = useStateString(subplebbit?.clients); + + const errorString = useMemo(() => { + if (subplebbit?.state === 'failed') { + let errorString = 'Failed fetching board "' + selectedAddress + '".'; + if (subplebbit.error) { + errorString += `: ${subplebbit.error.toString().slice(0, 300)}` + } + return errorString } - }, [subplebbit.error]); + }, [subplebbit?.state, subplebbit?.error, selectedAddress]) + + useEffect(() => { + if (errorString) { + setErrorMessage(errorString); + } + }, [errorString]); const { subscribed, subscribe, unsubscribe } = useSubscribe({subplebbitAddress: selectedAddress}); @@ -515,7 +526,7 @@ const Board = () => { ) : (
      - {formatState(subplebbit.state)} + {stateString}
      )}
      diff --git a/src/components/views/Catalog.jsx b/src/components/views/Catalog.jsx index 4e5f4241..c6798f39 100644 --- a/src/components/views/Catalog.jsx +++ b/src/components/views/Catalog.jsx @@ -1,4 +1,4 @@ -import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'; +import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Helmet } from 'react-helmet-async'; import InfiniteScroll from 'react-infinite-scroller'; import { Link, useNavigate, useParams } from 'react-router-dom'; @@ -13,11 +13,11 @@ import CatalogLoader from '../CatalogLoader'; import ImageBanner from '../ImageBanner'; import OfflineIndicator from '../OfflineIndicator'; import SettingsModal from '../SettingsModal'; -import formatState from '../../utils/formatState'; import getCommentMediaInfo from '../../utils/getCommentMediaInfo'; import handleStyleChange from '../../utils/handleStyleChange'; import useClickForm from '../../hooks/useClickForm'; import useError from '../../hooks/useError'; +import useStateString from '../../hooks/useStateString'; import useSuccess from '../../hooks/useSuccess'; import packageJson from '../../../package.json' const {version} = packageJson @@ -53,13 +53,23 @@ const Catalog = () => { const { subplebbitAddress } = useParams(); const subplebbit = useSubplebbit({subplebbitAddress: selectedAddress}); - useEffect(() => { - if (subplebbit.error) { - const errorMessage = formatState(subplebbit.error); - setErrorMessage(errorMessage); - } - }, [subplebbit.error]); + const stateString = useStateString(subplebbit?.clients); + const errorString = useMemo(() => { + if (subplebbit?.state === 'failed') { + let errorString = 'Failed fetching board "' + selectedAddress + '".'; + if (subplebbit.error) { + errorString += `: ${subplebbit.error.toString().slice(0, 300)}` + } + return errorString + } + }, [subplebbit?.state, subplebbit?.error, selectedAddress]) + + useEffect(() => { + if (errorString) { + setErrorMessage(errorString); + } + }, [errorString]); const { subscribed, subscribe, unsubscribe } = useSubscribe({subplebbitAddress: selectedAddress}); const [errorMessage, setErrorMessage] = useState(null); @@ -430,7 +440,7 @@ const Catalog = () => { ) : (
      - {formatState(subplebbit.state)} + {stateString}
      )}
      diff --git a/src/components/views/Pending.jsx b/src/components/views/Pending.jsx index b9911e05..68b4f3ad 100644 --- a/src/components/views/Pending.jsx +++ b/src/components/views/Pending.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { Helmet } from 'react-helmet-async'; import { Link, useNavigate, useParams } from 'react-router-dom'; import { Tooltip } from 'react-tooltip'; @@ -10,12 +10,12 @@ import ImageBanner from '../ImageBanner'; import Post from '../Post'; import PostLoader from '../PostLoader'; import SettingsModal from '../SettingsModal'; -import formatState from '../../utils/formatState'; import getCommentMediaInfo from '../../utils/getCommentMediaInfo'; import getDate from '../../utils/getDate'; import handleQuoteClick from '../../utils/handleQuoteClick'; import handleStyleChange from '../../utils/handleStyleChange'; import useError from '../../hooks/useError'; +import useStateString from '../../hooks/useStateString'; import packageJson from '../../../package.json' const {version} = packageJson @@ -35,20 +35,30 @@ const Pending = () => { const account = useAccount(); const comment = useAccountComment({commentIndex: index}); - const { publishingState, error } = useAccountComment({commentIndex: index}); - + + const stateString = useStateString(comment?.clients) + + const errorString = useMemo(() => { + if (comment?.state === 'failed') { + let errorString = 'Failed fetching pending thread. Pending index: ' + index; + if (comment.error) { + errorString += `: ${comment.error.toString().slice(0, 300)}` + } + return errorString + } + }, [comment?.state, comment?.error, index]) + + useEffect(() => { + if (errorString) { + setErrorMessage(errorString); + } + }, [errorString]); + const [visible] = useState(true); const [errorMessage, setErrorMessage] = useState(null); useError(errorMessage, [errorMessage]); - useEffect(() => { - if (error) { - const errorMessage = formatState(error); - setErrorMessage(errorMessage); - } - }, [error]); - const navigate = useNavigate(); const [commentMediaInfo, setCommentMediaInfo] = useState(null); const fallbackImgUrl = "assets/filedeleted-res.gif"; @@ -178,7 +188,7 @@ const Pending = () => { Catalog ] - {formatState(publishingState)} + {stateString}
      diff --git a/src/components/views/Thread.jsx b/src/components/views/Thread.jsx index ac49693b..d126baeb 100644 --- a/src/components/views/Thread.jsx +++ b/src/components/views/Thread.jsx @@ -15,7 +15,6 @@ import PostLoader from '../PostLoader'; import ReplyModal from '../ReplyModal'; import SettingsModal from '../SettingsModal'; import findShortParentCid from '../../utils/findShortParentCid'; -import formatState from '../../utils/formatState'; import getCommentMediaInfo from '../../utils/getCommentMediaInfo'; import getDate from '../../utils/getDate'; import handleAddressClick from '../../utils/handleAddressClick'; @@ -24,6 +23,7 @@ import handleQuoteClick from '../../utils/handleQuoteClick'; import handleStyleChange from '../../utils/handleStyleChange'; import useClickForm from '../../hooks/useClickForm'; import useError from '../../hooks/useError'; +import useStateString from '../../hooks/useStateString'; import packageJson from '../../../package.json' const {version} = packageJson @@ -61,6 +61,24 @@ const Thread = () => { const { subplebbitAddress, threadCid } = useParams(); const handleClickForm = useClickForm(); + const stateString = useStateString(comment?.clients); + + const errorString = useMemo(() => { + if (comment?.state === 'failed') { + let errorString = 'Failed fetching thread.' + if (comment.error) { + errorString += `: ${comment.error.toString().slice(0, 300)}` + } + return errorString + } + }, [comment?.state, comment?.error]) + + useEffect(() => { + if (errorString) { + setErrorMessage(errorString); + } + }, [errorString]); + const commentMediaInfo = getCommentMediaInfo(comment); const fallbackImgUrl = "assets/filedeleted-res.gif"; @@ -463,10 +481,10 @@ const Thread = () => { No replies yet ) ) : ( - {formatState(comment.state)} + {stateString} ) ) : ( - {formatState(comment.state)} + {stateString} )}
      @@ -1036,10 +1054,10 @@ const Thread = () => { No replies yet ) ) : ( - {formatState(comment.state)} + {stateString} ) ) : ( - {formatState(comment.state)} + {stateString} )}
      diff --git a/src/utils/formatState.js b/src/utils/formatState.js deleted file mode 100644 index 6251a7b2..00000000 --- a/src/utils/formatState.js +++ /dev/null @@ -1,27 +0,0 @@ -function formatState(str) { - if (!str) { - return null; - } - - const formattedWords = str - .replace(/-/g, " ") - .split(" ") - .map((word, index) => { - word = word.toLowerCase(); - if (word === "ipfs" || word === "ipns") { - return word.toUpperCase(); - } else if (index === 0) { - return word.charAt(0).toUpperCase() + word.slice(1); - } else { - return word; - } - }); - - if (formattedWords[0] === "Failed" || formattedWords[0] === "Succeeded") { - return formattedWords.join(" ") + "."; - } - - return formattedWords.join(" ") + "..."; -} - -export default formatState; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a1553cf4..4ca3a6ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2613,48 +2613,6 @@ mkdirp "^1.0.4" rimraf "^3.0.2" -"@plebbit/plebbit-js@https://github.com/plebbit/plebbit-js.git#1073e876f52514195e87512281a9d2d7bbefbd6c": - version "0.0.3" - resolved "https://github.com/plebbit/plebbit-js.git#1073e876f52514195e87512281a9d2d7bbefbd6c" - dependencies: - "@keyv/sqlite" "3.6.2" - "@plebbit/plebbit-logger" "github:plebbit/plebbit-logger" - "@types/node-fetch" "2.6.2" - "@types/proper-lockfile" "4.1.2" - "@types/uuid" "8.3.4" - assert "2.0.0" - async-wait-until "2.0.12" - buffer "6.0.3" - captcha-canvas "3.2.1" - err-code "3.0.1" - ethers "5.7.2" - file-type "16.5.4" - form-data "4.0.0" - hpagent "1.2.0" - ipfs-http-client "56.0.3" - ipfs-only-hash "4.0.0" - is-ipfs "6.0.2" - jose "4.11.0" - js-sha256 "0.9.0" - keyv "4.5.2" - knex "2.3.0" - libp2p-crypto "0.21.2" - limiter "2.1.0" - localforage "1.10.0" - lodash-es "4.17.21" - open-graph-scraper "5.2.3" - p-limit "3.1.0" - peer-id "0.16.0" - proper-lockfile "github:plebbit/node-proper-lockfile" - retry "0.13.1" - safe-stable-stringify "2.4.1" - skia-canvas "1.0.0" - sqlite3 "5.1.2" - tiny-typed-emitter "2.1.0" - tinycache "1.1.2" - ts-custom-error "3.3.1" - uuid "9.0.0" - "@plebbit/plebbit-js@https://github.com/plebbit/plebbit-js.git#bcf4ec7ba024fdd7dc0bb2fab76c27c93597dd50": version "0.0.3" resolved "https://github.com/plebbit/plebbit-js.git#bcf4ec7ba024fdd7dc0bb2fab76c27c93597dd50" @@ -2710,21 +2668,6 @@ dependencies: debug "4.3.3" -"@plebbit/plebbit-react-hooks@https://github.com/plebbit/plebbit-react-hooks.git#91ea5a494fde74836b085e912f671cc5489ecf09": - version "0.0.1" - resolved "https://github.com/plebbit/plebbit-react-hooks.git#91ea5a494fde74836b085e912f671cc5489ecf09" - dependencies: - "@plebbit/plebbit-js" "https://github.com/plebbit/plebbit-js.git#1073e876f52514195e87512281a9d2d7bbefbd6c" - "@plebbit/plebbit-logger" "https://github.com/plebbit/plebbit-logger.git" - assert "2.0.0" - ethers "5.6.9" - localforage "1.10.0" - lodash.isequal "4.5.0" - memoizee "0.4.15" - quick-lru "5.1.1" - uuid "8.3.2" - zustand "4.0.0" - "@plebbit/plebbit-react-hooks@https://github.com/plebbit/plebbit-react-hooks.git#e602eda8080f2b3449388c2d5868d6e6da60c8f6": version "0.0.1" resolved "https://github.com/plebbit/plebbit-react-hooks.git#e602eda8080f2b3449388c2d5868d6e6da60c8f6" From 4d43b190dfaea912021aa6492cfd25f106c797df Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 9 May 2023 16:30:02 +0200 Subject: [PATCH 07/17] fix disable skeleton if state is failed --- src/components/views/Board.jsx | 10 ++++++---- src/components/views/Catalog.jsx | 8 +++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/components/views/Board.jsx b/src/components/views/Board.jsx index b091bcab..69cbbd6c 100644 --- a/src/components/views/Board.jsx +++ b/src/components/views/Board.jsx @@ -538,10 +538,11 @@ const Board = () => {
      - {feed.length < 1 ? ( - + {subplebbit?.state === "failed" ? ( + null ) : ( - 1 ? ( + { @@ -1172,7 +1173,8 @@ const Board = () => { endReached={tryLoadMore} useWindowScroll={true} components={{ Footer: hasMore ? () => : null }} - /> + /> + ) : () )}
      diff --git a/src/components/views/Catalog.jsx b/src/components/views/Catalog.jsx index c6798f39..866b8271 100644 --- a/src/components/views/Catalog.jsx +++ b/src/components/views/Catalog.jsx @@ -452,9 +452,10 @@ const Catalog = () => { - {feed.length < 1 ? ( - + {subplebbit?.state === "failed" ? ( + null ) : ( + feed.length > 1 ? ( { )})} - )} + ) : () + )}
      Date: Tue, 9 May 2023 16:36:49 +0200 Subject: [PATCH 08/17] Update Thread.jsx --- src/components/views/Thread.jsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/views/Thread.jsx b/src/components/views/Thread.jsx index d126baeb..902b9565 100644 --- a/src/components/views/Thread.jsx +++ b/src/components/views/Thread.jsx @@ -316,10 +316,6 @@ const Thread = () => { setSelectedAddress(subplebbit.address); }} >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} ))} @@ -376,7 +372,12 @@ const Thread = () => {
      <>
      {selectedTitle}
      -
      p/{selectedAddress}
      +
      p/{selectedAddress} + +
      From 24af1e00ade2d8845fa424c83312775a8582dbf7 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 9 May 2023 21:20:30 +0200 Subject: [PATCH 09/17] add loading state to subscriptions view --- src/components/views/Board.jsx | 20 ++++---- src/components/views/Catalog.jsx | 2 +- src/components/views/Subscriptions.jsx | 34 ++++++++++++-- src/hooks/useFeedStateString.js | 65 ++++++++++++++++++++++++++ src/hooks/useStateString.js | 22 ++++++--- 5 files changed, 122 insertions(+), 21 deletions(-) create mode 100644 src/hooks/useFeedStateString.js diff --git a/src/components/views/Board.jsx b/src/components/views/Board.jsx index 69cbbd6c..c2562d50 100644 --- a/src/components/views/Board.jsx +++ b/src/components/views/Board.jsx @@ -68,6 +68,15 @@ const Board = () => { 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(() => { if (subplebbit?.state === 'failed') { let errorString = 'Failed fetching board "' + selectedAddress + '".'; @@ -84,15 +93,6 @@ const Board = () => { } }, [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(() => { return selectedFeed.reduce((acc, thread) => { @@ -541,7 +541,7 @@ const Board = () => { {subplebbit?.state === "failed" ? ( null ) : ( - feed.length > 1 ? ( + feed.length > 0 ? ( { {subplebbit?.state === "failed" ? ( null ) : ( - feed.length > 1 ? ( + feed.length > 0 ? ( { const navigate = useNavigate(); const [prevScrollPos, setPrevScrollPos] = useState(0); const [visible, setVisible] = useState(true); + + const [errorMessage, setErrorMessage] = useState(null); + useError(errorMessage, [errorMessage]); + const { feed, hasMore, loadMore } = useFeed({subplebbitAddresses: account?.subscriptions, sortType: 'new'}); 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(() => { setSelectedFeed(feed.sort((a, b) => b.timestamp - a.timestamp)); }, [feed]); - - const [errorMessage] = useState(null); - useError(errorMessage, [errorMessage]); const flattenedRepliesByThread = useMemo(() => { @@ -258,6 +277,13 @@ const Subscriptions = () => { Catalog ] + {feed.length > 0 ? ( + null + ) : ( +
      + {stateString} +
      + )}
      Catalog diff --git a/src/hooks/useFeedStateString.js b/src/hooks/useFeedStateString.js new file mode 100644 index 00000000..bc3da548 --- /dev/null +++ b/src/hooks/useFeedStateString.js @@ -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 \ No newline at end of file diff --git a/src/hooks/useStateString.js b/src/hooks/useStateString.js index b7f21e15..9c92685f 100644 --- a/src/hooks/useStateString.js +++ b/src/hooks/useStateString.js @@ -1,10 +1,12 @@ import { useMemo } from 'react' +import isValidUrl from '../utils/isValidUrl' const useStateString = (clients) => { - const stateString = useMemo(() => { + return useMemo(() => { if (!clients) { return } + const states = {} for (const clientType in clients) { for (const clientUrl in clients[clientType]) { @@ -22,7 +24,12 @@ const useStateString = (clients) => { let stateString = '' for (const state in states) { 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 ', ' if (stateString) { @@ -35,13 +42,16 @@ const useStateString = (clients) => { } // 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 - return stateString || undefined + console.log("second log:", stateString); + return stateString === '' ? undefined : stateString }, [clients]) - - return stateString } export default useStateString \ No newline at end of file From 76d32ab46e93217d6f0368afd7f6ba593ea698fa Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 9 May 2023 21:58:46 +0200 Subject: [PATCH 10/17] fix useFeedStateString eslint --- src/hooks/useFeedStateString.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/hooks/useFeedStateString.js b/src/hooks/useFeedStateString.js index bc3da548..62860894 100644 --- a/src/hooks/useFeedStateString.js +++ b/src/hooks/useFeedStateString.js @@ -1,26 +1,25 @@ 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 useMemo(() => { + 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 [...clientUrls] - } - return useMemo(() => { if (!subplebbits) { return undefined; } const states = {} - const clientUrls = {} for (const subplebbit of subplebbits) { states[subplebbit?.updatingState] = (states[subplebbit?.updatingState] || 0) + 1 } From 762dec840d982f5204bc2f3f9e0d3372ad4c86d6 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 9 May 2023 22:00:02 +0200 Subject: [PATCH 11/17] remove logs, fixes --- src/components/views/Subscriptions.jsx | 12 +++++++++--- src/hooks/useStateString.js | 3 --- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/views/Subscriptions.jsx b/src/components/views/Subscriptions.jsx index 81b62789..fbffd507 100644 --- a/src/components/views/Subscriptions.jsx +++ b/src/components/views/Subscriptions.jsx @@ -58,17 +58,23 @@ const Subscriptions = () => { const errorString = useMemo(() => { for (const subplebbit of subplebbits) { - if (subplebbit?.updatingState !== 'failed') { + if (subplebbit.updatingState !== 'failed') { return } } for (const subplebbit of subplebbits) { - if (subplebbit?.error) { - setErrorMessage(`Failed fetching subplebbit: ${subplebbit?.error.toString().slice(0, 300)}`); + if (subplebbit.error) { + return `Failed fetching subplebbit: ${subplebbit.error.toString().slice(0, 300)}` } } }, [subplebbits]) + useEffect(() => { + if (errorString) { + setErrorMessage(errorString) + } + }, [errorString]) + useEffect(() => { setSelectedFeed(feed.sort((a, b) => b.timestamp - a.timestamp)); diff --git a/src/hooks/useStateString.js b/src/hooks/useStateString.js index 9c92685f..34ff0a0a 100644 --- a/src/hooks/useStateString.js +++ b/src/hooks/useStateString.js @@ -44,12 +44,9 @@ const useStateString = (clients) => { // capitalize first letter if (stateString) { stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1) - - console.log("first log:", stateString); } // if string is empty, return undefined instead - console.log("second log:", stateString); return stateString === '' ? undefined : stateString }, [clients]) } From b8d7e11744673dabbe2af006889c66571eee6c8e Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 10 May 2023 10:00:08 +0200 Subject: [PATCH 12/17] fix loop bug in thread view --- src/components/ReplyModal.jsx | 6 ++---- src/components/views/Thread.jsx | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/components/ReplyModal.jsx b/src/components/ReplyModal.jsx index f11df31f..fa421a25 100644 --- a/src/components/ReplyModal.jsx +++ b/src/components/ReplyModal.jsx @@ -1,5 +1,4 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { useLocation } from 'react-router-dom'; import { usePublishComment } from '@plebbit/plebbit-react-hooks'; import { StyledModal } from './styled/ReplyModal.styled'; import useGeneralStore from '../hooks/stores/useGeneralStore'; @@ -33,8 +32,7 @@ const ReplyModal = ({ isOpen, closeModal }) => { const [selectedText, setSelectedText] = useState(''); useError(errorMessage, [errorMessage]); - - const location = useLocation(); + const onModalOpen = () => { @@ -109,7 +107,7 @@ const ReplyModal = ({ isOpen, closeModal }) => { if (index !== undefined) { setPendingCommentIndex(index); } - }, [index, location, setPendingCommentIndex]); + }, [index, setPendingCommentIndex]); const resetFields = useCallback(() => { diff --git a/src/components/views/Thread.jsx b/src/components/views/Thread.jsx index 902b9565..47029d09 100644 --- a/src/components/views/Thread.jsx +++ b/src/components/views/Thread.jsx @@ -52,6 +52,11 @@ const Thread = () => { const commentRef = useRef(); const linkRef = useRef(); + const [triggerPublishComment, setTriggerPublishComment] = useState(false); + + const [errorMessage, setErrorMessage] = useState(null); + useError(errorMessage, [errorMessage]); + const [isReplyOpen, setIsReplyOpen] = useState(false); const navigate = useNavigate(); const [prevScrollPos, setPrevScrollPos] = useState(0); @@ -63,6 +68,10 @@ const Thread = () => { const stateString = useStateString(comment?.clients); + const commentMediaInfo = getCommentMediaInfo(comment); + const fallbackImgUrl = "assets/filedeleted-res.gif"; + + const errorString = useMemo(() => { if (comment?.state === 'failed') { let errorString = 'Failed fetching thread.' @@ -73,20 +82,13 @@ const Thread = () => { } }, [comment?.state, comment?.error]) + useEffect(() => { if (errorString) { setErrorMessage(errorString); } }, [errorString]); - const commentMediaInfo = getCommentMediaInfo(comment); - const fallbackImgUrl = "assets/filedeleted-res.gif"; - - const [errorMessage, setErrorMessage] = useState(null); - useError(errorMessage, [errorMessage]); - - const [triggerPublishComment, setTriggerPublishComment] = useState(false); - const flattenedReplies = useMemo(() => flattenCommentsPages(comment.replies), [comment.replies] @@ -228,6 +230,7 @@ const Thread = () => { await publishComment(); resetFields(); })(); + setTriggerPublishComment(false); } }, [publishCommentOptions, triggerPublishComment, publishComment, resetFields]); From e82edf1165dcc4014afd119cb2d1d1e98e535c77 Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 10 May 2023 14:17:24 +0200 Subject: [PATCH 13/17] add account import and export --- src/components/SettingsModal.jsx | 70 ++++++++++++++++++++------ src/components/views/Subscriptions.jsx | 6 +-- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/components/SettingsModal.jsx b/src/components/SettingsModal.jsx index abcdc147..f93d7896 100644 --- a/src/components/SettingsModal.jsx +++ b/src/components/SettingsModal.jsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import Modal from "react-modal"; -import { deleteCaches, setAccount, useAccount } from "@plebbit/plebbit-react-hooks"; +import { deleteCaches, exportAccount, importAccount, setAccount, useAccount } from "@plebbit/plebbit-react-hooks"; import { StyledModal } from "./styled/SettingsModal.styled"; import useGeneralStore from "../hooks/stores/useGeneralStore"; import useError from "../hooks/useError"; @@ -10,17 +10,14 @@ import packageJson from '../../package.json' const {version} = packageJson -const customOverlayStyles = { - overlay: { - backgroundColor: 'rgba(0,0,0,.25)' - } -}; - const SettingsModal = ({ isOpen, closeModal }) => { const selectedStyle = useGeneralStore(state => state.selectedStyle); const navigate = useNavigate(); const location = useLocation(); const [expanded, setExpanded] = useState([]); + const [accountJson, setAccountJson] = useState(null); + const [setImportSuccess] = useState(false); + const [errorMessage, setErrorMessage] = useState(null); const [successMessage, setSuccessMessage] = useState(null); useError(errorMessage, [errorMessage]); @@ -28,10 +25,18 @@ const SettingsModal = ({ isOpen, closeModal }) => { const account = useAccount(); + useEffect(() => { + if (account) { + console.log(account); + } + }, [account]); + + const gatewayRef = useRef(); const ipfsRef = useRef(); const pubsubRef = useRef(); const dataPathRef = useRef(); + const importRef = useRef(); const isValidURL = (url) => { try { @@ -108,6 +113,8 @@ const SettingsModal = ({ isOpen, closeModal }) => { const handleCloseModal = () => { + setAccountJson(null); + if (location.pathname.endsWith("/settings")) { const newPath = location.pathname.slice(0, -9); closeModal(); @@ -146,7 +153,27 @@ const SettingsModal = ({ isOpen, closeModal }) => { localStorage.removeItem("cacheCleared"); } }, []); - + + + const handleExport = async () => { + const activeAccountJson = await exportAccount(); + setAccountJson(activeAccountJson); + }; + + + const handleImport = async () => { + const accountJson = importRef.current.value; + + try { + await importAccount(accountJson); + setImportSuccess(true); + localStorage.setItem("toastMessage", "Account Imported"); + window.location.reload(); + + } catch (error) { + setErrorMessage(error.message); + } + }; return ( @@ -154,7 +181,7 @@ const SettingsModal = ({ isOpen, closeModal }) => { isOpen={isOpen} onRequestClose={handleCloseModal} contentLabel="Settings" - style={customOverlayStyles} + style={{ overlay: { backgroundColor: "rgba(0,0,0,.25)" }}} selectedStyle={selectedStyle} expanded={expanded} > @@ -201,13 +228,26 @@ const SettingsModal = ({ isOpen, closeModal }) => {
      - -
      • -
      • +
      • + Export or Import Your Data
      • +
        + + +
        +
      • + To export, click "Export", then save your account data displayed below in a safe place. To import, paste your account data into the box below, then click "Import".
      • +
        +