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: () =>
, +})); + +describe("Identity Social Login Component", () => { + beforeEach(() => { + jest.clearAllMocks(); + useFusionContext.mockReturnValue({ + isAdmin: true, + siteProperties: SITE_PROPS_MOCK, + }); + }); + + it("renders Apple button for signIn", () => { + render(); + expect(screen.getByText("identity-block.social-signOn-apple-login")).not.toBeNull(); + }); + + it("renders Apple button for signUp", () => { + render(); + expect(screen.getByText("identity-block.social-signOn-apple-signUp")).not.toBeNull(); + }); +}); diff --git a/blocks/identity-block/components/social-sign-on/_children/FacebookSignIn.jsx b/blocks/identity-block/components/social-sign-on/_children/FacebookSignIn.jsx index 2daaa7bd21..2f5258f005 100644 --- a/blocks/identity-block/components/social-sign-on/_children/FacebookSignIn.jsx +++ b/blocks/identity-block/components/social-sign-on/_children/FacebookSignIn.jsx @@ -1,12 +1,15 @@ import React from "react"; -function FacebookSignIn() { +import { SIGN_UP } from "../constants"; + +function FacebookSignIn({socialSignOnIn}) { + const facebookTextType = socialSignOnIn === SIGN_UP ? 'continue_with' : 'login_with'; return (
{ - 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": {