From 2c99feb3af7fe474beb66ada8860b020ef39ab03 Mon Sep 17 00:00:00 2001
From: LauraPinilla <54566275+LauraPinilla@users.noreply.github.com>
Date: Mon, 15 Apr 2024 12:39:59 -0600
Subject: [PATCH] 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
---
blocks/identity-block/_index.scss | 20 ++++
.../identity-block/components/login/index.jsx | 19 +++-
.../social-sign-on/_children/AppleSignIn.jsx | 33 +++++++
.../_children/AppleSignIn.test.jsx | 40 ++++++++
.../_children/FacebookSignIn.jsx | 9 +-
.../components/social-sign-on/constants.js | 3 +
.../components/social-sign-on/index.jsx | 12 +--
.../social-sign-on/utils/useSocialSignIn.js | 17 ++--
.../EmailEditableFieldContainer.test.jsx | 40 ++++++++
.../PasswordEditableFieldContainer.test.jsx | 2 -
.../features/account-management/default.jsx | 1 -
.../account-management/default.test.jsx | 79 ++++++++++++---
.../features/login-links/default.jsx | 4 +-
.../identity-block/features/login/default.jsx | 5 +-
.../features/signup/default.jsx | 2 +-
.../features/social-sign-on/default.jsx | 59 +++++++++---
...fault.test-ignore.jsx => default.test.jsx} | 22 ++++-
blocks/identity-block/intl.json | 25 ++++-
blocks/identity-block/themes/news.json | 95 ++++++++++++++++++-
locale/en.json | 11 ++-
package-lock.json | 2 +-
21 files changed, 438 insertions(+), 62 deletions(-)
create mode 100644 blocks/identity-block/components/social-sign-on/_children/AppleSignIn.jsx
create mode 100644 blocks/identity-block/components/social-sign-on/_children/AppleSignIn.test.jsx
create mode 100644 blocks/identity-block/components/social-sign-on/constants.js
create mode 100644 blocks/identity-block/features/account-management/_children/EmailEditableFieldContainer.test.jsx
rename blocks/identity-block/features/social-sign-on/{default.test-ignore.jsx => default.test.jsx} (70%)
diff --git a/blocks/identity-block/_index.scss b/blocks/identity-block/_index.scss
index 237117212c..bd995bf816 100644
--- a/blocks/identity-block/_index.scss
+++ b/blocks/identity-block/_index.scss
@@ -108,6 +108,8 @@
@include scss.block-components("sign-up-tos-link");
@include scss.block-properties("sign-up-tos-link");
}
+ @include scss.block-components("sign-up-tos-container-link");
+ @include scss.block-properties("sign-up-tos-container-link");
}
@include scss.block-components("sign-up");
@@ -118,6 +120,24 @@
&__button-container {
@include scss.block-components("social-sign-on-button-container");
@include scss.block-properties("social-sign-on-button-container");
+
+ &__Apple {
+ @include scss.block-components("social-sign-on-button-container-apple");
+ @include scss.block-properties("social-sign-on-button-container-apple");
+ }
+ }
+
+ &__dividerWithText{
+ @include scss.block-components("social-sign-on-dividerWithText");
+ @include scss.block-properties("social-sign-on-dividerWithText");
+ &::before{
+ @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");
diff --git a/blocks/identity-block/components/login/index.jsx b/blocks/identity-block/components/login/index.jsx
index 88a7f7fb01..77c2fd0514 100644
--- a/blocks/identity-block/components/login/index.jsx
+++ b/blocks/identity-block/components/login/index.jsx
@@ -10,14 +10,31 @@ const useLogin = ({
redirectToPreviousPage,
loggedInPageLocation,
isOIDC,
+ appleCode,
}) => {
const { Identity } = useIdentity();
const validatedRedirectURL = validateURL(redirectURL);
const [redirectToURL, setRedirectToURL] = useState(validatedRedirectURL);
const [redirectQueryParam, setRedirectQueryParam] = useState(null);
+ const [isAppleAuthSuccess, setIsAppleAuthSuccess] = useState(false);
const { loginByOIDC } = useOIDCLogin();
+ useEffect(()=>{
+ const askForloginWithApple = async (code) => {
+ await Identity.appleSignOn(code);
+ const isLoggedIn = await Identity.isLoggedIn();
+
+ if(isLoggedIn){
+ setIsAppleAuthSuccess(true);
+ }
+ };
+
+ if(Identity && appleCode){
+ askForloginWithApple(appleCode);
+ }
+ },[appleCode, Identity]);
+
useEffect(() => {
if (window?.location?.search) {
const searchParams = new URLSearchParams(window.location.search.substring(1));
@@ -69,7 +86,7 @@ const useLogin = ({
if (Identity && !isAdmin) {
checkLoggedInStatus();
}
- }, [Identity, redirectQueryParam, loggedInPageLocation, isAdmin, loginByOIDC, isOIDC]);
+ }, [Identity, redirectQueryParam, loggedInPageLocation, isAdmin, loginByOIDC, isOIDC, isAppleAuthSuccess]);
return {
loginRedirect: redirectQueryParam || redirectToURL,
diff --git a/blocks/identity-block/components/social-sign-on/_children/AppleSignIn.jsx b/blocks/identity-block/components/social-sign-on/_children/AppleSignIn.jsx
new file mode 100644
index 0000000000..c691bc94e1
--- /dev/null
+++ b/blocks/identity-block/components/social-sign-on/_children/AppleSignIn.jsx
@@ -0,0 +1,33 @@
+import React from "react";
+import { Button, Icon, useIdentity } from "@wpmedia/arc-themes-components";
+import { useFusionContext } from "fusion:context";
+import getTranslatedPhrases from "fusion:intl";
+
+import { SIGN_UP } from "../constants";
+
+const AppleIcon = ;
+
+function AppleSignIn({ socialSignOnIn, className }) {
+ const { siteProperties } = useFusionContext();
+ const { locale } = siteProperties;
+ const phrases = getTranslatedPhrases(locale);
+ const { Identity } = useIdentity();
+
+ return (
+
+ );
+}
+
+export default AppleSignIn;
diff --git a/blocks/identity-block/components/social-sign-on/_children/AppleSignIn.test.jsx b/blocks/identity-block/components/social-sign-on/_children/AppleSignIn.test.jsx
new file mode 100644
index 0000000000..a65b739502
--- /dev/null
+++ b/blocks/identity-block/components/social-sign-on/_children/AppleSignIn.test.jsx
@@ -0,0 +1,40 @@
+import React from "react";
+import { render, screen } from "@testing-library/react";
+import { useFusionContext } from "fusion:context";
+
+import AppleSignIn from "./AppleSignIn";
+
+const SITE_PROPS_MOCK = {
+ breakpoints: {
+ small: 0,
+ medium: 768,
+ large: 992,
+ },
+ websiteAdPath: "news",
+ dfpId: 701,
+};
+
+jest.mock("@wpmedia/arc-themes-components", () => ({
+ ...jest.requireActual("@wpmedia/arc-themes-components"),
+ Icon: () =>
{
- const { facebookAppId, googleClientId } = useSocialSignIn(redirectURL, onError, isOIDC);
-
+const SocialSignOn = ({ className, onError, redirectURL, isOIDC, socialSignOnIn }) => {
+ const { facebookAppId, googleClientId, appleTeamId, appleKeyId, appleUrlToReceiveAuthToken} = useSocialSignIn(redirectURL, isOIDC, socialSignOnIn, onError);
return (
- {googleClientId ? : null}
- {facebookAppId ? : null}
+ {googleClientId ? : null}
+ {facebookAppId ? : null}
+ {appleTeamId && appleKeyId && appleUrlToReceiveAuthToken ? : null}
);
};
diff --git a/blocks/identity-block/components/social-sign-on/utils/useSocialSignIn.js b/blocks/identity-block/components/social-sign-on/utils/useSocialSignIn.js
index ac00d1312f..0c8f5d7e5b 100644
--- a/blocks/identity-block/components/social-sign-on/utils/useSocialSignIn.js
+++ b/blocks/identity-block/components/social-sign-on/utils/useSocialSignIn.js
@@ -4,7 +4,9 @@ import { GoogleSignInContext } from "./googleContext";
import useOIDCLogin from "../../../utils/useOIDCLogin";
import validateURL from "../../../utils/validate-redirect-url";
-function useSocialSignIn(redirectURL, onError = () => {}, isOIDC) {
+import {SIGN_UP} from "../constants";
+
+function useSocialSignIn(redirectURL, isOIDC, socialSignOnIn, onError = () => {}) {
const { Identity } = useIdentity();
const { isGoogleLoaded } = useContext(GoogleSignInContext);
const [config, setConfig] = useState(() => Identity?.configOptions ?? {});
@@ -25,7 +27,7 @@ function useSocialSignIn(redirectURL, onError = () => {}, isOIDC) {
onError();
}
};
- }, [Identity, onError, redirectURL]);
+ }, [Identity, onError, redirectURL, isOIDC, loginByOIDC]);
useEffect(() => {
const fetchConfig = async () => {
@@ -56,15 +58,15 @@ function useSocialSignIn(redirectURL, onError = () => {}, isOIDC) {
};
window.google.accounts.id.initialize(googleIdConfig);
-
+ const googleTextType = socialSignOnIn === SIGN_UP ? 'signup_with' : 'signin_with';
window.google.accounts.id.renderButton(document.getElementById("google-sign-in-button"), {
type: "standard",
theme: "outline",
size: "large",
- text: "continue_with",
+ text: googleTextType,
shape: "rectangular",
logo_alignment: "left",
- width: "300",
+ width: "400",
});
Identity.isLoggedIn().then((isLoggedIn) => {
@@ -75,7 +77,7 @@ function useSocialSignIn(redirectURL, onError = () => {}, isOIDC) {
}
});
}
- }, [config.googleClientId, Identity, isGoogleLoaded]);
+ }, [config.googleClientId, Identity, isGoogleLoaded, isOIDC, loginByOIDC, redirectURL, socialSignOnIn ]);
useEffect(() => {
const initializeFacebook = async () => {
@@ -91,6 +93,9 @@ function useSocialSignIn(redirectURL, onError = () => {}, isOIDC) {
// then they will have a truthy value here
facebookAppId: config.facebookAppId,
googleClientId: config.googleClientId,
+ appleTeamId: config.teamId,
+ appleKeyId: config.keyId,
+ appleUrlToReceiveAuthToken: config.urlToReceiveAuthToken
};
}
diff --git a/blocks/identity-block/features/account-management/_children/EmailEditableFieldContainer.test.jsx b/blocks/identity-block/features/account-management/_children/EmailEditableFieldContainer.test.jsx
new file mode 100644
index 0000000000..7351409129
--- /dev/null
+++ b/blocks/identity-block/features/account-management/_children/EmailEditableFieldContainer.test.jsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { render, fireEvent, screen} from '@testing-library/react';
+import EmailEditableFieldContainer from './EmailEditableFieldContainer';
+
+const mockUpdateProfile = jest.fn(() => Promise.resolve())
+const mockIdentity = {
+ apiOrigin: "http://origin/",
+ isLoggedIn: jest.fn(() => false),
+ getConfig: jest.fn(() => ({})),
+ updateUserProfile: mockUpdateProfile
+};
+
+jest.mock("@wpmedia/arc-themes-components", () => ({
+ ...jest.requireActual("@wpmedia/arc-themes-components"),
+ useIdentity: jest.fn(() => ({
+ isInitialized: true,
+ Identity: {
+ ...mockIdentity,
+ },
+ }))
+}));
+
+describe('EmailEditableFieldContainer', () => {
+ it('updates email and clears error on successful submission', async () => {
+ const setEmail = jest.fn();
+ render(
+
+ );
+
+ fireEvent.click(screen.getByText('identity-block.edit'));
+ const inputElement = screen.getByLabelText('identity-block.email')
+ fireEvent.input(inputElement, { target: { value: 'new@example.com' } });
+
+ expect(inputElement.value).toBe('new@example.com');
+ });
+});
\ No newline at end of file
diff --git a/blocks/identity-block/features/account-management/_children/PasswordEditableFieldContainer.test.jsx b/blocks/identity-block/features/account-management/_children/PasswordEditableFieldContainer.test.jsx
index 1822a2a89d..4612a6c09e 100644
--- a/blocks/identity-block/features/account-management/_children/PasswordEditableFieldContainer.test.jsx
+++ b/blocks/identity-block/features/account-management/_children/PasswordEditableFieldContainer.test.jsx
@@ -1,9 +1,7 @@
import React from "react";
import { fireEvent, render, screen } from "@testing-library/react";
-import { act } from "react-dom/test-utils";
import PasswordEditableFieldContainer from "./PasswordEditableFieldContainer";
-import FormPasswordConfirm from "../../../components/form-password-confirm";
jest.mock("../../../components/form-password-confirm", () => () =>
Password Confirm
);
diff --git a/blocks/identity-block/features/account-management/default.jsx b/blocks/identity-block/features/account-management/default.jsx
index 6e56956ce1..fa32a2c35a 100644
--- a/blocks/identity-block/features/account-management/default.jsx
+++ b/blocks/identity-block/features/account-management/default.jsx
@@ -94,7 +94,6 @@ function AccountManagement({ customFields }) {
const header = phrases.t("identity-block.account-information");
const socialProfileHeader = phrases.t("identity-block.connected-accounts");
- console.log(header, socialProfileHeader);
// if logged in, return account info
return (
diff --git a/blocks/identity-block/features/account-management/default.test.jsx b/blocks/identity-block/features/account-management/default.test.jsx
index 331af54723..afcf8de71d 100644
--- a/blocks/identity-block/features/account-management/default.test.jsx
+++ b/blocks/identity-block/features/account-management/default.test.jsx
@@ -1,18 +1,67 @@
import React from "react";
-import { render, screen } from "@testing-library/react";
+import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { useIdentity } from "@wpmedia/arc-themes-components";
import AccountManagement, { AccountManagementPresentational } from "./default";
-import EmailEditableFieldContainer from "./_children/EmailEditableFieldContainer";
-import PasswordEditableFieldContainer from "./_children/PasswordEditableFieldContainer";
-import SocialEditableSection from "./_children/SocialEditableSection";
-
jest.mock("./_children/EmailEditableFieldContainer", () => () =>
Email
);
jest.mock("./_children/PasswordEditableFieldContainer", () => () =>
Password
);
jest.mock("./_children/SocialEditableSection", () => () =>
Social
);
-jest.mock("@wpmedia/arc-themes-components");
+jest.mock("fusion:context", () => ({
+ useFusionContext: () => ({ isAdmin: false, globalContent: { credits: {} } }),
+}));
+jest.mock("fusion:properties", () => jest.fn(() => ({})));
+
+const defaultCustomFields = {
+ redirectURL: "",
+ showEmail: true,
+ showPassword: true,
+ showSocialProfile: false,
+};
+
+jest.mock("@arc-publishing/sdk-identity", () => ({
+ __esModule: true,
+ default: {
+ apiOrigin: "http://origin/",
+ options: jest.fn(),
+ },
+}));
+
+jest.mock("fusion:properties", () =>
+ jest.fn(() => ({
+ api: {
+ identity: {
+ origin: "https://corecomponents-arc-demo-3-prod.api.cdn.arcpublishing.com",
+ },
+ },
+ })),
+);
+
+const mockLogin = jest.fn(() => Promise.resolve());
+const mockIdentity = {
+ apiOrigin: "http://origin/",
+ isLoggedIn: jest.fn(() => false),
+ getConfig: jest.fn(() => ({})),
+ getUserProfile: jest.fn(() => ({})),
+ login: mockLogin,
+};
+
+jest.mock("@wpmedia/arc-themes-components", () => ({
+ useIdentity: jest.fn(() => ({
+ isInitialized: true,
+ Identity: {
+ ...mockIdentity,
+ },
+ })),
+ Heading: ({ children }) =>
{children}
,
+ Input: ({ type, label }) => (
+
+
+
+
+ ),
+}));
const userProfileMock = jest.fn(() =>
Promise.resolve({ email: "test@domain.com", identities: [] }),
@@ -25,21 +74,24 @@ describe("Account management", () => {
it("renders header text", async () => {
render(
);
- await expect(screen.findByText("header")).not.toBeNull();
+ const title = screen.getByText("header");
+ expect(title).not.toBeNull();
});
it("should render account management if logged in and initialized", async () => {
useIdentity.mockImplementation(() => ({
isInitialized: true,
Identity: {
+ apiOrigin: "http://origin/",
isLoggedIn: jest.fn(async () => true),
getConfig: jest.fn(async () => ({})),
getUserProfile: userProfileMock,
},
}));
- render(
);
- await expect(screen.findByText("Account Information")).not.toBeNull();
+ render(
);
+
+ await waitFor(() => expect(screen.getByText("identity-block.account-information")));
});
it("should not render if not logged in and not initialized", async () => {
@@ -65,7 +117,8 @@ describe("Account management", () => {
}));
render(
);
- await expect(screen.findByText("Email")).not.toBeNull();
+
+ await waitFor(() => expect(screen.getByText("Email")));
});
it("hides email input editable field if showing email", () => {
@@ -84,7 +137,8 @@ describe("Account management", () => {
}));
render(
);
- await expect(screen.findByText("Password")).not.toBeNull();
+
+ await waitFor(() => expect(screen.getByText("Password")));
});
it("hides password input editable field if showing password", async () => {
@@ -103,7 +157,8 @@ describe("Account management", () => {
}));
render(
);
- await expect(screen.findByText("Password")).not.toBeNull();
+
+ await waitFor(() => expect(screen.getByText("Social")));
});
it("hides social profile if showing social", async () => {
diff --git a/blocks/identity-block/features/login-links/default.jsx b/blocks/identity-block/features/login-links/default.jsx
index 4a1615492c..3e543d9b36 100644
--- a/blocks/identity-block/features/login-links/default.jsx
+++ b/blocks/identity-block/features/login-links/default.jsx
@@ -29,10 +29,10 @@ const LoginLinks = ({ customFields }) => {
return (
{showLogin ? (
- {phrases.t("identity-block.login-links-login")}
+ {phrases.t("identity-block.login-links-login")}{phrases.t("identity-block.log-in")}
) : null}
{showForgot ? (
- {phrases.t("identity-block.login-links-forgot")}
+ {phrases.t("identity-block.login-links-forgot")}
) : null}
{showSignUp ? (
{phrases.t("identity-block.login-links-signup")}{phrases.t("identity-block.sign-up-natural")}
diff --git a/blocks/identity-block/features/login/default.jsx b/blocks/identity-block/features/login/default.jsx
index 4faf237548..28a7bfa9e4 100644
--- a/blocks/identity-block/features/login/default.jsx
+++ b/blocks/identity-block/features/login/default.jsx
@@ -66,7 +66,7 @@ const Login = ({ customFields }) => {
setCaptchaError(null);
return Identity.login(email, password, {
rememberMe: true,
- recaptchaToken: captchaToken
+ recaptchaToken: captchaToken,
})
.then(() => {
if (isOIDC) {
@@ -86,8 +86,7 @@ const Login = ({ customFields }) => {
}
if (grecaptcha) {
grecaptcha.reset();
- }
-
+ }
});
}}
>
diff --git a/blocks/identity-block/features/signup/default.jsx b/blocks/identity-block/features/signup/default.jsx
index 331116c57b..36435c1817 100644
--- a/blocks/identity-block/features/signup/default.jsx
+++ b/blocks/identity-block/features/signup/default.jsx
@@ -185,4 +185,4 @@ SignUp.propTypes = {
}),
};
-export default SignUp;
+export default SignUp;
\ No newline at end of file
diff --git a/blocks/identity-block/features/social-sign-on/default.jsx b/blocks/identity-block/features/social-sign-on/default.jsx
index 4c991ce4ff..6f7a81f80f 100644
--- a/blocks/identity-block/features/social-sign-on/default.jsx
+++ b/blocks/identity-block/features/social-sign-on/default.jsx
@@ -3,7 +3,7 @@ import PropTypes from "@arc-fusion/prop-types";
import { useFusionContext } from "fusion:context";
import getProperties from "fusion:properties";
import getTranslatedPhrases from "fusion:intl";
-import { Paragraph, useIdentity } from "@wpmedia/arc-themes-components";
+import { Paragraph, useIdentity, Stack } from "@wpmedia/arc-themes-components";
import SocialSignOn from "../../components/social-sign-on";
import useLogin from "../../components/login";
import { GoogleSignInProvider } from "../../components/social-sign-on/utils/googleContext";
@@ -11,12 +11,32 @@ import { GoogleSignInProvider } from "../../components/social-sign-on/utils/goog
const BLOCK_CLASS_NAME = "b-social-sign-on";
const SocialSignOnBlock = ({ customFields }) => {
- const { redirectURL, redirectToPreviousPage, loggedInPageLocation, OIDC } = customFields;
+ const {
+ redirectURL,
+ redirectToPreviousPage,
+ loggedInPageLocation,
+ OIDC,
+ socialSignOnIn,
+ hideDiv,
+ } = customFields;
+
+ const checkAppleCodeExists = (url) => {
+ const urlQueryParams = url.split("?");
+ if (urlQueryParams.length) {
+ const charsAfterLastQuestionMark = urlQueryParams[urlQueryParams.length - 1];
+ const queryParams = new URLSearchParams(charsAfterLastQuestionMark);
+ const appleCode = queryParams.get("code");
+ return appleCode;
+ }
+ return null;
+ };
- const url_string = window.location.href;
- const url = new URL(url_string);
- const isOIDC = OIDC && url.searchParams.get("client_id") && url.searchParams.get("response_type") === "code";
+ const urlString = window.location.href;
+ const url = new URL(urlString);
+ const isOIDC =
+ OIDC && url.searchParams.get("client_id") && url.searchParams.get("response_type") === "code";
+ const appleCode = checkAppleCodeExists(urlString);
const { isAdmin, arcSite } = useFusionContext();
const { locale } = getProperties(arcSite);
const phrases = getTranslatedPhrases(locale);
@@ -30,7 +50,8 @@ const SocialSignOnBlock = ({ customFields }) => {
redirectURL,
redirectToPreviousPage,
loggedInPageLocation,
- isOIDC
+ isOIDC,
+ appleCode,
});
if (!isInitialized) {
@@ -38,7 +59,8 @@ const SocialSignOnBlock = ({ customFields }) => {
}
return (
-
+
+ {!hideDiv ? {phrases.t("identity-block.or")}
: null}
{
}}
redirectURL={loginRedirect}
isOIDC={isOIDC}
+ socialSignOnIn={socialSignOnIn}
/>
{error ? (
@@ -54,7 +77,7 @@ const SocialSignOnBlock = ({ customFields }) => {
{error}
) : null}
-
+
);
};
@@ -79,10 +102,22 @@ SocialSignOnBlock.propTypes = {
"The URL to which a user would be redirected to if logged in an vist a page with the login form on",
}),
OIDC: PropTypes.bool.tag({
- name: 'Login with OIDC',
- defaultValue: false,
- description: 'Used when authenticating a third party site with OIDC PKCE flow. This will use an ArcXp Org as an auth provider',
- }),
+ name: "Login with OIDC",
+ defaultValue: false,
+ description:
+ "Used when authenticating a third party site with OIDC PKCE flow. This will use an ArcXp Org as an auth provider",
+ }),
+ socialSignOnIn: PropTypes.oneOf(["Login", "SignUp"]).tag({
+ defaultValue: "Login",
+ description: "Social Sign on component to be rendered on Login or Sign Up form.",
+ label: "Social Sign On In",
+ }),
+ hideDiv: PropTypes.bool.tag({
+ name: "Hide divider",
+ defaultValue: false,
+ description:
+ "Used when we want to hide the ---OR--- divider",
+ })
}),
};
diff --git a/blocks/identity-block/features/social-sign-on/default.test-ignore.jsx b/blocks/identity-block/features/social-sign-on/default.test.jsx
similarity index 70%
rename from blocks/identity-block/features/social-sign-on/default.test-ignore.jsx
rename to blocks/identity-block/features/social-sign-on/default.test.jsx
index 76e7c4645d..2af7022553 100644
--- a/blocks/identity-block/features/social-sign-on/default.test-ignore.jsx
+++ b/blocks/identity-block/features/social-sign-on/default.test.jsx
@@ -14,6 +14,21 @@ const defaultCustomFields = {
redirectToPreviousPage: true,
};
+const mockIdentity = {
+ apiOrigin: "http://origin/",
+ getConfig: jest.fn(() => ({})),
+};
+
+jest.mock("@wpmedia/arc-themes-components", () => ({
+ ...jest.requireActual("@wpmedia/arc-themes-components"),
+ useIdentity: jest.fn(() => ({
+ isInitialized: true,
+ Identity: {
+ ...mockIdentity,
+ },
+ })),
+}));
+
describe("Subscriptions Social Login Feature", () => {
SocialSignOn.mockImplementation(() =>
);
@@ -23,11 +38,12 @@ describe("Subscriptions Social Login Feature", () => {
render(
);
expect(screen.queryByTestId("social-sign-on-container")).toBeNull();
});
- it("renders", () => {
+ it("renders", async () => {
useIdentity.mockImplementation(() => ({ isInitialized: true }));
render(
);
- expect(screen.queryByTestId("social-sign-on-container")).not.toBeNull();
+ const element = await screen.findByTestId("social-sign-on-container");
+ expect(element).not.toBeNull();
});
it("shows an error", () => {
SocialSignOn.mockImplementation(({ onError }) => {
@@ -35,6 +51,6 @@ describe("Subscriptions Social Login Feature", () => {
return
;
});
render(
);
- expect(screen.getByText("identity-block.login-form-error")).not.toBeNull();
+ expect(screen.getByText("identity-block.login-form-error"));
});
});
diff --git a/blocks/identity-block/intl.json b/blocks/identity-block/intl.json
index 933752f1b1..af46750ab2 100644
--- a/blocks/identity-block/intl.json
+++ b/blocks/identity-block/intl.json
@@ -504,7 +504,7 @@
"bn": "লগ ইন করুন",
"bo": "ཐོ་འཇུག",
"de": "Log In",
- "en": "Log In",
+ "en": "Log in",
"es": "Log In",
"fr": "Log In",
"id": "Masuk",
@@ -604,7 +604,7 @@
"bn": "ইতিমধ্যে একটি অ্যাকাউন্ট আছে?\nলগ ইন করুন",
"bo": "དྲ་གྲངས་ཡོད་པ་ཡིན་ནམ། ཐོ་འཇུག",
"de": "Already have an account? Log in.",
- "en": "Already have an account? Log in",
+ "en": "Already have an account?",
"es": "Already have an account? Log in.",
"fr": "Already have an account? Log in.",
"id": "Sudah memiliki akun? Masuk",
@@ -1277,6 +1277,9 @@
"identity-block.bot-protection-error": {
"en": "Please verify that you are not a robot."
},
+ "identity-block.create-an-account": {
+ "en": "Create an account"
+ },
"identity-block.email-label": {
"en": "Email"
},
@@ -1298,10 +1301,28 @@
"identity-block.login-form-error.invalid-email-password": {
"en": "Email or password is invalid. Try again."
},
+ "identity-block.or": {
+ "en": "OR"
+ },
"identity-block.privacy-statement": {
"en": "By creating an account, you agree to the Terms of Service and acknowledge our Privacy Policy."
},
"identity-block.sign-up-natural": {
"en": "Sign up"
+ },
+ "identity-block.social-signOn-apple-login": {
+ "en": "Sign in with Apple"
+ },
+ "identity-block.social-signOn-apple-signUp": {
+ "en": "Sign up with Apple"
+ },
+ "identity-block.social-signOn-google-login": {
+ "en": "Sign in with Google"
+ },
+ "identity-block.social-signOn-google-signUp": {
+ "en": "Sign up with Google"
+ },
+ "identity-block.terms-service-privacy-text": {
+ "en": "By creating an account, you agree to the
Terms of Service and acknowledge our Privacy Policy"
}
}
\ No newline at end of file
diff --git a/blocks/identity-block/themes/news.json b/blocks/identity-block/themes/news.json
index 849113dd61..b29fba5f51 100644
--- a/blocks/identity-block/themes/news.json
+++ b/blocks/identity-block/themes/news.json
@@ -393,7 +393,11 @@
"login-links-inner-link": {
"styles": {
"default": {
- "text-decoration": "underline"
+ "text-decoration": "underline",
+ "margin-block-end": "var(--global-spacing-5)",
+ "margin-inline-end": 0,
+ "margin-inline-start": 0,
+ "padding-inline-start": "var(--global-spacing-2)"
}
}
},
@@ -452,7 +456,7 @@
},
"heading": {
"border-block-end-color": "var(--border-color)",
- "border-block-end-style": "var(--global-border-style-1)",
+ "border-block-end-style": "var(--global-border-style-0)",
"border-block-end-width": "var(--global-border-width-1)",
"font-size": "var(--global-font-size-9)",
"margin-block-end": "var(--global-spacing-4)",
@@ -470,6 +474,9 @@
"padding-block-end": "var(--global-spacing-2)",
"padding-block-start": "var(--global-spacing-2)"
},
+ "input-tip": {
+ "font-size": "var(--global-font-size-3)"
+ },
"paragraph": {
"font-family": "var(--font-family-primary)",
"margin-block-end": "var(--global-spacing-5)"
@@ -486,11 +493,19 @@
}
}
},
+ "sign-up-tos-container-link":{
+ "styles": {
+ "default": {
+ "margin-block-end": "var(--global-spacing-5)"
+ },
+ "desktop": {}
+ }
+ },
"sign-up-tos-link": {
"styles": {
"default": {
"color": "var(--text-color)",
- "text-decoration": "none"
+ "text-decoration": "underline"
},
"desktop": {}
}
@@ -506,8 +521,9 @@
"social-sign-on": {
"styles": {
"default": {
- "inline-size": "300px",
+ "inline-size": "100%",
"margin-inline": "auto",
+ "gap": "var(--global-spacing-4)",
"components": {
"paragraph": {
"color": "var(--status-color-danger)",
@@ -523,7 +539,76 @@
"default": {
"display": "flex",
"flex-direction": "column",
- "gap": "var(--global-spacing-4)"
+ "align-items": "center",
+ "gap": "var(--global-spacing-4)",
+ "inline-size": "100%",
+ "margin-block-start": "var(--global-spacing-2)",
+ "margin-block-end": "var(--global-spacing-2)"
+ },
+ "desktop": {}
+ }
+ },
+ "social-sign-on-button-container-apple": {
+ "styles": {
+ "default": {
+ "justify-content": "center",
+ "border-block-start-width": "1px",
+ "border-block-end-width": "1px",
+ "border-inline-start-width": "1px",
+ "border-inline-end-width": "1px",
+ "border-block-start-color": "var(--border-color)",
+ "border-block-end-color": "var(--border-color)",
+ "border-inline-start-color": "var(--border-color)",
+ "border-inline-end-color": "var(--border-color)",
+ "border-radius": "var(--global-spacing-1)",
+ "color": "var(--text-color)",
+ "font-weight": "var(--global-font-weight-7)",
+ "font-family": "var(--font-family-primary)",
+ "inline-size": "400px",
+ "components": {
+ "button-secondary-reverse-hover": {
+ "color": "var(--text-color)"
+ }
+ }
+ },
+ "desktop": {}
+ }
+ },
+ "social-sign-on-dividerWithText": {
+ "styles": {
+ "default": {
+ "display": "flex",
+ "align-items": "center",
+ "flex-direction": "row",
+ "color": "var(--text-color-subtle)",
+ "font-family": "var(--font-family-primary)",
+ "font-weight": "var(--global-font-weight-4)",
+ "font-size": "var(--global-font-size-4)",
+ "margin-block-start": "var(--global-spacing-2)"
+ },
+ "desktop": {}
+ }
+ },
+ "social-sign-on-dividerWithText-before": {
+ "styles": {
+ "default": {
+ "content": "''",
+ "height": "1px",
+ "background-color": "var(--border-color)",
+ "flex-grow": "1",
+ "margin-inline-end": "var(--global-spacing-2)"
+ },
+ "desktop": {}
+ }
+ },
+ "social-sign-on-dividerWithText-after": {
+ "styles": {
+ "default": {
+ "content": "''",
+ "height": "1px",
+ "background-color": "var(--border-color)",
+ "flex-grow": "1",
+ "margin-inline-start": "var(--global-spacing-2)"
},
"desktop": {}
}
diff --git a/locale/en.json b/locale/en.json
index d8234a2270..3ebc0ee305 100644
--- a/locale/en.json
+++ b/locale/en.json
@@ -110,6 +110,7 @@
"identity-block.add-password": "Add Password",
"identity-block.bot-protection-error": "Please verify that you are not a robot.",
"identity-block.cancel": "Cancel",
+ "identity-block.create-an-account": "Create an account",
"identity-block.confirm-password": "Confirm password",
"identity-block.confirm-password-error": "Passwords must match",
"identity-block.connect-account": "Connected",
@@ -127,7 +128,7 @@
"identity-block.forgot-password-instruction": "Enter the email you use for your account",
"identity-block.forgot-password-instruction-submitted": "If there is an account associated with your email address, you’ll receive a link in your inbox to reset your password.",
"identity-block.forgot-password-submit": "Send",
- "identity-block.log-in": "Log In",
+ "identity-block.log-in": "Log in",
"identity-block.log-in-headline": "Log in to your account",
"identity-block.log-out": "Log Out",
"identity-block.login-form-error": "There's been an error logging you in",
@@ -137,11 +138,12 @@
"identity-block.login-form-error.max-devices": "User account has reached the max number of devices.",
"identity-block.login-form-error.invalid-email-password": "Email or password is invalid. Try again.",
"identity-block.login-links-forgot": "Forgot your password?",
- "identity-block.login-links-login": "Already have an account? Log in",
+ "identity-block.login-links-login": "Already have an account?",
"identity-block.login-links-signup": "Need to create an account? ",
"identity-block.login-options": "Log in options",
"identity-block.manage-account": "Manage Your Account",
"identity-block.new-password": "New Password",
+ "identity-block.or": "OR",
"identity-block.password": "Password",
"identity-block.password-placeholder": "**********",
"identity-block.password-requirements": "Please enter a valid password.",
@@ -163,6 +165,11 @@
"identity-block.sign-up-natural": "Sign up",
"identity-block.sign-up-form-error": "There's been an error creating your account",
"identity-block.terms-privacy-text": "By creating an account, you agree to the
Terms of Service<\/a> and acknowledge our Privacy Policy<\/a>.",
+ "identity-block.social-signOn-apple-login": "Sign in with Apple",
+ "identity-block.social-signOn-apple-signUp": "Sign up with Apple",
+ "identity-block.social-signOn-google-login": "Sign in with Google",
+ "identity-block.social-signOn-google-signUp": "Sign up with Google",
+ "identity-block.terms-service-privacy-text": "By creating an account, you agree to the 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"
diff --git a/package-lock.json b/package-lock.json
index 2b59174aa4..c7596baa73 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -405,7 +405,7 @@
"react-google-recaptcha-v3": "^1.10.1"
},
"peerDependencies": {
- "@wpmedia/arc-themes-components": "*"
+ "@wpmedia/arc-themes-components": "file:../../../arc-themes-components"
}
},
"blocks/large-manual-promo-block": {