diff --git a/public/assets/icons/offline-red.png b/public/assets/icons/offline-red.png
new file mode 100644
index 00000000..a0227105
Binary files /dev/null and b/public/assets/icons/offline-red.png differ
diff --git a/src/components/board-header/board-header.module.css b/src/components/board-header/board-header.module.css
index 01845509..cc553a7f 100644
--- a/src/components/board-header/board-header.module.css
+++ b/src/components/board-header/board-header.module.css
@@ -39,6 +39,10 @@
image-rendering: pixelated;
}
+.redOfflineIcon {
+ background-image: url('/public/assets/icons/offline-red.png') !important;
+}
+
@media (max-width: 640px) {
.boardTitle {
padding-top: 40px;
diff --git a/src/components/board-header/board-header.tsx b/src/components/board-header/board-header.tsx
index b4eb99ca..e891ac77 100644
--- a/src/components/board-header/board-header.tsx
+++ b/src/components/board-header/board-header.tsx
@@ -1,12 +1,11 @@
import { useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';
-import { useTranslation } from 'react-i18next';
import { useAccountComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
-import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
import styles from './board-header.module.css';
import { useMultisubMetadata } from '../../hooks/use-default-subplebbits';
import useIsMobile from '../../hooks/use-is-mobile';
+import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
const totalBanners = 60;
@@ -20,10 +19,8 @@ const ImageBanner = () => {
};
const BoardHeader = () => {
- const { t } = useTranslation();
const location = useLocation();
const params = useParams();
-
const isInAllView = isAllView(location.pathname, params);
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
@@ -31,18 +28,14 @@ const BoardHeader = () => {
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
const subplebbit = useSubplebbit({ subplebbitAddress });
- const { address, shortAddress, updatedAt } = subplebbit || {};
+ const { address, shortAddress } = subplebbit || {};
const multisubMetadata = useMultisubMetadata();
-
const title = isInAllView ? multisubMetadata?.title || 'all' : isInSubscriptionsView ? 'Subscriptions' : subplebbit?.title;
const subtitle = isInAllView ? 'p/all' : isInSubscriptionsView ? 'p/subscriptions' : `p/${address}`;
- const isBoardOffline = updatedAt && updatedAt < Date.now() / 1000 - 60 * 60;
-
- const offlineMessage = updatedAt
- ? isBoardOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
- : t('subplebbit_offline_info');
+ const { isOffline, isDefinitelyOffline, offlineTitle } = useIsSubplebbitOffline(subplebbit);
+ const iconClass = `${styles.offlineIcon} ${isDefinitelyOffline ? styles.redOfflineIcon : ''}`;
return (
@@ -53,7 +46,7 @@ const BoardHeader = () => {
)}
{title || `p/${shortAddress || subplebbitAddress}`}
- {isBoardOffline && }
+ {isOffline && }
{subtitle}
diff --git a/src/components/post-form/post-form.tsx b/src/components/post-form/post-form.tsx
index 7d871f68..287cbbf8 100644
--- a/src/components/post-form/post-form.tsx
+++ b/src/components/post-form/post-form.tsx
@@ -12,7 +12,7 @@ import useReply from '../../hooks/use-reply';
import useChallengesStore from '../../stores/use-challenges-store';
import styles from './post-form.module.css';
import _ from 'lodash';
-import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
+import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
type SubmitState = {
subplebbitAddress: string | undefined;
@@ -272,17 +272,12 @@ const PostForm = () => {
const [showForm, setShowForm] = useState(false);
const subplebbit = useSubplebbit({ subplebbitAddress: params?.subplebbitAddress });
- const { updatedAt } = subplebbit || {};
- const isBoardOffline = updatedAt && updatedAt < Date.now() / 1000 - 60 * 60;
-
- const offlineMessage = updatedAt
- ? isBoardOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
- : t('subplebbit_offline_info');
+ const { isOffline, offlineTitle } = useIsSubplebbitOffline(subplebbit);
return (
<>
- {!(isInAllView || isInSubscriptionsView) && showForm && isBoardOffline &&
{offlineMessage}
}
+ {!(isInAllView || isInSubscriptionsView) && showForm && isOffline &&
{offlineTitle}
}
{isThreadClosed ? (
{t('thread_closed')}
@@ -302,7 +297,7 @@ const PostForm = () => {
)}
- {!(isInAllView || isInSubscriptionsView) && showForm && isBoardOffline &&
{offlineMessage}
}
+ {!(isInAllView || isInSubscriptionsView) && showForm && isOffline &&
{offlineTitle}
}
{isThreadClosed ? (
{t('thread_closed')}
diff --git a/src/hooks/use-is-subplebbit-offline.ts b/src/hooks/use-is-subplebbit-offline.ts
new file mode 100644
index 00000000..33875c20
--- /dev/null
+++ b/src/hooks/use-is-subplebbit-offline.ts
@@ -0,0 +1,19 @@
+import { useTranslation } from 'react-i18next';
+import { Subplebbit } from '@plebbit/plebbit-react-hooks';
+import { getFormattedTimeAgo } from '../lib/utils/time-utils';
+
+const useIsSubplebbitOffline = (subplebbit: Subplebbit) => {
+ const { t } = useTranslation();
+ const { updatedAt, updatingState } = subplebbit || {};
+ const isProbablyOffline = !updatedAt || (updatedAt && updatedAt < Date.now() / 1000 - 60 * 60);
+ const isDefinitelyOffline = updatingState === 'failed';
+ const isOffline = isProbablyOffline || isDefinitelyOffline;
+
+ const offlineTitle = updatedAt
+ ? isOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
+ : t('subplebbit_offline_info');
+
+ return { isOffline, isDefinitelyOffline, offlineTitle };
+};
+
+export default useIsSubplebbitOffline;
diff --git a/src/index.css b/src/index.css
index 655e8185..ae102085 100644
--- a/src/index.css
+++ b/src/index.css
@@ -30,6 +30,10 @@ hr {
text-transform: capitalize;
}
+.red {
+ color: red !important;
+}
+
:root {
color-scheme: dark;
}
diff --git a/src/views/board/board.tsx b/src/views/board/board.tsx
index 3a82e812..eb1a87ad 100644
--- a/src/views/board/board.tsx
+++ b/src/views/board/board.tsx
@@ -72,14 +72,14 @@ const Board = () => {
const loadingString = (
{state === 'failed' ? (
- state
+
{state}
) : isInSubscriptionsView && subscriptions?.length === 0 ? (
t('not_subscribed_to_any_board')
) : (
)}
{error && (
-
+
{error.message}
diff --git a/src/views/home/boards-box/boards-box.tsx b/src/views/home/boards-box/boards-box.tsx
index 7dbee2d8..6f9cda02 100644
--- a/src/views/home/boards-box/boards-box.tsx
+++ b/src/views/home/boards-box/boards-box.tsx
@@ -2,12 +2,12 @@ import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Subplebbit, useAccount, useAccountSubplebbits } from '@plebbit/plebbit-react-hooks';
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
-import { getFormattedTimeAgo } from '../../../lib/utils/time-utils';
import useHomeFiltersStore from '../../../stores/use-home-filters-store';
import { useMultisubMetadata } from '../../../hooks/use-default-subplebbits';
import styles from '../home.module.css';
import { nsfwTags } from '../home';
import BoxModal from '../box-modal';
+import useIsSubplebbitOffline from '../../../hooks/use-is-subplebbit-offline';
const Board = ({ subplebbit, subplebbits }: { subplebbit: Subplebbit; subplebbits: any }) => {
const { t } = useTranslation();
@@ -18,15 +18,12 @@ const Board = ({ subplebbit, subplebbits }: { subplebbit: Subplebbit; subplebbit
const boardLink = useCatalog ? `/p/${address}/catalog` : `/p/${address}`;
const subplebbitData = subplebbits && subplebbits.find((sub: Subplebbit) => sub?.address === address);
- const updatedAt = subplebbitData?.updatedAt;
- const isOffline = updatedAt && updatedAt < Date.now() / 1000 - 60 * 60;
- const offlineTitle = updatedAt
- ? isOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
- : t('subplebbit_offline_info');
+ const { isDefinitelyOffline, isOffline, offlineTitle } = useIsSubplebbitOffline(subplebbitData);
+ const iconClass = `${styles.offlineIcon} ${isDefinitelyOffline ? styles.redOfflineIcon : ''}`;
return (
- {isOffline && }
+ {isOffline && }
{title || address}
{nsfwTag && ({t(nsfwTag)})}
diff --git a/src/views/home/home.module.css b/src/views/home/home.module.css
index 043f746c..9e28a197 100644
--- a/src/views/home/home.module.css
+++ b/src/views/home/home.module.css
@@ -187,6 +187,10 @@
image-rendering: pixelated;
}
+.redOfflineIcon {
+ background-image: url('/public/assets/icons/offline-red.png') !important;
+}
+
.boardsBoxContent {
font-size: 93%;
padding: 0.5em;