From af9870d725ed04ad4e6998a3ac344bd6bf810c2e Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+masterprog-cmd@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:17:18 +0100 Subject: [PATCH 1/6] feat: add spring banner --- src/app/banners/BannerWrapper.tsx | 7 ++- src/app/banners/FeaturesBanner.tsx | 90 ++++++++++++++---------------- src/app/i18n/locales/de.json | 25 +++++---- src/app/i18n/locales/en.json | 20 +++---- src/app/i18n/locales/es.json | 20 +++---- src/app/i18n/locales/fr.json | 20 +++---- src/app/i18n/locales/it.json | 20 +++---- src/app/i18n/locales/ru.json | 22 ++++---- src/app/i18n/locales/zh.json | 24 ++++---- 9 files changed, 123 insertions(+), 125 deletions(-) diff --git a/src/app/banners/BannerWrapper.tsx b/src/app/banners/BannerWrapper.tsx index d157ba5ad..0f08c4db8 100644 --- a/src/app/banners/BannerWrapper.tsx +++ b/src/app/banners/BannerWrapper.tsx @@ -8,9 +8,10 @@ import { useSelector } from 'react-redux'; import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings'; import Banner from './Banner'; +import FeaturesBanner from './FeaturesBanner'; -const SHOW_BANNER_COOKIE_NAME = 'show_lifetime_soft_banner'; -const OFFER_OFF_DAY = new Date('2024-03-04'); +const SHOW_BANNER_COOKIE_NAME = 'show_spring_banner'; +const OFFER_OFF_DAY = new Date('2024-03-18'); const BannerWrapper = (): JSX.Element => { const [showBanner, setShowBanner] = useState(false); @@ -41,7 +42,7 @@ const BannerWrapper = (): JSX.Element => { } } - return ; + return ; }; export default BannerWrapper; diff --git a/src/app/banners/FeaturesBanner.tsx b/src/app/banners/FeaturesBanner.tsx index 782e64e40..0f00682a6 100644 --- a/src/app/banners/FeaturesBanner.tsx +++ b/src/app/banners/FeaturesBanner.tsx @@ -1,74 +1,70 @@ -import { CheckCircle, CircleWavyCheck, X } from '@phosphor-icons/react'; -import { useTranslationContext } from 'app/i18n/provider/TranslationProvider'; +import { CheckCircle, Flower, X } from '@phosphor-icons/react'; +import { useTranslation } from 'react-i18next'; const FeaturesBanner = ({ showBanner, onClose }: { showBanner: boolean; onClose: () => void }): JSX.Element => { - const { translate } = useTranslationContext(); + const { t } = useTranslation(); - const features = [ - { - title: translate('featuresBanner.features.discount'), - }, - { - title: translate('featuresBanner.features.safeCloud'), - }, - { - title: translate('featuresBanner.features.openSource'), - }, - { - title: translate('featuresBanner.features.endToEnd'), - }, - { - title: translate('featuresBanner.features.unauthorized'), - }, - { - title: translate('featuresBanner.features.offerEnds'), - }, - ]; + const features = t('featuresBanner.features', { returnObjects: true }) as string[]; + + const handleOnClick = () => { + window.open('https://internxt.com/pricing', '_blank', 'nofollow noreferrer'); + }; return ( + //Background
+ {/* Banner */}
- -
-
-
-

{translate('featuresBanner.header')}

-

{translate('featuresBanner.title')}

+
+
+
+

{t('featuresBanner.label')}

-
+

+ {t('featuresBanner.title')} +

+ +
-
- -

{translate('lifetimeBanner.guarantee')}

+
+ +

{t('featuresBanner.guarantee')}

+ +

{t('featuresBanner.lastCta')}

-
- {features.map((item) => ( -
- -

{item.title}

+
+
+
+ {features.map((card) => ( +
+ +

{card}

+
+ ))}
- ))} +
); }; + export default FeaturesBanner; diff --git a/src/app/i18n/locales/de.json b/src/app/i18n/locales/de.json index 199d16982..ca0a9e9f7 100644 --- a/src/app/i18n/locales/de.json +++ b/src/app/i18n/locales/de.json @@ -4,18 +4,19 @@ "logOut": "Log-out" }, "featuresBanner": { - "header": "Spare 70%!", - "title": "Bereiten Sie sich auf die Datenschutzwoche vor", - "cta": "Plan auswählen", - "guarantee": "30-tägige Geld-zurück-Garantie", - "features": { - "discount": "Sparen Sie bei monatlichen und jährlichen Plänen", - "safeCloud": "Sicherer und geschützter Cloud-Speicher", - "openSource": "Open Source und transparent", - "endToEnd": "Ende-zu-Ende-verschlüsselte Übertragungen", - "unauthorized": "Kein unberechtigter Zugriff", - "offerEnds": "Angebot endet am 29. Februar" - } + "label": "Spare 75%", + "title": "Starten Sie Ihre digitale Frühjahrsputz", + "cta": "Wähle einen Plan", + "guarantee": "30 Tage Geld-zurück-Garantie", + "lastCta": "*Angebot gilt für kostenlose Konten oder neue Kunden", + "features": [ + "Sparen Sie bei allen unseren Plänen", + "Sicherer Cloud-Speicher", + "Backup privater Dateien und Fotos", + "End-to-end verschlüsselte Übertragungen", + "Kein unbefugter Zugriff", + "Angebot endet am 18. März" + ] }, "valentinesBanner": { "title": "Liebe ohne grenzen!", diff --git a/src/app/i18n/locales/en.json b/src/app/i18n/locales/en.json index 415a6a223..c4e31c8f9 100644 --- a/src/app/i18n/locales/en.json +++ b/src/app/i18n/locales/en.json @@ -4,19 +4,19 @@ "logOut": "Log Out" }, "featuresBanner": { - "header": "Save 70%!", - "title": "Get ready for Data Privacy Week", + "label": "Save 75%", + "title": "Start your digital spring cleaning", "cta": "Choose plan", "guarantee": "30-day money-back guarantee", "lastCta": "*Offer is for free accounts or new customers", - "features": { - "discount": "Save on monthly & annual plans", - "safeCloud": "Safe and secure cloud storage", - "openSource": "Open source and transparent", - "endToEnd": "End-to-end encrypted transfers", - "unauthorized": "No unauthorized access", - "offerEnds": "Offer ends February 29th" - } + "features": [ + "Save on all of our plans", + "Safe and secure cloud storage", + "Open source and transparent", + "End-to-end encrypted transfers", + "No unauthorized access", + "Offer ends March 18th" + ] }, "valentinesBanner": { "title": "Love without limits!", diff --git a/src/app/i18n/locales/es.json b/src/app/i18n/locales/es.json index d2fc32040..4eeb6f068 100644 --- a/src/app/i18n/locales/es.json +++ b/src/app/i18n/locales/es.json @@ -4,19 +4,19 @@ "logOut": "Cerrar sesión" }, "featuresBanner": { - "header": "¡Ahorra un 70%!", - "title": "Prepárate para la Semana de la Privacidad de Datos", + "label": "Ahorra un 75%", + "title": "Comienza a ahorrar esta primavera", "cta": "Elige un plan", "guarantee": "Garantía de devolución de 30 días", "lastCta": "*La oferta es para cuentas gratuitas o nuevos clientes", - "features": { - "discount": "Ahorra en suscripciones mensuales y anuales", - "safeCloud": "Almacenamiento seguro en la nube", - "openSource": "Código abierto y transparente", - "endToEnd": "Transferencias cifradas de extremo a extremo", - "unauthorized": "Sin acceso no autorizado", - "offerEnds": "La oferta finaliza el 29 de febrero" - } + "features": [ + "Ahorra en todos nuestros planes", + "Almacenamiento seguro en la nube", + "Código abierto y auditado", + "Transferencias cifradas de extremo a extremo", + "Sin accesos no autorizados", + "La oferta finaliza el 18 de marzo" + ] }, "valentinesBanner": { "title": "¡Amor sin limites!", diff --git a/src/app/i18n/locales/fr.json b/src/app/i18n/locales/fr.json index f520eb3de..f7d8e10e7 100644 --- a/src/app/i18n/locales/fr.json +++ b/src/app/i18n/locales/fr.json @@ -4,19 +4,19 @@ "logOut": "Déconnexion" }, "featuresBanner": { - "header": "Économisez 70% !", - "title": "Préparez-vous pour la Semaine de la Protection des Données", + "label": "Économisez 75%", + "title": "Profitez de votre offre de printemps", "cta": "Choisissez un plan", "guarantee": "Garantie de remboursement de 30 jours", "lastCta": "*L'offre est valable pour les comptes gratuits ou les nouveaux clients", - "features": { - "discount": "Économisez sur les plans mensuels et annuels", - "safeCloud": "Stockage cloud sûr et sécurisé", - "openSource": "Open source et transparent", - "endToEnd": "Transferts chiffrés de bout en bout", - "unauthorized": "Aucun accès non autorisé", - "offerEnds": "L'offre se termine le 29 février" - } + "features": [ + "Économisez sur tous nos plans", + "Stockage cloud sûr et sécurisé", + "Open source et transparent", + "Transferts chiffrés de bout en bout", + "Aucun accès non autorisé", + "L'offre se termine le 18 mars" + ] }, "valentinesBanner": { "title": "L'amour sans limites !", diff --git a/src/app/i18n/locales/it.json b/src/app/i18n/locales/it.json index 31d287ded..54b64f9b8 100644 --- a/src/app/i18n/locales/it.json +++ b/src/app/i18n/locales/it.json @@ -9,19 +9,19 @@ "cta": "Get the deal" }, "featuresBanner": { - "header": "Risparmia il 70%!", - "title": "Preparati per la Settimana della Privacy dei Dati", + "label": "Risparmia il 75%", + "title": "Inizia la tua pulizia digitale di primavera", "cta": "Scegli un piano", "guarantee": "Garanzia di rimborso entro 30 giorni", "lastCta": "*L'offerta è valida solo per account gratuiti o nuovi clienti", - "features": { - "discount": "Risparmia su piani mensili e annuali", - "safeCloud": "Archiviazione cloud sicura e protetta", - "openSource": "Open source e trasparente", - "endToEnd": "Trasferimenti crittografati end-to-end", - "unauthorized": "Nessun accesso non autorizzato", - "offerEnds": "L'offerta termina il 29 febbraio" - } + "features": [ + "Risparmia su tutti i nostri piani", + "Archiviazione cloud sicura e protetta", + "Open source e trasparente", + "Trasferimenti crittografati end-to-end", + "Nessun accesso non autorizzato", + "L'offerta termina il 18 marzo" + ] }, "lifetimeBanner": { "label": "Cercate uno spazio sicuro per i vostri dati per tutta la vita?", diff --git a/src/app/i18n/locales/ru.json b/src/app/i18n/locales/ru.json index ed04b362d..a65073863 100644 --- a/src/app/i18n/locales/ru.json +++ b/src/app/i18n/locales/ru.json @@ -9,19 +9,19 @@ "cta": "Получить скидку" }, "featuresBanner": { - "label": "Сэкономьте 70%!", - "title": "Приготовьтесь к Неделе конфиденциальности данных", + "label": "Скидка 75%", + "title": "Получите своё весеннее предложение", "cta": "Выбрать план", - "guarantee": "30-дневная гарантия возврата денег", + "guarantee": "Гарантия возврата денег в течение 30 дней", "lastCta": "*Предложение действует только для бесплатных аккаунтов или новых клиентов", - "features": { - "discount": "Скидка на годовые и месячные планы", - "safeCloud": "Надежное и безопасное облачное хранилище", - "openSource": "Открытый исходный код и прозрачность", - "endToEnd": "Передача данных в зашифрованном виде", - "unauthorized": "Отсутствие несанкционированного доступа", - "offerEnds": "Предложение действует до 29 февраля" - } + "features": [ + "Экономьте на всех наших планах", + "Надежное и безопасное облачное хранилище", + "Открытый исходный код и прозрачность", + "Передача данных в зашифрованном виде", + "Отсутствие несанкционированного доступа", + "Предложение заканчивается 18 марта" + ] }, "lifetimeBanner": { "label": "Ищите надежное хранилище данных на всю жизнь?", diff --git a/src/app/i18n/locales/zh.json b/src/app/i18n/locales/zh.json index 66d8e96a3..137e2b783 100644 --- a/src/app/i18n/locales/zh.json +++ b/src/app/i18n/locales/zh.json @@ -4,19 +4,19 @@ "logOut": "登出" }, "featuresBanner": { - "header": "省 70%!", - "title": "为数据隐私周做好准备", + "label": "省75%", + "title": "开始您的数字春季大扫除", "cta": "选择计划", - "guarantee": "30 天内退款保证", - "lastCta": "*此优惠仅适用于免费账户或新客户", - "features": { - "discount": "在月度和年度计划上节省", - "safeCloud": "安全可靠的云存储", - "openSource": "开源和透明", - "endToEnd": "端到端加密传输", - "unauthorized": "无未经授权访问", - "offerEnds": "优惠截止日期为2月29日" - } + "guarantee": "30天退款保证", + "lastCta": "*优惠仅适用于免费帐户或新客户", + "features": [ + "在我们所有的计划上节省", + "安全可靠的云存储", + "开源和透明", + "端到端加密传输", + "没有未经授权的访问", + "优惠截至日期为3月18日" + ] }, "valentinesBanner": { "title": "爱无极限!", From 4090ee8a32629fbc6f0ca94a7ff137d8a9f3983b Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+masterprog-cmd@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:19:55 +0100 Subject: [PATCH 2/6] fix: remove unused import --- src/app/banners/BannerWrapper.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/banners/BannerWrapper.tsx b/src/app/banners/BannerWrapper.tsx index 0f08c4db8..86e8ab3f1 100644 --- a/src/app/banners/BannerWrapper.tsx +++ b/src/app/banners/BannerWrapper.tsx @@ -7,7 +7,6 @@ import { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings'; -import Banner from './Banner'; import FeaturesBanner from './FeaturesBanner'; const SHOW_BANNER_COOKIE_NAME = 'show_spring_banner'; From da4ac46043d93fbb7427484031049f4e8bf82b66 Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+masterprog-cmd@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:25:14 +0100 Subject: [PATCH 3/6] feat: use custom hook (translations) --- src/app/banners/FeaturesBanner.tsx | 16 ++++++++-------- src/app/i18n/provider/TranslationProvider.tsx | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/banners/FeaturesBanner.tsx b/src/app/banners/FeaturesBanner.tsx index 0f00682a6..3be02ed85 100644 --- a/src/app/banners/FeaturesBanner.tsx +++ b/src/app/banners/FeaturesBanner.tsx @@ -1,10 +1,10 @@ import { CheckCircle, Flower, X } from '@phosphor-icons/react'; -import { useTranslation } from 'react-i18next'; +import { useTranslationContext } from 'app/i18n/provider/TranslationProvider'; const FeaturesBanner = ({ showBanner, onClose }: { showBanner: boolean; onClose: () => void }): JSX.Element => { - const { t } = useTranslation(); + const { translate } = useTranslationContext(); - const features = t('featuresBanner.features', { returnObjects: true }) as string[]; + const features = translate('featuresBanner.features', { returnObjects: true }) as string[]; const handleOnClick = () => { window.open('https://internxt.com/pricing', '_blank', 'nofollow noreferrer'); @@ -28,10 +28,10 @@ const FeaturesBanner = ({ showBanner, onClose }: { showBanner: boolean; onClose:
-

{t('featuresBanner.label')}

+

{translate('featuresBanner.label')}

- {t('featuresBanner.title')} + {translate('featuresBanner.title')}

@@ -39,14 +39,14 @@ const FeaturesBanner = ({ showBanner, onClose }: { showBanner: boolean; onClose: onClick={handleOnClick} className="flex w-max items-center rounded-lg bg-primary px-5 py-3 text-lg font-medium text-white hover:bg-primary-dark" > - {t('featuresBanner.cta')} + {translate('featuresBanner.cta')}
-

{t('featuresBanner.guarantee')}

+

{translate('featuresBanner.guarantee')}

-

{t('featuresBanner.lastCta')}

+

{translate('featuresBanner.lastCta')}

diff --git a/src/app/i18n/provider/TranslationProvider.tsx b/src/app/i18n/provider/TranslationProvider.tsx index 573534e8c..30192e10a 100644 --- a/src/app/i18n/provider/TranslationProvider.tsx +++ b/src/app/i18n/provider/TranslationProvider.tsx @@ -2,7 +2,7 @@ import React, { createContext, useContext, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; interface TranslationContextProps { - translate: (key: string, props?: Record) => string; + translate: (key: string, props?: Record) => string | string[] | undefined; } const TranslationContext = createContext({ translate: () => '' }); From 6ee23e572f7156bf784e2131665f1531aafc74eb Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+masterprog-cmd@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:30:08 +0100 Subject: [PATCH 4/6] fix: error in translations provider --- src/app/banners/FeaturesBanner.tsx | 2 +- src/app/i18n/provider/TranslationProvider.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/banners/FeaturesBanner.tsx b/src/app/banners/FeaturesBanner.tsx index 3be02ed85..36219ab1c 100644 --- a/src/app/banners/FeaturesBanner.tsx +++ b/src/app/banners/FeaturesBanner.tsx @@ -7,7 +7,7 @@ const FeaturesBanner = ({ showBanner, onClose }: { showBanner: boolean; onClose: const features = translate('featuresBanner.features', { returnObjects: true }) as string[]; const handleOnClick = () => { - window.open('https://internxt.com/pricing', '_blank', 'nofollow noreferrer'); + window.open('https://internxt.com/pricing', '_blank', 'noopener noreferrer'); }; return ( diff --git a/src/app/i18n/provider/TranslationProvider.tsx b/src/app/i18n/provider/TranslationProvider.tsx index 30192e10a..af02d67b0 100644 --- a/src/app/i18n/provider/TranslationProvider.tsx +++ b/src/app/i18n/provider/TranslationProvider.tsx @@ -2,7 +2,7 @@ import React, { createContext, useContext, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; interface TranslationContextProps { - translate: (key: string, props?: Record) => string | string[] | undefined; + translate: (key: string, props?: Record) => string | string[] | any; } const TranslationContext = createContext({ translate: () => '' }); From 2b7b19f18aea1e39255dcbbd5925ec1d10f5ff22 Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+masterprog-cmd@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:43:55 +0100 Subject: [PATCH 5/6] feat: adding space between components --- src/app/banners/FeaturesBanner.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/banners/FeaturesBanner.tsx b/src/app/banners/FeaturesBanner.tsx index 36219ab1c..3b41523c9 100644 --- a/src/app/banners/FeaturesBanner.tsx +++ b/src/app/banners/FeaturesBanner.tsx @@ -25,7 +25,7 @@ const FeaturesBanner = ({ showBanner, onClose }: { showBanner: boolean; onClose: -
+

{translate('featuresBanner.label')}

From 7cdba8515d9e3a4ee9badd574946cee60a05d2eb Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+masterprog-cmd@users.noreply.github.com> Date: Tue, 5 Mar 2024 11:19:11 +0100 Subject: [PATCH 6/6] feat: create new function to get arrays from json --- src/app/banners/FeaturesBanner.tsx | 4 ++-- src/app/i18n/provider/TranslationProvider.tsx | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/app/banners/FeaturesBanner.tsx b/src/app/banners/FeaturesBanner.tsx index 3b41523c9..3183ce2e7 100644 --- a/src/app/banners/FeaturesBanner.tsx +++ b/src/app/banners/FeaturesBanner.tsx @@ -2,9 +2,9 @@ import { CheckCircle, Flower, X } from '@phosphor-icons/react'; import { useTranslationContext } from 'app/i18n/provider/TranslationProvider'; const FeaturesBanner = ({ showBanner, onClose }: { showBanner: boolean; onClose: () => void }): JSX.Element => { - const { translate } = useTranslationContext(); + const { translate, translateList } = useTranslationContext(); - const features = translate('featuresBanner.features', { returnObjects: true }) as string[]; + const features = translateList('featuresBanner.features'); const handleOnClick = () => { window.open('https://internxt.com/pricing', '_blank', 'noopener noreferrer'); diff --git a/src/app/i18n/provider/TranslationProvider.tsx b/src/app/i18n/provider/TranslationProvider.tsx index af02d67b0..1a91f3e1c 100644 --- a/src/app/i18n/provider/TranslationProvider.tsx +++ b/src/app/i18n/provider/TranslationProvider.tsx @@ -2,17 +2,21 @@ import React, { createContext, useContext, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; interface TranslationContextProps { - translate: (key: string, props?: Record) => string | string[] | any; + translate: (key: string, props?: Record) => string; + translateList: (key: string) => string[]; } -const TranslationContext = createContext({ translate: () => '' }); +const TranslationContext = createContext({ translate: () => '', translateList: () => [] }); interface TranslationProviderProps { children: React.ReactNode; } export const TranslationProvider: React.FC = ({ children }) => { const { t } = useTranslation(); - const value = useMemo(() => ({ translate: t }), [t]); + + const translateList = (key: string) => t(key, { returnObjects: true }) as string[]; + + const value = useMemo(() => ({ translate: t, translateList }), [t]); return {children}; };