diff --git a/services/web/app/src/Features/Project/ProjectListController.js b/services/web/app/src/Features/Project/ProjectListController.js index 5c4bb1b813..249dd6c333 100644 --- a/services/web/app/src/Features/Project/ProjectListController.js +++ b/services/web/app/src/Features/Project/ProjectListController.js @@ -364,6 +364,7 @@ async function projectListPage(req, res, next) { ) let showInrGeoBanner = false + let showBrlGeoBanner = false let recommendedCurrency if (usersBestSubscription?.type === 'free') { @@ -372,6 +373,7 @@ async function projectListPage(req, res, next) { if (countryCode === 'IN') { showInrGeoBanner = true } + showBrlGeoBanner = countryCode === 'BR' } let hasIndividualRecurlySubscription = false @@ -423,6 +425,7 @@ async function projectListPage(req, res, next) { showWritefullPromoBanner, recommendedCurrency, showInrGeoBanner, + showBrlGeoBanner, projectDashboardReact: true, // used in navbar groupSsoSetupSuccess, groupSubscriptionsPendingEnrollment: diff --git a/services/web/app/src/Features/Subscription/SubscriptionController.js b/services/web/app/src/Features/Subscription/SubscriptionController.js index 3fe2f02124..5194b5d7dd 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionController.js +++ b/services/web/app/src/Features/Subscription/SubscriptionController.js @@ -32,7 +32,6 @@ const validGroupPlanModalOptions = { async function plansPage(req, res) { const plans = SubscriptionViewModelBuilder.buildPlansList() - let currency = null const queryCurrency = req.query.currency?.toUpperCase() if (GeoIpLookup.isValidCurrencyParam(queryCurrency)) { @@ -66,7 +65,6 @@ async function plansPage(req, res) { currency: getDefault('currency', 'currency', defaultGroupPlanModalCurrency), usage: getDefault('usage', 'usage', 'enterprise'), } - const plansPageViewSegmentation = { currency: recommendedCurrency, countryCode, @@ -94,6 +92,7 @@ async function plansPage(req, res) { initialLocalizedGroupPrice: SubscriptionHelper.generateInitialLocalizedGroupPrice(currency), showInrGeoBanner: countryCode === 'IN', + showBrlGeoBanner: countryCode === 'BR', }) } @@ -210,7 +209,6 @@ async function interstitialPaymentPage(req, res) { const hasSubscription = await LimitationsManager.promises.userHasV1OrV2Subscription(user) - const showSkipLink = req.query?.skipLink === 'true' if (hasSubscription) { @@ -235,6 +233,7 @@ async function interstitialPaymentPage(req, res) { interstitialPaymentConfig, showSkipLink, showInrGeoBanner: countryCode === 'IN', + showBrlGeoBanner: countryCode === 'BR', }) } } @@ -552,7 +551,7 @@ async function _getRecommendedCurrency(req, res) { const countryCode = currencyLookup.countryCode let recommendedCurrency = currencyLookup.currencyCode - if (['BRL', 'MXN', 'COP', 'CLP', 'PEN'].includes(recommendedCurrency)) { + if (['MXN', 'COP', 'CLP', 'PEN'].includes(recommendedCurrency)) { recommendedCurrency = GeoIpLookup.DEFAULT_CURRENCY_CODE } diff --git a/services/web/app/views/project/list-react.pug b/services/web/app/views/project/list-react.pug index 07a2feea48..72cafc3721 100644 --- a/services/web/app/views/project/list-react.pug +++ b/services/web/app/views/project/list-react.pug @@ -29,6 +29,7 @@ block append meta meta(name="ol-showWritefullPromoBanner" data-type="boolean" content=showWritefullPromoBanner) meta(name="ol-groupsAndEnterpriseBannerVariant" data-type="string" content=groupsAndEnterpriseBannerVariant) meta(name="ol-showInrGeoBanner" data-type="boolean" content=showInrGeoBanner) + meta(name="ol-showBrlGeoBanner" data-type="boolean" content=showBrlGeoBanner) meta(name="ol-recommendedCurrency" data-type="string" content=recommendedCurrency) meta(name="ol-groupSubscriptionsPendingEnrollment" data-type="json" content=groupSubscriptionsPendingEnrollment) meta(name="ol-hasIndividualRecurlySubscription" data-type="boolean" content=hasIndividualRecurlySubscription) diff --git a/services/web/app/views/subscriptions/interstitial-payment.pug b/services/web/app/views/subscriptions/interstitial-payment.pug index 31a0fe9985..14070bbfc6 100644 --- a/services/web/app/views/subscriptions/interstitial-payment.pug +++ b/services/web/app/views/subscriptions/interstitial-payment.pug @@ -20,6 +20,9 @@ block content if showInrGeoBanner div.notification.notification-type-success.text-centered div.notification-content !{translate("inr_discount_offer_plans_page_banner", {flag: '๐Ÿ‡ฎ๐Ÿ‡ณ'})} + if showBrlGeoBanner + div.notification.notification-type-success.text-centered + div.notification-content !{translate("brl_discount_offer_plans_page_banner", {flag: '๐Ÿ‡ง๐Ÿ‡ท'})} .row .col-md-12 diff --git a/services/web/app/views/subscriptions/plans.pug b/services/web/app/views/subscriptions/plans.pug index 981514228a..2c417a9c1c 100644 --- a/services/web/app/views/subscriptions/plans.pug +++ b/services/web/app/views/subscriptions/plans.pug @@ -18,6 +18,9 @@ block content if showInrGeoBanner div.notification.notification-type-success.text-centered div.notification-content !{translate("inr_discount_offer_plans_page_banner", {flag: '๐Ÿ‡ฎ๐Ÿ‡ณ'})} + if showBrlGeoBanner + div.notification.notification-type-success.text-centered + div.notification-content !{translate("brl_discount_offer_plans_page_banner", {flag: '๐Ÿ‡ง๐Ÿ‡ท'})} .row .col-md-12 diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 97615f19b0..49083ee906 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -104,6 +104,8 @@ "binary_history_error": "", "blank_project": "", "blocked_filename": "", + "brl_discount_modal_info": "", + "brl_discount_modal_title": "", "browser": "", "bulk_accept_confirm": "", "bulk_reject_confirm": "", diff --git a/services/web/frontend/js/features/project-list/components/notifications/ads/brl-banner.tsx b/services/web/frontend/js/features/project-list/components/notifications/ads/brl-banner.tsx new file mode 100644 index 0000000000..b52d2d66f5 --- /dev/null +++ b/services/web/frontend/js/features/project-list/components/notifications/ads/brl-banner.tsx @@ -0,0 +1,112 @@ +import { useCallback, useEffect, useRef, useState } from 'react' +import usePersistedState from '../../../../../shared/hooks/use-persisted-state' +import * as eventTracking from '../../../../../infrastructure/event-tracking' +import { Modal, Button } from 'react-bootstrap' +import AccessibleModal from '../../../../../shared/components/accessible-modal' +import { useTranslation } from 'react-i18next' + +export default function BRLBanner() { + const { t } = useTranslation() + const [dismissedUntil, setDismissedUntil] = usePersistedState< + Date | undefined + >(`has_dismissed_brl_banner_until`) + const viewEventSent = useRef(false) + + const [showModal, setShowModal] = useState(true) + + useEffect(() => { + if (dismissedUntil && new Date(dismissedUntil) > new Date()) { + return + } + if (!viewEventSent.current) { + eventTracking.sendMB('promo-prompt', { + location: 'dashboard-modal', + name: 'geo-pricing', + page: '/project', + content: 'modal', + country: 'BR', + }) + viewEventSent.current = true + } + }, [dismissedUntil]) + + const handleClick = useCallback(() => { + eventTracking.sendMB('promo-click', { + location: 'dashboard-modal', + name: 'geo-pricing', + page: '/project', + content: 'modal', + country: 'BR', + type: 'click', + }) + + setShowModal(false) + + window.open('/user/subscription/plans') + }, []) + + const bannerDismissed = useCallback(() => { + eventTracking.sendMB('promo-dismiss', { + location: 'dashboard-modal', + name: 'geo-pricing', + page: '/project', + content: 'modal', + country: 'BR', + }) + const until = new Date() + until.setDate(until.getDate() + 30) // 30 days + setDismissedUntil(until) + }, [setDismissedUntil]) + + const handleHide = useCallback(() => { + setShowModal(false) + bannerDismissed() + }, [bannerDismissed]) + + const handleMaybeLater = useCallback(() => { + eventTracking.sendMB('promo-click', { + location: 'dashboard-modal', + name: 'geo-pricing', + page: '/project', + content: 'modal', + country: 'BR', + type: 'pause', + }) + setShowModal(false) + const until = new Date() + until.setDate(until.getDate() + 1) // 1 day + setDismissedUntil(until) + }, [setDismissedUntil]) + + if (dismissedUntil && new Date(dismissedUntil) > new Date()) { + return null + } + + return ( + + + {t('brl_discount_modal_title')} + + +

+ {t('brl_discount_modal_title')} +

+

{t('brl_discount_modal_info')}

+
+ + + + +
+ ) +} diff --git a/services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx b/services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx index 8463ca4ea5..586aae6093 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx @@ -14,6 +14,7 @@ import customLocalStorage from '../../../../infrastructure/local-storage' import { sendMB } from '../../../../infrastructure/event-tracking' import classNames from 'classnames' import { isSplitTestEnabled } from '@/utils/splitTestUtils' +import BRLBanner from './ads/brl-banner' const isChromium = () => (window.navigator as any).userAgentData?.brands?.some( @@ -42,8 +43,8 @@ function UserNotifications() { 'ol-groupSubscriptionsPendingEnrollment', [] ) - const showInrGeoBanner = getMeta('ol-showInrGeoBanner', false) + const showBrlGeoBanner = getMeta('ol-showBrlGeoBanner', false) const writefullIntegrationSplitTestEnabled = isSplitTestEnabled( 'writefull-integration' ) @@ -111,6 +112,7 @@ function UserNotifications() { {!showWritefull && !dismissedWritefull && } {showInrGeoBanner && } + {showBrlGeoBanner && } {writefullBannerVariant === 'plans-page' ? ( Great news! Weโ€™ve applied a 50% discount to premium plans on this page for our users in Brazil. Check out the new lower prices.", "browser": "Browser", "built_in": "Built-In", "bulk_accept_confirm": "Are you sure you want to accept the selected __nChanges__ changes?", diff --git a/services/web/public/img/subscriptions/blr-discount-modal.png b/services/web/public/img/subscriptions/blr-discount-modal.png new file mode 100644 index 0000000000..c3490b54b4 Binary files /dev/null and b/services/web/public/img/subscriptions/blr-discount-modal.png differ