feat: New account menu and text input with icon & toggle (#665)

* feat: Add new icons

* Revert "feat: Add new icons"

This reverts commit 0acb403fe846dbb2e48fd22de35c3568c3cb4453.

* feat: Add new icons for account menu

* feat: Add new Icons

* feat: Add "currentPane" state to prefs view

* feat: Update account menu to new design

* feat: Add input component with icon & toggle

* fix: sync icon & function

* fix: Fix eye icon

* feat: Create re-usable checkbox

feat: Add "merge local" option

* feat: Allow using className on IconButton

* feat: Add disabled state on input

feat: Make toggle circle

* refactor: Move checkbox to components

* feat: Handle invalid email/password error

* feat: Implement new design for Create Account

* feat: Implement new account menu design

* feat: Add disabled option to IconButton

* feat: Set account menu pane from other component

* feat: Add 2fa account menu pane

feat: Add lock icon

* feat: Remove unnecessary 2FA menu pane

feat: Reset current menu pane on clickOutside

* feat: Change "Log in" to "Sign in"

* feat: Remove sync from footer

* feat: Change "Login" to "Sign in"

feat: Add spinner to "Syncing..."

refactor: Use then-catch-finally for sync

* feat: Use common enableCustomServer state

* feat: Animate account menu closing

* fix: Reset menu pane only after it's closed

* feat: Add keyDown handler to InputWithIcon

* feat: Handle Enter press in inputs

* Update app/assets/javascripts/components/InputWithIcon.tsx

Co-authored-by: Antonella Sgarlatta <antsgar@gmail.com>

* Update app/assets/javascripts/components/InputWithIcon.tsx

Co-authored-by: Antonella Sgarlatta <antsgar@gmail.com>

* refactor: Use server state from AccountMenuState

* Update app/assets/javascripts/components/AccountMenu/CreateAccount.tsx

Co-authored-by: Antonella Sgarlatta <antsgar@gmail.com>

* Update app/assets/javascripts/components/AccountMenu/ConfirmPassword.tsx

Co-authored-by: Antonella Sgarlatta <antsgar@gmail.com>

* feat: Use common AdvancedOptions

* feat: Add "eye-off" icon and toggle state

* feat: Allow undefined values

* refactor: Remove enableCustomServer state

* feat: Persist server option state

* feat: Add bottom-100 and cursor-auto util classes

refactor: Use bottom-100 and cursor-auto classes

* refactor: Invert ternary operator

* refactor: Remove unused imports

* refactor: Use toggled as prop instead of state

* refactor: Change "Log in/out" to "Sign in/out"

* refactor: Change "Login" to "Sign in"

* refactor: Remove hardcoded width/height

* refactor: Use success class

* feat: Remove hardcoded width & height from svg

* fix: Fix chevron-down icon

Co-authored-by: Antonella Sgarlatta <antsgar@gmail.com>
Co-authored-by: Antonella Sgarlatta <antonella@standardnotes.org>
This commit is contained in:
Aman Harwara
2021-10-08 21:48:31 +05:30
committed by GitHub
parent 7b6c99d188
commit f1122f292e
51 changed files with 1566 additions and 407 deletions

View File

@@ -3,7 +3,7 @@ import {
STRING_ACCOUNT_MENU_UNCHECK_MERGE,
STRING_GENERATING_LOGIN_KEYS,
STRING_GENERATING_REGISTER_KEYS,
STRING_NON_MATCHING_PASSWORDS
STRING_NON_MATCHING_PASSWORDS,
} from '@/strings';
import { JSXInternal } from 'preact/src/jsx';
import TargetedEvent = JSXInternal.TargetedEvent;
@@ -17,13 +17,9 @@ import { AppState } from '@/ui_models/app_state';
type Props = {
application: WebApplication;
appState: AppState;
}
const Authentication = observer(({
application,
appState,
}: Props) => {
};
const Authentication = observer(({ application, appState }: Props) => {
const [showAdvanced, setShowAdvanced] = useState(false);
const [isAuthenticating, setIsAuthenticating] = useState(false);
const [email, setEmail] = useState('');
@@ -39,12 +35,12 @@ const Authentication = observer(({
const {
server,
notesAndTagsCount,
showLogin,
showSignIn,
showRegister,
setShowLogin,
setShowSignIn,
setShowRegister,
setServer,
closeAccountMenu
closeAccountMenu,
} = appState.accountMenu;
const user = application.getUser();
@@ -58,11 +54,11 @@ const Authentication = observer(({
// Reset password and confirmation fields when hiding the form
useEffect(() => {
if (!showLogin && !showRegister) {
if (!showSignIn && !showRegister) {
setPassword('');
setPasswordConfirmation('');
}
}, [showLogin, showRegister]);
}, [showSignIn, showRegister]);
const handleHostInputChange = (event: TargetedEvent<HTMLInputElement>) => {
const { value } = event.target as HTMLInputElement;
@@ -75,7 +71,7 @@ const Authentication = observer(({
const passwordConfirmationInputRef = useRef<HTMLInputElement>();
const handleSignInClick = () => {
setShowLogin(true);
setShowSignIn(true);
setIsEmailFocused(true);
};
@@ -90,7 +86,7 @@ const Authentication = observer(({
passwordConfirmationInputRef.current?.blur();
};
const login = async () => {
const signin = async () => {
setStatus(STRING_GENERATING_LOGIN_KEYS);
setIsAuthenticating(true);
@@ -105,13 +101,13 @@ const Authentication = observer(({
if (!error) {
setIsAuthenticating(false);
setPassword('');
setShowLogin(false);
setShowSignIn(false);
closeAccountMenu();
return;
}
setShowLogin(true);
setShowSignIn(true);
setStatus(undefined);
setPassword('');
@@ -150,10 +146,11 @@ const Authentication = observer(({
}
};
const handleAuthFormSubmit = (event:
TargetedEvent<HTMLFormElement> |
TargetedMouseEvent<HTMLButtonElement> |
TargetedKeyboardEvent<HTMLButtonElement>
const handleAuthFormSubmit = (
event:
| TargetedEvent<HTMLFormElement>
| TargetedMouseEvent<HTMLButtonElement>
| TargetedKeyboardEvent<HTMLButtonElement>
) => {
event.preventDefault();
@@ -163,8 +160,8 @@ const Authentication = observer(({
blurAuthFields();
if (showLogin) {
login();
if (showSignIn) {
signin();
} else {
register();
}
@@ -186,19 +183,23 @@ const Authentication = observer(({
setEmail(value);
};
const handlePasswordConfirmationChange = (event: TargetedEvent<HTMLInputElement>) => {
const handlePasswordConfirmationChange = (
event: TargetedEvent<HTMLInputElement>
) => {
const { value } = event.target as HTMLInputElement;
setPasswordConfirmation(value);
};
const handleMergeLocalData = async (event: TargetedEvent<HTMLInputElement>) => {
const handleMergeLocalData = async (
event: TargetedEvent<HTMLInputElement>
) => {
const { checked } = event.target as HTMLInputElement;
setShouldMergeLocal(checked);
if (!checked) {
const confirmResult = await confirmDialog({
text: STRING_ACCOUNT_MENU_UNCHECK_MERGE,
confirmButtonStyle: 'danger'
confirmButtonStyle: 'danger',
});
setShouldMergeLocal(!confirmResult);
}
@@ -206,10 +207,12 @@ const Authentication = observer(({
return (
<>
{!user && !showLogin && !showRegister && (
{!user && !showSignIn && !showRegister && (
<div className="sk-panel-section sk-panel-hero">
<div className="sk-panel-row">
<div className="sk-h1">Sign in or register to enable sync and end-to-end encryption.</div>
<div className="sk-h1">
Sign in or register to enable sync and end-to-end encryption.
</div>
</div>
<div className="flex my-1">
<button
@@ -226,17 +229,21 @@ const Authentication = observer(({
</button>
</div>
<div className="sk-panel-row sk-p">
Standard Notes is free on every platform, and comes
standard with sync and encryption.
Standard Notes is free on every platform, and comes standard with
sync and encryption.
</div>
</div>
)}
{(showLogin || showRegister) && (
{(showSignIn || showRegister) && (
<div className="sk-panel-section">
<div className="sk-panel-section-title">
{showLogin ? 'Sign In' : 'Register'}
{showSignIn ? 'Sign In' : 'Register'}
</div>
<form className="sk-panel-form" onSubmit={handleAuthFormSubmit} noValidate>
<form
className="sk-panel-form"
onSubmit={handleAuthFormSubmit}
noValidate
>
<div className="sk-panel-section">
<input
className="sk-input contrast"
@@ -261,26 +268,28 @@ const Authentication = observer(({
onKeyDown={handleKeyPressKeyDown}
ref={passwordInputRef}
/>
{showRegister &&
<input
className="sk-input contrast"
name="password_conf"
type="password"
placeholder="Confirm Password"
required
onKeyPress={handleKeyPressKeyDown}
onKeyDown={handleKeyPressKeyDown}
value={passwordConfirmation}
onChange={handlePasswordConfirmationChange}
ref={passwordConfirmationInputRef}
/>}
{showRegister && (
<input
className="sk-input contrast"
name="password_conf"
type="password"
placeholder="Confirm Password"
required
onKeyPress={handleKeyPressKeyDown}
onKeyDown={handleKeyPressKeyDown}
value={passwordConfirmation}
onChange={handlePasswordConfirmationChange}
ref={passwordConfirmationInputRef}
/>
)}
<div className="sk-panel-row" />
<button
type="button"
className="sk-a info font-bold text-left p-0 cursor-pointer hover:underline mr-1 ml-1"
onClick={() => {
setShowAdvanced(!showAdvanced);
}}>
}}
>
Advanced Options
</button>
</div>
@@ -301,24 +310,28 @@ const Authentication = observer(({
required
/>
</div>
{showLogin && (
{showSignIn && (
<label className="sk-label padded-row sk-panel-row justify-left">
<div className="sk-horizontal-group tight cursor-pointer">
<input
className="sk-input"
type="checkbox"
checked={isStrictSignIn}
onChange={() => setIsStrictSignIn(prevState => !prevState)}
onChange={() =>
setIsStrictSignIn((prevState) => !prevState)
}
/>
<p className="sk-p">Use strict sign in</p>
<span>
<a className="info"
href="https://standardnotes.com/help/security" rel="noopener"
target="_blank"
>
(Learn more)
</a>
</span>
<a
className="info"
href="https://standardnotes.com/help/security"
rel="noopener"
target="_blank"
>
(Learn more)
</a>
</span>
</div>
</label>
)}
@@ -327,9 +340,12 @@ const Authentication = observer(({
)}
{!isAuthenticating && (
<div className="sk-panel-section form-submit">
<button className="sn-button info text-base py-3 text-center" type="submit"
disabled={isAuthenticating}>
{showLogin ? 'Sign In' : 'Register'}
<button
className="sn-button info text-base py-3 text-center"
type="submit"
disabled={isAuthenticating}
>
{showSignIn ? 'Sign In' : 'Register'}
</button>
</div>
)}
@@ -337,9 +353,9 @@ const Authentication = observer(({
<div className="sk-notification neutral">
<div className="sk-notification-title">No Password Reset.</div>
<div className="sk-notification-text">
Because your notes are encrypted using your password,
Standard Notes does not have a password reset option.
You cannot forget your password.
Because your notes are encrypted using your password, Standard
Notes does not have a password reset option. You cannot forget
your password.
</div>
</div>
)}
@@ -358,7 +374,7 @@ const Authentication = observer(({
<input
type="checkbox"
checked={!isEphemeral}
onChange={() => setIsEphemeral(prevState => !prevState)}
onChange={() => setIsEphemeral((prevState) => !prevState)}
/>
<p className="sk-p">Stay signed in</p>
</div>
@@ -371,7 +387,9 @@ const Authentication = observer(({
checked={shouldMergeLocal}
onChange={handleMergeLocalData}
/>
<p className="sk-p">Merge local data ({notesAndTagsCount}) notes and tags</p>
<p className="sk-p">
Merge local data ({notesAndTagsCount}) notes and tags
</p>
</div>
</label>
)}
@@ -379,7 +397,8 @@ const Authentication = observer(({
)}
</form>
</div>
)}</>
)}
</>
);
});