From 1940170d28a07bed5ce2caa0ce37ebf1b6cd14f3 Mon Sep 17 00:00:00 2001
From: Bill John Tran <bill@billjohntran.com>
Date: Wed, 8 May 2024 08:44:26 -0700
Subject: [PATCH] Asub 8194/magic link login without pw (#2110)

* add login without password

* add login without password

* Bump @babel/preset-react from 7.23.3 to 7.24.1 (#2050)

Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.23.3 to 7.24.1.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.1/packages/babel-preset-react)

---
updated-dependencies:
- dependency-name: "@babel/preset-react"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Added esc event listener to useEffect (#2044)

* Added esc event listener to useEffect

---------

Co-authored-by: Malavika Koppula <mkreddy1110@gmail.com>

* Added overflow to section-title links (#2027)

* Added flex to section-title links

---------

Co-authored-by: Malavika Koppula <mkreddy1110@gmail.com>

* Bump algoliasearch from 4.23.1 to 4.23.2 (#2057)

Bumps [algoliasearch](https://github.com/algolia/algoliasearch-client-javascript) from 4.23.1 to 4.23.2.
- [Release notes](https://github.com/algolia/algoliasearch-client-javascript/releases)
- [Changelog](https://github.com/algolia/algoliasearch-client-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/algolia/algoliasearch-client-javascript/compare/4.23.1...4.23.2)

---
updated-dependencies:
- dependency-name: algoliasearch
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump eslint-plugin-react from 7.33.2 to 7.34.1 (#2062)

Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.33.2 to 7.34.1.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/v7.34.1/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.33.2...v7.34.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump glob from 10.3.10 to 10.3.12 (#2063)

Bumps [glob](https://github.com/isaacs/node-glob) from 10.3.10 to 10.3.12.
- [Changelog](https://github.com/isaacs/node-glob/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/node-glob/compare/v10.3.10...v10.3.12)

---
updated-dependencies:
- dependency-name: glob
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Manual promo blocks now respect focal point (#1996)

* add focal point code and tests

* fix eslint errors

* fix formatting

* fix formatting p2

* shorten PR template based on eng sync discussions (#2065)

* add onetime password

* ASUB-8201 Sign In with Apple (#2067)

* Sign In with Apple

* fixing linting and tests

* fixing test & linting

* fixing linting errors

* removing update from  package.json

* fixing linting errors

* disable eslint warnings

* fixing warnings

* fixing sintax

* removing keys

* removing only

* fixing linting errors

* add sucess page and recaptcha

* add translations

* update intl.json

* add tests for ota feature

* remove act

* lint fixes

* lint fixes

* lint fixes

* update translation to sort by order

* revision changes

* remove extra error message

* lint fix

* update styling fontsize for heading and remove padding

* fix for button not showing up

* fix for button not showing up

* update default url

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: malavikakoppula <83021791+malavikakoppula@users.noreply.github.com>
Co-authored-by: Malavika Koppula <mkreddy1110@gmail.com>
Co-authored-by: Anna Sherman <sherman.anna@gmail.com>
Co-authored-by: LauraPinilla <54566275+LauraPinilla@users.noreply.github.com>
---
 .storybook/themes/news.scss                   |   4 +
 blocks/identity-block/_index.scss             |  24 +-
 .../headlined-submit-form/index.jsx           |   2 +-
 .../features/login-links/default.jsx          |  29 +-
 .../features/login-links/default.test.jsx     |  16 +
 .../features/one-time-password/default.jsx    | 106 ++++
 .../one-time-password/default.test.jsx        | 126 +++++
 blocks/identity-block/intl.json               |  21 +
 blocks/identity-block/themes/news.json        |  81 ++-
 locale/en.json                                |  11 +-
 package-lock.json                             | 471 +++++++++++-------
 package.json                                  |   2 +-
 12 files changed, 703 insertions(+), 190 deletions(-)
 create mode 100644 blocks/identity-block/features/one-time-password/default.jsx
 create mode 100644 blocks/identity-block/features/one-time-password/default.test.jsx

diff --git a/.storybook/themes/news.scss b/.storybook/themes/news.scss
index 124014a736..2615966ea0 100644
--- a/.storybook/themes/news.scss
+++ b/.storybook/themes/news.scss
@@ -2854,6 +2854,10 @@
 					"display": flex,
 					"flex-wrap": wrap
 				),
+				"section-title-links": (
+					"display": flex,
+					"flex-wrap": wrap
+				),
 				"share-bar": (
 					"background": var(--background-color),
 					"box-shadow": var(--global-box-shadow-1),
diff --git a/blocks/identity-block/_index.scss b/blocks/identity-block/_index.scss
index a8617a98df..f7129a10a4 100644
--- a/blocks/identity-block/_index.scss
+++ b/blocks/identity-block/_index.scss
@@ -105,7 +105,27 @@
 	@include scss.block-properties("login-form");
 }
 
+.b-one-time-login-form {
+	&__ota-sub-headline {
+		@include scss.block-components("ota-sub-headline");
+		@include scss.block-properties("ota-sub-headline");
+	}
+
+	&__recaptcha {
+		@include scss.block-components("ota-recaptcha");
+		@include scss.block-properties("ota-recaptcha");
+	}
+
+	@include scss.block-components("one-time-login-form");
+	@include scss.block-properties("one-time-login-form");
+}
+
 .b-login-links {
+	&__ota-link {
+		@include scss.block-components("login-links-ota-link");
+		@include scss.block-properties("login-links-ota-link");
+	}
+
 	&__inner-link {
 		@include scss.block-components("login-links-inner-link");
 		@include scss.block-properties("login-links-inner-link");
@@ -162,12 +182,12 @@
 			@include scss.block-components("social-sign-on-dividerWithText-before");
 			@include scss.block-properties("social-sign-on-dividerWithText-before");
 		}
-		
+
 		&::after{
 			@include scss.block-components("social-sign-on-dividerWithText-after");
 			@include scss.block-properties("social-sign-on-dividerWithText-after");
 		}
-		
+
 		@include scss.block-components("social-sign-on-dividerWithText");
 		@include scss.block-properties("social-sign-on-dividerWithText");
 	}
diff --git a/blocks/identity-block/components/headlined-submit-form/index.jsx b/blocks/identity-block/components/headlined-submit-form/index.jsx
index 84e1b07b74..4b106a2e57 100644
--- a/blocks/identity-block/components/headlined-submit-form/index.jsx
+++ b/blocks/identity-block/components/headlined-submit-form/index.jsx
@@ -36,7 +36,7 @@ const HeadlinedSubmitForm = ({
 			</HeadingSection>
 			<form aria-label={headline} onSubmit={handleSubmit} ref={formRef}>
 				{children}
-				<Button size="medium" variant="primary" fullWidth type="submit">
+				<Button size="large" variant="primary" fullWidth type="submit">
 					{buttonLabel}
 				</Button>
 				{formErrorText ? (
diff --git a/blocks/identity-block/features/login-links/default.jsx b/blocks/identity-block/features/login-links/default.jsx
index 3e543d9b36..84be9f5e67 100644
--- a/blocks/identity-block/features/login-links/default.jsx
+++ b/blocks/identity-block/features/login-links/default.jsx
@@ -2,17 +2,20 @@ import React from "react";
 import PropTypes from "@arc-fusion/prop-types";
 import { useFusionContext } from "fusion:context";
 import getTranslatedPhrases from "fusion:intl";
-import { Link, Paragraph, Stack } from "@wpmedia/arc-themes-components";
+import { Link, Stack, Button, Paragraph } from "@wpmedia/arc-themes-components";
 
 const BLOCK_CLASS_NAME = "b-login-links";
 const defaultLoginURL = "/account/login/";
 const defaultForgotURL = "/account/forgot-password/";
 const defaultSignUpURL = "/account/signup/";
+const defaultRequestOneTimePasswordURL = "/account/request-one-time/";
 
 const LoginLinks = ({ customFields }) => {
 	const {
 		showLogin = false,
+		showLoginWithoutPassword = false,
 		loginURL = defaultLoginURL,
+		loginWithOutPasswordUrl = defaultRequestOneTimePasswordURL,
 		showForgot = false,
 		forgotURL = defaultForgotURL,
 		showSignUp = false,
@@ -22,12 +25,24 @@ const LoginLinks = ({ customFields }) => {
 	const { locale } = siteProperties;
 	const phrases = getTranslatedPhrases(locale);
 
-	if (!showLogin && !showForgot && !showSignUp) {
+	const logInLinks = [showLogin, showForgot, showSignUp, showLoginWithoutPassword];
+
+	if (!logInLinks.includes(true)) {
 		return null;
 	}
 
 	return (
 		<Stack as="div" className={BLOCK_CLASS_NAME}>
+			{showLoginWithoutPassword && (
+				<Button
+					href={loginWithOutPasswordUrl}
+					className={`${BLOCK_CLASS_NAME}__ota-link`}
+					size="large"
+					fullWidth
+				>
+					{phrases.t("identity-block.ota-button")}
+				</Button>
+			)}
 			{showLogin ? (
 				<Paragraph>{phrases.t("identity-block.login-links-login")}<Link href={loginURL} className={`${BLOCK_CLASS_NAME}__inner-link`}>{phrases.t("identity-block.log-in")}</Link></Paragraph>
 			) : null}
@@ -57,6 +72,16 @@ LoginLinks.propTypes = {
 			defaultValue: defaultLoginURL,
 			group: "Login",
 		}),
+		showLoginWithoutPassword: PropTypes.bool.tag({
+			name: "Show Login without password",
+			defaultValue: false,
+			group: "Login Without Password",
+		}),
+		loginWithOutPasswordUrl: PropTypes.string.tag({
+			name: "Login without password URL",
+			defaultValue: defaultRequestOneTimePasswordURL,
+			group: "Login Without Password",
+		}),
 		showForgot: PropTypes.bool.tag({
 			name: "Show Forgot Password link",
 			defaultValue: false,
diff --git a/blocks/identity-block/features/login-links/default.test.jsx b/blocks/identity-block/features/login-links/default.test.jsx
index 2f78edd619..0636b233b1 100644
--- a/blocks/identity-block/features/login-links/default.test.jsx
+++ b/blocks/identity-block/features/login-links/default.test.jsx
@@ -53,4 +53,20 @@ describe("LoginLinks", () => {
 		expect(links[1]).toHaveAttribute("href", customFields.forgotURL);
 		expect(links[2]).toHaveAttribute("href", customFields.signUpURL);
 	});
+
+	it("renders one-time password", () => {
+		const customFields = {
+			showLogin: true,
+			showLoginWithoutPassword: true,
+			showSignUp: false,
+			showForgot: false,
+			loginURL: "custom-login",
+			forgotURL: "custom-forgot",
+			signUpURL: "custom-signup",
+		};
+		render(<LoginLinks customFields={customFields} />);
+		const links = screen.getAllByRole("link");
+		
+		expect(links[0]).toHaveAttribute("href", customFields.loginWithOutPasswordUrl);
+	});
 });
diff --git a/blocks/identity-block/features/one-time-password/default.jsx b/blocks/identity-block/features/one-time-password/default.jsx
new file mode 100644
index 0000000000..ecbb6ac863
--- /dev/null
+++ b/blocks/identity-block/features/one-time-password/default.jsx
@@ -0,0 +1,106 @@
+import React, { useState } from "react";
+import { useFusionContext } from "fusion:context";
+import getProperties from "fusion:properties";
+import getTranslatedPhrases from "fusion:intl";
+import { Input, useIdentity, BotChallengeProtection, Heading, HeadingSection } from "@wpmedia/arc-themes-components";
+import HeadlinedSubmitForm from "../../components/headlined-submit-form";
+
+const BLOCK_CLASS_NAME = "b-one-time-login-form";
+
+const errorCodes = {
+	100015: "identity-block.login-form-error.account-is-disabled",
+	130001: "identity-block.login-form-error.captcha-token-invalid",
+	130051: "identity-block.login-form-error.unverified-email-address",
+	100013: "identity-block.login-form-error.max-devices",
+	0: "identity-block.login-form-error.invalid-email-password",
+};
+
+const definedMessageByCode = (code) => errorCodes[code] || errorCodes["0"];
+
+const OneTimePasswordLogin = () => {
+	const { arcSite } = useFusionContext();
+	const { locale } = getProperties(arcSite);
+	const phrases = getTranslatedPhrases(locale);
+	const { Identity, isInitialized } = useIdentity();
+	const [captchaToken, setCaptchaToken] = useState();
+	const [resetRecaptcha, setResetRecaptcha] = useState(true);
+	const [error, setError] = useState();
+	const [captchaError, setCaptchaError] = useState();
+	const [success, setSuccess] = useState(false);
+	const [userEmail, setUserEmail] = useState('');
+
+	if (!isInitialized) {
+		return null;
+	}
+
+	if (success) {
+		return (
+			<div className={BLOCK_CLASS_NAME}>
+				<HeadingSection>
+					<Heading>{phrases.t("identity-block.ota-success-heading")}</Heading>
+				</HeadingSection>
+				<p
+					className={`${BLOCK_CLASS_NAME}__ota-sub-headline`}
+					dangerouslySetInnerHTML={{__html: phrases.t("identity-block.ota-success-body", { userEmail })}}
+				/>
+			</div>
+		)
+	}
+
+	return (
+		<div>
+			<HeadlinedSubmitForm
+				buttonLabel={phrases.t("identity-block.ota-form-button")}
+				className={BLOCK_CLASS_NAME}
+				formErrorText={error}
+				headline={phrases.t("identity-block.ota-headline")}
+				onSubmit={({ email }) => {
+					setError(null);
+					setCaptchaError(null);
+					return Identity.requestOTALink(
+						email,
+						captchaToken,
+					).then(() => {
+						setUserEmail(email);
+						setSuccess(true);
+					})
+					.catch((e) => {
+						setResetRecaptcha(!resetRecaptcha);
+						if (e?.code === "130001") {
+							setCaptchaError(phrases.t(definedMessageByCode(e.code)));
+						} else {
+							setError(phrases.t(definedMessageByCode(e.code)));
+						}				
+					});
+				}}
+			>
+				<p className={`${BLOCK_CLASS_NAME}__ota-sub-headline`}>{phrases.t("identity-block.ota-subheadline")}</p>
+				<Input
+					autoComplete="email"
+					label={phrases.t("identity-block.email-label")}
+					name="email"
+					placeholder={phrases.t("identity-block.ota-input-placeholder")}
+					required
+					showDefaultError={false}
+					type="email"
+					validationErrorMessage={phrases.t("identity-block.email-requirements")}
+				/>
+
+				<div className={`${BLOCK_CLASS_NAME}__recaptcha`}>
+					<BotChallengeProtection
+						className={BLOCK_CLASS_NAME}
+						challengeIn="magicLink"
+						setCaptchaToken={setCaptchaToken}
+						captchaError={captchaError}
+						setCaptchaError={setCaptchaError}
+						resetRecaptcha={resetRecaptcha}
+					/>
+				</div>
+			</HeadlinedSubmitForm>
+		</div>
+	);
+};
+
+OneTimePasswordLogin.label = "Identity One Time Password Request Form - Arc Block";
+
+export default OneTimePasswordLogin;
diff --git a/blocks/identity-block/features/one-time-password/default.test.jsx b/blocks/identity-block/features/one-time-password/default.test.jsx
new file mode 100644
index 0000000000..9ed107628b
--- /dev/null
+++ b/blocks/identity-block/features/one-time-password/default.test.jsx
@@ -0,0 +1,126 @@
+import React from "react";
+import { fireEvent, render, screen, waitFor } from "@testing-library/react";
+import { useIdentity } from "@wpmedia/arc-themes-components";
+import OneTimePassword from "./default";
+
+const mockSubmitForm = jest.fn(() => Promise.resolve());
+const mockIdentity = {
+	requestOTALink: mockSubmitForm,
+};
+
+jest.mock("@wpmedia/arc-themes-components", () => ({
+	...jest.requireActual("@wpmedia/arc-themes-components"),
+	useIdentity: jest.fn(() => ({
+		isInitialized: false,
+		Identity: {
+			...mockIdentity,
+		},
+	})),
+	BotChallengeProtection: ({ challengeIn= 'magicLink' }) => <div data-testid={`reCapctha-${challengeIn}`} />
+}));
+jest.mock("fusion:properties", () => jest.fn(() => ({})));
+
+describe("Identity One Time Password Request Form - Arc Block", () => {
+	beforeEach(() => {
+		useIdentity.mockImplementation(() => ({
+			isInitialized: true,
+			Identity: {
+				...mockIdentity,
+			},
+		}));
+	});
+
+	afterEach(() => {
+		jest.clearAllMocks();
+	});
+
+	it("Renders", () => {
+		useIdentity.mockImplementation(() => ({
+			isInitialized: false,
+			Identity: {
+				...mockIdentity,
+			},
+		}));
+
+		render(<OneTimePassword />);
+		
+		expect(screen.queryAllByRole("form").length).toEqual(0);
+	});
+
+	it("Does not render if Identity isn't initialized", () => {
+		render(<OneTimePassword />);
+		
+		expect(screen.queryAllByRole("form").length).toEqual(1);
+		expect(screen.getByTestId('reCapctha-magicLink')).toBeTruthy();
+	});
+
+	it("Should be able submit form", async () => {
+		render(<OneTimePassword />);
+		
+		await waitFor(() => expect(screen.getByLabelText("identity-block.email-label")));
+		fireEvent.change(screen.getByLabelText("identity-block.email-label"), {
+			target: { value: "email@test.com" },
+		});
+
+		await waitFor(() => expect(screen.getByRole("button")));
+		fireEvent.click(screen.getByRole("button"));
+
+		await waitFor(() => expect(mockSubmitForm).toHaveBeenCalled());
+		await waitFor(() => expect(screen.getByText("identity-block.ota-success-heading")));
+		await waitFor(() => expect(screen.getByText("identity-block.ota-success-body")));
+	});
+
+	it("Form submission handles 130001 error", async () => {
+		const error = new Error("Captcha token invalid");
+		error.code = "130001";
+
+		const errorMessage = jest.fn(() => Promise.reject(error));
+
+		useIdentity.mockImplementation(() => ({
+			isInitialized: true,
+			Identity: {
+				...mockIdentity,
+				requestOTALink: errorMessage,
+			},
+		}));
+
+		render(<OneTimePassword />);
+		
+		await waitFor(() => expect(screen.getByLabelText("identity-block.email-label")));
+		fireEvent.change(screen.getByLabelText("identity-block.email-label"), {
+			target: { value: "email@test.com" },
+		});
+
+		await waitFor(() => expect(screen.getByRole("button")));
+		fireEvent.click(screen.getByRole("button"));
+
+		await waitFor(() => expect(errorMessage).toHaveBeenCalled());
+	});
+
+	it("Form submission handle other errors", async () => {
+		const error = new Error("Fake error");
+		error.code = "30001";
+
+		const errorMessage = jest.fn(() => Promise.reject(error));
+
+		useIdentity.mockImplementation(() => ({
+			isInitialized: true,
+			Identity: {
+				...mockIdentity,
+				requestOTALink: errorMessage,
+			},
+		}));
+
+		render(<OneTimePassword />);
+		
+		await waitFor(() => expect(screen.getByLabelText("identity-block.email-label")));
+		fireEvent.change(screen.getByLabelText("identity-block.email-label"), {
+			target: { value: "email@test.com" },
+		});
+
+		await waitFor(() => expect(screen.getByRole("button")));
+		fireEvent.click(screen.getByRole("button"));
+
+		await waitFor(() => expect(errorMessage).toHaveBeenCalled());
+	});
+});
diff --git a/blocks/identity-block/intl.json b/blocks/identity-block/intl.json
index 32f73e47b8..0bae6111b0 100644
--- a/blocks/identity-block/intl.json
+++ b/blocks/identity-block/intl.json
@@ -1701,5 +1701,26 @@
 	},
 	"identity-block.signup-form-error.identity-already-exists": {
 		"en": "Account already exists"
+	},
+	"identity-block.ota-button": {
+		"en": "Log in without password"
+	},
+	"identity-block.ota-headline": {
+		"en": "Request one time log in link"
+	},
+	"identity-block.ota-subheadline": {
+		"en": "To sign in without a password, enter your email below and you will receive a one time log in link."
+	},
+	"identity-block.ota-form-button": {
+		"en": "Send log in link"
+	},
+	"identity-block.ota-input-placeholder": {
+		"en": "Enter email address"
+	},
+	"identity-block.ota-success-heading": {
+		"en": "Check Your Email"
+	},
+	"identity-block.ota-success-body": {
+		"en": "If there's an account associated with <b>%{userEmail}</b>, you'll get a link in your inbox that will automatically sign you in to your account. The link will expire in 24 hours."
 	}
 }
\ No newline at end of file
diff --git a/blocks/identity-block/themes/news.json b/blocks/identity-block/themes/news.json
index 9561efc3b0..7f72c07519 100644
--- a/blocks/identity-block/themes/news.json
+++ b/blocks/identity-block/themes/news.json
@@ -236,6 +236,65 @@
 			"desktop": {}
 		}
 	},
+	"one-time-login-form": {
+		"styles": {
+			"default": {
+				"font-family": "var(--font-family-primary)",
+				"components": {
+					"button": {
+						"font-size": "var(--global-font-size-4)"
+					},
+					"heading": {
+						"border-block-end-color": "var(--border-color)",
+						"border-block-end-style": "var(--global-border-style-0)",
+						"border-block-end-width": "var(--global-border-width-0)",
+						"font-size": "var(--global-font-size-12)",
+						"margin-block-end": "var(--global-spacing-4)",
+						"padding-block-end": 0,
+						"text-align": "center"
+					},
+					"input": {
+						"margin-block-end": "var(--global-spacing-5)"
+					},
+					"input-error-tip": {
+						"color": "var(--status-color-danger)"
+					},
+					"input-input": {
+						"inline-size": "100%",
+						"padding-block-end": "var(--global-spacing-2)",
+						"padding-block-start": "var(--global-spacing-2)"
+					},
+					"paragraph": {
+						"font-family": "var(--font-family-primary)",
+						"margin-block-end": "var(--global-spacing-5)"
+					}
+				}
+			},
+			"desktop": {
+				"components": {
+					"heading": {
+						"font-size": "var(--global-font-size-11)",
+						"padding-block-end": 0
+					}
+				}
+			}
+		}
+	},
+	"ota-sub-headline": {
+		"styles": {
+			"default": {
+				"text-align": "center",
+				"margin-block-end": "var(--global-spacing-4)"
+			}
+		}
+	},
+	"ota-recaptcha": {
+		"styles": {
+			"default": {
+				"margin-block-end": "var(--global-spacing-4)"
+			}
+		}
+	},
 	"login-form": {
 		"styles": {
 			"default": {
@@ -255,7 +314,7 @@
 						"padding-block-start": 0,
 						"padding-inline-end": 0,
 						"margin-block-end": "var(--global-spacing-0)",
-                        "padding-block-end": "var(--global-spacing-2)"
+						"padding-block-end": "var(--global-spacing-2)"
 					},
 					"input": {
 						"margin-block-end": "var(--global-spacing-4)"
@@ -348,7 +407,7 @@
 			}
 		}
 	},
-	"login-form-error":{
+	"login-form-error": {
 		"styles": {
 			"default": {
 				"font-family": "var(--font-family-primary)",
@@ -389,6 +448,14 @@
 			"desktop": {}
 		}
 	},
+	"login-links-ota-link": {
+		"styles": {
+			"default": {
+				"border": "1px solid var(--border-color)"
+			},
+			"desktop": {}
+		}
+	},
 	"login-links-inner-link": {
 		"styles": {
 			"default": {
@@ -417,7 +484,7 @@
 			"desktop": {}
 		}
 	},
-	"login-form-tos-container-link":{
+	"login-form-tos-container-link": {
 		"styles": {
 			"default": {
 				"margin-block-start": "var(--global-spacing-5)",
@@ -490,7 +557,7 @@
 						"padding-block-start": 0,
 						"padding-inline-end": 0,
 						"margin-block-end": "var(--global-spacing-0)",
-                        "padding-block-end": "var(--global-spacing-2)"
+						"padding-block-end": "var(--global-spacing-2)"
 					},
 					"input": {
 						"margin-block-end": "var(--global-spacing-5)"
@@ -522,7 +589,7 @@
 			}
 		}
 	},
-	"sign-up-tos-container-link":{
+	"sign-up-tos-container-link": {
 		"styles": {
 			"default": {
 				"margin-block-start": "var(--global-spacing-5)",
@@ -531,7 +598,7 @@
 			"desktop": {}
 		}
 	},
-	"sign-up-form-error":{
+	"sign-up-form-error": {
 		"styles": {
 			"default": {
 				"font-family": "var(--font-family-primary)",
@@ -663,4 +730,4 @@
 			"desktop": {}
 		}
 	}
-}
+}
\ No newline at end of file
diff --git a/locale/en.json b/locale/en.json
index 941eb1a57c..2286f6bcef 100644
--- a/locale/en.json
+++ b/locale/en.json
@@ -173,7 +173,14 @@
 		"identity-block.terms-service-privacy-text": "By creating an account, you agree to the <a href='%{termsAndPrivacyURL}'>Terms of Service and acknowledge our Privacy Policy<\/a>",
 		"identity-block.update-email-error": "There's been an error updating your email address",
 		"identity-block.update-password-error": "There's been an error updating your password",
-		"identity-block.username": "Username"
+		"identity-block.username": "Username",
+		"identity-block.ota-button": "Log in without password",
+		"identity-block.ota-headline": "Request one time log in link",
+		"identity-block.ota-subheadline": "To sign in without a password, enter your email below and you will receive a one time log in link.",
+		"identity-block.ota-form-button": "Send log in link",
+		"identity-block.ota-input-placeholder": "Enter email address",
+		"identity-block.ota-success-heading": "Check Your Email",
+		"identity-block.ota-success-body": "If there's an account associated with <b>%{userEmail}<\/b>, you'll get a link in your inbox that will automatically sign you in to your account. The link will expire in 24 hours."
 	},
 	"lead-art-block": {
 		"lead-art-block.fullscreen-enter": "Enter full screen mode displaying the lead image",
@@ -555,4 +562,4 @@
 		"subscription-block.shared-No": "No",
 		"subscription-block.shared-Payment-method": "Payment method"
 	}
-}
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index c91f709e78..23e2f4e27c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -827,151 +827,151 @@
 			"dev": true
 		},
 		"node_modules/@algolia/cache-browser-local-storage": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.23.1.tgz",
-			"integrity": "sha512-1sAJYmXN9TOk6Hd8BUQOglxP9Kq9F0qlISsuWxH6y4UjevevgxhLvA6VrODJb1ghwwQi0nODXxwUhNh0sGF8xw==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.23.2.tgz",
+			"integrity": "sha512-PvRQdCmtiU22dw9ZcTJkrVKgNBVAxKgD0/cfiqyxhA5+PHzA2WDt6jOmZ9QASkeM2BpyzClJb/Wr1yt2/t78Kw==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/cache-common": "4.23.1"
+				"@algolia/cache-common": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/cache-common": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.23.1.tgz",
-			"integrity": "sha512-w0sqXuwbGyIDsFDHTZzTv79rZjW7vc/6vCPdqYAAkiUlvvCdUo0cCWFXpbMpvYHBS2IXZXJaQY0R9yL/bmk9VQ==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.23.2.tgz",
+			"integrity": "sha512-OUK/6mqr6CQWxzl/QY0/mwhlGvS6fMtvEPyn/7AHUx96NjqDA4X4+Ju7aXFQKh+m3jW9VPB0B9xvEQgyAnRPNw==",
 			"dev": true
 		},
 		"node_modules/@algolia/cache-in-memory": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.23.1.tgz",
-			"integrity": "sha512-Wy5J4c2vLi1Vfsc3qoM/trVtvN9BlV+X2hfiAhfTVclyney6fs/Rjus8lbadl1x5GjlPIgMNGxvr/A/wnJQUBw==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.23.2.tgz",
+			"integrity": "sha512-rfbi/SnhEa3MmlqQvgYz/9NNJ156NkU6xFxjbxBtLWnHbpj+qnlMoKd+amoiacHRITpajg6zYbLM9dnaD3Bczw==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/cache-common": "4.23.1"
+				"@algolia/cache-common": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/client-account": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.23.1.tgz",
-			"integrity": "sha512-E8rALAfC7G1gruxW4zO3WgBkWQDJq1Crnxi45uo/KUYf78x+T7YwojyS42fHz//thbtPyPUC5WZCQlnzqgMZlg==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.23.2.tgz",
+			"integrity": "sha512-VbrOCLIN/5I7iIdskSoSw3uOUPF516k4SjDD4Qz3BFwa3of7D9A0lzBMAvQEJJEPHWdVraBJlGgdJq/ttmquJQ==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/client-common": "4.23.1",
-				"@algolia/client-search": "4.23.1",
-				"@algolia/transporter": "4.23.1"
+				"@algolia/client-common": "4.23.2",
+				"@algolia/client-search": "4.23.2",
+				"@algolia/transporter": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/client-analytics": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.23.1.tgz",
-			"integrity": "sha512-xtfp/M3TjHStStH/UQoxmt8SeVpxSgdZGcCY61+chG9fmbJHgeYtzECQu7SVZ+LPTW0nmyqMrpKQ9kFcgPnV1A==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.23.2.tgz",
+			"integrity": "sha512-lLj7irsAztGhMoEx/SwKd1cwLY6Daf1Q5f2AOsZacpppSvuFvuBrmkzT7pap1OD/OePjLKxicJS8wNA0+zKtuw==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/client-common": "4.23.1",
-				"@algolia/client-search": "4.23.1",
-				"@algolia/requester-common": "4.23.1",
-				"@algolia/transporter": "4.23.1"
+				"@algolia/client-common": "4.23.2",
+				"@algolia/client-search": "4.23.2",
+				"@algolia/requester-common": "4.23.2",
+				"@algolia/transporter": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/client-common": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.23.1.tgz",
-			"integrity": "sha512-01lBsO8r4KeXWIDzVQoPMYwOndeAvSQk3xk3Bxwrt2ag5jrGswiq8DgEqPVx+PQw+7T5GY6dS25cYcdv1dVorA==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.23.2.tgz",
+			"integrity": "sha512-Q2K1FRJBern8kIfZ0EqPvUr3V29ICxCm/q42zInV+VJRjldAD9oTsMGwqUQ26GFMdFYmqkEfCbY4VGAiQhh22g==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/requester-common": "4.23.1",
-				"@algolia/transporter": "4.23.1"
+				"@algolia/requester-common": "4.23.2",
+				"@algolia/transporter": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/client-personalization": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.23.1.tgz",
-			"integrity": "sha512-B8UEALAg1/6DaLuJOxYTfGBVrLZN4M7FoaYrjbHLw2oF5Y6bxe59Y5ug+lSbs6v9bWx7U9rNVpd8m2I8pobFcA==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.23.2.tgz",
+			"integrity": "sha512-vwPsgnCGhUcHhhQG5IM27z8q7dWrN9itjdvgA6uKf2e9r7vB+WXt4OocK0CeoYQt3OGEAExryzsB8DWqdMK5wg==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/client-common": "4.23.1",
-				"@algolia/requester-common": "4.23.1",
-				"@algolia/transporter": "4.23.1"
+				"@algolia/client-common": "4.23.2",
+				"@algolia/requester-common": "4.23.2",
+				"@algolia/transporter": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/client-search": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.23.1.tgz",
-			"integrity": "sha512-jeA1ZksO0N33SZhcLRa4paUI7LFJrrhtMlw27eIdPTVv/npV0dMLoNGPg3MuLSeZqRKqfpY7tTOBjRZFMhskLg==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.23.2.tgz",
+			"integrity": "sha512-CxSB29OVGSE7l/iyoHvamMonzq7Ev8lnk/OkzleODZ1iBcCs3JC/XgTIKzN/4RSTrJ9QybsnlrN/bYCGufo7qw==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/client-common": "4.23.1",
-				"@algolia/requester-common": "4.23.1",
-				"@algolia/transporter": "4.23.1"
+				"@algolia/client-common": "4.23.2",
+				"@algolia/requester-common": "4.23.2",
+				"@algolia/transporter": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/logger-common": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.23.1.tgz",
-			"integrity": "sha512-hGsqJrpeZfw1Ng8ctWj9gg8zXlSmEMA0cfbBn3yoZa3so8oQZmB9uz57AJcJj1CfSBf+5SK8/AF4kjTungvgUA==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.23.2.tgz",
+			"integrity": "sha512-jGM49Q7626cXZ7qRAWXn0jDlzvoA1FvN4rKTi1g0hxKsTTSReyYk0i1ADWjChDPl3Q+nSDhJuosM2bBUAay7xw==",
 			"dev": true
 		},
 		"node_modules/@algolia/logger-console": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.23.1.tgz",
-			"integrity": "sha512-6QYjtxsDwrdFeLoCcZmi9af/EbWkpUYSclx2d342EoayaY8S2tCORgqwzDmPPOpvi5Y6zPnDsj2BG7vrpK8bdg==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.23.2.tgz",
+			"integrity": "sha512-oo+lnxxEmlhTBTFZ3fGz1O8PJ+G+8FiAoMY2Qo3Q4w23xocQev6KqDTA1JQAGPDxAewNA2VBwWOsVXeXFjrI/Q==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/logger-common": "4.23.1"
+				"@algolia/logger-common": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/recommend": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.23.1.tgz",
-			"integrity": "sha512-9Td+htxUYkUxrkaPOum9Q1jAy+NogxpwZ+Vvn3X+IBIfXECrNhIff+u1ddIirRM2rMphWrrO/3GWLZaKY7FOxw==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.23.2.tgz",
+			"integrity": "sha512-Q75CjnzRCDzgIlgWfPnkLtrfF4t82JCirhalXkSSwe/c1GH5pWh4xUyDOR3KTMo+YxxX3zTlrL/FjHmUJEWEcg==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/cache-browser-local-storage": "4.23.1",
-				"@algolia/cache-common": "4.23.1",
-				"@algolia/cache-in-memory": "4.23.1",
-				"@algolia/client-common": "4.23.1",
-				"@algolia/client-search": "4.23.1",
-				"@algolia/logger-common": "4.23.1",
-				"@algolia/logger-console": "4.23.1",
-				"@algolia/requester-browser-xhr": "4.23.1",
-				"@algolia/requester-common": "4.23.1",
-				"@algolia/requester-node-http": "4.23.1",
-				"@algolia/transporter": "4.23.1"
+				"@algolia/cache-browser-local-storage": "4.23.2",
+				"@algolia/cache-common": "4.23.2",
+				"@algolia/cache-in-memory": "4.23.2",
+				"@algolia/client-common": "4.23.2",
+				"@algolia/client-search": "4.23.2",
+				"@algolia/logger-common": "4.23.2",
+				"@algolia/logger-console": "4.23.2",
+				"@algolia/requester-browser-xhr": "4.23.2",
+				"@algolia/requester-common": "4.23.2",
+				"@algolia/requester-node-http": "4.23.2",
+				"@algolia/transporter": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/requester-browser-xhr": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.23.1.tgz",
-			"integrity": "sha512-dM8acMp6sn1HRoQrUiBYQCZvTrFwLwFuHagZH88nKhL52bUrtZXH2qUQ8RMQBb9am71J9COLyMgZYdyR+u8Ktg==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.23.2.tgz",
+			"integrity": "sha512-TO9wLlp8+rvW9LnIfyHsu8mNAMYrqNdQ0oLF6eTWFxXfxG3k8F/Bh7nFYGk2rFAYty4Fw4XUtrv/YjeNDtM5og==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/requester-common": "4.23.1"
+				"@algolia/requester-common": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/requester-common": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.23.1.tgz",
-			"integrity": "sha512-G9+ySLxPBtn2o6Mk4NoxPnkYtAe/isxrVy5LmJ4za+aYEdV5tvZpgvn+k4558T7XoRBrI2eQKyjnvQs7zJeCdw==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.23.2.tgz",
+			"integrity": "sha512-3EfpBS0Hri0lGDB5H/BocLt7Vkop0bTTLVUBB844HH6tVycwShmsV6bDR7yXbQvFP1uNpgePRD3cdBCjeHmk6Q==",
 			"dev": true
 		},
 		"node_modules/@algolia/requester-node-http": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.23.1.tgz",
-			"integrity": "sha512-prpVKKc/WRAtZqZx3A6Ds+D6bl3jgnY4Nw8BhCO9yzwMu5oXaOFsZrzFRBeVUJbtOWMc/DMP38vY6DpdV6NSfw==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.23.2.tgz",
+			"integrity": "sha512-SVzgkZM/malo+2SB0NWDXpnT7nO5IZwuDTaaH6SjLeOHcya1o56LSWXk+3F3rNLz2GVH+I/rpYKiqmHhSOjerw==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/requester-common": "4.23.1"
+				"@algolia/requester-common": "4.23.2"
 			}
 		},
 		"node_modules/@algolia/transporter": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.23.1.tgz",
-			"integrity": "sha512-8ucVx0hV7yIeTZUFsix31UEIJFRauPriWlzLBbDy9gRHrK45WbMQ1S9FliDdoY5OvbFxi0/5OKRj0Dw1EkbcJA==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.23.2.tgz",
+			"integrity": "sha512-GY3aGKBy+8AK4vZh8sfkatDciDVKad5rTY2S10Aefyjh7e7UGBP4zigf42qVXwU8VOPwi7l/L7OACGMOFcjB0Q==",
 			"dev": true,
 			"dependencies": {
-				"@algolia/cache-common": "4.23.1",
-				"@algolia/logger-common": "4.23.1",
-				"@algolia/requester-common": "4.23.1"
+				"@algolia/cache-common": "4.23.2",
+				"@algolia/logger-common": "4.23.2",
+				"@algolia/requester-common": "4.23.2"
 			}
 		},
 		"node_modules/@ampproject/remapping": {
@@ -9625,26 +9625,26 @@
 			}
 		},
 		"node_modules/algoliasearch": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.23.1.tgz",
-			"integrity": "sha512-LNK5n23zDXVf8kaLMZrVDEy4ecxIFUDEsQlx+He1l+TCmP8eiheLVMi5eyZlU6qmmq3UWCxZmp6hzCXS/hvXEw==",
-			"dev": true,
-			"dependencies": {
-				"@algolia/cache-browser-local-storage": "4.23.1",
-				"@algolia/cache-common": "4.23.1",
-				"@algolia/cache-in-memory": "4.23.1",
-				"@algolia/client-account": "4.23.1",
-				"@algolia/client-analytics": "4.23.1",
-				"@algolia/client-common": "4.23.1",
-				"@algolia/client-personalization": "4.23.1",
-				"@algolia/client-search": "4.23.1",
-				"@algolia/logger-common": "4.23.1",
-				"@algolia/logger-console": "4.23.1",
-				"@algolia/recommend": "4.23.1",
-				"@algolia/requester-browser-xhr": "4.23.1",
-				"@algolia/requester-common": "4.23.1",
-				"@algolia/requester-node-http": "4.23.1",
-				"@algolia/transporter": "4.23.1"
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.23.2.tgz",
+			"integrity": "sha512-8aCl055IsokLuPU8BzLjwzXjb7ty9TPcUFFOk0pYOwsE5DMVhE3kwCMFtsCFKcnoPZK7oObm+H5mbnSO/9ioxQ==",
+			"dev": true,
+			"dependencies": {
+				"@algolia/cache-browser-local-storage": "4.23.2",
+				"@algolia/cache-common": "4.23.2",
+				"@algolia/cache-in-memory": "4.23.2",
+				"@algolia/client-account": "4.23.2",
+				"@algolia/client-analytics": "4.23.2",
+				"@algolia/client-common": "4.23.2",
+				"@algolia/client-personalization": "4.23.2",
+				"@algolia/client-search": "4.23.2",
+				"@algolia/logger-common": "4.23.2",
+				"@algolia/logger-console": "4.23.2",
+				"@algolia/recommend": "4.23.2",
+				"@algolia/requester-browser-xhr": "4.23.2",
+				"@algolia/requester-common": "4.23.2",
+				"@algolia/requester-node-http": "4.23.2",
+				"@algolia/transporter": "4.23.2"
 			}
 		},
 		"node_modules/ansi-colors": {
@@ -9897,6 +9897,26 @@
 				"url": "https://github.com/sponsors/ljharb"
 			}
 		},
+		"node_modules/array.prototype.findlast": {
+			"version": "1.2.5",
+			"resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
+			"integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
+			"dev": true,
+			"dependencies": {
+				"call-bind": "^1.0.7",
+				"define-properties": "^1.2.1",
+				"es-abstract": "^1.23.2",
+				"es-errors": "^1.3.0",
+				"es-object-atoms": "^1.0.0",
+				"es-shim-unscopables": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
 		"node_modules/array.prototype.findlastindex": {
 			"version": "1.2.4",
 			"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz",
@@ -9952,6 +9972,18 @@
 				"url": "https://github.com/sponsors/ljharb"
 			}
 		},
+		"node_modules/array.prototype.toreversed": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz",
+			"integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==",
+			"dev": true,
+			"dependencies": {
+				"call-bind": "^1.0.2",
+				"define-properties": "^1.2.0",
+				"es-abstract": "^1.22.1",
+				"es-shim-unscopables": "^1.0.0"
+			}
+		},
 		"node_modules/array.prototype.tosorted": {
 			"version": "1.1.3",
 			"resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz",
@@ -12281,6 +12313,57 @@
 				"node": ">=12"
 			}
 		},
+		"node_modules/data-view-buffer": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
+			"integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
+			"dev": true,
+			"dependencies": {
+				"call-bind": "^1.0.6",
+				"es-errors": "^1.3.0",
+				"is-data-view": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/data-view-byte-length": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
+			"integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
+			"dev": true,
+			"dependencies": {
+				"call-bind": "^1.0.7",
+				"es-errors": "^1.3.0",
+				"is-data-view": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/data-view-byte-offset": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
+			"integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
+			"dev": true,
+			"dependencies": {
+				"call-bind": "^1.0.6",
+				"es-errors": "^1.3.0",
+				"is-data-view": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
 		"node_modules/dateformat": {
 			"version": "3.0.3",
 			"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
@@ -13010,18 +13093,22 @@
 			}
 		},
 		"node_modules/es-abstract": {
-			"version": "1.22.4",
-			"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz",
-			"integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==",
+			"version": "1.23.3",
+			"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
+			"integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
 			"dev": true,
 			"dependencies": {
 				"array-buffer-byte-length": "^1.0.1",
 				"arraybuffer.prototype.slice": "^1.0.3",
-				"available-typed-arrays": "^1.0.6",
+				"available-typed-arrays": "^1.0.7",
 				"call-bind": "^1.0.7",
+				"data-view-buffer": "^1.0.1",
+				"data-view-byte-length": "^1.0.1",
+				"data-view-byte-offset": "^1.0.0",
 				"es-define-property": "^1.0.0",
 				"es-errors": "^1.3.0",
-				"es-set-tostringtag": "^2.0.2",
+				"es-object-atoms": "^1.0.0",
+				"es-set-tostringtag": "^2.0.3",
 				"es-to-primitive": "^1.2.1",
 				"function.prototype.name": "^1.1.6",
 				"get-intrinsic": "^1.2.4",
@@ -13029,15 +13116,16 @@
 				"globalthis": "^1.0.3",
 				"gopd": "^1.0.1",
 				"has-property-descriptors": "^1.0.2",
-				"has-proto": "^1.0.1",
+				"has-proto": "^1.0.3",
 				"has-symbols": "^1.0.3",
-				"hasown": "^2.0.1",
+				"hasown": "^2.0.2",
 				"internal-slot": "^1.0.7",
 				"is-array-buffer": "^3.0.4",
 				"is-callable": "^1.2.7",
-				"is-negative-zero": "^2.0.2",
+				"is-data-view": "^1.0.1",
+				"is-negative-zero": "^2.0.3",
 				"is-regex": "^1.1.4",
-				"is-shared-array-buffer": "^1.0.2",
+				"is-shared-array-buffer": "^1.0.3",
 				"is-string": "^1.0.7",
 				"is-typed-array": "^1.1.13",
 				"is-weakref": "^1.0.2",
@@ -13045,17 +13133,17 @@
 				"object-keys": "^1.1.1",
 				"object.assign": "^4.1.5",
 				"regexp.prototype.flags": "^1.5.2",
-				"safe-array-concat": "^1.1.0",
+				"safe-array-concat": "^1.1.2",
 				"safe-regex-test": "^1.0.3",
-				"string.prototype.trim": "^1.2.8",
-				"string.prototype.trimend": "^1.0.7",
-				"string.prototype.trimstart": "^1.0.7",
-				"typed-array-buffer": "^1.0.1",
-				"typed-array-byte-length": "^1.0.0",
-				"typed-array-byte-offset": "^1.0.0",
-				"typed-array-length": "^1.0.4",
+				"string.prototype.trim": "^1.2.9",
+				"string.prototype.trimend": "^1.0.8",
+				"string.prototype.trimstart": "^1.0.8",
+				"typed-array-buffer": "^1.0.2",
+				"typed-array-byte-length": "^1.0.1",
+				"typed-array-byte-offset": "^1.0.2",
+				"typed-array-length": "^1.0.6",
 				"unbox-primitive": "^1.0.2",
-				"which-typed-array": "^1.1.14"
+				"which-typed-array": "^1.1.15"
 			},
 			"engines": {
 				"node": ">= 0.4"
@@ -13143,6 +13231,18 @@
 			"integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==",
 			"dev": true
 		},
+		"node_modules/es-object-atoms": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
+			"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
+			"dev": true,
+			"dependencies": {
+				"es-errors": "^1.3.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
 		"node_modules/es-set-tostringtag": {
 			"version": "2.0.3",
 			"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
@@ -13578,27 +13678,29 @@
 			}
 		},
 		"node_modules/eslint-plugin-react": {
-			"version": "7.33.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz",
-			"integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==",
+			"version": "7.34.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz",
+			"integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==",
 			"dev": true,
 			"dependencies": {
-				"array-includes": "^3.1.6",
-				"array.prototype.flatmap": "^1.3.1",
-				"array.prototype.tosorted": "^1.1.1",
+				"array-includes": "^3.1.7",
+				"array.prototype.findlast": "^1.2.4",
+				"array.prototype.flatmap": "^1.3.2",
+				"array.prototype.toreversed": "^1.1.2",
+				"array.prototype.tosorted": "^1.1.3",
 				"doctrine": "^2.1.0",
-				"es-iterator-helpers": "^1.0.12",
+				"es-iterator-helpers": "^1.0.17",
 				"estraverse": "^5.3.0",
 				"jsx-ast-utils": "^2.4.1 || ^3.0.0",
 				"minimatch": "^3.1.2",
-				"object.entries": "^1.1.6",
-				"object.fromentries": "^2.0.6",
-				"object.hasown": "^1.1.2",
-				"object.values": "^1.1.6",
+				"object.entries": "^1.1.7",
+				"object.fromentries": "^2.0.7",
+				"object.hasown": "^1.1.3",
+				"object.values": "^1.1.7",
 				"prop-types": "^15.8.1",
-				"resolve": "^2.0.0-next.4",
+				"resolve": "^2.0.0-next.5",
 				"semver": "^6.3.1",
-				"string.prototype.matchall": "^4.0.8"
+				"string.prototype.matchall": "^4.0.10"
 			},
 			"engines": {
 				"node": ">=4"
@@ -15316,16 +15418,16 @@
 			"dev": true
 		},
 		"node_modules/glob": {
-			"version": "10.3.10",
-			"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
-			"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
+			"version": "10.3.12",
+			"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz",
+			"integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==",
 			"dev": true,
 			"dependencies": {
 				"foreground-child": "^3.1.0",
-				"jackspeak": "^2.3.5",
+				"jackspeak": "^2.3.6",
 				"minimatch": "^9.0.1",
-				"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
-				"path-scurry": "^1.10.1"
+				"minipass": "^7.0.4",
+				"path-scurry": "^1.10.2"
 			},
 			"bin": {
 				"glob": "dist/esm/bin.mjs"
@@ -15620,9 +15722,9 @@
 			"dev": true
 		},
 		"node_modules/hasown": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
-			"integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+			"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
 			"dev": true,
 			"dependencies": {
 				"function-bind": "^1.1.2"
@@ -16733,6 +16835,21 @@
 				"url": "https://github.com/sponsors/ljharb"
 			}
 		},
+		"node_modules/is-data-view": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
+			"integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
+			"dev": true,
+			"dependencies": {
+				"is-typed-array": "^1.1.13"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
 		"node_modules/is-date-object": {
 			"version": "1.0.5",
 			"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
@@ -23779,12 +23896,12 @@
 			"dev": true
 		},
 		"node_modules/path-scurry": {
-			"version": "1.10.1",
-			"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
-			"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
+			"version": "1.10.2",
+			"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz",
+			"integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==",
 			"dev": true,
 			"dependencies": {
-				"lru-cache": "^9.1.1 || ^10.0.0",
+				"lru-cache": "^10.2.0",
 				"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
 			},
 			"engines": {
@@ -25632,13 +25749,13 @@
 			}
 		},
 		"node_modules/safe-array-concat": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz",
-			"integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==",
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
+			"integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
 			"dev": true,
 			"dependencies": {
-				"call-bind": "^1.0.5",
-				"get-intrinsic": "^1.2.2",
+				"call-bind": "^1.0.7",
+				"get-intrinsic": "^1.2.4",
 				"has-symbols": "^1.0.3",
 				"isarray": "^2.0.5"
 			},
@@ -26610,14 +26727,15 @@
 			}
 		},
 		"node_modules/string.prototype.trim": {
-			"version": "1.2.8",
-			"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz",
-			"integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==",
+			"version": "1.2.9",
+			"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
+			"integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
 			"dev": true,
 			"dependencies": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1"
+				"call-bind": "^1.0.7",
+				"define-properties": "^1.2.1",
+				"es-abstract": "^1.23.0",
+				"es-object-atoms": "^1.0.0"
 			},
 			"engines": {
 				"node": ">= 0.4"
@@ -26627,28 +26745,31 @@
 			}
 		},
 		"node_modules/string.prototype.trimend": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz",
-			"integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==",
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
+			"integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
 			"dev": true,
 			"dependencies": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1"
+				"call-bind": "^1.0.7",
+				"define-properties": "^1.2.1",
+				"es-object-atoms": "^1.0.0"
 			},
 			"funding": {
 				"url": "https://github.com/sponsors/ljharb"
 			}
 		},
 		"node_modules/string.prototype.trimstart": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz",
-			"integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==",
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+			"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
 			"dev": true,
 			"dependencies": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1"
+				"call-bind": "^1.0.7",
+				"define-properties": "^1.2.1",
+				"es-object-atoms": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
 			},
 			"funding": {
 				"url": "https://github.com/sponsors/ljharb"
@@ -28108,9 +28229,9 @@
 			}
 		},
 		"node_modules/typed-array-length": {
-			"version": "1.0.5",
-			"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz",
-			"integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==",
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
+			"integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
 			"dev": true,
 			"dependencies": {
 				"call-bind": "^1.0.7",
@@ -28880,16 +29001,16 @@
 			}
 		},
 		"node_modules/which-typed-array": {
-			"version": "1.1.14",
-			"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz",
-			"integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==",
+			"version": "1.1.15",
+			"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
+			"integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
 			"dev": true,
 			"dependencies": {
-				"available-typed-arrays": "^1.0.6",
-				"call-bind": "^1.0.5",
+				"available-typed-arrays": "^1.0.7",
+				"call-bind": "^1.0.7",
 				"for-each": "^0.3.3",
 				"gopd": "^1.0.1",
-				"has-tostringtag": "^1.0.1"
+				"has-tostringtag": "^1.0.2"
 			},
 			"engines": {
 				"node": ">= 0.4"
diff --git a/package.json b/package.json
index 26c7a61779..35e9d0a220 100644
--- a/package.json
+++ b/package.json
@@ -198,4 +198,4 @@
 			"stylelint": "$stylelint"
 		}
 	}
-}
+}
\ No newline at end of file