mirror of
https://github.com/plebbit/seedit.git
synced 2026-02-08 04:50:57 -05:00
feat(submit page): alert user if selected subplebbit might be offline
This commit is contained in:
51
src/hooks/use-is-subplebbit-offline.ts
Normal file
51
src/hooks/use-is-subplebbit-offline.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useEffect } from 'react';
|
||||
import { Subplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { getFormattedTimeAgo } from '../lib/utils/time-utils';
|
||||
import useSubplebbitOfflineStore from '../stores/use-subplebbit-offline-store';
|
||||
import useSubplebbitsLoadingStartTimestamps from '../stores/use-subplebbits-loading-start-timestamps-store';
|
||||
|
||||
const useIsSubplebbitOffline = (subplebbit: Subplebbit) => {
|
||||
const { t } = useTranslation();
|
||||
const { address, state, updatedAt, updatingState } = subplebbit || {};
|
||||
const { subplebbitOfflineState, setSubplebbitOfflineState, initializesubplebbitOfflineState } = useSubplebbitOfflineStore();
|
||||
const subplebbitsLoadingStartTimestamps = useSubplebbitsLoadingStartTimestamps([address]);
|
||||
|
||||
useEffect(() => {
|
||||
if (address && !subplebbitOfflineState[address]) {
|
||||
initializesubplebbitOfflineState(address);
|
||||
}
|
||||
}, [address, subplebbitOfflineState, initializesubplebbitOfflineState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (address) {
|
||||
setSubplebbitOfflineState(address, { state, updatedAt, updatingState });
|
||||
}
|
||||
}, [address, state, updatedAt, updatingState, setSubplebbitOfflineState]);
|
||||
|
||||
const subplebbitOfflineStore = subplebbitOfflineState[address] || { initialLoad: true };
|
||||
const loadingStartTimestamp = subplebbitsLoadingStartTimestamps[0] || 0;
|
||||
|
||||
const isLoading = subplebbitOfflineStore.initialLoad && (!updatedAt || Date.now() / 1000 - updatedAt >= 60 * 60) && Date.now() / 1000 - loadingStartTimestamp < 30;
|
||||
|
||||
const isOffline = !isLoading && ((updatedAt && updatedAt < Date.now() / 1000 - 60 * 60) || (!updatedAt && Date.now() / 1000 - loadingStartTimestamp >= 30));
|
||||
|
||||
const isOnline = updatedAt && Date.now() / 1000 - updatedAt < 60 * 60;
|
||||
|
||||
const offlineTitle = isLoading
|
||||
? t('loading')
|
||||
: updatedAt
|
||||
? isOffline && t('posts_last_synced_info', { time: getFormattedTimeAgo(updatedAt), interpolation: { escapeValue: false } })
|
||||
: t('subplebbit_offline_info');
|
||||
|
||||
// ensure isOffline is false until we have enough information
|
||||
const hasEnoughInfo = subplebbitOfflineStore.initialLoad === false || updatedAt !== undefined;
|
||||
|
||||
return {
|
||||
isOffline: hasEnoughInfo && !isOnline && isOffline,
|
||||
isOnlineStatusLoading: !isOnline && isLoading,
|
||||
offlineTitle,
|
||||
};
|
||||
};
|
||||
|
||||
export default useIsSubplebbitOffline;
|
||||
51
src/stores/use-subplebbit-offline-store.ts
Normal file
51
src/stores/use-subplebbit-offline-store.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
interface SubplebbitOfflineState {
|
||||
state?: string;
|
||||
updatedAt?: number;
|
||||
updatingState?: string;
|
||||
initialLoad: boolean;
|
||||
}
|
||||
|
||||
interface SubplebbitOfflineStore {
|
||||
subplebbitOfflineState: Record<string, SubplebbitOfflineState>;
|
||||
setSubplebbitOfflineState: (address: string, state: Partial<SubplebbitOfflineState>) => void;
|
||||
initializesubplebbitOfflineState: (address: string) => void;
|
||||
}
|
||||
|
||||
const useSubplebbitOfflineStore = create<SubplebbitOfflineStore>((set) => ({
|
||||
subplebbitOfflineState: {},
|
||||
setSubplebbitOfflineState: (address, newState) =>
|
||||
set((state) => ({
|
||||
subplebbitOfflineState: {
|
||||
...state.subplebbitOfflineState,
|
||||
[address]: {
|
||||
...state.subplebbitOfflineState[address],
|
||||
...newState,
|
||||
},
|
||||
},
|
||||
})),
|
||||
initializesubplebbitOfflineState: (address) => {
|
||||
set((state) => ({
|
||||
subplebbitOfflineState: {
|
||||
...state.subplebbitOfflineState,
|
||||
[address]: {
|
||||
initialLoad: true,
|
||||
},
|
||||
},
|
||||
}));
|
||||
setTimeout(() => {
|
||||
set((state) => ({
|
||||
subplebbitOfflineState: {
|
||||
...state.subplebbitOfflineState,
|
||||
[address]: {
|
||||
...state.subplebbitOfflineState[address],
|
||||
initialLoad: false,
|
||||
},
|
||||
},
|
||||
}));
|
||||
}, 30000);
|
||||
},
|
||||
}));
|
||||
|
||||
export default useSubplebbitOfflineStore;
|
||||
42
src/stores/use-subplebbits-loading-start-timestamps-store.ts
Normal file
42
src/stores/use-subplebbits-loading-start-timestamps-store.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { create } from 'zustand';
|
||||
|
||||
interface SubplebbitsLoadingStartTimestampsState {
|
||||
timestamps: Record<string, number>;
|
||||
addSubplebbits: (subplebbitAddresses: string[]) => void;
|
||||
}
|
||||
|
||||
const useSubplebbitsLoadingStartTimestampsStore = create<SubplebbitsLoadingStartTimestampsState>((set, get) => ({
|
||||
timestamps: {},
|
||||
addSubplebbits: (subplebbitAddresses) => {
|
||||
const { timestamps } = get();
|
||||
const newTimestamps: Record<string, number> = {};
|
||||
subplebbitAddresses.forEach((subplebbitAddress) => {
|
||||
if (!timestamps[subplebbitAddress]) {
|
||||
newTimestamps[subplebbitAddress] = Math.round(Date.now() / 1000);
|
||||
}
|
||||
});
|
||||
if (Object.keys(newTimestamps).length) {
|
||||
set((state) => ({ timestamps: { ...state.timestamps, ...newTimestamps } }));
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
const useSubplebbitsLoadingStartTimestamps = (subplebbitAddresses?: string[]) => {
|
||||
const timestampsStore = useSubplebbitsLoadingStartTimestampsStore((state) => state.timestamps);
|
||||
const addSubplebbits = useSubplebbitsLoadingStartTimestampsStore((state) => state.addSubplebbits);
|
||||
|
||||
useEffect(() => {
|
||||
if (subplebbitAddresses) {
|
||||
addSubplebbits(subplebbitAddresses);
|
||||
}
|
||||
}, [subplebbitAddresses, addSubplebbits]);
|
||||
|
||||
const subplebbitsLoadingStartTimestamps = useMemo(() => {
|
||||
return subplebbitAddresses?.map((subplebbitAddress) => timestampsStore[subplebbitAddress]) || [];
|
||||
}, [timestampsStore, subplebbitAddresses]);
|
||||
|
||||
return subplebbitsLoadingStartTimestamps;
|
||||
};
|
||||
|
||||
export default useSubplebbitsLoadingStartTimestamps;
|
||||
@@ -11,6 +11,7 @@ import { isSubmitView } from '../../lib/utils/view-utils';
|
||||
import Embed from '../../components/post/embed';
|
||||
import Markdown from '../../components/markdown';
|
||||
import styles from './submit-page.module.css';
|
||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||
|
||||
const UrlField = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -87,23 +88,7 @@ const Submit = () => {
|
||||
const { subscriptions } = account || {};
|
||||
const defaultSubplebbitAddresses = useDefaultSubplebbitAddresses();
|
||||
|
||||
const [isOffline, setIsOffline] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const checkOfflineStatus = () => {
|
||||
if (subplebbit?.updatedAt !== undefined) {
|
||||
setIsOffline(subplebbit.updatedAt < Date.now() / 1000 - 60 * 60);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
setIsOffline(subplebbit?.updatedAt === undefined || subplebbit.updatedAt < Date.now() / 1000 - 60 * 60);
|
||||
}, 5000);
|
||||
}
|
||||
};
|
||||
|
||||
if (subplebbitAddress) {
|
||||
checkOfflineStatus();
|
||||
}
|
||||
}, [subplebbit?.updatedAt, subplebbitAddress]);
|
||||
const { isOffline, offlineTitle } = useIsSubplebbitOffline(subplebbit);
|
||||
|
||||
const onPublish = () => {
|
||||
if (!title) {
|
||||
@@ -235,7 +220,7 @@ const Submit = () => {
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
{isOffline && <div className={styles.infobar}>test</div>}
|
||||
{isOffline && selectedSubplebbit && <div className={styles.infobar}>{offlineTitle}</div>}
|
||||
<h1>
|
||||
<Trans
|
||||
i18nKey='submit_to'
|
||||
|
||||
Reference in New Issue
Block a user