MNTOR-2802 - Close dialog after pressing send verification button (#4134)

* MNTOR-2802 - Close dialog after pressing send verification button

* Add loader instead

* make laoder a component

* remove styles from emailaddressadder

* rm commented out code

* rm commented out code

* clean up comments

* add more detailed regex comment

* ignore test

* aria-polite and visuallyhidden msg

* lint

* move loader into btn component

* update loading string id
This commit is contained in:
Kaitlyn Andres 2024-02-12 13:02:47 -05:00 коммит произвёл GitHub
Родитель 7030e2b7cc
Коммит 430e6b162a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
5 изменённых файлов: 109 добавлений и 10 удалений

Просмотреть файл

@ -989,3 +989,6 @@ floating-banner-dismiss-button-label = No thanks
banner-monitor-rebrand-text = <b>{ -brand-mozilla-monitor }</b>: New name, look and even more ways to <b>reclaim your privacy</b>.
banner-monitor-rebrand-dismiss-button-label = OK
banner-monitor-rebrand-dismiss-button-tooltip = Dismiss
loading-accessibility = Loading

Просмотреть файл

@ -4,6 +4,10 @@
display: flex;
flex-direction: column;
gap: $spacing-md;
.description {
text-align: center;
}
}
.newEmailAddressForm {
@ -24,4 +28,8 @@
padding: $spacing-sm $spacing-md;
width: 100%;
}
.btn {
width: 300px;
}
}

Просмотреть файл

@ -4,7 +4,7 @@
"use client";
import { useEffect } from "react";
import { ChangeEvent, useEffect, useState } from "react";
import { useFormState } from "react-dom";
import { useOverlayTriggerState } from "react-stately";
import { useOverlayTrigger } from "react-aria";
@ -85,6 +85,8 @@ const EmailAddressAddForm = () => {
const l10n = useL10n();
const recordTelemetry = useTelemetry();
const [formState, formAction] = useFormState(onAddEmail, {});
const [hasPressedButton, setHasPressedButton] = useState(false);
const [email, setEmail] = useState("");
useEffect(() => {
if (typeof formState.success !== "undefined") {
@ -94,6 +96,18 @@ const EmailAddressAddForm = () => {
}
}, [formState, recordTelemetry]);
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
setEmail(e.target.value);
};
const isEmailValid = () => {
// Regex for checking email format
// ensuring it contains a local part, an "@" symbol,
// and a domain part.
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
return !formState.success ? (
<>
<p>
@ -105,14 +119,29 @@ const EmailAddressAddForm = () => {
<label htmlFor="newEmailAddress">
{l10n.getString("add-email-address-input-label")}
</label>
<input type="email" name="newEmailAddress" id="newEmailAddress" />
<Button type="submit" variant="primary">
<input
type="email"
name="newEmailAddress"
id="newEmailAddress"
onChange={handleInputChange}
/>
<Button
type="submit"
variant="primary"
className={styles.btn}
disabled={!isEmailValid()}
onPress={() => {
setHasPressedButton(true);
}}
isLoading={hasPressedButton}
aria-live="polite"
>
{l10n.getString("add-email-send-verification-button")}
</Button>
</form>
</>
) : (
<p>
<p className={styles.description}>
{l10n.getFragment("add-email-verify-the-link-2", {
vars: { email: formState.submittedAddress },
elems: { b: <b /> },

Просмотреть файл

@ -36,6 +36,11 @@
outline: $border-focus-width solid $color-red-30;
}
}
&.disabled {
background: $color-grey-20;
pointer-events: none;
}
}
&.secondary {
@ -58,6 +63,13 @@
color: $color-white;
}
}
&.disabled {
color: $color-grey-20;
background: transparent;
box-shadow: inset 0 0 0 2px $color-grey-20;
pointer-events: none;
}
}
&.tertiary {
@ -81,11 +93,39 @@
&.wide {
padding: $spacing-md $spacing-2xl;
}
}
&.disabled {
color: $color-grey-20;
background: transparent;
box-shadow: inset 0 0 0 2px $color-grey-20;
pointer-events: none;
// Loading animation
.ldsRing {
margin: 0 auto;
height: 18px;
width: 18px;
}
.ldsRing div {
box-sizing: border-box;
display: block;
position: absolute;
width: 18px;
height: 18px;
border: 4px solid #fff;
border-radius: 50%;
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: #fff transparent transparent transparent;
}
.ldsRing div:nth-child(1) {
animation-delay: -0.45s;
}
.ldsRing div:nth-child(2) {
animation-delay: -0.3s;
}
.ldsRing div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes lds-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

Просмотреть файл

@ -8,6 +8,8 @@ import { ReactNode, RefObject, useRef } from "react";
import Link from "next/link";
import styles from "./Button.module.scss";
import { useButton } from "react-aria";
import { useL10n } from "../../hooks/l10n";
import { VisuallyHidden } from "../server/VisuallyHidden";
export interface Props {
variant: "primary" | "secondary" | "tertiary";
@ -76,7 +78,24 @@ export const Button = (props: ButtonProps) => {
ref={buttonRef as RefObject<HTMLButtonElement>}
className={classes}
>
{children}
{isLoading ? <Loader /> : children}
</button>
);
};
/* This animation was adapted from https://loading.io/css/ */
/* c8 ignore start */
export const Loader = () => {
const l10n = useL10n();
return (
<div className={styles.ldsRing}>
<VisuallyHidden>{l10n.getString("loading-accessibility")}</VisuallyHidden>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
);
};
/* c8 ignore stop */