Settings Page: add warning for unsaved settings (#430)
* Settings Page: add warning for unsaved settings ## Issue When entering Settings Page, sync-loop is disable until user exist Settings Page. If browser is closed, changes will be lost. ## Change Add the usual browser-level modal popup. Note that all modern browsers have stopped supporting customized messages, but I still left the message there for clarity. Tried to use our own toast for it, but the handler locks all GUI until it is serviced. * app: remove unused props * app: use lighter selectors When all we need is to know if something exists or their count, use the ID version instead of the url/claim version to avoid the heavy transformation.
This commit is contained in:
parent
fb7c5d0fff
commit
08ebedb4cc
3 changed files with 28 additions and 18 deletions
|
@ -2242,5 +2242,6 @@
|
|||
"Switch to Credits": "Switch to Credits",
|
||||
"Cookies": "Cookies",
|
||||
"Did someone invite you to use Odysee? Tell us who and you both get a reward!": "Did someone invite you to use Odysee? Tell us who and you both get a reward!",
|
||||
"There are unsaved settings. Exit the Settings Page to finalize them.": "There are unsaved settings. Exit the Settings Page to finalize them.",
|
||||
"--end--": "--end--"
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
import { hot } from 'react-hot-loader/root';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectGetSyncErrorMessage, selectSyncFatalError } from 'redux/selectors/sync';
|
||||
import { selectGetSyncErrorMessage, selectSyncFatalError, selectSyncIsLocked } from 'redux/selectors/sync';
|
||||
import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user';
|
||||
import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
import { selectUnclaimedRewards } from 'redux/selectors/rewards';
|
||||
import { doFetchChannelListMine, doFetchCollectionListMine, doResolveUris } from 'redux/actions/claims';
|
||||
import { selectMyChannelUrls } from 'redux/selectors/claims';
|
||||
import * as SETTINGS from 'constants/settings';
|
||||
import { selectMyChannelClaimIds } from 'redux/selectors/claims';
|
||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||
import { selectClientSetting, selectLanguage, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings';
|
||||
import { selectLanguage, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings';
|
||||
import {
|
||||
selectIsUpgradeAvailable,
|
||||
selectAutoUpdateDownloaded,
|
||||
selectModal,
|
||||
selectActiveChannelClaim,
|
||||
selectActiveChannelId,
|
||||
selectIsReloadRequired,
|
||||
} from 'redux/selectors/app';
|
||||
import { selectUploadCount } from 'redux/selectors/publish';
|
||||
|
@ -28,19 +27,19 @@ const select = (state) => ({
|
|||
accessToken: selectAccessToken(state),
|
||||
theme: selectThemePath(state),
|
||||
language: selectLanguage(state),
|
||||
syncEnabled: selectClientSetting(state, SETTINGS.ENABLE_SYNC),
|
||||
languages: selectLoadedLanguages(state),
|
||||
autoUpdateDownloaded: selectAutoUpdateDownloaded(state),
|
||||
isUpgradeAvailable: selectIsUpgradeAvailable(state),
|
||||
isReloadRequired: selectIsReloadRequired(state),
|
||||
syncError: selectGetSyncErrorMessage(state),
|
||||
syncIsLocked: selectSyncIsLocked(state),
|
||||
uploadCount: selectUploadCount(state),
|
||||
rewards: selectUnclaimedRewards(state),
|
||||
isAuthenticated: selectUserVerifiedEmail(state),
|
||||
currentModal: selectModal(state),
|
||||
syncFatalError: selectSyncFatalError(state),
|
||||
activeChannelClaim: selectActiveChannelClaim(state),
|
||||
myChannelUrls: selectMyChannelUrls(state),
|
||||
activeChannelId: selectActiveChannelId(state),
|
||||
myChannelClaimIds: selectMyChannelClaimIds(state),
|
||||
subscriptions: selectSubscriptions(state),
|
||||
});
|
||||
|
||||
|
|
|
@ -62,24 +62,22 @@ type Props = {
|
|||
fetchCollectionListMine: () => void,
|
||||
signIn: () => void,
|
||||
requestDownloadUpgrade: () => void,
|
||||
onSignedIn: () => void,
|
||||
setLanguage: (string) => void,
|
||||
isUpgradeAvailable: boolean,
|
||||
isReloadRequired: boolean,
|
||||
autoUpdateDownloaded: boolean,
|
||||
uploadCount: number,
|
||||
balance: ?number,
|
||||
syncIsLocked: boolean,
|
||||
syncError: ?string,
|
||||
syncEnabled: boolean,
|
||||
rewards: Array<Reward>,
|
||||
setReferrer: (string, boolean) => void,
|
||||
isAuthenticated: boolean,
|
||||
socketConnect: () => void,
|
||||
syncLoop: (?boolean) => void,
|
||||
currentModal: any,
|
||||
syncFatalError: boolean,
|
||||
activeChannelClaim: ?ChannelClaim,
|
||||
myChannelUrls: ?Array<string>,
|
||||
activeChannelId: ?string,
|
||||
myChannelClaimIds: ?Array<string>,
|
||||
subscriptions: Array<Subscription>,
|
||||
setActiveChannelIfNotSet: () => void,
|
||||
setIncognito: (boolean) => void,
|
||||
|
@ -103,6 +101,7 @@ function App(props: Props) {
|
|||
uploadCount,
|
||||
history,
|
||||
syncError,
|
||||
syncIsLocked,
|
||||
language,
|
||||
languages,
|
||||
setLanguage,
|
||||
|
@ -112,8 +111,8 @@ function App(props: Props) {
|
|||
syncLoop,
|
||||
currentModal,
|
||||
syncFatalError,
|
||||
myChannelUrls,
|
||||
activeChannelClaim,
|
||||
myChannelClaimIds,
|
||||
activeChannelId,
|
||||
setActiveChannelIfNotSet,
|
||||
setIncognito,
|
||||
fetchModBlockedList,
|
||||
|
@ -150,10 +149,10 @@ function App(props: Props) {
|
|||
const shouldHideNag = pathname.startsWith(`/$/${PAGES.EMBED}`) || pathname.startsWith(`/$/${PAGES.AUTH_VERIFY}`);
|
||||
const userId = user && user.id;
|
||||
const useCustomScrollbar = !IS_MAC;
|
||||
const hasMyChannels = myChannelUrls && myChannelUrls.length > 0;
|
||||
const hasNoChannels = myChannelUrls && myChannelUrls.length === 0;
|
||||
const hasMyChannels = myChannelClaimIds && myChannelClaimIds.length > 0;
|
||||
const hasNoChannels = myChannelClaimIds && myChannelClaimIds.length === 0;
|
||||
const shouldMigrateLanguage = LANGUAGE_MIGRATIONS[language];
|
||||
const hasActiveChannelClaim = activeChannelClaim !== undefined;
|
||||
const hasActiveChannelClaim = activeChannelId !== undefined;
|
||||
const isPersonalized = !IS_WEB || hasVerifiedEmail;
|
||||
const renderFiledrop = !IS_WEB || isAuthenticated;
|
||||
const isOnline = navigator.onLine;
|
||||
|
@ -219,6 +218,17 @@ function App(props: Props) {
|
|||
}
|
||||
}, [userId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (syncIsLocked) {
|
||||
const handleBeforeUnload = (event) => {
|
||||
event.preventDefault();
|
||||
event.returnValue = __('There are unsaved settings. Exit the Settings Page to finalize them.');
|
||||
};
|
||||
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
}
|
||||
}, [syncIsLocked]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!uploadCount) return;
|
||||
const handleBeforeUnload = (event) => {
|
||||
|
|
Loading…
Reference in a new issue