diff --git a/app/assets/javascripts/components/AccountMenu/GeneralAccountMenu.tsx b/app/assets/javascripts/components/AccountMenu/GeneralAccountMenu.tsx index 88fd1c718..68e00ed9a 100644 --- a/app/assets/javascripts/components/AccountMenu/GeneralAccountMenu.tsx +++ b/app/assets/javascripts/components/AccountMenu/GeneralAccountMenu.tsx @@ -70,16 +70,19 @@ export const GeneralAccountMenu: FunctionComponent = observer(
{user.email}
{application.getHost()} -
+
{isSyncingInProgress ? (
Syncing...
) : ( -
- - Last synced: {lastSyncDate} +
+ +
+
Last synced:
+
{lastSyncDate}
+
)}
= observer( useEffect(() => { if (emailInputRef?.current) { - emailInputRef.current!.focus(); + emailInputRef.current?.focus(); } }, []); @@ -73,8 +73,8 @@ export const SignInPane: FunctionComponent = observer( const signIn = () => { setIsSigningIn(true); - emailInputRef?.current!.blur(); - passwordInputRef?.current!.blur(); + emailInputRef?.current?.blur(); + passwordInputRef?.current?.blur(); application .signIn(email, password, isStrictSignin, isEphemeral, shouldMergeLocal) @@ -92,7 +92,7 @@ export const SignInPane: FunctionComponent = observer( application.alertService.alert(err); } setPassword(''); - passwordInputRef?.current!.blur(); + passwordInputRef?.current?.blur(); }) .finally(() => { setIsSigningIn(false); @@ -109,12 +109,12 @@ export const SignInPane: FunctionComponent = observer( e.preventDefault(); if (!email || email.length === 0) { - emailInputRef?.current!.focus(); + emailInputRef?.current?.focus(); return; } if (!password || password.length === 0) { - passwordInputRef?.current!.focus(); + passwordInputRef?.current?.focus(); return; } @@ -134,69 +134,67 @@ export const SignInPane: FunctionComponent = observer( />
Sign in
-
-
- - - {isInvalid ? ( -
- Invalid email or password. -
- ) : null} -
-
+ ) : null} +
(null); + + useCloseOnClickOutside(menuRef as any, (open: boolean) => { + if (!open) { + setShowMenuFalse(); + } + }); + return ( -
+
Sort by diff --git a/app/assets/javascripts/components/QuickSettingsMenu/QuickSettingsMenu.tsx b/app/assets/javascripts/components/QuickSettingsMenu/QuickSettingsMenu.tsx index c9d0fc86d..e99780544 100644 --- a/app/assets/javascripts/components/QuickSettingsMenu/QuickSettingsMenu.tsx +++ b/app/assets/javascripts/components/QuickSettingsMenu/QuickSettingsMenu.tsx @@ -76,55 +76,67 @@ const QuickSettingsMenu: FunctionComponent = observer( }, [focusModeEnabled]); const reloadThemes = useCallback(() => { - application.streamItems(ContentType.Theme, () => { - const themes = application.getDisplayableItems( - ContentType.Theme - ) as SNTheme[]; - setThemes( - themes.sort((a, b) => { - const aIsLayerable = a.isLayerable(); - const bIsLayerable = b.isLayerable(); + const themes = application.getDisplayableItems( + ContentType.Theme + ) as SNTheme[]; + setThemes( + themes.sort((a, b) => { + const aIsLayerable = a.isLayerable(); + const bIsLayerable = b.isLayerable(); - if (aIsLayerable && !bIsLayerable) { - return 1; - } else if (!aIsLayerable && bIsLayerable) { - return -1; - } else { - return a.package_info.name.toLowerCase() < - b.package_info.name.toLowerCase() - ? -1 - : 1; - } - }) - ); - setDefaultThemeOn( - !themes.find((theme) => theme.active && !theme.isLayerable()) - ); - }); + if (aIsLayerable && !bIsLayerable) { + return 1; + } else if (!aIsLayerable && bIsLayerable) { + return -1; + } else { + return a.package_info.name.toLowerCase() < + b.package_info.name.toLowerCase() + ? -1 + : 1; + } + }) + ); + setDefaultThemeOn( + !themes.find((theme) => theme.active && !theme.isLayerable()) + ); }, [application]); const reloadToggleableComponents = useCallback(() => { - application.streamItems(ContentType.Component, () => { - const toggleableComponents = ( - application.getDisplayableItems( - ContentType.Component - ) as SNComponent[] - ).filter((component) => - [ComponentArea.EditorStack, ComponentArea.TagsList].includes( - component.area - ) - ); - setToggleableComponents(toggleableComponents); - }); + const toggleableComponents = ( + application.getDisplayableItems(ContentType.Component) as SNComponent[] + ).filter((component) => + [ComponentArea.EditorStack, ComponentArea.TagsList].includes( + component.area + ) + ); + setToggleableComponents(toggleableComponents); }, [application]); useEffect(() => { - reloadThemes(); - }, [reloadThemes]); + const cleanupItemStream = application.streamItems( + ContentType.Theme, + () => { + reloadThemes(); + } + ); + + return () => { + cleanupItemStream(); + }; + }, [application, reloadThemes]); useEffect(() => { - reloadToggleableComponents(); - }, [reloadToggleableComponents]); + const cleanupItemStream = application.streamItems( + ContentType.Component, + () => { + reloadToggleableComponents(); + } + ); + + return () => { + cleanupItemStream(); + }; + }, [application, reloadToggleableComponents]); useEffect(() => { if (themesMenuOpen) { @@ -274,10 +286,9 @@ const QuickSettingsMenu: FunctionComponent = observer( ) : null} {toggleableComponents.map((component) => ( - { +
- + + ))} = observer(({ application, appState }) => { - const [activationCode, setActivationCode] = useState(''); - const [isSuccessfullyActivated, setIsSuccessfullyActivated] = useState(false); - const [isSuccessfullyRemoved, setIsSuccessfullyRemoved] = useState(false); - const [hasUserPreviouslyStoredCode, setHasUserPreviouslyStoredCode] = useState(false); +export const OfflineSubscription: FunctionalComponent = observer( + ({ application, appState }) => { + const [activationCode, setActivationCode] = useState(''); + const [isSuccessfullyActivated, setIsSuccessfullyActivated] = + useState(false); + const [isSuccessfullyRemoved, setIsSuccessfullyRemoved] = useState(false); + const [hasUserPreviouslyStoredCode, setHasUserPreviouslyStoredCode] = + useState(false); - useEffect(() => { - if (application.hasOfflineRepo()) { - setHasUserPreviouslyStoredCode(true); + useEffect(() => { + if (application.hasOfflineRepo()) { + setHasUserPreviouslyStoredCode(true); + } + }, [application]); + + const shouldShowOfflineSubscription = () => { + return !application.hasAccount() || application.isThirdPartyHostUsed(); + }; + + const handleSubscriptionCodeSubmit = async ( + event: TargetedEvent + ) => { + event.preventDefault(); + + const result = await application.setOfflineFeaturesCode(activationCode); + + if (result?.error) { + await application.alertService.alert(result.error); + } else { + setIsSuccessfullyActivated(true); + setHasUserPreviouslyStoredCode(true); + setIsSuccessfullyRemoved(false); + } + }; + + const handleRemoveOfflineKey = async () => { + await application.deleteOfflineFeatureRepo(); + + setIsSuccessfullyActivated(false); + setHasUserPreviouslyStoredCode(false); + setActivationCode(''); + setIsSuccessfullyRemoved(true); + }; + + const handleRemoveClick = async () => { + application.alertService + .confirm( + STRING_REMOVE_OFFLINE_KEY_CONFIRMATION, + 'Remove offline key?', + 'Remove Offline Key', + ButtonType.Danger, + 'Cancel' + ) + .then(async (shouldRemove: boolean) => { + if (shouldRemove) { + await handleRemoveOfflineKey(); + } + }) + .catch((err: string) => { + application.alertService.alert(err); + }); + }; + + if (!shouldShowOfflineSubscription()) { + return null; } - }, [application]); - const shouldShowOfflineSubscription = () => { - return !application.hasAccount() || application.isCustomServerHostUsed(); - }; - - const handleSubscriptionCodeSubmit = async (event: TargetedEvent) => { - event.preventDefault(); - - const result = await application.setOfflineFeaturesCode(activationCode); - - if (result?.error) { - await application.alertService.alert(result.error); - } else { - setIsSuccessfullyActivated(true); - setHasUserPreviouslyStoredCode(true); - setIsSuccessfullyRemoved(false); - } - }; - - const handleRemoveOfflineKey = async () => { - await application.deleteOfflineFeatureRepo(); - - setIsSuccessfullyActivated(false); - setHasUserPreviouslyStoredCode(false); - setActivationCode(''); - setIsSuccessfullyRemoved(true); - }; - - const handleRemoveClick = async () => { - application.alertService.confirm( - STRING_REMOVE_OFFLINE_KEY_CONFIRMATION, - 'Remove offline key?', - 'Remove Offline Key', - ButtonType.Danger, - 'Cancel' - ) - .then(async (shouldRemove: boolean) => { - if (shouldRemove) { - await handleRemoveOfflineKey(); - } - }) - .catch((err: string) => { - application.alertService.alert(err); - }); - }; - - if (!shouldShowOfflineSubscription()) { - return null; - } - - return ( - <> -
-
- {!hasUserPreviouslyStoredCode && 'Activate'} Offline Subscription -
-
- {!hasUserPreviouslyStoredCode && ( - setActivationCode(code)} - placeholder={'Offline Subscription Code'} - text={activationCode} - disabled={isSuccessfullyActivated} - className={'mb-3'} + return ( + <> +
+
+ + {!hasUserPreviouslyStoredCode && 'Activate'} Offline Subscription + + +
+ {!hasUserPreviouslyStoredCode && ( + setActivationCode(code)} + placeholder={'Offline Subscription Code'} + text={activationCode} + disabled={isSuccessfullyActivated} + className={'mb-3'} + /> + )} +
+ {(isSuccessfullyActivated || isSuccessfullyRemoved) && ( +
+ Your offline subscription code has been successfully{' '} + {isSuccessfullyActivated ? 'activated' : 'removed'}. +
+ )} + {hasUserPreviouslyStoredCode && ( +
- {(isSuccessfullyActivated || isSuccessfullyRemoved) && ( -
- Your offline subscription code has been successfully {isSuccessfullyActivated ? 'activated' : 'removed'}. -
- )} - {hasUserPreviouslyStoredCode && ( -
-
- - - ); -}); + + + ); + } +); diff --git a/app/assets/stylesheets/_sn.scss b/app/assets/stylesheets/_sn.scss index d15fd11d5..ccc5f0960 100644 --- a/app/assets/stylesheets/_sn.scss +++ b/app/assets/stylesheets/_sn.scss @@ -256,6 +256,10 @@ margin-right: 0.75rem; } +.mr-4 { + margin-right: 1rem; +} + .mr-12 { margin-right: 3rem; } @@ -283,6 +287,10 @@ margin-bottom: 0.5rem; } +.max-w-1\/2 { + max-width: 50%; +} + .max-w-3\/4 { max-width: 75%; } diff --git a/package.json b/package.json index 988b47cb0..24e14d0eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "standard-notes-web", - "version": "3.9.8", + "version": "3.9.10", "license": "AGPL-3.0-or-later", "repository": { "type": "git", @@ -85,7 +85,7 @@ "@reach/listbox": "^0.16.2", "@standardnotes/features": "1.10.2", "@standardnotes/sncrypto-web": "1.5.3", - "@standardnotes/snjs": "2.20.1", + "@standardnotes/snjs": "2.20.3", "mobx": "^6.3.5", "mobx-react-lite": "^3.2.2", "preact": "^10.5.15", diff --git a/yarn.lock b/yarn.lock index 4594c405f..497074ac1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2614,10 +2614,10 @@ buffer "^6.0.3" libsodium-wrappers "^0.7.9" -"@standardnotes/snjs@2.20.1": - version "2.20.1" - resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.20.1.tgz#4813adbfd16a1c373357bd4c7ece3085abf142b4" - integrity sha512-wJILt7YerLFaZTKoIZaCkqSuvpVWoVKqCVjP0KNHrMknnbgMHZygHqrb9sr57JL1AcNCkAULEFS/kev2GYTG3Q== +"@standardnotes/snjs@2.20.3": + version "2.20.3" + resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.20.3.tgz#11fe962dfb017be459e856b9fbc6311c5046a0b0" + integrity sha512-FHog3p3SuMvTXsEl76UenbjY8PS6VL/b6MjaC9whJR5ZwsvmLwE0G16dWZ+z+izm+CsRaHMWU8R2cy7RG7HjZg== dependencies: "@standardnotes/auth" "^3.8.1" "@standardnotes/common" "^1.2.1"