diff --git a/public/assets/buttons/close-x-button.png b/public/assets/buttons/close-x-button.png
new file mode 100644
index 00000000..07aa2128
Binary files /dev/null and b/public/assets/buttons/close-x-button.png differ
diff --git a/public/translations/ar/default.json b/public/translations/ar/default.json
index d146c6c7..1437c5c8 100644
--- a/public/translations/ar/default.json
+++ b/public/translations/ar/default.json
@@ -303,5 +303,6 @@
"show": "اظهر",
"plebbit_options": "خيارات plebbit",
"general": "عام",
- "own_communities": "المجتمعات الخاصة بي"
+ "own_communities": "المجتمعات الخاصة بي",
+ "invalid_community_address": "عنوان المجتمع غير صالح"
}
\ No newline at end of file
diff --git a/public/translations/bn/default.json b/public/translations/bn/default.json
index 08c3dda6..dac44a14 100644
--- a/public/translations/bn/default.json
+++ b/public/translations/bn/default.json
@@ -303,5 +303,6 @@
"show": "দেখান",
"plebbit_options": "প্লেবিট বিকল্প",
"general": "সাধারণ",
- "own_communities": "নিজস্ব সম্প্রদায়"
+ "own_communities": "নিজস্ব সম্প্রদায়",
+ "invalid_community_address": "অবৈধ সম্প্রদায় ঠিকানা"
}
\ No newline at end of file
diff --git a/public/translations/cs/default.json b/public/translations/cs/default.json
index 6db59c80..df1be12c 100644
--- a/public/translations/cs/default.json
+++ b/public/translations/cs/default.json
@@ -303,5 +303,6 @@
"show": "ukázat",
"plebbit_options": "plebbit možnosti",
"general": "obecné",
- "own_communities": "vlastní komunity"
+ "own_communities": "vlastní komunity",
+ "invalid_community_address": "Neplatná adresa komunity"
}
\ No newline at end of file
diff --git a/public/translations/da/default.json b/public/translations/da/default.json
index 95197a07..54f40e11 100644
--- a/public/translations/da/default.json
+++ b/public/translations/da/default.json
@@ -303,5 +303,6 @@
"show": "vise",
"plebbit_options": "plebbit indstillinger",
"general": "almindelig",
- "own_communities": "egne fællesskaber"
+ "own_communities": "egne fællesskaber",
+ "invalid_community_address": "Ugyldig fællesskabsadresse"
}
\ No newline at end of file
diff --git a/public/translations/de/default.json b/public/translations/de/default.json
index 7af80197..75c82c90 100644
--- a/public/translations/de/default.json
+++ b/public/translations/de/default.json
@@ -303,5 +303,6 @@
"show": "zeigen",
"plebbit_options": "plebbit optionen",
"general": "allgemein",
- "own_communities": "eigene Gemeinschaften"
+ "own_communities": "eigene Gemeinschaften",
+ "invalid_community_address": "Ungültige Gemeindeadresse"
}
\ No newline at end of file
diff --git a/public/translations/el/default.json b/public/translations/el/default.json
index 709d0982..c2d50198 100644
--- a/public/translations/el/default.json
+++ b/public/translations/el/default.json
@@ -303,5 +303,6 @@
"show": "εμφάνιση",
"plebbit_options": "επιλογές plebbit",
"general": "γενικός",
- "own_communities": "δικές μου κοινότητες"
+ "own_communities": "δικές μου κοινότητες",
+ "invalid_community_address": "Μη έγκυρη διεύθυνση κοινότητας"
}
\ No newline at end of file
diff --git a/public/translations/en/default.json b/public/translations/en/default.json
index 803a822d..f8b44050 100644
--- a/public/translations/en/default.json
+++ b/public/translations/en/default.json
@@ -303,5 +303,6 @@
"show": "show",
"plebbit_options": "plebbit options",
"general": "general",
- "own_communities": "own communities"
+ "own_communities": "own communities",
+ "invalid_community_address": "Invalid community address"
}
\ No newline at end of file
diff --git a/public/translations/es/default.json b/public/translations/es/default.json
index 8443369e..4feddba4 100644
--- a/public/translations/es/default.json
+++ b/public/translations/es/default.json
@@ -303,5 +303,6 @@
"show": "mostrar",
"plebbit_options": "opciones plebbit",
"general": "general",
- "own_communities": "comunidades propias"
+ "own_communities": "comunidades propias",
+ "invalid_community_address": "Dirección de comunidad no válida"
}
\ No newline at end of file
diff --git a/public/translations/fa/default.json b/public/translations/fa/default.json
index 4dc44161..4f00f52b 100644
--- a/public/translations/fa/default.json
+++ b/public/translations/fa/default.json
@@ -303,5 +303,6 @@
"show": "نمایش",
"plebbit_options": "گزینه های plebbit",
"general": "عمومی",
- "own_communities": "انجمنهای خودم"
+ "own_communities": "انجمنهای خودم",
+ "invalid_community_address": "آدرس انجمن نامعتبر است"
}
\ No newline at end of file
diff --git a/public/translations/fi/default.json b/public/translations/fi/default.json
index 4743ab81..2da6b41b 100644
--- a/public/translations/fi/default.json
+++ b/public/translations/fi/default.json
@@ -303,5 +303,6 @@
"show": "näyttää",
"plebbit_options": "plebbit-vaihtoehdot",
"general": "yleinen",
- "own_communities": "omat yhteisöt"
+ "own_communities": "omat yhteisöt",
+ "invalid_community_address": "Virheellinen yhteisön osoite"
}
\ No newline at end of file
diff --git a/public/translations/fil/default.json b/public/translations/fil/default.json
index 8ac721fa..98f1945e 100644
--- a/public/translations/fil/default.json
+++ b/public/translations/fil/default.json
@@ -303,5 +303,6 @@
"show": "ipakita",
"plebbit_options": "mga pagpipilian ng plebbit",
"general": "pangkalahatan",
- "own_communities": "sariling mga pamayanan"
+ "own_communities": "sariling mga pamayanan",
+ "invalid_community_address": "Hindi wastong address ng pamayanan"
}
\ No newline at end of file
diff --git a/public/translations/fr/default.json b/public/translations/fr/default.json
index 8dddb11e..9da034b3 100644
--- a/public/translations/fr/default.json
+++ b/public/translations/fr/default.json
@@ -303,5 +303,6 @@
"show": "montrer",
"plebbit_options": "options plebbit",
"general": "général",
- "own_communities": "communautés propres"
+ "own_communities": "communautés propres",
+ "invalid_community_address": "Adresse de la communauté non valide"
}
\ No newline at end of file
diff --git a/public/translations/he/default.json b/public/translations/he/default.json
index 3e79849c..f22ac893 100644
--- a/public/translations/he/default.json
+++ b/public/translations/he/default.json
@@ -303,5 +303,6 @@
"show": "תצוגה",
"plebbit_options": "אפשרויות plebbit",
"general": "כללי",
- "own_communities": "הקהילות שלי"
+ "own_communities": "הקהילות שלי",
+ "invalid_community_address": "כתובת הקהילה אינה חוקית"
}
\ No newline at end of file
diff --git a/public/translations/hi/default.json b/public/translations/hi/default.json
index dfe1bf01..7f4db9ee 100644
--- a/public/translations/hi/default.json
+++ b/public/translations/hi/default.json
@@ -303,5 +303,6 @@
"show": "दिखाएँ",
"plebbit_options": "plebbit विकल्प",
"general": "सामान्य",
- "own_communities": "खुद की समुदायें"
+ "own_communities": "खुद की समुदायें",
+ "invalid_community_address": "अमान्य समुदाय पता"
}
\ No newline at end of file
diff --git a/public/translations/hu/default.json b/public/translations/hu/default.json
index 04dcfd28..c686121d 100644
--- a/public/translations/hu/default.json
+++ b/public/translations/hu/default.json
@@ -303,5 +303,6 @@
"show": "mutat",
"plebbit_options": "plebbit lehetőségek",
"general": "általános",
- "own_communities": "saját közösségek"
+ "own_communities": "saját közösségek",
+ "invalid_community_address": "Érvénytelen közösségi cím"
}
\ No newline at end of file
diff --git a/public/translations/id/default.json b/public/translations/id/default.json
index 347a6e08..725e3a84 100644
--- a/public/translations/id/default.json
+++ b/public/translations/id/default.json
@@ -303,5 +303,6 @@
"show": "menunjukkan",
"plebbit_options": "opsi plebbit",
"general": "umum",
- "own_communities": "komunitas sendiri"
+ "own_communities": "komunitas sendiri",
+ "invalid_community_address": "Alamat komunitas tidak valid"
}
\ No newline at end of file
diff --git a/public/translations/it/default.json b/public/translations/it/default.json
index c7628d73..5a869e76 100644
--- a/public/translations/it/default.json
+++ b/public/translations/it/default.json
@@ -303,5 +303,6 @@
"show": "mostra",
"plebbit_options": "opzioni plebbit",
"general": "generali",
- "own_communities": "comunità che possiedo"
+ "own_communities": "comunità che possiedo",
+ "invalid_community_address": "Indirizzo comunità non valido"
}
\ No newline at end of file
diff --git a/public/translations/ja/default.json b/public/translations/ja/default.json
index 6a6d3e94..783f9629 100644
--- a/public/translations/ja/default.json
+++ b/public/translations/ja/default.json
@@ -303,5 +303,6 @@
"show": "表示",
"plebbit_options": "plebbitのオプション",
"general": "一般的な",
- "own_communities": "自分のコミュニティ"
+ "own_communities": "自分のコミュニティ",
+ "invalid_community_address": "無効なコミュニティアドレス"
}
\ No newline at end of file
diff --git a/public/translations/ko/default.json b/public/translations/ko/default.json
index 3b575b52..3d042d85 100644
--- a/public/translations/ko/default.json
+++ b/public/translations/ko/default.json
@@ -303,5 +303,6 @@
"show": "보여주다",
"plebbit_options": "plebbit 옵션",
"general": "일반",
- "own_communities": "나의 커뮤니티"
+ "own_communities": "나의 커뮤니티",
+ "invalid_community_address": "잘못된 커뮤니티 주소"
}
\ No newline at end of file
diff --git a/public/translations/mr/default.json b/public/translations/mr/default.json
index 2b9afe0a..6af94f8a 100644
--- a/public/translations/mr/default.json
+++ b/public/translations/mr/default.json
@@ -303,5 +303,6 @@
"show": "दाखवा",
"plebbit_options": "प्लेबिट पर्याय",
"general": "सामान्य",
- "own_communities": "स्वत: समुदाये"
+ "own_communities": "स्वत: समुदाये",
+ "invalid_community_address": "अवैध समुदाय पत्ता"
}
\ No newline at end of file
diff --git a/public/translations/nl/default.json b/public/translations/nl/default.json
index 8cef5c4b..4fb9c5ae 100644
--- a/public/translations/nl/default.json
+++ b/public/translations/nl/default.json
@@ -303,5 +303,6 @@
"show": "tonen",
"plebbit_options": "plebbit-opties",
"general": "algemeen",
- "own_communities": "eigen gemeenschappen"
+ "own_communities": "eigen gemeenschappen",
+ "invalid_community_address": "Ongeldig gemeenschapsadres"
}
\ No newline at end of file
diff --git a/public/translations/no/default.json b/public/translations/no/default.json
index 9a5da4e2..cdda3f88 100644
--- a/public/translations/no/default.json
+++ b/public/translations/no/default.json
@@ -303,5 +303,6 @@
"show": "vise",
"plebbit_options": "plebbit alternativer",
"general": "generell",
- "own_communities": "egne fellesskap"
+ "own_communities": "egne fellesskap",
+ "invalid_community_address": "Ugyldig fellesskapsadresse"
}
\ No newline at end of file
diff --git a/public/translations/pl/default.json b/public/translations/pl/default.json
index 84aef444..0d14a53c 100644
--- a/public/translations/pl/default.json
+++ b/public/translations/pl/default.json
@@ -303,5 +303,6 @@
"show": "pokazać",
"plebbit_options": "opcje plebbit",
"general": "ogólny",
- "own_communities": "własne społeczności"
+ "own_communities": "własne społeczności",
+ "invalid_community_address": "Nieprawidłowy adres społeczności"
}
\ No newline at end of file
diff --git a/public/translations/pt/default.json b/public/translations/pt/default.json
index 7b856031..f95a86ad 100644
--- a/public/translations/pt/default.json
+++ b/public/translations/pt/default.json
@@ -303,5 +303,6 @@
"show": "mostrar",
"plebbit_options": "opções plebbit",
"general": "geral",
- "own_communities": "comunidades próprias"
+ "own_communities": "comunidades próprias",
+ "invalid_community_address": "Endereço da comunidade inválido"
}
\ No newline at end of file
diff --git a/public/translations/ro/default.json b/public/translations/ro/default.json
index f8936269..bd3b1035 100644
--- a/public/translations/ro/default.json
+++ b/public/translations/ro/default.json
@@ -303,5 +303,6 @@
"show": "arată",
"plebbit_options": "opțiuni plebbit",
"general": "general",
- "own_communities": "comunități proprii"
+ "own_communities": "comunități proprii",
+ "invalid_community_address": "Adresă comunitară nevalidă"
}
\ No newline at end of file
diff --git a/public/translations/ru/default.json b/public/translations/ru/default.json
index 0f251866..b4d320d8 100644
--- a/public/translations/ru/default.json
+++ b/public/translations/ru/default.json
@@ -303,5 +303,6 @@
"show": "показать",
"plebbit_options": "опции plebbit",
"general": "общий",
- "own_communities": "собственные сообщества"
+ "own_communities": "собственные сообщества",
+ "invalid_community_address": "Недействительный адрес сообщества"
}
\ No newline at end of file
diff --git a/public/translations/sq/default.json b/public/translations/sq/default.json
index 0efa1026..3144682c 100644
--- a/public/translations/sq/default.json
+++ b/public/translations/sq/default.json
@@ -303,5 +303,6 @@
"show": "shfaq",
"plebbit_options": "opsione plebbit",
"general": "i përgjithshëm",
- "own_communities": "komunitete të mia"
+ "own_communities": "komunitete të mia",
+ "invalid_community_address": "Adresa e komunitetit e pavlefshme"
}
\ No newline at end of file
diff --git a/public/translations/sv/default.json b/public/translations/sv/default.json
index fe279cb2..fd9c4e74 100644
--- a/public/translations/sv/default.json
+++ b/public/translations/sv/default.json
@@ -303,5 +303,6 @@
"show": "visa",
"plebbit_options": "plebbit-alternativ",
"general": "allmän",
- "own_communities": "egna samhällen"
+ "own_communities": "egna samhällen",
+ "invalid_community_address": "Ogiltig samhällsadress"
}
\ No newline at end of file
diff --git a/public/translations/te/default.json b/public/translations/te/default.json
index 01e9c748..37709d95 100644
--- a/public/translations/te/default.json
+++ b/public/translations/te/default.json
@@ -303,5 +303,6 @@
"show": "చూపించు",
"plebbit_options": "plebbit ఎంపికలు",
"general": "సాధారణ",
- "own_communities": "నా సముదాయాలు"
+ "own_communities": "నా సముదాయాలు",
+ "invalid_community_address": "అమాన్యమైన సముదాయ చిరునామా"
}
\ No newline at end of file
diff --git a/public/translations/th/default.json b/public/translations/th/default.json
index f46b3bde..d22a40f0 100644
--- a/public/translations/th/default.json
+++ b/public/translations/th/default.json
@@ -303,5 +303,6 @@
"show": "แสดง",
"plebbit_options": "ตัวเลือก plebbit",
"general": "ทั่วไป",
- "own_communities": "ชุมชนของฉัน"
+ "own_communities": "ชุมชนของฉัน",
+ "invalid_community_address": "ที่อยู่ชุมชนไม่ถูกต้อง"
}
\ No newline at end of file
diff --git a/public/translations/tr/default.json b/public/translations/tr/default.json
index efde2ecd..6aaf6daa 100644
--- a/public/translations/tr/default.json
+++ b/public/translations/tr/default.json
@@ -303,5 +303,6 @@
"show": "göstermek",
"plebbit_options": "plebbit seçenekleri",
"general": "genel",
- "own_communities": "kendi topluluklarım"
+ "own_communities": "kendi topluluklarım",
+ "invalid_community_address": "Geçersiz topluluk adresi"
}
\ No newline at end of file
diff --git a/public/translations/uk/default.json b/public/translations/uk/default.json
index 9da4132e..eb8de81d 100644
--- a/public/translations/uk/default.json
+++ b/public/translations/uk/default.json
@@ -303,5 +303,6 @@
"show": "показати",
"plebbit_options": "плебіт варіанти",
"general": "загальний",
- "own_communities": "власні спільноти"
+ "own_communities": "власні спільноти",
+ "invalid_community_address": "Недійсна адреса спільноти"
}
\ No newline at end of file
diff --git a/public/translations/ur/default.json b/public/translations/ur/default.json
index d3fe3d9c..a9acf943 100644
--- a/public/translations/ur/default.json
+++ b/public/translations/ur/default.json
@@ -303,5 +303,6 @@
"show": "دکھائیں",
"plebbit_options": "پلیبٹ اختیارات",
"general": "عام",
- "own_communities": "اپنی کمیونٹیاں"
+ "own_communities": "اپنی کمیونٹیاں",
+ "invalid_community_address": "غیر درست مجتمع کا پتہ"
}
\ No newline at end of file
diff --git a/public/translations/vi/default.json b/public/translations/vi/default.json
index 983dff8d..82b949dd 100644
--- a/public/translations/vi/default.json
+++ b/public/translations/vi/default.json
@@ -303,5 +303,6 @@
"show": "hiển thị",
"plebbit_options": "tùy chọn plebbit",
"general": "chung",
- "own_communities": "cộng đồng của riêng tôi"
+ "own_communities": "cộng đồng của riêng tôi",
+ "invalid_community_address": "Địa chỉ cộng đồng không hợp lệ"
}
\ No newline at end of file
diff --git a/public/translations/zh/default.json b/public/translations/zh/default.json
index 4293737a..9ed2ecf8 100644
--- a/public/translations/zh/default.json
+++ b/public/translations/zh/default.json
@@ -303,5 +303,6 @@
"show": "显示",
"plebbit_options": "plebbit选项",
"general": "一般",
- "own_communities": "自己的社区"
+ "own_communities": "自己的社区",
+ "invalid_community_address": "无效的社区地址"
}
\ No newline at end of file
diff --git a/src/app.tsx b/src/app.tsx
index fcea846f..ce449717 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -26,16 +26,13 @@ import TopBar from './components/topbar';
export const sortTypes = ['hot', 'new', 'active', 'controversialAll', 'topAll'];
const CheckRouteParams = () => {
- const { accountCommentIndex, commentCid, sortType, subplebbitAddress, timeFilterName } = useParams();
-
+ const { accountCommentIndex, sortType, timeFilterName } = useParams();
const isValidAccountCommentIndex = !accountCommentIndex || (!isNaN(parseInt(accountCommentIndex)) && parseInt(accountCommentIndex) >= 0);
- const isValidCommentCid = !commentCid || /^Qm[a-zA-Z0-9]{44}$/.test(commentCid);
- const isValidSubplebbitAddress = !subplebbitAddress || subplebbitAddress.includes('.') || /^12D3K[a-zA-Z0-9]{44}$/.test(subplebbitAddress);
const isSortTypeValid = !sortType || sortTypes.includes(sortType);
const isTimeFilterNameValid = !timeFilterName || timeFilterNames.includes(timeFilterName as any);
const isAccountCommentIndexValid = !accountCommentIndex || !isNaN(parseInt(accountCommentIndex));
- if (!isValidAccountCommentIndex || !isValidCommentCid || !isValidSubplebbitAddress || !isSortTypeValid || !isTimeFilterNameValid || !isAccountCommentIndexValid) {
+ if (!isValidAccountCommentIndex || !isSortTypeValid || !isTimeFilterNameValid || !isAccountCommentIndexValid) {
return ;
}
@@ -95,6 +92,7 @@ const App = () => {
} />
} />
} />
+ } />
} />
} />
diff --git a/src/components/account-bar/account-bar.tsx b/src/components/account-bar/account-bar.tsx
index 890de39c..5b1d3c76 100644
--- a/src/components/account-bar/account-bar.tsx
+++ b/src/components/account-bar/account-bar.tsx
@@ -13,9 +13,9 @@ const AccountBar = () => {
const location = useLocation();
const params = useParams();
const subplebbitAddress = params.subplebbitAddress;
- const isSubplebbit = isSubplebbitView(location.pathname, params);
- const isSubmit = isSubmitView(location.pathname);
- const isSettings = isSettingsView(location.pathname);
+ const isInSubplebbitView = isSubplebbitView(location.pathname, params);
+ const isInSubmitView = isSubmitView(location.pathname);
+ const isInSettingsView = isSettingsView(location.pathname);
const [searchVisible, setSearchVisible] = useState(false);
const toggleSearchVisible = () => setSearchVisible(!searchVisible);
@@ -33,7 +33,7 @@ const AccountBar = () => {
const mailClass = unreadNotificationCount ? styles.mailIconUnread : styles.mailIconRead;
let submitLink = '/submit';
- if (isSubplebbit) {
+ if (isInSubplebbitView) {
submitLink = `/p/${subplebbitAddress}/submit`;
}
@@ -102,7 +102,7 @@ const AccountBar = () => {
|
-
+
{t('submit')}
@@ -123,7 +123,7 @@ const AccountBar = () => {
)}
|
-
+
{t('preferences')}
diff --git a/src/components/header/header.tsx b/src/components/header/header.tsx
index d6c970a4..e7ed9227 100644
--- a/src/components/header/header.tsx
+++ b/src/components/header/header.tsx
@@ -22,6 +22,7 @@ import {
isProfileCommentsView,
isProfileDownvotedView,
isProfileSubmittedView,
+ isProfileHiddenView,
isSettingsView,
isSubmitView,
isSubplebbitView,
@@ -124,6 +125,7 @@ const AuthorHeaderTabs = () => {
const isInProfileCommentsView = isProfileCommentsView(location.pathname);
const isInProfileSubmittedView = isProfileSubmittedView(location.pathname);
const isInProfileUpvotedView = isProfileUpvotedView(location.pathname);
+ const isInProfileHiddenView = isProfileHiddenView(location.pathname);
const authorRoute = `/u/${params.authorAddress}/c/${params.commentCid}`;
const overviewSelectedClass =
@@ -173,12 +175,12 @@ const AuthorHeaderTabs = () => {
{t('downvoted')}
- {/* TODO: implement functionality from API once available
- e.preventDefault()}>
+
{t('hidden')}
+ {/* TODO: implement functionality from API once available
e.preventDefault()}>
{t('saved')}
diff --git a/src/components/newer-posts-button/index.ts b/src/components/newer-posts-button/index.ts
new file mode 100644
index 00000000..02138c92
--- /dev/null
+++ b/src/components/newer-posts-button/index.ts
@@ -0,0 +1 @@
+export { default } from './newer-posts-button';
diff --git a/src/components/newer-posts-button/newer-posts-button.module.css b/src/components/newer-posts-button/newer-posts-button.module.css
new file mode 100644
index 00000000..62e7581a
--- /dev/null
+++ b/src/components/newer-posts-button/newer-posts-button.module.css
@@ -0,0 +1,43 @@
+.newerPostsButton {
+ position: fixed;
+ left: 10%;
+ border-radius: 25px;
+ background-color: green;
+ color: white;
+ z-index: 5;
+ transition: top 0.3s ease-in-out;
+ font-size: 13px;
+}
+
+.resetButton {
+ display: inline-block;
+ cursor: pointer;
+ font-weight: 700;
+ padding: 5px 10px;
+}
+
+.resetButton:hover {
+ opacity: 0.8;
+}
+
+.hide {
+ display: none;
+}
+
+.hideButton {
+ display: inline-block;
+ cursor: pointer;
+ background-image: url("/public/assets/buttons/close-x-button.png");
+ background-size: cover;
+ height: 12px;
+ width: 12px;
+ transform: translateY(1px);
+}
+
+.hideButtonWrapper {
+ padding-right: 10px;
+}
+
+.hideButton:hover {
+ opacity: 0.8;
+}
\ No newline at end of file
diff --git a/src/components/newer-posts-button/newer-posts-button.tsx b/src/components/newer-posts-button/newer-posts-button.tsx
new file mode 100644
index 00000000..922ee958
--- /dev/null
+++ b/src/components/newer-posts-button/newer-posts-button.tsx
@@ -0,0 +1,51 @@
+import { useState, useEffect } from 'react';
+import styles from './newer-posts-button.module.css';
+
+interface NewerPostsButtonProps {
+ subplebbitAddressesWithNewerPosts: string[];
+ reset: () => void;
+}
+
+const NewerPostsButton = ({ reset, subplebbitAddressesWithNewerPosts }: NewerPostsButtonProps) => {
+ const [hideButton, setHideButton] = useState(false);
+ const [buttonPosition, setButtonPosition] = useState(80);
+ const hide = hideButton || subplebbitAddressesWithNewerPosts.length === 0;
+
+ const handleNewerPostsButtonClick = () => {
+ window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
+ // Delay the reset and hide actions to ensure smooth scrolling completes first
+ setTimeout(() => {
+ reset();
+ setHideButton(true);
+ }, 300); // Adjust the delay as needed
+ };
+
+ const handleScroll = () => {
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
+ if (scrollTop > 60) {
+ setButtonPosition(20);
+ } else {
+ setButtonPosition(80 - scrollTop);
+ }
+ };
+
+ useEffect(() => {
+ window.addEventListener('scroll', handleScroll);
+ return () => {
+ window.removeEventListener('scroll', handleScroll);
+ };
+ }, []);
+
+ return (
+
+
+ Newer Posts
+
+
+ setHideButton(true)} />
+
+
+ );
+};
+
+export default NewerPostsButton;
diff --git a/src/components/post/comment-tools/hide-menu/hide-menu.tsx b/src/components/post/comment-tools/hide-menu/hide-menu.tsx
index c4ee7ac9..12f03c57 100644
--- a/src/components/post/comment-tools/hide-menu/hide-menu.tsx
+++ b/src/components/post/comment-tools/hide-menu/hide-menu.tsx
@@ -1,9 +1,11 @@
import { useState } from 'react';
+import { useLocation } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
import { Author, useBlock } from '@plebbit/plebbit-react-hooks';
+import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
import { autoUpdate, flip, FloatingFocusManager, offset, shift, useClick, useDismiss, useFloating, useId, useInteractions, useRole } from '@floating-ui/react';
+import { isProfileHiddenView } from '../../../../lib/utils/view-utils';
import styles from './hide-menu.module.css';
-import { useTranslation } from 'react-i18next';
-import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
type HideMenuProps = {
author?: Author | undefined;
@@ -43,7 +45,7 @@ const BlockSubplebbitButton = ({ subplebbitAddress }: HideMenuProps) => {
const BlockCommentButton = ({ cid }: HideMenuProps) => {
const { t } = useTranslation();
- const { blocked, unblock, block } = useBlock({ address: cid });
+ const { blocked, unblock, block } = useBlock({ cid });
return (
@@ -57,6 +59,9 @@ const HideMenu = ({ author, cid, isAccountMod, subplebbitAddress }: HideMenuProp
const [isHideMenuOpen, setIsHideMenuOpen] = useState(false);
const toggleIsMenuOpen = () => setIsHideMenuOpen(!isHideMenuOpen);
+ const isInProfileHiddenView = isProfileHiddenView(useLocation().pathname);
+ const { unblock } = useBlock({ cid });
+
const { refs, floatingStyles, context } = useFloating({
placement: 'bottom-start',
open: isHideMenuOpen,
@@ -76,9 +81,9 @@ const HideMenu = ({ author, cid, isAccountMod, subplebbitAddress }: HideMenuProp
return (
<>
- cid && setIsHideMenuOpen(!isHideMenuOpen)}>{t('hide')}
+ {isInProfileHiddenView ? {t('unhide')} : cid && setIsHideMenuOpen(!isHideMenuOpen)}>{t('hide')}}
- {isHideMenuOpen && (
+ {isHideMenuOpen && !isInProfileHiddenView && (
diff --git a/src/components/post/post.tsx b/src/components/post/post.tsx
index 2dd3c0c0..97e43645 100644
--- a/src/components/post/post.tsx
+++ b/src/components/post/post.tsx
@@ -3,7 +3,7 @@ import styles from './post.module.css';
import { Link, useLocation, useParams } from 'react-router-dom';
import { Comment, useAuthorAddress, useBlock, useComment, useEditedComment, useSubplebbit, useSubscribe } from '@plebbit/plebbit-react-hooks';
import { useTranslation } from 'react-i18next';
-import { isAllView, isPostView, isSubplebbitView } from '../../lib/utils/view-utils';
+import { isAllView, isPostView, isProfileHiddenView, isSubplebbitView } from '../../lib/utils/view-utils';
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import { getHostname } from '../../lib/utils/url-utils';
import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
@@ -114,6 +114,7 @@ const Post = ({ index, post = {} }: PostProps) => {
const isInAllView = isAllView(location.pathname);
const isInPostView = isPostView(location.pathname, params);
+ const isInProfileHiddenView = isProfileHiddenView(location.pathname);
const isInSubplebbitView = isSubplebbitView(location.pathname, params);
const [isExpanded, setIsExpanded] = useState(isInPostView);
@@ -133,7 +134,7 @@ const Post = ({ index, post = {} }: PostProps) => {
const linkUrl = getHostname(link);
const linkClass = `${isInPostView ? (link ? styles.externalLink : styles.internalLink) : styles.link} ${pinned ? styles.pinnedLink : ''}`;
- const { blocked, unblock } = useBlock({ address: cid });
+ const { blocked, unblock } = useBlock({ cid });
const [hasClickedSubscribe, setHasClickedSubscribe] = useState(false);
const { subscribe, subscribed } = useSubscribe({ subplebbitAddress });
@@ -153,13 +154,13 @@ const Post = ({ index, post = {} }: PostProps) => {
return (
-
+
{t('post_hidden').charAt(0).toUpperCase() + t('post_hidden').slice(1)}
{t('undo')}
-
+
diff --git a/src/components/reply/reply.tsx b/src/components/reply/reply.tsx
index 1aba91ae..e6015a6e 100644
--- a/src/components/reply/reply.tsx
+++ b/src/components/reply/reply.tsx
@@ -265,7 +265,7 @@ const Reply = ({ cidOfReplyWithContext, depth = 0, isSingleComment, isSingleRepl
const [showSpoiler, setShowSpoiler] = useState(false);
- const { blocked, unblock } = useBlock({ address: cid });
+ const { blocked, unblock } = useBlock({ cid });
const [collapsed, setCollapsed] = useState(blocked);
useEffect(() => {
if (blocked) {
diff --git a/src/components/topbar/topbar.tsx b/src/components/topbar/topbar.tsx
index 56f0df08..6a559eb0 100644
--- a/src/components/topbar/topbar.tsx
+++ b/src/components/topbar/topbar.tsx
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
-import { useAccount, useAccountSubplebbits } from '@plebbit/plebbit-react-hooks';
+import { useAccount } from '@plebbit/plebbit-react-hooks';
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
import styles from './topbar.module.css';
import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
@@ -121,8 +121,6 @@ const TopBar = () => {
}
};
- const { accountSubplebbits } = useAccountSubplebbits();
-
return (
@@ -137,11 +135,9 @@ const TopBar = () => {
{t('create_community')}
- {accountSubplebbits && Object.keys(accountSubplebbits).length > 0 && (
-
- {t('own_communities')}
-
- )}
+
+ {t('my_communities')}
+
{t('default_communities')}
diff --git a/src/hooks/use-challenge-settings.ts b/src/hooks/use-challenge-settings.ts
new file mode 100644
index 00000000..921dace2
--- /dev/null
+++ b/src/hooks/use-challenge-settings.ts
@@ -0,0 +1,10 @@
+import { usePlebbitRpcSettings } from '@plebbit/plebbit-react-hooks';
+
+const useChallengeSettings = (challengeName: string) => {
+ const { challenges } = usePlebbitRpcSettings().plebbitRpcSettings || {};
+ if (challenges) {
+ return challenges[challengeName] || {};
+ }
+};
+
+export default useChallengeSettings;
diff --git a/src/hooks/use-challenges-options.ts b/src/hooks/use-challenges-options.ts
new file mode 100644
index 00000000..5362747e
--- /dev/null
+++ b/src/hooks/use-challenges-options.ts
@@ -0,0 +1,21 @@
+import { usePlebbitRpcSettings } from '@plebbit/plebbit-react-hooks';
+
+const useChallengesOptions = () => {
+ const { challenges } = usePlebbitRpcSettings().plebbitRpcSettings || {};
+
+ const options = Object.keys(challenges || {}).reduce(
+ (acc, challengeName) => {
+ const challengeSettings = challenges[challengeName];
+ acc[challengeName] = challengeSettings.optionInputs.reduce((optionsAcc: any, input: any) => {
+ optionsAcc[input.option] = input.default || '';
+ return optionsAcc;
+ }, {});
+ return acc;
+ },
+ {} as Record>,
+ );
+
+ return options;
+};
+
+export default useChallengesOptions;
diff --git a/src/lib/utils/challenge-utils.ts b/src/lib/utils/challenge-utils.ts
index 36f09f82..f0692746 100644
--- a/src/lib/utils/challenge-utils.ts
+++ b/src/lib/utils/challenge-utils.ts
@@ -61,219 +61,3 @@ export const getPublicationPreview = (publication: any) => {
}
return publicationPreview;
};
-
-export const getDefaultChallengeDescription = (challengeType: string) => {
- switch (challengeType) {
- case 'text-math':
- return 'Ask a plain text math question, insecure, use ONLY for testing.';
- case 'captcha-canvas-v3':
- return 'make custom image captcha';
- case 'fail':
- return 'A challenge that automatically fails with a custom error message.';
- case 'blacklist':
- return 'Blacklist author addresses.';
- case 'question':
- return "Ask a question, like 'What is the password?'";
- case 'evm-contract-call':
- return 'The response from an EVM contract call passes a condition, e.g. a token balance challenge.';
- default:
- return '';
- }
-};
-
-export const getDefaultChallengeOptions = (challengeType: string) => {
- switch (challengeType) {
- case 'text-math':
- return {
- difficulty: '',
- };
- case 'captcha-canvas-v3':
- return {
- characters: '',
- height: '',
- width: '',
- color: '',
- };
- case 'fail':
- return {
- error: '',
- };
- case 'blacklist':
- return {
- blacklist: '',
- error: '',
- };
- case 'question':
- return {
- question: '',
- answer: '',
- };
- case 'evm-contract-call':
- return {
- chainTicker: '',
- address: '',
- abi: '',
- condition: '',
- error: '',
- };
- default:
- return {};
- }
-};
-
-export type OptionInput = {
- option: string;
- label: string;
- default?: string;
- description: string;
- placeholder?: string;
- required?: boolean;
-};
-
-export type Exclude = {
- postScore?: number;
- replyScore?: number;
- firstCommentTimestamp?: number;
- challenges?: number[];
- post?: boolean;
- reply?: boolean;
- vote?: boolean;
- role?: string[];
- address?: string[];
- rateLimit?: number;
- rateLimitChallengeSuccess?: boolean;
-};
-
-export const getDefaultChallengeSettings = (challengeType: string) => {
- switch (challengeType) {
- case 'text-math':
- return [
- {
- option: 'difficulty',
- label: 'Difficulty',
- default: '1',
- description: 'The math difficulty of the challenge between 1-3.',
- placeholder: '1',
- },
- ];
- case 'captcha-canvas-v3':
- return [
- {
- option: 'characters',
- label: 'Characters',
- description: 'Amount of characters of the captcha.',
- default: '6',
- placeholder: 'example: 6',
- },
- {
- option: 'height',
- label: 'Height',
- description: 'Height of the captcha.',
- default: '100',
- placeholder: 'example: 100',
- },
- {
- option: 'width',
- label: 'Width',
- description: 'Width of the captcha.',
- default: '300',
- placeholder: 'example: 300',
- },
- {
- option: 'color',
- label: 'Color',
- description: 'Color of the captcha.',
- default: '#32cf7e',
- placeholder: 'example: #ff0000,#00ff00,#0000ff',
- },
- ];
- case 'fail':
- return [
- {
- option: 'error',
- label: 'Error',
- default: "You're not allowed to publish.",
- description: 'The error to display to the author.',
- placeholder: "You're not allowed to publish.",
- },
- ];
- case 'blacklist':
- return [
- {
- option: 'blacklist',
- label: 'Blacklist',
- default: '',
- description: 'Comma separated list of author addresses to be blacklisted.',
- placeholder: 'address1.eth,address2.eth,address3.eth',
- },
- {
- option: 'error',
- label: 'Error',
- default: "You're blacklisted.",
- description: 'The error to display to the author.',
- placeholder: "You're blacklisted.",
- },
- ];
- case 'question':
- return [
- {
- option: 'question',
- label: 'Question',
- default: '',
- description: 'The question to answer.',
- placeholder: '',
- },
- {
- option: 'answer',
- label: 'Answer',
- default: '',
- description: 'The answer to the question.',
- placeholder: '',
- required: true,
- },
- ];
- case 'evm-contract-call':
- return [
- {
- option: 'chainTicker',
- label: 'chainTicker',
- default: 'eth',
- description: 'The chain ticker',
- placeholder: 'eth',
- required: true,
- },
- {
- option: 'address',
- label: 'Address',
- default: '',
- description: 'The contract address.',
- placeholder: '0x...',
- required: true,
- },
- {
- option: 'abi',
- label: 'ABI',
- default: '',
- description: 'The ABI of the contract method.',
- placeholder: '{"constant":true,"inputs":[{"internalType":"address","name":"account...',
- required: true,
- },
- {
- option: 'condition',
- label: 'Condition',
- default: '',
- description: 'The condition the contract call response must pass.',
- placeholder: '>1000',
- required: true,
- },
- {
- option: 'error',
- label: 'Error',
- default: "Contract call response doesn't pass condition.",
- description: 'The error to display to the author.',
- },
- ];
- default:
- return [];
- }
-};
diff --git a/src/lib/utils/view-utils.ts b/src/lib/utils/view-utils.ts
index e31bbb2a..5aeb2efa 100644
--- a/src/lib/utils/view-utils.ts
+++ b/src/lib/utils/view-utils.ts
@@ -122,8 +122,12 @@ export const isProfileUpvotedView = (pathname: string): boolean => {
return pathname === '/profile/upvoted';
};
+export const isProfileHiddenView = (pathname: string): boolean => {
+ return pathname === '/profile/hidden';
+};
+
export const isSettingsView = (pathname: string): boolean => {
- return pathname === '/settings';
+ return pathname === '/settings' || pathname === '/settings/plebbit-options';
};
export const isSettingsPlebbitOptionsView = (pathname: string): boolean => {
diff --git a/src/views/home/home.module.css b/src/views/home/home.module.css
index 5e4b8bff..2a004bca 100644
--- a/src/views/home/home.module.css
+++ b/src/views/home/home.module.css
@@ -6,6 +6,10 @@
text-transform: lowercase;
}
+.feed {
+ position: relative;
+}
+
@media (max-width: 640px) {
.content {
padding: 7px 2px 0px 2px;
diff --git a/src/views/home/home.tsx b/src/views/home/home.tsx
index 038472d0..7f05cc87 100644
--- a/src/views/home/home.tsx
+++ b/src/views/home/home.tsx
@@ -5,6 +5,7 @@ import { useFeed } from '@plebbit/plebbit-react-hooks';
import { useTranslation } from 'react-i18next';
import styles from './home.module.css';
import LoadingEllipsis from '../../components/loading-ellipsis';
+import NewerPostsButton from '../../components/newer-posts-button';
import Post from '../../components/post';
import Sidebar from '../../components/sidebar';
import { useDefaultAndSubscriptionsSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
@@ -21,11 +22,11 @@ const Home = () => {
const timeFilterName = params.timeFilterName as TimeFilterKey;
const { timeFilter } = useTimeFilter(sortType, timeFilterName);
- const { feed, hasMore, loadMore } = useFeed({
- subplebbitAddresses: subplebbitAddresses || [],
- sortType,
- postsPerPage: 10,
+ const { feed, hasMore, loadMore, reset, subplebbitAddressesWithNewerPosts } = useFeed({
filter: timeFilter,
+ postsPerPage: 10,
+ sortType,
+ subplebbitAddresses: subplebbitAddresses || [],
});
let loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading');
@@ -72,6 +73,7 @@ const Home = () => {
+
{
{!isSingleComment && (
- {replyCount !== undefined ? commentCount : t('loading_comments')}
+ {replyCount !== undefined ? commentCount : `${t('loading_comments')}...`}
)}
diff --git a/src/views/profile/profile.tsx b/src/views/profile/profile.tsx
index db04d3c6..fd926274 100644
--- a/src/views/profile/profile.tsx
+++ b/src/views/profile/profile.tsx
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { useLocation, useParams } from 'react-router-dom';
import { StateSnapshot, Virtuoso, VirtuosoHandle } from 'react-virtuoso';
import { useAccount, useAccountComments, useAccountVotes, useComments } from '@plebbit/plebbit-react-hooks';
-import { isProfileDownvotedView, isProfileUpvotedView, isProfileCommentsView, isProfileSubmittedView } from '../../lib/utils/view-utils';
+import { isProfileDownvotedView, isProfileUpvotedView, isProfileCommentsView, isProfileSubmittedView, isProfileHiddenView } from '../../lib/utils/view-utils';
import useWindowWidth from '../../hooks/use-window-width';
import AuthorSidebar from '../../components/author-sidebar';
import Post from '../../components/post';
@@ -17,7 +17,7 @@ type SortDropdownProps = {
onSortChange: (sortType: string) => void;
};
-const SortDropdown: React.FC
= ({ onSortChange }) => {
+const SortDropdown = ({ onSortChange }: SortDropdownProps) => {
const { t } = useTranslation();
const sortLabels: string[] = sortTypes.map((sortType) => t(sortType));
const [selectedSort, setSelectedSort] = useState(sortTypes[0]);
@@ -77,17 +77,21 @@ const Profile = () => {
const { accountVotes } = useAccountVotes();
const isInProfileUpvotedView = isProfileUpvotedView(location.pathname);
const isInProfileDownvotedView = isProfileDownvotedView(location.pathname);
+ const isInProfileHiddenView = isProfileHiddenView(location.pathname);
const isInCommentsView = isProfileCommentsView(location.pathname);
const isInSubmittedView = isProfileSubmittedView(location.pathname);
const isMobile = useWindowWidth() < 640;
// get comments for upvoted/downvoted/comments/submitted pages
+ const postComments = useMemo(() => accountComments?.filter((comment) => !comment.parentCid) || [], [accountComments]);
+ const replyComments = useMemo(() => accountComments?.filter((comment) => comment.parentCid) || [], [accountComments]);
const upvotedCommentCids = useMemo(() => accountVotes?.filter((vote) => vote.vote === 1).map((vote) => vote.commentCid) || [], [accountVotes]);
const downvotedCommentCids = useMemo(() => accountVotes?.filter((vote) => vote.vote === -1).map((vote) => vote.commentCid) || [], [accountVotes]);
- const replyComments = useMemo(() => accountComments?.filter((comment) => comment.parentCid) || [], [accountComments]);
- const postComments = useMemo(() => accountComments?.filter((comment) => !comment.parentCid) || [], [accountComments]);
+ const hiddenCommentCids = useMemo(() => Object.keys(account?.blockedCids ?? {}), [account?.blockedCids]);
+
const { comments: upvotedComments } = useComments({ commentCids: upvotedCommentCids });
const { comments: downvotedComments } = useComments({ commentCids: downvotedCommentCids });
+ const { comments: hiddenComments } = useComments({ commentCids: hiddenCommentCids });
const [sortType, setSortType] = useState('new');
const handleSortChange = (newSortType: string) => {
@@ -103,18 +107,22 @@ const Profile = () => {
return replyComments;
} else if (isInSubmittedView) {
return postComments;
+ } else if (isInProfileHiddenView) {
+ return hiddenComments;
} else {
return accountComments;
}
}, [
isInProfileUpvotedView,
isInProfileDownvotedView,
+ isInProfileHiddenView,
isInCommentsView,
isInSubmittedView,
upvotedComments,
downvotedComments,
replyComments,
postComments,
+ hiddenComments,
accountComments,
]);
diff --git a/src/views/settings/plebbit-options/plebbit-options.module.css b/src/views/settings/plebbit-options/plebbit-options.module.css
index b19aa818..7dc9f937 100644
--- a/src/views/settings/plebbit-options/plebbit-options.module.css
+++ b/src/views/settings/plebbit-options/plebbit-options.module.css
@@ -38,11 +38,22 @@
}
.content textarea {
- height: 80px;
font-size: 13px;
font-family: Arial, Helvetica, sans-serif;
}
+.ipfsGatewaysSettings textarea {
+ height: 80px;
+}
+
+.pubsubProvidersSettings textarea {
+ height: 50px;
+}
+
+.blockchainProvidersSettings textarea {
+ height: 50px;
+}
+
.content button {
vertical-align: top;
margin-left: 5px;
@@ -67,6 +78,11 @@
padding-left: 40px;
}
+.saveOptions {
+ text-transform: lowercase;
+ margin-top: 10px;
+}
+
@media (max-width: 640px) {
.categoryTitle {
flex: 0 0 65px;
diff --git a/src/views/settings/plebbit-options/plebbit-options.tsx b/src/views/settings/plebbit-options/plebbit-options.tsx
index 1625bcfc..c318ae3f 100644
--- a/src/views/settings/plebbit-options/plebbit-options.tsx
+++ b/src/views/settings/plebbit-options/plebbit-options.tsx
@@ -1,75 +1,105 @@
-import { useState } from 'react';
-import { useAccount } from '@plebbit/plebbit-react-hooks';
-import styles from './plebbit-options.module.css';
+import { RefObject, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
+import { setAccount, useAccount, usePlebbitRpcSettings } from '@plebbit/plebbit-react-hooks';
+import styles from './plebbit-options.module.css';
-const isElectron = window.isElectron === true;
+interface SettingsProps {
+ ipfsGatewayUrlsRef?: RefObject;
+ mediaIpfsGatewayUrlRef?: RefObject;
+ pubsubProvidersRef?: RefObject;
+ ethRpcRef?: RefObject;
+ solRpcRef?: RefObject;
+ maticRpcRef?: RefObject;
+ avaxRpcRef?: RefObject;
+ plebbitRpcRef?: RefObject;
+ nodeDataPathRef?: RefObject;
+}
-const IPFSGatewaysSettings = ({ ipfsGatewayUrls, mediaIpfsGatewayUrl }: { ipfsGatewayUrls: any; mediaIpfsGatewayUrl: any }) => {
- const { t } = useTranslation();
+const IPFSGatewaysSettings = ({ ipfsGatewayUrlsRef, mediaIpfsGatewayUrlRef }: SettingsProps) => {
+ const account = useAccount();
+ const { plebbitOptions, mediaIpfsGatewayUrl } = account || {};
+ const { ipfsGatewayUrls } = plebbitOptions || {};
+ const plebbitRpc = usePlebbitRpcSettings();
+ const isConnectedToRpc = plebbitRpc?.state === 'succeeded';
const ipfsGatewayUrlsDefaultValue = ipfsGatewayUrls?.join('\n');
return (
);
};
-const PubsubProvidersSettings = ({ pubsubHttpClientsOptions }: { pubsubHttpClientsOptions: any }) => {
- const { t } = useTranslation();
+const PubsubProvidersSettings = ({ pubsubProvidersRef }: SettingsProps) => {
+ const account = useAccount();
+ const { plebbitOptions } = account || {};
+ const { pubsubHttpClientsOptions } = plebbitOptions || {};
+ const plebbitRpc = usePlebbitRpcSettings();
+ const isConnectedToRpc = plebbitRpc?.state === 'succeeded';
const pubsubProvidersDefaultValue = pubsubHttpClientsOptions?.join('\n');
return (
-
-
+
);
};
-const BlockchainProvidersSettings = ({ chainProviders }: { chainProviders: any }) => {
- const { t } = useTranslation();
- const ethRpcDefaultValue = chainProviders?.['eth']?.urls.join(', ');
- const solRpcDefaultValue = chainProviders?.['sol']?.urls.join(', ');
- const maticRpcDefaultValue = chainProviders?.['matic']?.urls.join(', ');
+const BlockchainProvidersSettings = ({ ethRpcRef, solRpcRef, maticRpcRef, avaxRpcRef }: SettingsProps) => {
+ const account = useAccount();
+ const { plebbitOptions } = account || {};
+ const { chainProviders } = plebbitOptions || {};
+ const ethRpcDefaultValue = chainProviders?.['eth']?.urls.join('\n');
+ const solRpcDefaultValue = chainProviders?.['sol']?.urls.join('\n');
+ const maticRpcDefaultValue = chainProviders?.['matic']?.urls.join('\n');
+ const avaxRpcDefaultValue = chainProviders?.['avax']?.urls.join('\n');
return (
);
};
-const PlebbitRPCSettings = ({ isElectron }: { isElectron: boolean }) => {
- const { t } = useTranslation();
+const PlebbitRPCSettings = ({ plebbitRpcRef }: SettingsProps) => {
const [showInfo, setShowInfo] = useState(false);
+ const account = useAccount();
+ const { plebbitOptions } = account || {};
+ const { plebbitRpcClientsOptions } = plebbitOptions || {};
return (
-
+
-
{showInfo && (
@@ -89,57 +119,125 @@ const PlebbitRPCSettings = ({ isElectron }: { isElectron: boolean }) => {
);
};
-const NodeDataPathSettings = ({ isElectron }: { isElectron: boolean }) => {
- const { t } = useTranslation();
- const path = '~/Application Support/seedit';
+const NodeDataPathSettings = ({ nodeDataPathRef }: SettingsProps) => {
+ const plebbitRpc = usePlebbitRpcSettings();
+ const { plebbitRpcSettings } = plebbitRpc || {};
+ const isConnectedToRpc = plebbitRpc?.state === 'succeeded';
+ const path = plebbitRpcSettings?.plebbitOptions?.dataPath || '';
return (
);
};
const PlebbitOptions = () => {
- // const { t } = useTranslation();
- const { plebbitOptions, mediaIpfsGatewayUrl } = useAccount() || {};
- const { ipfsGatewayUrls, pubsubHttpClientsOptions, chainProviders } = plebbitOptions || {};
+ const { t } = useTranslation();
+ const account = useAccount();
+ const { plebbitOptions } = account || {};
+
+ const ipfsGatewayUrlsRef = useRef
(null);
+ const mediaIpfsGatewayUrlRef = useRef(null);
+ const pubsubProvidersRef = useRef(null);
+ const ethRpcRef = useRef(null);
+ const solRpcRef = useRef(null);
+ const maticRpcRef = useRef(null);
+ const avaxRpcRef = useRef(null);
+ const plebbitRpcRef = useRef(null);
+ const nodeDataPathRef = useRef(null);
+
+ const handleSave = async () => {
+ const ipfsGatewayUrls = ipfsGatewayUrlsRef.current?.value.split('\n').map((url) => url.trim());
+ const mediaIpfsGatewayUrl = mediaIpfsGatewayUrlRef.current?.value.trim();
+ const pubsubHttpClientsOptions = pubsubProvidersRef.current?.value.split('\n').map((url) => url.trim());
+ const ethRpcUrls = ethRpcRef.current?.value.split('\n').map((url) => url.trim());
+ const solRpcUrls = solRpcRef.current?.value.split('\n').map((url) => url.trim());
+ const maticRpcUrls = maticRpcRef.current?.value.split('\n').map((url) => url.trim());
+ const avaxRpcUrls = avaxRpcRef.current?.value.split('\n').map((url) => url.trim());
+ const plebbitRpcClientsOptions = plebbitRpcRef.current?.value.trim();
+ const dataPath = nodeDataPathRef.current?.value.trim();
+
+ const chainProviders = {
+ eth: {
+ urls: ethRpcUrls,
+ chainId: 1,
+ },
+ sol: {
+ urls: solRpcUrls,
+ chainId: 1,
+ },
+ matic: {
+ urls: maticRpcUrls,
+ chainId: 137,
+ },
+ avax: {
+ urls: avaxRpcUrls,
+ chainId: 43114,
+ },
+ };
+
+ try {
+ await setAccount({
+ ...account,
+ mediaIpfsGatewayUrl,
+ plebbitOptions: {
+ ...plebbitOptions,
+ ipfsGatewayUrls,
+ pubsubHttpClientsOptions,
+ chainProviders,
+ plebbitRpcClientsOptions,
+ dataPath,
+ },
+ });
+ alert('Options saved.');
+ } catch (e) {
+ if (e instanceof Error) {
+ alert('Error saving options: ' + e.message);
+ console.log(e);
+ } else {
+ alert('Error');
+ }
+ }
+ };
return (
ipfs gateways
-
+
blockchain providers
-
+
node data path
-
+
+
);
};
diff --git a/src/views/submit-page/submit-page.tsx b/src/views/submit-page/submit-page.tsx
index c2c059a6..467202e9 100644
--- a/src/views/submit-page/submit-page.tsx
+++ b/src/views/submit-page/submit-page.tsx
@@ -349,7 +349,7 @@ const Submit = () => {
diff --git a/src/views/subplebbit/subplebbit-settings/subplebbit-settings.tsx b/src/views/subplebbit/subplebbit-settings/subplebbit-settings.tsx
index cfd6beea..8b70a39a 100644
--- a/src/views/subplebbit/subplebbit-settings/subplebbit-settings.tsx
+++ b/src/views/subplebbit/subplebbit-settings/subplebbit-settings.tsx
@@ -14,11 +14,12 @@ import { useTranslation } from 'react-i18next';
import { create } from 'zustand';
import styles from './subplebbit-settings.module.css';
import { isValidURL } from '../../../lib/utils/url-utils';
-import { OptionInput, Exclude, getDefaultChallengeDescription, getDefaultChallengeOptions, getDefaultChallengeSettings } from '../../../lib/utils/challenge-utils';
+import { isCreateSubplebbitView, isSubplebbitSettingsView } from '../../../lib/utils/view-utils';
+import useChallengesOptions from '../../../hooks/use-challenges-options';
+import useChallengeSettings from '../../../hooks/use-challenge-settings';
import LoadingEllipsis from '../../../components/loading-ellipsis';
import Markdown from '../../../components/markdown';
import Sidebar from '../../../components/sidebar';
-import { isCreateSubplebbitView, isSubplebbitSettingsView } from '../../../lib/utils/view-utils';
import _ from 'lodash';
type SubplebbitSettingsState = {
@@ -365,13 +366,36 @@ interface ChallengeSettingsProps {
showSettings: boolean;
}
+type OptionInput = {
+ option: string;
+ label: string;
+ default?: string;
+ description: string;
+ placeholder?: string;
+ required?: boolean;
+};
+
+type Exclude = {
+ postScore?: number;
+ replyScore?: number;
+ firstCommentTimestamp?: number;
+ challenges?: number[];
+ post?: boolean;
+ reply?: boolean;
+ vote?: boolean;
+ role?: string[];
+ address?: string[];
+ rateLimit?: number;
+ rateLimitChallengeSuccess?: boolean;
+};
+
const rolesToExclude = ['moderator', 'admin', 'owner'];
const actionsToExclude: Array<'post' | 'reply' | 'vote'> = ['post', 'reply', 'vote'];
const nonActionsToExclude: Array<'not post' | 'not reply' | 'not vote'> = ['not post', 'not reply', 'not vote'];
const ChallengeSettings = ({ challenge, index, isReadOnly, setSubplebbitSettingsStore, settings, showSettings }: ChallengeSettingsProps) => {
const { name, options } = challenge || {};
- const challengeSettings: OptionInput[] = getDefaultChallengeSettings(name);
+ const challengeSettings: any = useChallengeSettings(name);
const handleOptionChange = (optionName: string, newValue: string) => {
const updatedOptions = { ...options, [optionName]: newValue };
@@ -469,12 +493,12 @@ const ChallengeSettings = ({ challenge, index, isReadOnly, setSubplebbitSettings
{isReadOnly ? (
<>
type: {challenge?.type}
-
{challenge?.description}
+
{challengeSettings?.description}
>
) : (
-
{getDefaultChallengeDescription(name)}
+
{challengeSettings?.description}
)}
- {challengeSettings.map((setting) => (
+ {challengeSettings?.optionInputs.map((setting: OptionInput) => (
{setting?.label}
@@ -694,6 +718,7 @@ const Challenges = ({ isReadOnly, readOnlyChallenges }: { isReadOnly: boolean; r
const { settings, setSubplebbitSettingsStore } = useSubplebbitSettingsStore();
const challenges = settings?.challenges || readOnlyChallenges || [];
const [showSettings, setShowSettings] = useState
(challenges.map(() => false));
+ const challengeOptions = useChallengesOptions();
const location = useLocation();
const isInCreateSubplebbitView = isCreateSubplebbitView(location.pathname);
@@ -705,11 +730,10 @@ const Challenges = ({ isReadOnly, readOnlyChallenges }: { isReadOnly: boolean; r
};
const handleAddChallenge = () => {
- const defaultChallenge = 'captcha-canvas-v3';
- const options = getDefaultChallengeOptions(defaultChallenge);
+ const defaultOptions = challengeOptions['captcha-canvas-v3'] || {};
const newChallenge = {
- name: defaultChallenge,
- options,
+ name: 'captcha-canvas-v3',
+ defaultOptions,
};
const updatedChallenges = [...(settings?.challenges || []), newChallenge];
setSubplebbitSettingsStore({ settings: { ...settings, challenges: updatedChallenges } });
@@ -723,8 +747,9 @@ const Challenges = ({ isReadOnly, readOnlyChallenges }: { isReadOnly: boolean; r
};
const handleChallengeTypeChange = (index: number, newType: string) => {
+ const options = challengeOptions[newType] || {};
const updatedChallenges = [...challenges];
- updatedChallenges[index] = { ...updatedChallenges[index], name: newType, options: getDefaultChallengeOptions(newType) };
+ updatedChallenges[index] = { ...updatedChallenges[index], name: newType, options };
setSubplebbitSettingsStore({ settings: { ...settings, challenges: updatedChallenges } });
};
@@ -895,11 +920,28 @@ const SubplebbitSettings = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [subplebbitAddress, resetSubplebbitSettingsStore]);
+ const defaultChallengeSettings = useChallengeSettings('captcha-canvas-v3');
+
useEffect(() => {
- if (isInCreateSubplebbitView) {
+ if (isInCreateSubplebbitView && defaultChallengeSettings) {
+ const defaultChallenge = {
+ ...(defaultChallengeSettings && typeof defaultChallengeSettings === 'object' ? defaultChallengeSettings : {}),
+ name: 'captcha-canvas-v3',
+ options: {
+ characters: '6',
+ height: '100',
+ width: '300',
+ colors: '#32cf7e',
+ },
+ };
resetSubplebbitSettingsStore();
+ setSubplebbitSettingsStore({
+ settings: {
+ challenges: [defaultChallenge],
+ },
+ });
}
- }, [isInCreateSubplebbitView, resetSubplebbitSettingsStore]);
+ }, [isInCreateSubplebbitView, defaultChallengeSettings, resetSubplebbitSettingsStore, setSubplebbitSettingsStore]);
useEffect(() => {
window.scrollTo(0, 0);
diff --git a/src/views/subplebbit/subplebbit.tsx b/src/views/subplebbit/subplebbit.tsx
index a78d616e..55b7f99c 100644
--- a/src/views/subplebbit/subplebbit.tsx
+++ b/src/views/subplebbit/subplebbit.tsx
@@ -5,6 +5,7 @@ import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { useTranslation } from 'react-i18next';
import styles from '../home/home.module.css';
import LoadingEllipsis from '../../components/loading-ellipsis';
+import NewerPostsButton from '../../components/newer-posts-button';
import Post from '../../components/post';
import Sidebar from '../../components/sidebar';
import useFeedStateString from '../../hooks/use-feed-state-string';
@@ -15,17 +16,29 @@ const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
const Subplebbit = () => {
const { t } = useTranslation();
const params = useParams();
+ const subplebbitAddress = params.subplebbitAddress;
+ const subplebbitAddresses = useMemo(() => [subplebbitAddress], [subplebbitAddress]) as string[];
+
const sortType = params?.sortType || 'hot';
const timeFilterName = (params.timeFilterName as TimeFilterKey) || 'all';
const { timeFilter } = useTimeFilter(sortType, timeFilterName);
- const subplebbitAddress = params.subplebbitAddress;
- const subplebbitAddresses = useMemo(() => [subplebbitAddress], [subplebbitAddress]) as string[];
- const subplebbit = useSubplebbit({ subplebbitAddress });
- const { createdAt, description, roles, rules, shortAddress, started, state, title, updatedAt, settings } = subplebbit || {};
- const { feed, hasMore, loadMore } = useFeed({ subplebbitAddresses, sortType, filter: timeFilter });
+ const { feed, hasMore, loadMore, reset, subplebbitAddressesWithNewerPosts } = useFeed({ subplebbitAddresses, sortType, filter: timeFilter });
+
+ const { subplebbit, error } = useSubplebbit({ subplebbitAddress });
+ const { createdAt, description, roles, rules, shortAddress, started, title, updatedAt, settings } = subplebbit || {};
const loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading');
- const loadingString = {state === 'failed' ? state : }
;
+ const loadingString = (
+ <>
+ {loadingStateString === 'Failed' ? 'failed' : }
+ {error && (
+
+
+ {error.message}
+
+ )}
+ >
+ );
let isOnline = updatedAt && updatedAt > Date.now() / 1000 - 60 * 30;
const isSubCreatedButNotYetPublished = typeof createdAt === 'number' && !updatedAt;
@@ -33,8 +46,8 @@ const Subplebbit = () => {
const { blocked } = useBlock({ address: subplebbitAddress });
useEffect(() => {
- document.title = title ? title : shortAddress;
- }, [title, shortAddress]);
+ document.title = title ? title : shortAddress || subplebbitAddress;
+ }, [title, shortAddress, subplebbitAddress]);
const Footer = () => {
let footerContent;
@@ -88,6 +101,7 @@ const Subplebbit = () => {
/>
+