diff --git a/.env.development b/.env.development
index baaf32cd9..9d543351d 100644
--- a/.env.development
+++ b/.env.development
@@ -1,4 +1,5 @@
REACT_APP_DOPPLER_LEGACY_URL=http://localhost:52191
+REACT_APP_DOPPLER_SITES_URL= https://www.fromdoppler.com
REACT_APP_DATAHUB_URL=https://hubapisecint.fromdoppler.com
REACT_APP_RECAPTCHA_PUBLIC_KEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
REACT_APP_USE_DOPPLER_LEGACY_LOGIN=false
diff --git a/.env.int b/.env.int
index d00aeb147..8cb09f54c 100644
--- a/.env.int
+++ b/.env.int
@@ -1,4 +1,5 @@
REACT_APP_DOPPLER_LEGACY_URL=https://appint.fromdoppler.net
+REACT_APP_DOPPLER_SITES_URL= https://www.fromdoppler.com
REACT_APP_DATAHUB_URL=https://hubapisecint.fromdoppler.com
REACT_APP_RECAPTCHA_PUBLIC_KEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
REACT_APP_USE_DOPPLER_LEGACY_LOGIN=false
diff --git a/.env.production b/.env.production
index 3df81be30..0a7f93c2c 100644
--- a/.env.production
+++ b/.env.production
@@ -1,4 +1,5 @@
REACT_APP_DOPPLER_LEGACY_URL=https://app2.fromdoppler.com
+REACT_APP_DOPPLER_SITES_URL= https://www.fromdoppler.com
REACT_APP_DATAHUB_URL=https://hubapisec.fromdoppler.com
REACT_APP_RECAPTCHA_PUBLIC_KEY=6LddzZ8UAAAAAPSs09txKtTl9ewIyqYihfOC-dzf
REACT_APP_USE_DOPPLER_LEGACY_LOGIN=false
diff --git a/.env.qa b/.env.qa
index d77a1e6d3..3b7a55c01 100644
--- a/.env.qa
+++ b/.env.qa
@@ -1,4 +1,5 @@
REACT_APP_DOPPLER_LEGACY_URL=https://appqa.fromdoppler.net
+REACT_APP_DOPPLER_SITES_URL= https://www.fromdoppler.com
REACT_APP_DATAHUB_URL=https://hubapisecqa.fromdoppler.com
REACT_APP_RECAPTCHA_PUBLIC_KEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
REACT_APP_USE_DOPPLER_LEGACY_LOGIN=false
diff --git a/src/components/ForgotPassword/ForgotPassword.js b/src/components/ForgotPassword/ForgotPassword.js
index 038c230c7..5c605ba54 100644
--- a/src/components/ForgotPassword/ForgotPassword.js
+++ b/src/components/ForgotPassword/ForgotPassword.js
@@ -15,6 +15,7 @@ import './ForgotPassword.css';
import { FormattedMessageMarkdown } from '../../i18n/FormattedMessageMarkdown';
import { Helmet } from 'react-helmet';
import { connect } from 'formik';
+import Promotions from '../shared/Promotions/Promotions';
const fieldNames = {
email: 'email',
@@ -149,23 +150,7 @@ const ForgotPassword = ({ intl, location, dependencies: { dopplerLegacyClient }
-
-
-
- {_('feature_panel.forms')}
- {_('feature_panel.forms_description')}
- {_('feature_panel.forms_remarks')}
-
-
-
-
+
);
};
diff --git a/src/components/Login/Login.js b/src/components/Login/Login.js
index 58820684d..7ca8f16e0 100644
--- a/src/components/Login/Login.js
+++ b/src/components/Login/Login.js
@@ -17,6 +17,7 @@ import { InjectAppServices } from '../../services/pure-di';
import { LoginErrorAccountNotValidated } from './LoginErrorAccountNotValidated';
import { FormattedMessageMarkdown } from '../../i18n/FormattedMessageMarkdown';
import { connect } from 'formik';
+import Promotions from '../shared/Promotions/Promotions';
const fieldNames = {
user: 'user',
@@ -199,23 +200,7 @@ const Login = ({ intl, location, dependencies: { dopplerLegacyClient, sessionMan
-
-
-
- {_('feature_panel.forms')}
- {_('feature_panel.forms_description')}
- {_('feature_panel.forms_remarks')}
-
-
-
-
+
);
};
diff --git a/src/components/Signup/Signup.js b/src/components/Signup/Signup.js
index a0ebc3c14..8d4f5ebd6 100644
--- a/src/components/Signup/Signup.js
+++ b/src/components/Signup/Signup.js
@@ -17,6 +17,8 @@ import {
import LanguageSelector from '../shared/LanguageSelector/LanguageSelector';
import SignupConfirmation from './SignupConfirmation';
import { FormattedMessageMarkdown } from '../../i18n/FormattedMessageMarkdown';
+import Promotions from '../shared/Promotions/Promotions';
+import queryString from 'query-string';
const fieldNames = {
firstname: 'firstname',
@@ -33,6 +35,12 @@ const minLength = {
errorMessageKey: 'validation_messages.error_min_length_2',
};
+/** Extract the page parameter from url*/
+function extractPage(location) {
+ const parsedQuery = location && location.search && queryString.parse(location.search);
+ return (parsedQuery && (parsedQuery['page'] || parsedQuery['Page'])) || null;
+}
+
/** Prepare empty values for all fields
* It is required because in another way, the fields are not marked as touched.
*/
@@ -48,7 +56,7 @@ const getFormInitialValues = () =>
* @param { import('react-intl').InjectedIntl } props.intl
* @param { import('../../services/pure-di').AppServices } props.dependencies
*/
-const Signup = function({ intl, dependencies: { dopplerLegacyClient, originResolver } }) {
+const Signup = function({ intl, location, dependencies: { dopplerLegacyClient, originResolver } }) {
const _ = (id, values) => intl.formatMessage({ id: id }, values);
const [registeredUser, setRegisteredUser] = useState(null);
@@ -143,7 +151,9 @@ const Signup = function({ intl, dependencies: { dopplerLegacyClient, originResol
{_('signup.sign_up')}
{_('signup.sign_up_sub')} {_('signup.do_you_already_have_an_account')}{' '}
- {_('signup.log_in')}
+
+ {_('signup.log_in')}
+
-
-
-
- {_('feature_panel.email_automation')}
- {_('feature_panel.email_automation_description')}
- {_('feature_panel.email_automation_remarks')}
-
-
-
-
+
);
};
diff --git a/src/components/shared/Promotions/Promotions.js b/src/components/shared/Promotions/Promotions.js
new file mode 100644
index 000000000..83e8b64b5
--- /dev/null
+++ b/src/components/shared/Promotions/Promotions.js
@@ -0,0 +1,79 @@
+import React, { useState, useEffect } from 'react';
+import { injectIntl } from 'react-intl';
+import { InjectAppServices } from '../../../services/pure-di';
+import Loading from '../../Loading/Loading';
+
+const getDefaultBannerData = (intl) => {
+ const _ = (id, values) => intl.formatMessage({ id: id }, values);
+
+ return {
+ title: _('default_banner_data.title'),
+ description: _('default_banner_data.description'),
+ backgroundUrl: _('default_banner_data.background_url'),
+ imageUrl: _('default_banner_data.image_url'),
+ functionality: _('default_banner_data.functionality'),
+ fontColor: '#000',
+ };
+};
+
+/**
+ * Promotions
+ * @param { Object } props
+ * @param { import('react-intl').InjectedIntl } props.intl
+ * @param { import('../../services/pure-di').AppServices } props.dependencies
+ */
+const Promotions = function({
+ intl,
+ type,
+ page,
+ disabledSitesContent,
+ dependencies: { dopplerSitesClient },
+}) {
+ const [bannerData, setBannerData] = useState({});
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ if (disabledSitesContent) {
+ setBannerData(getDefaultBannerData(intl));
+ setIsLoading(false);
+ } else {
+ const fetchData = async () => {
+ setIsLoading(true);
+ const bannerData = await dopplerSitesClient.getBannerData(intl.locale, type, page || '');
+ setBannerData(
+ bannerData.success && bannerData.value ? bannerData.value : getDefaultBannerData(intl),
+ );
+ setIsLoading(false);
+ };
+
+ fetchData();
+ }
+ }, [disabledSitesContent, dopplerSitesClient, page, intl, type]);
+
+ return (
+
+ {isLoading ? (
+
+ ) : (
+
+
+ {bannerData.functionality}
+ {bannerData.title}
+ {bannerData.description}
+
+
+
+ )}
+
+ );
+};
+
+export default InjectAppServices(injectIntl(Promotions));
diff --git a/src/components/shared/Promotions/Promotions.test.js b/src/components/shared/Promotions/Promotions.test.js
new file mode 100644
index 000000000..165c742b8
--- /dev/null
+++ b/src/components/shared/Promotions/Promotions.test.js
@@ -0,0 +1,84 @@
+import React from 'react';
+import { render, cleanup, waitForDomChange } from '@testing-library/react';
+import 'jest-dom/extend-expect';
+import Promotions from './Promotions';
+import DopplerIntlProvider from '../../../i18n/DopplerIntlProvider.double-with-ids-as-values';
+import { AppServicesProvider } from '../../../services/pure-di';
+import { async } from 'q';
+
+const emptyResponse = { success: false, error: new Error('Dummy error') };
+const fullResponse = {
+ success: true,
+ value: {
+ title: 'default_banner_data.title',
+ description: 'default_banner_data.description',
+ backgroundUrl: 'default_banner_data.background_url',
+ imageUrl: 'default_banner_data.image_url',
+ functionality: 'default_banner_data.functionality',
+ color: '#fff',
+ },
+};
+
+describe('Promotions Component', () => {
+ afterEach(cleanup);
+ it('should sites response fail', async () => {
+ const dopplerSitesClientDouble = {
+ getBannerData: async () => emptyResponse,
+ };
+
+ const { container, getByText } = render(
+
+
+
+
+ ,
+ );
+ expect(container.querySelector('.loading-box')).toBeInTheDocument();
+ await waitForDomChange();
+ expect(getByText('default_banner_data.title'));
+ });
+
+ it('should disabled sites content', () => {
+ const dopplerSitesClientDouble = {
+ getBannerData: async () => emptyResponse,
+ };
+
+ const { getByText } = render(
+
+
+
+
+ ,
+ );
+ expect(getByText('default_banner_data.title'));
+ });
+
+ it('should has full data from service', async () => {
+ const dopplerSitesClientDouble = {
+ getBannerData: async () => fullResponse,
+ };
+
+ const { container, getByText } = render(
+
+
+
+
+ ,
+ );
+ expect(container.querySelector('.loading-box')).toBeInTheDocument();
+ await waitForDomChange();
+ expect(getByText(fullResponse.value.title));
+ });
+});
diff --git a/src/doppler-types.ts b/src/doppler-types.ts
index 0cad7aa2d..6911a3373 100644
--- a/src/doppler-types.ts
+++ b/src/doppler-types.ts
@@ -1,6 +1,9 @@
export type UnexpectedError = { success?: false; message?: string | null; error?: any };
export type ErrorResult = { success?: false; expectedError: TError } | UnexpectedError;
export type Result = { success: true; value: TResult } | ErrorResult;
+export type ResultWithoutExpectedErrors =
+ | { success: true; value: TResult }
+ | UnexpectedError;
export type EmptyResult = { success: true } | ErrorResult;
// It does not work:
// type EmptyResult = { success: true } | UnexpectedError;
diff --git a/src/i18n/en.js b/src/i18n/en.js
index eafe800da..4a0df7f40 100644
--- a/src/i18n/en.js
+++ b/src/i18n/en.js
@@ -35,6 +35,13 @@ export default {
send: `Send`,
show: `Show`,
},
+ default_banner_data: {
+ background_url: 'https://cdn.fromdoppler.com/doppler-ui-library/v2.5.0/img/violet-yellow.png',
+ description: 'Classics and pop-ups with Single or Double Opt-In subscription. You decide how you want them to look, what data to request and where to place them!',
+ functionality: 'subscription forms',
+ image_url: 'https://cdn.fromdoppler.com/doppler-ui-library/v2.5.0/img/login-en.png',
+ title: 'Add new contacts to your Lists using custom Forms',
+ },
empty_notification_text: `You don't have pending notifications.`,
feature_panel: {
email_automation: `Email Automation`,
diff --git a/src/i18n/es.js b/src/i18n/es.js
index aa36af488..3ff84aa9c 100644
--- a/src/i18n/es.js
+++ b/src/i18n/es.js
@@ -35,6 +35,13 @@ export default {
send: `Enviar`,
show: `Mostrar`,
},
+ default_banner_data: {
+ background_url: 'https://cdn.fromdoppler.com/doppler-ui-library/v2.5.0/img/violet-yellow.png',
+ description: 'Clásicos y pop-ups con suscripción Simple o Doble Opt-In. ¡Tú eliges cómo quieres que luzcan, qué datos solicitar y dónde ubicarlos!',
+ functionality: 'Formularios de suscripción',
+ image_url: 'https://cdn.fromdoppler.com/doppler-ui-library/v2.5.0/img/login-es.png',
+ title: 'Suma contactos a tus Listas con Formularios personalizados',
+ },
empty_notification_text: `No tienes notificaciones pendientes.`,
feature_panel: {
email_automation: `Email Automation`,
diff --git a/src/index.js b/src/index.js
index fe1e10b82..c9c8dc6a5 100644
--- a/src/index.js
+++ b/src/index.js
@@ -10,6 +10,7 @@ import ReactGA from 'react-ga';
// Only used in development environment, it does not affect production build
import { HardcodedDopplerLegacyClient } from './services/doppler-legacy-client.doubles';
import { HardcodedDatahubClient } from './services/datahub-client.doubles';
+import { HardcodedDopplerSitesClient } from './services/doppler-sites-client.doubles';
import { polyfill } from 'es6-object-assign';
import 'polyfill-array-includes';
import 'promise-polyfill/src/polyfill';
@@ -29,6 +30,7 @@ const forcedServices =
process.env.NODE_ENV === 'development'
? {
dopplerLegacyClient: new HardcodedDopplerLegacyClient(),
+ dopplerSitesClient: new HardcodedDopplerSitesClient(),
datahubClient: new HardcodedDatahubClient(),
shopifyClient: new HardcodedShopifyClient(),
}
diff --git a/src/services/doppler-sites-client.doubles.ts b/src/services/doppler-sites-client.doubles.ts
new file mode 100644
index 000000000..601df9a6d
--- /dev/null
+++ b/src/services/doppler-sites-client.doubles.ts
@@ -0,0 +1,33 @@
+import { DopplerSitesClient, PromotionsResult } from './doppler-sites-client';
+
+import { timeout } from '../utils';
+
+export class HardcodedDopplerSitesClient implements DopplerSitesClient {
+ public async getBannerData(lang: string, type: string, page: string): Promise {
+ console.log('getBannerData');
+ await timeout(1500);
+ const response: any = {
+ title: 'mi funcionalidad',
+ functionality: 'mi funcionalidad',
+ description: 'mi descripcion',
+ image_url: 'https://qa.fromdoppler.com/wp-content/uploads/2019/06/login-es.746bf048.png',
+ background_url: 'https://qa.fromdoppler.com/wp-content/uploads/2019/06/violet-yellow.png',
+ font_color: '#000',
+ };
+ return {
+ success: true,
+ value: {
+ title: response.title,
+ functionality: response.functionality,
+ description: response.description,
+ imageUrl: response.image_url,
+ backgroundUrl: response.background_url,
+ fontColor: response.font_color,
+ },
+ };
+ //return {
+ // success: false,
+ // error: new Error('Dummy error'),
+ //};
+ }
+}
diff --git a/src/services/doppler-sites-client.ts b/src/services/doppler-sites-client.ts
new file mode 100644
index 000000000..9bf68eff2
--- /dev/null
+++ b/src/services/doppler-sites-client.ts
@@ -0,0 +1,63 @@
+import { AxiosInstance, AxiosStatic } from 'axios';
+import { ResultWithoutExpectedErrors } from '../doppler-types';
+
+export interface DopplerSitesClient {
+ getBannerData(lang: string, type: string, page?: string | null): Promise;
+}
+
+export interface Promotions {
+ title: string;
+ functionality: string;
+ description: string;
+ imageUrl: string;
+ backgroundUrl: string;
+ fontColor: string;
+}
+
+export type PromotionsResult = ResultWithoutExpectedErrors;
+
+export class HttpDopplerSitesClient implements DopplerSitesClient {
+ private readonly axios: AxiosInstance;
+ private readonly baseUrl: string;
+
+ constructor({ axiosStatic, baseUrl }: { axiosStatic: AxiosStatic; baseUrl: string }) {
+ this.baseUrl = baseUrl;
+ this.axios = axiosStatic.create({
+ baseURL: baseUrl,
+ });
+ }
+
+ public async getBannerData(
+ lang: string,
+ type: string,
+ page?: string | null,
+ ): Promise {
+ try {
+ const response: any = await this.axios.get(
+ `${
+ this.baseUrl
+ }/wp-json/doppler2019/v1/getbanner?filter[lang]=${lang}&filter[type]=${type}&filter[page]=${page ||
+ ''}`,
+ );
+ if (!response || !response.data) {
+ throw new Error('Empty Site response');
+ }
+ return {
+ success: true,
+ value: {
+ title: response.title,
+ functionality: response.functionality,
+ description: response.description,
+ imageUrl: response.image_url,
+ backgroundUrl: response.background_url,
+ fontColor: response.font_color,
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error,
+ };
+ }
+ }
+}
diff --git a/src/services/pure-di.tsx b/src/services/pure-di.tsx
index 6a5b4a29d..b49dbd9c4 100644
--- a/src/services/pure-di.tsx
+++ b/src/services/pure-di.tsx
@@ -6,10 +6,12 @@ import { DatahubClient, HttpDatahubClient } from './datahub-client';
import { AppSession, createAppSessionRef } from './app-session';
import { OriginResolver, LocalStorageOriginResolver } from './origin-management';
import { ShopifyClient } from './shopify-client';
+import { DopplerSitesClient, HttpDopplerSitesClient } from './doppler-sites-client';
import { HardcodedShopifyClient } from './shopify-client.doubles';
interface AppConfiguration {
dopplerLegacyUrl: string;
+ dopplerSitesUrl: string;
datahubUrl: string;
dopplerLegacyKeepAliveMilliseconds: number;
recaptchaPublicKey: string;
@@ -34,6 +36,7 @@ export interface AppServices {
localStorage: Storage;
originResolver: OriginResolver;
shopifyClient: ShopifyClient;
+ dopplerSitesClient: DopplerSitesClient;
}
/**
@@ -67,6 +70,7 @@ export class AppCompositionRoot implements AppServices {
get appConfiguration() {
return this.singleton('appConfiguration', () => ({
dopplerLegacyUrl: process.env.REACT_APP_DOPPLER_LEGACY_URL as string,
+ dopplerSitesUrl: process.env.REACT_APP_DOPPLER_SITES_URL as string,
datahubUrl: process.env.REACT_APP_DATAHUB_URL as string,
recaptchaPublicKey: process.env.REACT_APP_RECAPTCHA_PUBLIC_KEY as string,
dopplerLegacyKeepAliveMilliseconds: parseInt(process.env
@@ -102,6 +106,17 @@ export class AppCompositionRoot implements AppServices {
);
}
+ get dopplerSitesClient() {
+ return this.singleton(
+ 'dopplerSitesClient',
+ () =>
+ new HttpDopplerSitesClient({
+ axiosStatic: this.axiosStatic,
+ baseUrl: this.appConfiguration.dopplerSitesUrl,
+ }),
+ );
+ }
+
get shopifyClient() {
return this.singleton('shopifyClient', () => new HardcodedShopifyClient());
}