Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add validation/error handling to account settings update credentials #854

Merged
merged 42 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3b7d0c4
multi-step modal login/signup flow
austensen Feb 20, 2024
cc1d308
+
austensen Feb 20, 2024
dd08c25
ignore unused footer for now
austensen Feb 20, 2024
0beb6b3
add preview urls pattern to cors whitelist
austensen Feb 20, 2024
8343e22
add back preview urls to whitelist
austensen Feb 20, 2024
7c9eb33
clean up styles for login - text styles, padding, etc.
austensen Feb 21, 2024
dd804a8
refactor error handling in input components, clean type
austensen Feb 21, 2024
64768ca
login flow ending
austensen Feb 21, 2024
33a66af
ix double padding on subscribed box
austensen Feb 21, 2024
c266c18
prettier
austensen Feb 21, 2024
3b99332
clean up styles and fix subscribed icon
austensen Feb 21, 2024
c35e754
update headers and existinguser alerts on building apge
austensen Feb 22, 2024
b7e7220
update verify copy/styles, fix input-level errors for sign up
austensen Feb 22, 2024
3df1a46
update password props on reset and change pages
austensen Feb 23, 2024
7228b2b
fix account settings pw input styles
austensen Feb 23, 2024
670de39
remove unused icon
austensen Feb 23, 2024
edd268a
fix duplicate id on change password page
austensen Feb 23, 2024
ece5b38
don't show input-lvel error on bad pw format during login
austensen Feb 23, 2024
34d4c4a
make setError required for password input
austensen Feb 23, 2024
4bd4fe0
use same showError props for usertype error handling
austensen Feb 26, 2024
be1f499
add input props extends for email/pw, set auto focus on modal
austensen Feb 26, 2024
fff9d57
remove old id prop for pw input
austensen Feb 26, 2024
da8d76f
prevent extra i18n prop getting passed to input
austensen Feb 26, 2024
85e3760
usertype input remove preventDefault bug radio not updating
austensen Feb 26, 2024
3e5a4bb
add "didn't get link" line to on page verify reminder
austensen Feb 26, 2024
45c4318
show footer on login as well as sign up in modal
austensen Feb 26, 2024
5b5ff59
Merge branch 'email-alerts-account-signup' into user-type-modal
austensen Feb 26, 2024
baa71c5
fix typo in usertype input error
austensen Feb 28, 2024
200b1de
fix typo in email validation regex, add label as optional prop
austensen Feb 29, 2024
cc51ec5
show password rules when showError (even if empty)
austensen Feb 29, 2024
d0a60ff
add error handling of inputs before updating credentials
austensen Feb 29, 2024
46fc355
add missing pw field label
austensen Feb 29, 2024
a3b94d2
change email pattern to regex instead of string
austensen Feb 29, 2024
d7e1d3a
add password error label, fix label styles on account page
austensen Feb 29, 2024
aa60710
use icon components for password rules
austensen Mar 1, 2024
1388af5
fix spacing and alert placement/icon
austensen Mar 1, 2024
a807af3
change cancel button style
austensen Mar 1, 2024
31572bf
handle un-verifying on email change & display callout
austensen Mar 5, 2024
dfde959
Merge branch 'email-alerts-account-signup' into edit-credentials-vali…
austensen Mar 6, 2024
7bcd0e5
adjust for 16px base font
austensen Mar 6, 2024
0ef1dd8
fix some font sizes
austensen Mar 6, 2024
b4a2862
simplify PW rules/errors, cut duplicate cors setting
austensen Mar 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions client/src/components/EmailInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ interface EmailInputProps extends React.ComponentPropsWithoutRef<"input"> {
showError: boolean;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
i18nHash?: string;
labelText?: string;
}

const EmailInputWithoutI18n = forwardRef<HTMLInputElement, EmailInputProps>(
({ i18n, i18nHash, email, error, setError, showError, onChange, ...props }, ref) => {
({ i18n, i18nHash, email, error, setError, showError, onChange, labelText, ...props }, ref) => {
const isBadEmailFormat = (value: string) => {
/* valid email regex rules
alpha numeric characters are ok, upper/lower case agnostic
username: leading \_ ok, chars \_\.\-\+ ok in all other positions
domain name: chars \.\- ok as long as not leading. must end in a \. and at least two alphabet chars */
const pattern =
"^([a-zA-Z0-9_]+[a-zA-Z0-9+_.-]+@[a-zA-Z0-9]+[a-zA-Z0-9.-]+[a-zA-Z0-9]+.[a-zA-Z]{2,})$";
const pattern = /^([a-zA-Z0-9_]+[a-zA-Z0-9+_.-]+@[a-zA-Z0-9]+[a-zA-Z0-9.-]+[a-zA-Z0-9]+\.[a-zA-Z]{2,})$/;

// HTML input element has loose email validation requirements, so we check the input against a custom regex
const passStrictRegex = value.match(pattern);
Expand All @@ -43,9 +43,11 @@ const EmailInputWithoutI18n = forwardRef<HTMLInputElement, EmailInputProps>(

return (
<div className="email-input-field">
<div className="email-input-label">
<label htmlFor="email-input">{i18n._(t`Email address`)}</label>
</div>
{!!labelText && (
<div className="email-input-label">
<label htmlFor="email-input">{labelText}</label>
</div>
)}
{showError && error && (
<div className="email-input-errors">
<span id="input-field-error">
Expand Down
25 changes: 19 additions & 6 deletions client/src/components/Icons.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import React, { SVGProps } from "react";

export const DotIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
width="20"
height="21"
viewBox="0 0 20 21"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<circle cx="9.5" cy="10.1751" r="1.5" fill="currentcolor" />
</svg>
);

export const CloseIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
fill="none"
Expand Down Expand Up @@ -134,21 +147,21 @@ export const AlertIconOutline = (props: SVGProps<SVGSVGElement>) => (
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M10 18C5.58857 18 2 14.4113 2 10C2 5.58865 5.58865 2 10 2C14.4113 2 18 5.58865 18 10C18 14.3886 14.4113 18 10 18ZM10 3.34857C6.34278 3.34857 3.37143 6.32004 3.37143 9.97714C3.37143 13.6344 6.3429 16.6057 10 16.6057C13.6572 16.6057 16.6286 13.6342 16.6286 9.97714C16.6286 6.32004 13.6573 3.34857 10 3.34857Z"
fill="#242323"
fill="#FAF8F4"
/>
<path
d="M10.0002 11.1655C9.61166 11.1655 9.31445 10.8683 9.31445 10.4798V6.98263C9.31445 6.59408 9.61164 6.29688 10.0002 6.29688C10.3888 6.29688 10.686 6.59407 10.686 6.98263V10.4798C10.686 10.8685 10.3888 11.1655 10.0002 11.1655Z"
fill="#242323"
d="M9.99996 11.1657C9.61141 11.1657 9.31421 10.8685 9.31421 10.48V6.98281C9.31421 6.59426 9.6114 6.29706 9.99996 6.29706C10.3885 6.29706 10.6857 6.59425 10.6857 6.98281V10.48C10.6857 10.8687 10.3885 11.1657 9.99996 11.1657Z"
fill="#FAF8F4"
/>
<path
d="M10.0002 13.6799C9.81733 13.6799 9.63446 13.6114 9.52013 13.4743C9.38301 13.3371 9.31445 13.1771 9.31445 12.9942C9.31445 12.9484 9.31445 12.9028 9.33725 12.8571C9.33725 12.8113 9.36005 12.7657 9.38301 12.7199C9.40581 12.6742 9.42877 12.6514 9.45157 12.6056C9.47437 12.5599 9.49733 12.5371 9.54293 12.4913C9.79437 12.2399 10.2515 12.2399 10.5029 12.4913C10.5257 12.5141 10.5715 12.5599 10.5943 12.6056C10.6171 12.6514 10.64 12.6742 10.6628 12.7199C10.6856 12.7657 10.6856 12.8113 10.7086 12.8571C10.7086 12.9028 10.7314 12.9484 10.7314 12.9942C10.7314 13.1771 10.6628 13.3599 10.5257 13.4743C10.366 13.6114 10.1831 13.6799 10.0002 13.6799H10.0002Z"
fill="#242323"
d="M9.99997 13.68C9.81709 13.68 9.63422 13.6114 9.51989 13.4743C9.38277 13.3372 9.31421 13.1771 9.31421 12.9942C9.31421 12.9485 9.31421 12.9029 9.33701 12.8571C9.33701 12.8114 9.35981 12.7658 9.38277 12.72C9.40557 12.6743 9.42853 12.6514 9.45133 12.6057C9.47413 12.5599 9.49709 12.5371 9.54269 12.4914C9.79412 12.2399 10.2512 12.2399 10.5027 12.4914C10.5255 12.5142 10.5712 12.5599 10.594 12.6057C10.6168 12.6514 10.6398 12.6743 10.6626 12.72C10.6854 12.7658 10.6854 12.8114 10.7084 12.8571C10.7084 12.9029 10.7312 12.9485 10.7312 12.9942C10.7312 13.1771 10.6626 13.36 10.5255 13.4743C10.3657 13.6114 10.1829 13.68 9.99998 13.68H9.99997Z"
fill="#FAF8F4"
/>
</svg>
);
Expand Down
1 change: 1 addition & 0 deletions client/src/components/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ const LoginWithoutI18n = (props: LoginProps) => {
setError={setEmailError}
showError={showEmailError}
autoFocus={showRegisterModal && !email}
labelText={i18n._(t`Email address`)}
/>
)}
{(isLoginStep || isRegisterAccountStep) && (
Expand Down
29 changes: 22 additions & 7 deletions client/src/components/PasswordInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { LocaleLink } from "i18n";
import { createWhoOwnsWhatRoutePaths } from "routes";
import { I18n } from "@lingui/core";
import { t } from "@lingui/macro";
import { HideIcon, ShowIcon } from "./Icons";
import { AlertIcon, CheckIcon, DotIcon, HideIcon, ShowIcon } from "./Icons";
import classNames from "classnames";

type PasswordRule = {
Expand Down Expand Up @@ -82,26 +82,41 @@ const PasswordInputWithoutI18n = forwardRef<HTMLInputElement, PasswordInputProps
<LocaleLink
to={`${account.forgotPassword}?email=${encodeURIComponent(username || "")}`}
>
Forgot your password?
{i18n._(t`Forgot your password?`)}
</LocaleLink>
)}
</div>
{showPasswordRules && (
kiwansim marked this conversation as resolved.
Show resolved Hide resolved
<div className="password-input-rules">
{passwordRules.map((rule, i) => {
const ruleClass = !!password
? password.match(rule.regex)
? "valid"
: "invalid"
: "";
let ruleClass = "";
let RuleIcon = <DotIcon />;
if (!!password || showError) {
if (password.match(rule.regex)) {
ruleClass = "valid";
RuleIcon = <CheckIcon />;
} else {
ruleClass = "invalid";
RuleIcon = <AlertIcon />;
}
}
return (
<span className={`password-input-rule ${ruleClass}`} key={`rule-${i}`}>
{RuleIcon}
{rule.label}
</span>
);
})}
</div>
)}
{!showPasswordRules && showError && error && (
<div className="password-input-errors">
<span id="input-field-error">
<AlertIcon />
{i18n._(t`Please enter password.`)}
</span>
</div>
)}
<div className="password-input">
<input
type={showPassword ? "text" : "password"}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/UserContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export const UserContextProvider = ({ children }: { children: React.ReactNode })
if (user) {
const asyncUpdateEmail = async () => {
const response = await AuthClient.updateEmail(email);
setUser({ ...user, email: response.email });
setUser({ ...user, email: response.email, verified: false });
};
asyncUpdateEmail();
}
Expand Down
Loading