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:
Родитель
7030e2b7cc
Коммит
430e6b162a
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче