From 81ef6c5ee8050f9567e6c83643cea52147b8d06c Mon Sep 17 00:00:00 2001 From: Corinna Hillebrand Date: Fri, 15 Nov 2024 14:55:38 +0100 Subject: [PATCH 1/9] Prepare campaign for C24_WMDE_Mobile_DE_09 https://phabricator.wikimedia.org/T379953 --- .../C24_WMDE_Mobile_DE_09/MinimisedTracker.ts | 27 +++ .../C24_WMDE_Mobile_DE_09/banner_ctrl.ts | 69 ++++++ .../C24_WMDE_Mobile_DE_09/banner_var.ts | 70 ++++++ .../components/BannerCtrl.vue | 224 ++++++++++++++++++ .../components/BannerVar.vue | 224 ++++++++++++++++++ .../components/FullPageBanner.vue | 43 ++++ .../components/MiniBanner.vue | 37 +++ .../components/MiniBannerVar.vue | 37 +++ .../components/MinimisedBanner.vue | 32 +++ .../content/BannerSlides.vue | 75 ++++++ .../content/BannerText.vue | 50 ++++ .../mobile/C24_WMDE_Mobile_DE_09/event_map.ts | 33 +++ .../C24_WMDE_Mobile_DE_09/form_items.ts | 23 ++ .../mobile/C24_WMDE_Mobile_DE_09/messages.ts | 30 +++ .../C24_WMDE_Mobile_DE_09/styles/Banner.scss | 56 +++++ .../styles/FullPageBanner.scss | 99 ++++++++ .../styles/MiniBanner.scss | 157 ++++++++++++ .../styles/MinimisedBanner.scss | 96 ++++++++ .../C24_WMDE_Mobile_DE_09/styles/styles.scss | 29 +++ campaign_info.toml | 18 +- .../components/BannerCtrl.spec.ts | 181 ++++++++++++++ .../components/BannerVar.spec.ts | 181 ++++++++++++++ 22 files changed, 1782 insertions(+), 9 deletions(-) create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/MinimisedTracker.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/banner_ctrl.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/components/FullPageBanner.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBannerVar.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/components/MinimisedBanner.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/event_map.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/form_items.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/messages.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/styles/Banner.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/styles/FullPageBanner.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/styles/MiniBanner.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/styles/MinimisedBanner.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles.scss create mode 100644 test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.spec.ts create mode 100644 test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.spec.ts diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/MinimisedTracker.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/MinimisedTracker.ts new file mode 100644 index 000000000..2e207100e --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/MinimisedTracker.ts @@ -0,0 +1,27 @@ +import hasLocalStorage from '@src/utils/hasLocalStorage'; + +/** + * This feature is to track the minimised state and load the banner + * minimised on page change. It was removed from the ticket, but + * I'm leaving it here in case it gets re-added while I'm away. + */ +export interface MinimisedTracker { + setMinimised( minimised: boolean ): void; + isMinimised(): boolean; +} + +export class LocalStorageMinimisedTracker implements MinimisedTracker { + public setMinimised( minimised: boolean ): void { + if ( !hasLocalStorage() ) { + return; + } + window.localStorage.setItem( 'fundraising.minimised', minimised ? 'true' : 'false' ); + } + + public isMinimised(): boolean { + if ( !hasLocalStorage() ) { + return false; + } + return window.localStorage.getItem( 'fundraising.minimised' ) === 'true'; + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/banner_ctrl.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_ctrl.ts new file mode 100644 index 000000000..9bd77f7f5 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_ctrl.ts @@ -0,0 +1,69 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles.scss'; + +import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; +import Banner from './components/BannerCtrl.vue'; +import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import eventMappings from './event_map'; +import messages from './messages'; +import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; +import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; +import { WindowTimer } from '@src/utils/Timer'; + +const localeFactory = new LocaleFactoryDe(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'mobile' ) ), + localCloseTracker: new LocalStorageCloseTracker() + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date: new Date(), + formatters: localeFactory.getFormatters(), + impressionCount, + translator, + urgencyMessageDaysLeft: 45 +} ); +const currencyFormatter = localeFactory.getCurrencyFormatter(); + +app.provide( 'currencyFormatter', currencyFormatter ); +app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) ); +app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { afo: '1', ap: '0' } ) ); +app.provide( 'tracker', tracker ); +app.provide( 'timer', new WindowTimer() ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts new file mode 100644 index 000000000..75b96dd94 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts @@ -0,0 +1,70 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles.scss'; + +import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; +import Banner from './components/BannerVar.vue'; +import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import eventMappings from './event_map'; +import messages from './messages'; +import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; + +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; +import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; +import { WindowTimer } from '@src/utils/Timer'; + +const localeFactory = new LocaleFactoryDe(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'mobile' ) ), + localCloseTracker: new LocalStorageCloseTracker() + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date: new Date(), + formatters: localeFactory.getFormatters(), + impressionCount, + translator, + urgencyMessageDaysLeft: 45 +} ); +const currencyFormatter = localeFactory.getCurrencyFormatter(); + +app.provide( 'currencyFormatter', currencyFormatter ); +app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) ); +app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { afo: '1', ap: '0' } ) ); +app.provide( 'tracker', tracker ); +app.provide( 'timer', new WindowTimer() ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.vue new file mode 100644 index 000000000..1191153ce --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.vue @@ -0,0 +1,224 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue new file mode 100644 index 000000000..4814078c1 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue @@ -0,0 +1,224 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/FullPageBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/FullPageBanner.vue new file mode 100644 index 000000000..d75bb5b68 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/FullPageBanner.vue @@ -0,0 +1,43 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue new file mode 100644 index 000000000..b8d3ea00a --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue @@ -0,0 +1,37 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBannerVar.vue new file mode 100644 index 000000000..7ab1e5afd --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBannerVar.vue @@ -0,0 +1,37 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/MinimisedBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MinimisedBanner.vue new file mode 100644 index 000000000..7678ce7c6 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MinimisedBanner.vue @@ -0,0 +1,32 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides.vue new file mode 100644 index 000000000..48524e525 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides.vue @@ -0,0 +1,75 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText.vue new file mode 100644 index 000000000..c0b3d6b27 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText.vue @@ -0,0 +1,50 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/event_map.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/event_map.ts new file mode 100644 index 000000000..d7a00a5dd --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/event_map.ts @@ -0,0 +1,33 @@ +import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; +import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; +import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; +import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; +import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; +import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; +import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; +import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; + +export default new Map( [ + [ CloseEvent.EVENT_NAME, mapCloseEvent ], + [ MobileMiniBannerExpandedEvent.EVENT_NAME, + ( e: MobileMiniBannerExpandedEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ], + [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], + [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], + + [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { + switch ( e.feature ) { + case 'MiniBanner': + case 'UpgradeToYearlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + default: + return new WMDESizeIssueEvent( `submit`, createViewportInfo(), 1 ); + } + } ], + [ BannerSubmitOnReturnEvent.EVENT_NAME, + ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ] +] ); diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/form_items.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/form_items.ts new file mode 100644 index 000000000..53c204d06 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/form_items.ts @@ -0,0 +1,23 @@ +import FormItemsBuilder from '@src/utils/FormItemsBuilder/FormItemsBuilder'; +import { Translator } from '@src/Translator'; +import { DonationFormItems } from '@src/utils/FormItemsBuilder/DonationFormItems'; +import { Intervals } from '@src/utils/FormItemsBuilder/fields/Intervals'; +import { PaymentMethods } from '@src/utils/FormItemsBuilder/fields/PaymentMethods'; +import { NumberFormatter } from '@src/utils/DynamicContent/formatters/NumberFormatter'; + +export function createFormItems( translations: Translator, amountFormatter: NumberFormatter ): DonationFormItems { + return new FormItemsBuilder( translations, amountFormatter ) + .setIntervals( + Intervals.ONCE, + Intervals.MONTHLY, + Intervals.YEARLY + ) + .setAmounts( 10, 15, 25, 50, 100 ) + .setPaymentMethods( + PaymentMethods.PAYPAL, + PaymentMethods.DIRECT_DEBIT, + PaymentMethods.BANK_TRANSFER, + PaymentMethods.CREDIT_CARD, + PaymentMethods.SOFORT + ).getItems(); +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/messages.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/messages.ts new file mode 100644 index 000000000..930f9b38f --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/messages.ts @@ -0,0 +1,30 @@ +import DynamicCampaignTextDe from '@src/utils/DynamicContent/messages/DynamicCampaignText.de'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyDe from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.de'; +import FooterDe from '@src/components/Footer/messages/Footer.de'; +import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/MainDonationForm.de'; +import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; + +const messages: TranslationMessages = { + ...DynamicCampaignTextDe, + ...FooterDe, + ...MainDonationFormDe, + ...UpgradeToYearlyDe, + ...SoftCloseDe, + + // custom messages here + 'use-of-funds-link': 'Was Ihre Spende bewirkt', + 'payment-bank-transfer': 'Überweisung', + 'payment-sofort': 'Sofort', + 'upgrade-to-yearly-copy': '

Jedes Jahr sind wir auf Menschen wie Sie angewiesen. Jährliche Spenden helfen uns' + + ' besonders und ermöglichen langfristige Weiterentwicklungen.

' + + '

Sie gehen kein Risiko ein: Jederzeit formlos zu sofort kündbar.

', + 'upgrade-to-yearly-no': 'Nein, ich spende einmalig {{amount}}', + 'upgrade-to-yearly-yes': 'Ja, ich spende {{amount}} jährlich', + 'campaign-day-only-n-days': 'Heute sind es nur noch {{days}} Tage bis zum Ende unserer Spendenkampagne.', + 'soft-close-prompt': 'Wikipedia später unterstützen?', + 'soft-close-button-already-donated': 'Habe schon gespendet', + 'amount-total': '' +}; + +export default messages; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/Banner.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/Banner.scss new file mode 100644 index 000000000..ef5ca15ed --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/Banner.scss @@ -0,0 +1,56 @@ +@use 'src/themes/Mikings/variables/globals'; +@use 'src/themes/Mikings/variables/fonts'; + +@keyframes hide-mini { + 0% { + opacity: 1; + } + 99% { + opacity: 0; + } + 100% { + display: none; + } +} + +.wmde-banner { + + &-full { + visibility: hidden; + opacity: 0; + transform: scale( 1.1 ); + transition: opacity 500ms globals.$banner-easing, transform 500ms globals.$banner-easing; + } + + &-wrapper { + font-size: 16px; + font-family: fonts.$ui; + box-shadow: 0 3px 0.6em rgba( 60 60 60 / 40% ); + background-color: var( --main-background ); + color: var( --main-color ); + + &--full-page { + .wmde-banner-mini { + animation: hide-mini 500ms; + } + .wmde-banner-full { + visibility: visible; + opacity: 1; + transform: scale( 1 ); + } + } + + &--soft-closing { + .wmde-banner-mini { + display: none; + } + } + } + + &--closed, + &--not-shown { + .wmde-banner-wrapper { + display: none; + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/FullPageBanner.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/FullPageBanner.scss new file mode 100644 index 000000000..266b1a19f --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/FullPageBanner.scss @@ -0,0 +1,99 @@ +@use '@src/themes/Mikings/variables/globals'; +@use '@src/themes/Mikings/variables/breakpoints'; + +.wmde-banner { + &-full { + border: 2px solid var( --full-border ); + background: var( --full-background ); + position: fixed; + top: 0; + z-index: 1000; + height: 100vh; + width: 100vw; + + &-content { + overflow-y: auto; + height: 100%; + width: 100%; + } + + p { + padding-bottom: 16px; + } + + &-close { + position: absolute; + top: 16px; + right: 16px; + height: 35px; + width: 35px; + padding: 5px; + background: var( --full-background ); + z-index: 99; + border: none; + border-radius: 50%; + + &:hover { + cursor: pointer; + } + + .close-button { + text-decoration: underline; + } + } + + &-info { + padding: 16px; + } + + &-call-to-action { + position: relative; + color: var( --full-cta-color ); + background: var( --full-cta-background ); + font-weight: bold; + height: 31px; + line-height: 31px; + text-align: center; + + &-optional-text { + display: none; + + @include breakpoints.tablet-portrait-up { + display: inline; + } + } + + &::after { + content: ''; + position: absolute; + bottom: -4px; + left: 50%; + margin-left: -4px; + width: 0; + height: 0; + border-style: solid; + border-width: 5px 4px 0; + border-color: var( --full-cta-background ) transparent transparent transparent; + } + } + + .banner-text-title { + margin-right: 30px; + } + + &-small-print { + text-align: center; + font-size: 12px; + margin-bottom: 16px; + + a { + color: var( --full-smallprint-color ); + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MiniBanner.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MiniBanner.scss new file mode 100644 index 000000000..2bd2f4059 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MiniBanner.scss @@ -0,0 +1,157 @@ +@use '@src/themes/Mikings/variables/globals'; + +$height: 288px !default; + +.wmde-banner { + &-mini { + display: flex; + flex-direction: column; + min-height: $height; + padding: 16px 0; + position: relative; + border: 2px solid var( --mini-border ); + background: var( --mini-background ); + + &-close { + position: absolute; + height: 36px; + width: 36px; + top: 11px; + right: 16px; + text-align: center; + background: var( --mini-close-background ); + padding: 10px; + z-index: 2; + + &-button { + border: none; + margin-top: auto; + float: right; + height: 16px; + line-height: 16px; + width: 16px; + background: var( --mini-close-background ); + z-index: 2; + + svg { + height: 16px; + width: 16px; + } + + &:hover { + cursor: pointer; + } + } + } + + &-headline { + height: 25px; + text-align: center; + margin: 0 16px 16px; + + &-background { + position: relative; + text-align: left; + + @media ( min-width: 400px ) { + text-align: center; + } + + /* single line above container */ + &::before { + content: ''; + display: block; + background: var( --mini-headline-line ); + width: 100%; + height: 1px; + position: absolute; + top: 50%; + z-index: 1; + } + } + + &-content { + position: relative; + display: inline-block; + font-weight: bold; + font-size: 14px; + line-height: 25px; + color: var( --mini-headline-color ); + background: var( --mini-headline-background ); + padding: 0 5px; + z-index: 2; + white-space: nowrap; + + @media ( min-width: 330px ) { + font-size: 16px; + } + + @media ( min-width: 360px ) { + font-size: 18px; + } + } + } + + &-slideshow { + display: flex; + flex-direction: column; + flex: 1 1 auto; + } + + &-button-group { + display: flex; + justify-content: center; + } + + &-button, + &-button-preselect { + width: 50%; + height: 40px; + border: none; + border-radius: 20px; + font-weight: bold; + color: var( --mini-button-color ); + margin: 0 16px; + font-size: 14px; + white-space: nowrap; + + @media ( min-width: 370px ) { + font-size: 16px; + } + } + + &-button { + background: var( --mini-button-background ); + + &:hover, + &:focus { + background: var( --mini-button-background-hover ); + } + } + + &-button-preselect { + background: var( --mini-button-alt-background ); + + &:hover, + &:focus { + background: var( --mini-button-alt-background-hover ); + } + } + + .smallprint-mini { + text-align: center; + font-size: 11px; + margin-top: 12px; + margin-bottom: -5px; + + a { + color: var( --mini-smallprint-color ); + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MinimisedBanner.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MinimisedBanner.scss new file mode 100644 index 000000000..71c9abf8d --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MinimisedBanner.scss @@ -0,0 +1,96 @@ +$transition-easing: cubic-bezier( 0.555, 0.155, 0.14, 0.945 ) !default; + +.wmde-banner { + &-minimised { + + height: 82px; + + &-inner { + flex: 1 0 auto; + display: flex; + flex-direction: column; + padding: 16px 0 18px; + position: relative; + border: 2px solid var( --mini-border ); + background: var( --mini-background ); + height: auto; + box-shadow: none; + } + + &-headline, + &-content { + padding: 0 16px; + margin-right: 26px; + } + + &-headline { + font-weight: bold; + } + + &-highlighted-text { + background: var( --minimise-text-highlight-background ); + font-weight: bold; + } + + &-close { + position: absolute; + height: 36px; + width: 36px; + top: 2px; + right: 6px; + text-align: center; + background: var( --mini-close-background ); + padding: 10px; + z-index: 2; + + &-button { + border: none; + margin-top: auto; + float: right; + height: 16px; + line-height: 16px; + width: 16px; + background: var( --mini-close-background ); + z-index: 2; + + svg { + height: 16px; + width: 16px; + } + + &:hover { + cursor: pointer; + } + } + } + + &-maximise { + height: 16px; + display: flex; + justify-content: center; + transition: height $transition-easing var( --wmde-banner-transition-duration ); + + &-tab { + height: 16px; + border: 2px solid var( --mini-border ); + border-top: none; + border-radius: 0 0 3px 3px; + box-shadow: var( --mini-box-shadow ); + } + + &-button { + border: none; + border-radius: 2px; + background: var( --mini-background ); + color: var( --minimise-color ); + position: relative; + height: 32px; + top: -18px; + cursor: pointer; + font-size: 14px; + font-weight: bold; + width: 175px; + } + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles.scss new file mode 100644 index 000000000..cb6632a99 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles.scss @@ -0,0 +1,29 @@ +@use 'src/themes/Mikings/swatches/skin_default' with ( + $upgrade-to-yearly-button-form: true, + $progress-bar: true, + $soft-close: true, + $thank-you-box: true +); +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Mikings/defaults'; +@use './Banner'; +@use './MiniBanner' with ( + $height: 288px +); +@use './FullPageBanner'; +@use 'src/themes/Mikings/Footer/Footer'; +@use 'src/themes/Mikings/ThankYouBox/ThankYouBox'; +@use 'src/themes/Mikings/Footer/SelectionInput'; +@use 'src/themes/Mikings/DonationForm/MultiStepDonation'; +@use 'src/themes/Mikings/DonationForm/Forms/UpgradeToYearlyButtonForm'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SelectCustomAmount'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Mikings/Slider/Slider' with ( + $pagination-padding: 10px, + $pagination-height: 40px +); +@use 'src/themes/Mikings/SoftClose/SoftClose'; +@use 'src/themes/Mikings/ProgressBar/ProgressBar'; diff --git a/campaign_info.toml b/campaign_info.toml index ccc6adb5d..6b302cad7 100644 --- a/campaign_info.toml +++ b/campaign_info.toml @@ -34,9 +34,9 @@ resolution = ["800x600", "1024x768", "1280x960", "1600x1200", "1920x1200", "2560 [mobile] name = "Mobile" icon = "mobile" -campaign = "C24_WMDE_Mobile_DE_08" -description = "Based on CTRL of C24_WMDE_Mobile_DE_07, VAR has different copy." -campaign_tracking = "mob-de-08-ba-241112" +campaign = "C24_WMDE_Mobile_DE_09" +description = "Based on VAR of C24_WMDE_Mobile_DE_08, VAR has 10 reasons pop-up." +campaign_tracking = "mob-de-09-ba-241118" preview_link = "/mobile/wiki/Wikipedia:Hauptseite?devbanner={{banner}}&banner=B22_WMDE_local_prototype&useskin=minerva" preview_link_darkmode = "/mobile/wiki/Wikipedia:Hauptseite?devbanner={{banner}}&banner=B22_WMDE_local_prototype&useskin=minerva&minervanightmode=1" preview_url = 'https://de.m.wikipedia.org/wiki/Wikipedia:Hauptseite?banner={{banner}}&useskin=minerva&devMode' @@ -45,14 +45,14 @@ use_of_funds_source = "MediaWiki:WMDE_Fundraising/UseOfFunds_2024_DE" # Banners of the campaign, key after "banners" can be anything [mobile.banners.ctrl] -filename = "./banners/mobile/C24_WMDE_Mobile_DE_08/banner_ctrl.ts" -pagename = "B24_WMDE_Mobile_DE_08_ctrl" -tracking = "org-mob08-241112-ctrl" +filename = "./banners/mobile/C24_WMDE_Mobile_DE_09/banner_ctrl.ts" +pagename = "B24_WMDE_Mobile_DE_09_ctrl" +tracking = "org-mob09-241118-ctrl" [mobile.banners.var] -filename = "./banners/mobile/C24_WMDE_Mobile_DE_08/banner_var.ts" -pagename = "B24_WMDE_Mobile_DE_08_var" -tracking = "org-mob08-241112-var" +filename = "./banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts" +pagename = "B24_WMDE_Mobile_DE_09_var" +tracking = "org-mob09-241118-var" [mobile.test_matrix] device = [ 'samsung_s10', 'iphone_xs_max', 'iphone_5s', 'iphone_se', "iphone_8", "iphone_12_mini", "iphone_7_plus", "iphone_11_pro_max"] diff --git a/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.spec.ts b/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.spec.ts new file mode 100644 index 000000000..1631ad80f --- /dev/null +++ b/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.spec.ts @@ -0,0 +1,181 @@ +import { afterEach, beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerCtrl.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; +import { formItems } from '@test/banners/formItems'; +import { softCloseFeatures } from '@test/features/SoftCloseMobile'; +import { useOfFundsFeatures, useOfFundsScrollFeatures } from '@test/features/UseOfFunds'; +import { miniBannerFeatures } from '@test/features/MiniBanner'; +import { donationFormFeatures } from '@test/features/forms/MainDonation_UpgradeToYearlyButton'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { fullPageBannerFeatures } from '@test/features/FullPageBanner'; +import { formActionSwitchFeatures } from '@test/features/form_action_switch/MainDonation_UpgradeToYearlyButton'; +import { Tracker } from '@src/tracking/Tracker'; +import { bannerContentAnimatedTextFeatures, bannerContentDateAndTimeFeatures } from '@test/features/BannerContent'; +import { softCloseSubmitTrackingFeatures } from '@test/features/SoftCloseSubmitTracking'; +import { Timer } from '@src/utils/Timer'; +import { TimerStub } from '@test/fixtures/TimerStub'; + +let pageScroller: PageScroller; +let tracker: Tracker; +const formModel = useFormModel(); +const translator = ( key: string ): string => key; +describe( 'BannerCtrl.vue', () => { + + let wrapper: VueWrapper; + beforeEach( () => { + resetFormModel( formModel ); + + pageScroller = { + scrollIntoView: vi.fn(), + scrollToTop: vi.fn() + }; + + tracker = { + trackEvent: vi.fn() + }; + } ); + + afterEach( () => { + wrapper.unmount(); + } ); + + const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { + // attachTo the document body to fix an issue with Vue Test Utils where + // clicking a submit button in a form does not fire the submit event + wrapper = mount( Banner, { + attachTo: document.body, + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + pageScroller, + remainingImpressions: 10, + localCloseTracker: { + getItem: () => '', + setItem: () => {} + } + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + formActions: { donateWithAddressAction: 'https://example.com/with-address', donateAnonymouslyAction: 'https://example.com/without-address' }, + currencyFormatter: new CurrencyEn(), + formItems, + tracker, + timer: timer ?? new TimerStub() + } + } + } ); + + return wrapper; + }; + + describe( 'Content', () => { + test.each( [ + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + + test.each( [ + [ 'expectShowsLiveDateAndTimeInMiniBanner' ], + [ 'expectShowsLiveDateAndTimeInFullPageBanner' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectMainDonationFormSubmitsWithAddressForDirectDebit' ], + [ 'expectUpgradeToYearlyFormSubmitsWithAddressForDirectDebit' ] + ] )( '%s', async ( testName: string ) => { + await formActionSwitchFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftCloseOnMiniBannerClose' ], + [ 'expectDoesNotShowSoftCloseOnFullBannerClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseMaybeLaterEvent' ], + [ 'expectEmitsSoftCloseAlreadyDonatedEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Soft Close Submit Tracking', () => { + test.each( [ + [ 'expectStoresMaybeLateCloseChoice' ], + [ 'expectStoresCloseCloseChoice' ], + [ 'expectStoresAlreadyDonatedCloseChoice' ], + [ 'expectEmitsBannerSubmitOnReturnEvent' ], + [ 'expectDoesNotEmitsBannerSubmitOnReturnEventWhenLocalStorageItemIsMissing' ] + ] )( '%s', async ( testName: string ) => { + await softCloseSubmitTrackingFeatures[ testName ]( getWrapper(), tracker ); + } ); + } ); + + describe( 'Use of Funds', () => { + test.each( [ + [ 'expectShowsUseOfFunds' ], + [ 'expectHidesUseOfFunds' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectScrollsToFormWhenCallToActionIsClicked' ], + [ 'expectScrollsToLinkWhenCloseIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsScrollFeatures[ testName ]( getWrapper(), pageScroller ); + } ); + } ); + + describe( 'Mini Banner', () => { + test.each( [ + [ 'expectSlideShowPlaysWhenMiniBannerBecomesVisible' ], + [ 'expectSlideShowStopsWhenFullBannerBecomesVisible' ], + [ 'expectShowsFullPageWhenCallToActionIsClicked' ], + [ 'expectEmitsBannerContentChangedEventWhenCallToActionIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await miniBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Full Page Banner', () => { + test.each( [ + [ 'expectEmitsCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await fullPageBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); +} ); diff --git a/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.spec.ts b/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.spec.ts new file mode 100644 index 000000000..756e6bbda --- /dev/null +++ b/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.spec.ts @@ -0,0 +1,181 @@ +import { afterEach, beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; +import { formItems } from '@test/banners/formItems'; +import { softCloseFeatures } from '@test/features/SoftCloseMobile'; +import { useOfFundsFeatures, useOfFundsScrollFeatures } from '@test/features/UseOfFunds'; +import { miniBannerFeatures } from '@test/features/MiniBanner'; +import { donationFormFeatures } from '@test/features/forms/MainDonation_UpgradeToYearlyButton'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { fullPageBannerFeatures } from '@test/features/FullPageBanner'; +import { formActionSwitchFeatures } from '@test/features/form_action_switch/MainDonation_UpgradeToYearlyButton'; +import { Tracker } from '@src/tracking/Tracker'; +import { bannerContentAnimatedTextFeatures, bannerContentDateAndTimeFeatures } from '@test/features/BannerContent'; +import { softCloseSubmitTrackingFeatures } from '@test/features/SoftCloseSubmitTracking'; +import { Timer } from '@src/utils/Timer'; +import { TimerStub } from '@test/fixtures/TimerStub'; + +let pageScroller: PageScroller; +let tracker: Tracker; +const formModel = useFormModel(); +const translator = ( key: string ): string => key; +describe( 'BannerVar.vue', () => { + + let wrapper: VueWrapper; + beforeEach( () => { + resetFormModel( formModel ); + + pageScroller = { + scrollIntoView: vi.fn(), + scrollToTop: vi.fn() + }; + + tracker = { + trackEvent: vi.fn() + }; + } ); + + afterEach( () => { + wrapper.unmount(); + } ); + + const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { + // attachTo the document body to fix an issue with Vue Test Utils where + // clicking a submit button in a form does not fire the submit event + wrapper = mount( Banner, { + attachTo: document.body, + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + pageScroller, + remainingImpressions: 10, + localCloseTracker: { + getItem: () => '', + setItem: () => {} + } + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + formActions: { donateWithAddressAction: 'https://example.com/with-address', donateAnonymouslyAction: 'https://example.com/without-address' }, + currencyFormatter: new CurrencyEn(), + formItems, + tracker, + timer: timer ?? new TimerStub() + } + } + } ); + + return wrapper; + }; + + describe( 'Content', () => { + test.each( [ + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + + test.each( [ + [ 'expectShowsLiveDateAndTimeInMiniBanner' ], + [ 'expectShowsLiveDateAndTimeInFullPageBanner' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectMainDonationFormSubmitsWithAddressForDirectDebit' ], + [ 'expectUpgradeToYearlyFormSubmitsWithAddressForDirectDebit' ] + ] )( '%s', async ( testName: string ) => { + await formActionSwitchFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftCloseOnMiniBannerClose' ], + [ 'expectDoesNotShowSoftCloseOnFullBannerClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseMaybeLaterEvent' ], + [ 'expectEmitsSoftCloseAlreadyDonatedEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Soft Close Submit Tracking', () => { + test.each( [ + [ 'expectStoresMaybeLateCloseChoice' ], + [ 'expectStoresCloseCloseChoice' ], + [ 'expectStoresAlreadyDonatedCloseChoice' ], + [ 'expectEmitsBannerSubmitOnReturnEvent' ], + [ 'expectDoesNotEmitsBannerSubmitOnReturnEventWhenLocalStorageItemIsMissing' ] + ] )( '%s', async ( testName: string ) => { + await softCloseSubmitTrackingFeatures[ testName ]( getWrapper(), tracker ); + } ); + } ); + + describe( 'Use of Funds', () => { + test.each( [ + [ 'expectShowsUseOfFunds' ], + [ 'expectHidesUseOfFunds' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectScrollsToFormWhenCallToActionIsClicked' ], + [ 'expectScrollsToLinkWhenCloseIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsScrollFeatures[ testName ]( getWrapper(), pageScroller ); + } ); + } ); + + describe( 'Mini Banner', () => { + test.each( [ + [ 'expectSlideShowPlaysWhenMiniBannerBecomesVisible' ], + [ 'expectSlideShowStopsWhenFullBannerBecomesVisible' ], + [ 'expectShowsFullPageWhenCallToActionIsClicked' ], + [ 'expectEmitsBannerContentChangedEventWhenCallToActionIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await miniBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Full Page Banner', () => { + test.each( [ + [ 'expectEmitsCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await fullPageBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); +} ); From 0e47b99ac38a876c5ec078b451db26e5b8bb5a6b Mon Sep 17 00:00:00 2001 From: Corinna Hillebrand Date: Fri, 15 Nov 2024 15:06:29 +0100 Subject: [PATCH 2/9] Prepare CTRL for C24_WMDE_Mobile_DE_09 - based on VAR 08 https://phabricator.wikimedia.org/T379953 --- banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts | 1 - banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts index 75b96dd94..30a5573d2 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts @@ -19,7 +19,6 @@ import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; import eventMappings from './event_map'; import messages from './messages'; import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; - import { createFormItems } from './form_items'; import { createFormActions } from '@src/createFormActions'; import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue index b8d3ea00a..7ab1e5afd 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBanner.vue @@ -8,7 +8,7 @@
- Ist Ihnen Wikipedia 10 € wert? + Wikipedia ist unverkäuflich
From ce203d0e76fc9f4cf86c730f15fb8b47ba0e6198 Mon Sep 17 00:00:00 2001 From: Corinna Hillebrand Date: Fri, 15 Nov 2024 15:08:29 +0100 Subject: [PATCH 3/9] Prepare VAR for C24_WMDE_Mobile_DE_09 - copy ctrl files --- .../C24_WMDE_Mobile_DE_09/banner_var.ts | 4 +- .../components/BannerVar.vue | 2 +- .../content/BannerSlides_var.vue | 75 +++++++++++++++++++ .../C24_WMDE_Mobile_DE_09/event_map_var.ts | 33 ++++++++ .../styles/styles_var.scss | 29 +++++++ 5 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/event_map_var.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts index 30a5573d2..257e96848 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts @@ -1,6 +1,6 @@ import { createVueApp } from '@src/createVueApp'; -import './styles/styles.scss'; +import './styles/styles_var.scss'; import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; import Banner from './components/BannerVar.vue'; @@ -16,7 +16,7 @@ import DynamicTextPlugin from '@src/DynamicTextPlugin'; import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; -import eventMappings from './event_map'; +import eventMappings from './event_map_var'; import messages from './messages'; import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; import { createFormItems } from './form_items'; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue index 4814078c1..d81bcffb1 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue @@ -113,7 +113,7 @@ import { PageScroller } from '@src/utils/PageScroller/PageScroller'; import MainDonationForm from '@src/components/DonationForm/Forms/MainDonationForm.vue'; import MultiStepDonation from '@src/components/DonationForm/MultiStepDonation.vue'; import BannerText from '../content/BannerText.vue'; -import BannerSlides from '../content/BannerSlides.vue'; +import BannerSlides from '../content/BannerSlides_var.vue'; import BannerFooter from '@src/components/Footer/BannerFooter.vue'; import KeenSlider from '@src/components/Slider/KeenSlider.vue'; import { Tracker } from '@src/tracking/Tracker'; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue new file mode 100644 index 000000000..48524e525 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue @@ -0,0 +1,75 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/event_map_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/event_map_var.ts new file mode 100644 index 000000000..d7a00a5dd --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/event_map_var.ts @@ -0,0 +1,33 @@ +import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; +import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; +import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; +import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; +import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; +import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; +import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; +import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; + +export default new Map( [ + [ CloseEvent.EVENT_NAME, mapCloseEvent ], + [ MobileMiniBannerExpandedEvent.EVENT_NAME, + ( e: MobileMiniBannerExpandedEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ], + [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], + [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], + + [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { + switch ( e.feature ) { + case 'MiniBanner': + case 'UpgradeToYearlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + default: + return new WMDESizeIssueEvent( `submit`, createViewportInfo(), 1 ); + } + } ], + [ BannerSubmitOnReturnEvent.EVENT_NAME, + ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ] +] ); diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss new file mode 100644 index 000000000..cb6632a99 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss @@ -0,0 +1,29 @@ +@use 'src/themes/Mikings/swatches/skin_default' with ( + $upgrade-to-yearly-button-form: true, + $progress-bar: true, + $soft-close: true, + $thank-you-box: true +); +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Mikings/defaults'; +@use './Banner'; +@use './MiniBanner' with ( + $height: 288px +); +@use './FullPageBanner'; +@use 'src/themes/Mikings/Footer/Footer'; +@use 'src/themes/Mikings/ThankYouBox/ThankYouBox'; +@use 'src/themes/Mikings/Footer/SelectionInput'; +@use 'src/themes/Mikings/DonationForm/MultiStepDonation'; +@use 'src/themes/Mikings/DonationForm/Forms/UpgradeToYearlyButtonForm'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SelectCustomAmount'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Mikings/Slider/Slider' with ( + $pagination-padding: 10px, + $pagination-height: 40px +); +@use 'src/themes/Mikings/SoftClose/SoftClose'; +@use 'src/themes/Mikings/ProgressBar/ProgressBar'; From bdb72450f6a5b36be60c27ee5c20fea1dd9b4d62 Mon Sep 17 00:00:00 2001 From: Corinna Hillebrand Date: Fri, 15 Nov 2024 15:34:04 +0100 Subject: [PATCH 4/9] Implement VAR for C24_WMDE_Mobile_DE_09 - var uses 10 reasons popup - tracks shown, cta-click and accordion item clicks - make minibanners the same size - remove old MinimisedTracker (leftover) - add tests for tracking https://phabricator.wikimedia.org/T379953 --- .../C24_WMDE_Mobile_DE_09/MinimisedTracker.ts | 27 --- .../C24_WMDE_Mobile_DE_09/banner_var.ts | 2 +- .../components/BannerVar.vue | 51 +++++- .../components/MiniBannerVar.vue | 37 ---- .../content/BannerSlides_var.vue | 21 +++ .../content/BannerText_var.vue | 61 +++++++ .../C24_WMDE_Mobile_DE_09/event_map_var.ts | 11 +- .../C24_WMDE_Mobile_DE_09/messages_var.ts | 32 ++++ .../styles/MiniBanner_var.scss | 161 ++++++++++++++++++ .../C24_WMDE_Mobile_DE_09/styles/styles.scss | 2 +- .../styles/styles_var.scss | 6 +- .../ReasonsToDonate/ReasonsToDonate.vue | 8 +- .../messages/ReasonsToDonate.de.ts | 20 +-- .../styles/ReasonsToDonate.scss | 2 +- .../events/ReasonsToDonateCTAClickedEvent.ts | 4 - .../events/ReasonsToDonateItemClickedEvent.ts | 3 +- .../events/ReasonsToDonateShownEvent.ts | 4 - .../components/BannerVar.spec.ts | 30 +++- .../ReasonsToDonate/ReasonsToDonate.spec.ts | 4 +- test/features/ReasonsToDonate.ts | 58 +++++++ 20 files changed, 439 insertions(+), 105 deletions(-) delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/MinimisedTracker.ts delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBannerVar.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText_var.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/messages_var.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_09/styles/MiniBanner_var.scss create mode 100644 test/features/ReasonsToDonate.ts diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/MinimisedTracker.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/MinimisedTracker.ts deleted file mode 100644 index 2e207100e..000000000 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/MinimisedTracker.ts +++ /dev/null @@ -1,27 +0,0 @@ -import hasLocalStorage from '@src/utils/hasLocalStorage'; - -/** - * This feature is to track the minimised state and load the banner - * minimised on page change. It was removed from the ticket, but - * I'm leaving it here in case it gets re-added while I'm away. - */ -export interface MinimisedTracker { - setMinimised( minimised: boolean ): void; - isMinimised(): boolean; -} - -export class LocalStorageMinimisedTracker implements MinimisedTracker { - public setMinimised( minimised: boolean ): void { - if ( !hasLocalStorage() ) { - return; - } - window.localStorage.setItem( 'fundraising.minimised', minimised ? 'true' : 'false' ); - } - - public isMinimised(): boolean { - if ( !hasLocalStorage() ) { - return false; - } - return window.localStorage.getItem( 'fundraising.minimised' ) === 'true'; - } -} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts index 257e96848..37b018974 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/banner_var.ts @@ -17,7 +17,7 @@ import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; import eventMappings from './event_map_var'; -import messages from './messages'; +import messages from './messages_var'; import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; import { createFormItems } from './form_items'; import { createFormActions } from '@src/createFormActions'; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue index d81bcffb1..a93181a2a 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue @@ -9,7 +9,11 @@ @@ -21,7 +25,10 @@ @close="() => onClose( 'FullPageBanner', CloseChoices.Hide )" > + + @@ -105,14 +119,14 @@ import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; import { computed, inject, ref, watch } from 'vue'; import FullPageBanner from './FullPageBanner.vue'; -import MiniBanner from './MiniBannerVar.vue'; +import MiniBanner from './MiniBanner.vue'; import FundsModal from '@src/components/UseOfFunds/FundsModal.vue'; import { UseOfFundsContent as useOfFundsContentInterface } from '@src/domain/UseOfFunds/UseOfFundsContent'; import { UseOfFundsCloseSources } from '@src/components/UseOfFunds/UseOfFundsCloseSources'; import { PageScroller } from '@src/utils/PageScroller/PageScroller'; import MainDonationForm from '@src/components/DonationForm/Forms/MainDonationForm.vue'; import MultiStepDonation from '@src/components/DonationForm/MultiStepDonation.vue'; -import BannerText from '../content/BannerText.vue'; +import BannerText from '../content/BannerText_var.vue'; import BannerSlides from '../content/BannerSlides_var.vue'; import BannerFooter from '@src/components/Footer/BannerFooter.vue'; import KeenSlider from '@src/components/Slider/KeenSlider.vue'; @@ -136,6 +150,10 @@ import ProgressBar from '@src/components/ProgressBar/ProgressBar.vue'; import { LocalCloseTracker } from '@src/utils/LocalCloseTracker'; import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; import SoftClose from '@src/components/SoftClose/SoftClose.vue'; +import ReasonsToDonate from '@src/components/ReasonsToDonate/ReasonsToDonate.vue'; +import { ReasonsToDonateCTAClickedEvent } from '@src/tracking/events/ReasonsToDonateCTAClickedEvent'; +import { ReasonsToDonateShownEvent } from '@src/tracking/events/ReasonsToDonateShownEvent'; +import { ReasonsToDonateItemClickedEvent } from '@src/tracking/events/ReasonsToDonateItemClickedEvent'; enum ContentStates { Mini = 'wmde-banner-wrapper--mini', @@ -157,11 +175,12 @@ interface Props { } const props = defineProps(); -const emit = defineEmits( [ 'bannerClosed', 'bannerContentChanged' ] ); +const emit = defineEmits( [ 'bannerClosed', 'bannerContentChanged', 'reasonsToDonate' ] ); const tracker = inject( 'tracker' ); const isFundsModalVisible = ref( false ); +const isReasonsToDonateVisible = ref( false ); const slideShowStopped = ref( false ); const slideshowShouldPlay = computed( () => props.bannerState === BannerStates.Visible && !slideShowStopped.value ); const contentState = ref( ContentStates.Mini ); @@ -221,4 +240,26 @@ const onHideFundsModal = ( payload: { source: UseOfFundsCloseSources } ): void = isFundsModalVisible.value = false; }; +const onShowReasonsToDonate = (): void => { + isReasonsToDonateVisible.value = true; + tracker.trackEvent( new ReasonsToDonateShownEvent() ); +}; + +const onReasonsToDonateAccordionItemClicked = ( payload: { itemNumber: string } ): void => { + tracker.trackEvent( new ReasonsToDonateItemClickedEvent( payload.itemNumber ) ); +}; + +const onReasonsToDonateCallToActionClicked = (): void => { + tracker.trackEvent( new ReasonsToDonateCTAClickedEvent() ); + + slideShowStopped.value = true; + contentState.value = ContentStates.FullPage; + + props.pageScroller.scrollIntoView( '.wmde-banner-form' ); + isReasonsToDonateVisible.value = false; +}; +const onHideReasonsToDonate = (): void => { + isReasonsToDonateVisible.value = false; +}; + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBannerVar.vue deleted file mode 100644 index 7ab1e5afd..000000000 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/components/MiniBannerVar.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue index 48524e525..6d8f1a4e2 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue @@ -3,6 +3,16 @@

Unser Spendenziel: {{ goalDonationSum }} Millionen €

+

Falls Sie zögern, + + hier sind 10 gute Gründe + + für eine Spende.

@@ -32,6 +42,16 @@

Dann entscheiden Sie sich, eine der seltenen Ausnahmen zu sein, und geben Sie etwas zurück. + Falls Sie zögern, + + hier sind 10 gute Gründe + + für eine Spende. Vielen Dank!

@@ -52,6 +72,7 @@ interface Props { } const props = defineProps(); +defineEmits( [ 'showReasonsToDonate' ] ); const { currentDayName, diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText_var.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText_var.vue new file mode 100644 index 000000000..a5956142e --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText_var.vue @@ -0,0 +1,61 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/event_map_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/event_map_var.ts index d7a00a5dd..994c1e94a 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/event_map_var.ts +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/event_map_var.ts @@ -11,6 +11,9 @@ import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; +import { ReasonsToDonateShownEvent } from '@src/tracking/events/ReasonsToDonateShownEvent'; +import { ReasonsToDonateItemClickedEvent } from '@src/tracking/events/ReasonsToDonateItemClickedEvent'; +import { ReasonsToDonateCTAClickedEvent } from '@src/tracking/events/ReasonsToDonateCTAClickedEvent'; export default new Map( [ [ CloseEvent.EVENT_NAME, mapCloseEvent ], @@ -29,5 +32,11 @@ export default new Map( [ } } ], [ BannerSubmitOnReturnEvent.EVENT_NAME, - ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ] + ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ], + + [ ReasonsToDonateShownEvent.EVENT_NAME, ( e: ReasonsToDonateShownEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ], + [ ReasonsToDonateItemClickedEvent.EVENT_NAME, ( e: ReasonsToDonateItemClickedEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) + ], + [ ReasonsToDonateCTAClickedEvent.EVENT_NAME, ( e: ReasonsToDonateCTAClickedEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ] ] ); diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/messages_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_09/messages_var.ts new file mode 100644 index 000000000..e88a1650a --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/messages_var.ts @@ -0,0 +1,32 @@ +import DynamicCampaignTextDe from '@src/utils/DynamicContent/messages/DynamicCampaignText.de'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyDe from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.de'; +import FooterDe from '@src/components/Footer/messages/Footer.de'; +import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/MainDonationForm.de'; +import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; +import ReasonsToDonate from '@src/components/ReasonsToDonate/messages/ReasonsToDonate.de'; + +const messages: TranslationMessages = { + ...DynamicCampaignTextDe, + ...FooterDe, + ...MainDonationFormDe, + ...UpgradeToYearlyDe, + ...SoftCloseDe, + ...ReasonsToDonate, + + // custom messages here + 'use-of-funds-link': 'Was Ihre Spende bewirkt', + 'payment-bank-transfer': 'Überweisung', + 'payment-sofort': 'Sofort', + 'upgrade-to-yearly-copy': '

Jedes Jahr sind wir auf Menschen wie Sie angewiesen. Jährliche Spenden helfen uns' + + ' besonders und ermöglichen langfristige Weiterentwicklungen.

' + + '

Sie gehen kein Risiko ein: Jederzeit formlos zu sofort kündbar.

', + 'upgrade-to-yearly-no': 'Nein, ich spende einmalig {{amount}}', + 'upgrade-to-yearly-yes': 'Ja, ich spende {{amount}} jährlich', + 'campaign-day-only-n-days': 'Heute sind es nur noch {{days}} Tage bis zum Ende unserer Spendenkampagne.', + 'soft-close-prompt': 'Wikipedia später unterstützen?', + 'soft-close-button-already-donated': 'Habe schon gespendet', + 'amount-total': '' +}; + +export default messages; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MiniBanner_var.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MiniBanner_var.scss new file mode 100644 index 000000000..aafadbf3c --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/MiniBanner_var.scss @@ -0,0 +1,161 @@ +@use '@src/themes/Mikings/variables/globals'; + +$height: 288px !default; + +.wmde-banner { + &-mini { + display: flex; + flex-direction: column; + min-height: $height; + padding: 16px 0; + position: relative; + border: 2px solid var( --mini-border ); + background: var( --mini-background ); + + &-close { + position: absolute; + height: 36px; + width: 36px; + top: 11px; + right: 16px; + text-align: center; + background: var( --mini-close-background ); + padding: 10px; + z-index: 2; + + &-button { + border: none; + margin-top: auto; + float: right; + height: 16px; + line-height: 16px; + width: 16px; + background: var( --mini-close-background ); + z-index: 2; + + svg { + height: 16px; + width: 16px; + } + + &:hover { + cursor: pointer; + } + } + } + + &-headline { + height: 25px; + text-align: center; + margin: 0 16px 16px; + + &-background { + position: relative; + text-align: left; + + @media ( min-width: 400px ) { + text-align: center; + } + + /* single line above container */ + &::before { + content: ''; + display: block; + background: var( --mini-headline-line ); + width: 100%; + height: 1px; + position: absolute; + top: 50%; + z-index: 1; + } + } + + &-content { + position: relative; + display: inline-block; + font-weight: bold; + font-size: 14px; + line-height: 25px; + color: var( --mini-headline-color ); + background: var( --mini-headline-background ); + padding: 0 5px; + z-index: 2; + white-space: nowrap; + + @media ( min-width: 330px ) { + font-size: 16px; + } + + @media ( min-width: 360px ) { + font-size: 18px; + } + } + } + + &-slideshow { + display: flex; + flex-direction: column; + flex: 1 1 auto; + } + + &-button-group { + display: flex; + justify-content: center; + } + + &-button, + &-button-preselect { + width: 50%; + height: 40px; + border: none; + border-radius: 20px; + font-weight: bold; + color: var( --mini-button-color ); + margin: 0 16px; + font-size: 14px; + white-space: nowrap; + + @media ( min-width: 370px ) { + font-size: 16px; + } + } + + &-button { + background: var( --mini-button-background ); + + &:hover, + &:focus { + background: var( --mini-button-background-hover ); + } + } + + &-button-preselect { + background: var( --mini-button-alt-background ); + + &:hover, + &:focus { + background: var( --mini-button-alt-background-hover ); + } + } + + .smallprint-mini { + text-align: center; + font-size: 11px; + margin-top: 12px; + margin-bottom: -5px; + + a { + color: var( --mini-smallprint-color ); + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + + .wmde-banner-slide-reasons-to-donate-sentence { + margin-bottom: 0; + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles.scss index cb6632a99..f6b7092a4 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles.scss +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles.scss @@ -10,7 +10,7 @@ @use 'src/themes/Mikings/defaults'; @use './Banner'; @use './MiniBanner' with ( - $height: 288px + $height: 306px ); @use './FullPageBanner'; @use 'src/themes/Mikings/Footer/Footer'; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss index cb6632a99..d68714006 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss @@ -9,8 +9,8 @@ @use 'src/themes/UseOfFunds/UseOfFunds'; @use 'src/themes/Mikings/defaults'; @use './Banner'; -@use './MiniBanner' with ( - $height: 288px +@use './MiniBanner_var' with ( + $height: 306px ); @use './FullPageBanner'; @use 'src/themes/Mikings/Footer/Footer'; @@ -27,3 +27,5 @@ ); @use 'src/themes/Mikings/SoftClose/SoftClose'; @use 'src/themes/Mikings/ProgressBar/ProgressBar'; +@use 'src/components/ReasonsToDonate/styles/swatches/skin_default' as reasons-default; +@use 'src/components/ReasonsToDonate/styles/ReasonsToDonate'; diff --git a/src/components/ReasonsToDonate/ReasonsToDonate.vue b/src/components/ReasonsToDonate/ReasonsToDonate.vue index 37827dbc7..9994eb9fb 100644 --- a/src/components/ReasonsToDonate/ReasonsToDonate.vue +++ b/src/components/ReasonsToDonate/ReasonsToDonate.vue @@ -14,7 +14,7 @@ class="wmde-banner-10-reasons-accordion-title" tabindex="0" :class="$translate( `reasons-${index}-class` )" - @click="$emit( 'accordionItemClicked', index.toString() )" + @click="$emit( 'accordionItemClicked', { itemNumber: index.toString() } )" > {{ index }}.{{ $translate( `reasons-${index}-title` ) }} @@ -41,7 +41,7 @@ diff --git a/src/components/ReasonsToDonate/messages/ReasonsToDonate.de.ts b/src/components/ReasonsToDonate/messages/ReasonsToDonate.de.ts index 174211cda..fa85511dd 100644 --- a/src/components/ReasonsToDonate/messages/ReasonsToDonate.de.ts +++ b/src/components/ReasonsToDonate/messages/ReasonsToDonate.de.ts @@ -3,7 +3,7 @@ import { TranslationMessages } from '@src/Translator'; const translations: TranslationMessages = { 'reasons-title': '10 Gründe, warum Sie für Wikipedia spenden sollten:', - 'reasons-1-title': 'Etwas zurückgeben.', + 'reasons-1-title': 'Etwas zurückgeben', 'reasons-1-content': 'Das kostenlose Wissen in Wikipedia hilft Ihnen regelmäßig weiter? Mit einer Spende geben Sie' + ' etwas zurück – und helfen uns damit sehr wirkungsvoll. Denn wir haben Kosten wie jede andere Top-Website der Welt.', 'reasons-1-class': 'reasons-giving-back', @@ -13,49 +13,49 @@ const translations: TranslationMessages = { ' Denn dieses gigantische Wissensprojekt entsteht nur dank dieser unermüdlichen, ehrenamtlichen Arbeit.', 'reasons-2-class': 'reasons-giving-back', - 'reasons-3-title': 'In (Ihr) Wissen investieren.', + 'reasons-3-title': 'In (Ihr) Wissen investieren', 'reasons-3-content': 'Ihre Spende stellt sicher, dass Wikipedia auch in Zukunft wachsen und gedeihen kann. Und Sie damit' + ' weiterhin 24/7 auf kostenloses und fundiertes Wissen zugreifen können.', 'reasons-3-class': 'reasons-giving-back', - 'reasons-4-title': 'Unabhängigkeit sichern.', + 'reasons-4-title': 'Unabhängigkeit sichern', 'reasons-4-content': 'Wikipedia ist und bleibt unverkäuflich! Sie wird niemals Konzernen, Milliardären oder Regierungen' + ' gehören. Ihre Spende sichert die finanzielle Unabhängigkeit der Wikipedia. So bleiben ihre Inhalte neutral und vertrauenswürdig. ', 'reasons-4-class': 'reasons-knowledge', - 'reasons-5-title': 'Freien Zugang zu Wissen ermöglichen.', + 'reasons-5-title': 'Freien Zugang zu Wissen ermöglichen', 'reasons-5-content': 'Ihre Spende ermöglicht allen Menschen weltweit kostenfreien Zugang zu zuverlässigem, vertrauenswürdigem' + ' Wissen – unabhängig von Geld, Status und Herkunft.', 'reasons-5-class': 'reasons-knowledge', - 'reasons-6-title': 'Den Fels in der Brandung stärken.', + 'reasons-6-title': 'Den Fels in der Brandung stärken', 'reasons-6-content': 'Fake News, Manipulation, Desinformation und Zensur verbreiten sich rasant. Ihre Spende ermöglicht unsere' + ' Arbeit an technischen Lösungen zur Verbesserung der “Abwehrkräfte”, damit Wikipedia auch in Zukunft mit neutralem und gesichertem Wissen Orientierung gibt.', 'reasons-6-class': 'reasons-knowledge', - 'reasons-7-title': 'Wissen bewahren.', + 'reasons-7-title': 'Wissen bewahren', 'reasons-7-content': 'Wikipedia & Co. sichern Wissen in Form von Text, Bildern, Filmen und Daten im digitalen Raum. Ihre Spende' + ' trägt dazu bei, dass dieses kulturelle Erbe auch in Zukunft erhalten und für alle zugänglich ist.', 'reasons-7-class': 'reasons-knowledge', - 'reasons-8-title': 'Die Freiwilligen unterstützen.', + 'reasons-8-title': 'Die Freiwilligen unterstützen', 'reasons-8-content': 'Wir fördern die unermüdliche Arbeit der Freiwilligen für Wikipedia mit vielen Projekten und Aktivitäten. Ihre' + ' Spende hilft uns, diese Arbeit bestmöglich zu unterstützen, damit sich Wikipedia weiterentwickelt.', 'reasons-8-class': 'reasons-technical', - 'reasons-9-title': 'Das technische Fundament finanzieren.', + 'reasons-9-title': 'Das technische Fundament finanzieren', 'reasons-9-content': 'Der technische Betrieb der Wikimedia-Projekte verursacht hohe laufende Kosten. Ihre Spende hilft' + ' sicherzustellen, dass Wikipedia überall, jederzeit und schnell erreichbar ist sowie die höchsten Sicherheitsstandards erfüllt.', 'reasons-9-class': 'reasons-technical', - 'reasons-10-title': 'Technische Innovationen ermöglichen.', + 'reasons-10-title': 'Technische Innovationen ermöglichen', 'reasons-10-content': 'Ihre Spende ermöglicht technische Verbesserungen, damit die Nutzung von Wikipedia noch einfacher und' + ' vielfältiger wird. Zudem erleichtern wir durch ständige Optimierung der Software, dass die Freiwilligen die besten Bedingungen für ihre Arbeit vorfinden.', 'reasons-10-class': 'reasons-technical', 'reasons-final-content': 'Überzeugt? Ganz gleich, ob Sie „Ihre“ Wikipedia unterstützen, die wichtige Rolle der' + ' Wikipedia für die ganze Gesellschaft stärken oder einfach nur Danke sagen wollen –', - 'reasons-final-content-highlighted': 'Ihre Spende, ganz gleich, ob 5 € oder 50 €, ist immer ein wichtiger Beitrag.', + 'reasons-final-content-highlighted': 'Jede Spende, ob 5 € oder 50 €, ist immer ein wichtiger Beitrag.', 'reasons-cta': 'Jetzt spenden' }; diff --git a/src/components/ReasonsToDonate/styles/ReasonsToDonate.scss b/src/components/ReasonsToDonate/styles/ReasonsToDonate.scss index 3666a269f..3311d6834 100644 --- a/src/components/ReasonsToDonate/styles/ReasonsToDonate.scss +++ b/src/components/ReasonsToDonate/styles/ReasonsToDonate.scss @@ -169,7 +169,7 @@ } &-accordion-content { - font-size: 14px; + font-size: 16px; padding: 0 20px 14px 60px; } diff --git a/src/tracking/events/ReasonsToDonateCTAClickedEvent.ts b/src/tracking/events/ReasonsToDonateCTAClickedEvent.ts index e8f904855..5f41421e1 100644 --- a/src/tracking/events/ReasonsToDonateCTAClickedEvent.ts +++ b/src/tracking/events/ReasonsToDonateCTAClickedEvent.ts @@ -7,8 +7,4 @@ export class ReasonsToDonateCTAClickedEvent implements TrackingEvent { public readonly customData: void; public readonly feature: TrackingFeatureName; public readonly userChoice: string = ''; - - public constructor( feature: TrackingFeatureName ) { - this.feature = feature; - } } diff --git a/src/tracking/events/ReasonsToDonateItemClickedEvent.ts b/src/tracking/events/ReasonsToDonateItemClickedEvent.ts index efcbcc65d..cd50d8af2 100644 --- a/src/tracking/events/ReasonsToDonateItemClickedEvent.ts +++ b/src/tracking/events/ReasonsToDonateItemClickedEvent.ts @@ -8,8 +8,7 @@ export class ReasonsToDonateItemClickedEvent implements TrackingEvent { public readonly feature: TrackingFeatureName; public readonly userChoice: string; - public constructor( feature: TrackingFeatureName, userChoice: string ) { - this.feature = feature; + public constructor( userChoice: string ) { this.userChoice = userChoice; } } diff --git a/src/tracking/events/ReasonsToDonateShownEvent.ts b/src/tracking/events/ReasonsToDonateShownEvent.ts index 0e571f519..71e66a662 100644 --- a/src/tracking/events/ReasonsToDonateShownEvent.ts +++ b/src/tracking/events/ReasonsToDonateShownEvent.ts @@ -7,8 +7,4 @@ export class ReasonsToDonateShownEvent implements TrackingEvent { public readonly customData: void; public readonly feature: TrackingFeatureName; public readonly userChoice: string = ''; - - public constructor( feature: TrackingFeatureName ) { - this.feature = feature; - } } diff --git a/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.spec.ts b/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.spec.ts index 756e6bbda..ec83a0e5a 100644 --- a/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.spec.ts +++ b/test/banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.spec.ts @@ -1,4 +1,4 @@ -import { afterEach, beforeEach, describe, test, vi } from 'vitest'; +import { afterEach, beforeEach, describe, Mock, test, vi } from 'vitest'; import { mount, VueWrapper } from '@vue/test-utils'; import Banner from '@banners/mobile/C24_WMDE_Mobile_DE_09/components/BannerVar.vue'; import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; @@ -21,12 +21,15 @@ import { bannerContentAnimatedTextFeatures, bannerContentDateAndTimeFeatures } f import { softCloseSubmitTrackingFeatures } from '@test/features/SoftCloseSubmitTracking'; import { Timer } from '@src/utils/Timer'; import { TimerStub } from '@test/fixtures/TimerStub'; +import { useReasonsToDonateFeatures, useReasonsToDonateScrollFeatures } from '@test/features/ReasonsToDonate'; let pageScroller: PageScroller; let tracker: Tracker; const formModel = useFormModel(); const translator = ( key: string ): string => key; describe( 'BannerVar.vue', () => { + let showCallback: Mock; + let closeCallback: Mock; let wrapper: VueWrapper; beforeEach( () => { @@ -40,6 +43,12 @@ describe( 'BannerVar.vue', () => { tracker = { trackEvent: vi.fn() }; + + // for the reasonsToDonate feature + showCallback = vi.fn(); + closeCallback = vi.fn(); + HTMLDialogElement.prototype.showModal = showCallback; + HTMLDialogElement.prototype.close = closeCallback; } ); afterEach( () => { @@ -71,7 +80,7 @@ describe( 'BannerVar.vue', () => { formActions: { donateWithAddressAction: 'https://example.com/with-address', donateAnonymouslyAction: 'https://example.com/without-address' }, currencyFormatter: new CurrencyEn(), formItems, - tracker, + tracker: tracker, timer: timer ?? new TimerStub() } } @@ -160,6 +169,23 @@ describe( 'BannerVar.vue', () => { } ); } ); + describe( 'Reasons to Donate', () => { + test.each( [ + [ 'expectContainsReasonsToDonateDialogue' ], + [ 'expectTracksReasonsToDonateShownEvent' ], + [ 'expectTracksReasonsToDonateCTAClickedEvent' ], + [ 'expectTracksReasonsToDonateItemClickedEvent' ] + ] )( '%s', async ( testName: string ) => { + await useReasonsToDonateFeatures[ testName ]( getWrapper(), tracker ); + } ); + + test.each( [ + [ 'expectScrollsToFormWhenCallToActionIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await useReasonsToDonateScrollFeatures[ testName ]( getWrapper(), pageScroller ); + } ); + } ); + describe( 'Mini Banner', () => { test.each( [ [ 'expectSlideShowPlaysWhenMiniBannerBecomesVisible' ], diff --git a/test/components/ReasonsToDonate/ReasonsToDonate.spec.ts b/test/components/ReasonsToDonate/ReasonsToDonate.spec.ts index eb5df1a92..bc16e841c 100644 --- a/test/components/ReasonsToDonate/ReasonsToDonate.spec.ts +++ b/test/components/ReasonsToDonate/ReasonsToDonate.spec.ts @@ -59,8 +59,8 @@ describe( 'ReasonsToDonate.vue', () => { await wrapper.find( '.wmde-banner-10-reasons-accordion-item:nth-child(8) .wmde-banner-10-reasons-accordion-title' ).trigger( 'click' ); expect( wrapper.emitted( 'accordionItemClicked' ).length ).toStrictEqual( 2 ); - expect( wrapper.emitted( 'accordionItemClicked' )[ 0 ][ 0 ] ).toStrictEqual( '1' ); - expect( wrapper.emitted( 'accordionItemClicked' )[ 1 ][ 0 ] ).toStrictEqual( '8' ); + expect( wrapper.emitted( 'accordionItemClicked' )[ 0 ][ 0 ] ).toStrictEqual( { itemNumber: '1' } ); + expect( wrapper.emitted( 'accordionItemClicked' )[ 1 ][ 0 ] ).toStrictEqual( { itemNumber: '8' } ); await wrapper.find( '.wmde-banner-10-reasons-cta button' ).trigger( 'click' ); expect( wrapper.emitted( 'callToActionClicked' ).length ).toStrictEqual( 1 ); diff --git a/test/features/ReasonsToDonate.ts b/test/features/ReasonsToDonate.ts new file mode 100644 index 000000000..ca9593977 --- /dev/null +++ b/test/features/ReasonsToDonate.ts @@ -0,0 +1,58 @@ +import { VueWrapper } from '@vue/test-utils'; +import { expect } from 'vitest'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; +import { Tracker } from '@src/tracking/Tracker'; +import { ReasonsToDonateShownEvent } from '@src/tracking/events/ReasonsToDonateShownEvent'; +import { ReasonsToDonateCTAClickedEvent } from '@src/tracking/events/ReasonsToDonateCTAClickedEvent'; +import { ReasonsToDonateItemClickedEvent } from '@src/tracking/events/ReasonsToDonateItemClickedEvent'; +import ReasonsToDonate from '@src/components/ReasonsToDonate/ReasonsToDonate.vue'; + +const expectContainsReasonsToDonateDialogue = async ( wrapper: VueWrapper ): Promise => { + expect( wrapper.findComponent( ReasonsToDonate ).exists() ).toBeTruthy(); +}; + +const expectScrollsToFormWhenCallToActionIsClicked = async ( wrapper: VueWrapper, pageScroller: PageScroller ): Promise => { + await wrapper.find( '.wmde-banner-reasons-to-donate-link' ).trigger( 'click' ); + await wrapper.find( '.wmde-banner-10-reasons-cta button' ).trigger( 'click' ); + + expect( pageScroller.scrollIntoView ).toHaveBeenCalledOnce(); + expect( pageScroller.scrollIntoView ).toHaveBeenCalledWith( '.wmde-banner-form' ); +}; + +const expectTracksReasonsToDonateShownEvent = async ( wrapper: VueWrapper, tracker: Tracker ): Promise => { + + await wrapper.find( '.wmde-banner-reasons-to-donate-link' ).trigger( 'click' ); + + expect( tracker.trackEvent ).toHaveBeenCalledOnce(); + expect( tracker.trackEvent ).toHaveBeenCalledWith( new ReasonsToDonateShownEvent() ); +}; + +const expectTracksReasonsToDonateCTAClickedEvent = async ( wrapper: VueWrapper, tracker: Tracker ): Promise => { + await wrapper.find( '.wmde-banner-reasons-to-donate-link' ).trigger( 'click' ); + + await wrapper.find( '.wmde-banner-10-reasons-cta button' ).trigger( 'click' ); + + expect( tracker.trackEvent ).toHaveBeenCalledTimes( 2 ); + expect( tracker.trackEvent ).toBeCalledWith( new ReasonsToDonateCTAClickedEvent() ); +}; + +const expectTracksReasonsToDonateItemClickedEvent = async ( wrapper: VueWrapper, tracker: Tracker ): Promise => { + await wrapper.find( '.wmde-banner-reasons-to-donate-link' ).trigger( 'click' ); + + const itemNumber = '5'; + await wrapper.find( `.wmde-banner-10-reasons-accordion-item:nth-child(${itemNumber}) .wmde-banner-10-reasons-accordion-title` ).trigger( 'click' ); + + expect( tracker.trackEvent ).toHaveBeenCalledWith( new ReasonsToDonateItemClickedEvent( itemNumber ) ); +}; + +export const useReasonsToDonateFeatures: Record, tracker: Tracker ) => Promise> = { + expectContainsReasonsToDonateDialogue, + expectTracksReasonsToDonateShownEvent, + expectTracksReasonsToDonateCTAClickedEvent, + expectTracksReasonsToDonateItemClickedEvent + +}; + +export const useReasonsToDonateScrollFeatures: Record, pageScroller: PageScroller ) => Promise> = { + expectScrollsToFormWhenCallToActionIsClicked +}; From fc9d9cdce8c4f323f628b02cb6e736b10b23bb29 Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Tue, 19 Nov 2024 15:30:50 +0100 Subject: [PATCH 5/9] Add content button styling to Mikings theme (#626) This adds some styles so we can use buttons in the slider and full page content in the mobile de banners. Ticket: https://phabricator.wikimedia.org/T379953 --- .../content/BannerSlides_var.vue | 9 ++------- .../content/BannerText_var.vue | 9 +-------- .../styles/styles_var.scss | 1 + src/themes/Mikings/Message/Message.scss | 18 ++++++++++++++++++ src/themes/Mikings/Slider/Slider.scss | 15 +++++++++++++++ src/themes/Mikings/swatches/color_light.scss | 2 ++ 6 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 src/themes/Mikings/Message/Message.scss diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue index 6d8f1a4e2..32d01c23f 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerSlides_var.vue @@ -43,14 +43,9 @@

Dann entscheiden Sie sich, eine der seltenen Ausnahmen zu sein, und geben Sie etwas zurück. Falls Sie zögern, - + für eine Spende. Vielen Dank!

diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText_var.vue b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText_var.vue index a5956142e..13679edf3 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText_var.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/content/BannerText_var.vue @@ -13,14 +13,7 @@ weiter. Hat Wikipedia Ihnen in diesem Jahr Wissen im Wert einer Tasse Kaffee geschenkt? Dann entscheiden Sie sich, eine der seltenen Ausnahmen zu sein, und geben Sie etwas zurück. Falls Sie zögern, - - hier sind 10 gute Gründe - + für eine Spende. Vielen Dank!

diff --git a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss index d68714006..4bf6a0dda 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss +++ b/banners/mobile/C24_WMDE_Mobile_DE_09/styles/styles_var.scss @@ -21,6 +21,7 @@ @use 'src/themes/Mikings/DonationForm/SubComponents/SelectGroup'; @use 'src/themes/Mikings/DonationForm/SubComponents/SelectCustomAmount'; @use 'src/themes/Mikings/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Mikings/Message/Message'; @use 'src/themes/Mikings/Slider/Slider' with ( $pagination-padding: 10px, $pagination-height: 40px diff --git a/src/themes/Mikings/Message/Message.scss b/src/themes/Mikings/Message/Message.scss new file mode 100644 index 000000000..7cf42649c --- /dev/null +++ b/src/themes/Mikings/Message/Message.scss @@ -0,0 +1,18 @@ +.wmde-banner { + &-message { + button { + all: unset; + } + + button, + a { + color: var( --content-link-color ); + cursor: pointer; + + &:hover, + &:focus { + color: var( --content-link-color-hover ); + } + } + } +} diff --git a/src/themes/Mikings/Slider/Slider.scss b/src/themes/Mikings/Slider/Slider.scss index 6324a0bca..76d5d9d27 100644 --- a/src/themes/Mikings/Slider/Slider.scss +++ b/src/themes/Mikings/Slider/Slider.scss @@ -31,6 +31,21 @@ $pagination-height: 60px !default; margin: 13px 0 16px; padding: 0; } + + button { + all: unset; + } + + button, + a { + color: var( --content-link-color ); + cursor: pointer; + + &:hover, + &:focus { + color: var( --content-link-color-hover ); + } + } } } diff --git a/src/themes/Mikings/swatches/color_light.scss b/src/themes/Mikings/swatches/color_light.scss index 4b22b105f..e71d9ea01 100644 --- a/src/themes/Mikings/swatches/color_light.scss +++ b/src/themes/Mikings/swatches/color_light.scss @@ -40,6 +40,8 @@ $purple100: #6b4ba1; --main-background: #{$white}; --main-color: #{$grey800}; --color-error: #{$error}; + --content-link-color: #{$blue600}; + --content-link-color-hover: #{$blue400}; --mini-background: #{$white}; --mini-border: #{$blue600}; From d47aa59e7a496e89e0f6cd71b964eef9663e156f Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Mon, 18 Nov 2024 10:57:14 +0100 Subject: [PATCH 6/9] Prepare campaign for C24_WMDE_Desktop_DE_14 Ticket: https://phabricator.wikimedia.org/T379950 --- .../C24_WMDE_Desktop_DE_14/banner_ctrl.ts | 74 +++++++ .../C24_WMDE_Desktop_DE_14/banner_var.ts | 78 +++++++ .../components/BannerCtrl.vue | 165 +++++++++++++++ .../components/BannerVar.vue | 171 ++++++++++++++++ .../components/FallbackBanner.vue | 108 ++++++++++ .../components/MainBanner.vue | 44 ++++ .../content/BannerSlides.vue | 63 ++++++ .../content/BannerText.vue | 47 +++++ .../content/FallbackSlides.vue | 27 +++ .../content/FallbackText.vue | 25 +++ .../C24_WMDE_Desktop_DE_14/event_map.ts | 47 +++++ .../C24_WMDE_Desktop_DE_14/event_map_var.ts | 49 +++++ .../C24_WMDE_Desktop_DE_14/form_items.ts | 23 +++ .../C24_WMDE_Desktop_DE_14/messages.ts | 32 +++ .../C24_WMDE_Desktop_DE_14/messages_var.ts | 33 +++ .../C24_WMDE_Desktop_DE_14/styles/Banner.scss | 22 ++ .../styles/FallbackBanner.scss | 121 +++++++++++ .../styles/MainBanner.scss | 53 +++++ .../C24_WMDE_Desktop_DE_14/styles/styles.scss | 54 +++++ .../styles/styles_var.scss | 55 +++++ campaign_info.toml | 18 +- .../components/BannerCtrl.spec.ts | 179 +++++++++++++++++ .../components/BannerVar.spec.ts | 190 ++++++++++++++++++ .../components/FallbackBanner.spec.ts | 58 ++++++ 24 files changed, 1727 insertions(+), 9 deletions(-) create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/components/MainBanner.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlides.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerText.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/content/FallbackSlides.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/content/FallbackText.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/event_map.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/form_items.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/messages.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/styles/Banner.scss create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/styles/FallbackBanner.scss create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/styles/MainBanner.scss create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles.scss create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss create mode 100644 test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.spec.ts create mode 100644 test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.spec.ts create mode 100644 test/banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.spec.ts diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts new file mode 100644 index 000000000..c0b50d8ba --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts @@ -0,0 +1,74 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles.scss'; + +import BannerConductor from '@src/components/BannerConductor/FallbackBannerConductor.vue'; +import Banner from './components/BannerCtrl.vue'; +import FallbackBanner from './components/FallbackBanner.vue'; +import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import eventMappings from './event_map'; +import { createFallbackDonationURL } from '@src/createFallbackDonationURL'; +import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; +import messages from './messages'; +import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; +import { WindowTimer } from '@src/utils/Timer'; + +const date = new Date(); +const localeFactory = new LocaleFactoryDe(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker( 400 ) ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'desktop' ) ), + localCloseTracker: new LocalStorageCloseTracker(), + donationLink: createFallbackDonationURL( page.getTracking(), impressionCount ) + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + fallbackBanner: FallbackBanner, + minWidthForMainBanner: 800, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date, + formatters: localeFactory.getFormatters(), + impressionCount, + translator, + urgencyMessageDaysLeft: 45 +} ); + +const currencyFormatter = localeFactory.getCurrencyFormatter(); + +app.provide( 'currencyFormatter', currencyFormatter ); +app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) ); +app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { afo: '1', ap: '0' } ) ); +app.provide( 'tracker', tracker ); +app.provide( 'timer', new WindowTimer() ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts new file mode 100644 index 000000000..4473f6217 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts @@ -0,0 +1,78 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles_var.scss'; + +import BannerConductor from '@src/components/BannerConductor/FallbackBannerConductor.vue'; +import Banner from './components/BannerVar.vue'; +import FallbackBanner from './components/FallbackBanner.vue'; +import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import eventMappings from './event_map_var'; +import { createFallbackDonationURL } from '@src/createFallbackDonationURL'; +import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; + +// Locale-specific imports +import messages from './messages_var'; +import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; + +// Channel specific form setup +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; +import { WindowTimer } from '@src/utils/Timer'; + +const date = new Date(); +const localeFactory = new LocaleFactoryDe(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker( 400 ) ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'desktop' ) ), + localCloseTracker: new LocalStorageCloseTracker(), + donationLink: createFallbackDonationURL( page.getTracking(), impressionCount ) + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + fallbackBanner: FallbackBanner, + minWidthForMainBanner: 800, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date, + formatters: localeFactory.getFormatters(), + impressionCount, + translator, + urgencyMessageDaysLeft: 45 +} ); + +const currencyFormatter = localeFactory.getCurrencyFormatter(); + +app.provide( 'currencyFormatter', currencyFormatter ); +app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) ); +app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { afo: '1', ap: '0' } ) ); +app.provide( 'tracker', tracker ); +app.provide( 'timer', new WindowTimer() ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.vue new file mode 100644 index 000000000..54ea355f0 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.vue @@ -0,0 +1,165 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue new file mode 100644 index 000000000..9b73613f5 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue @@ -0,0 +1,171 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.vue new file mode 100644 index 000000000..6550131fa --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.vue @@ -0,0 +1,108 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/components/MainBanner.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/components/MainBanner.vue new file mode 100644 index 000000000..ab097bf67 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/components/MainBanner.vue @@ -0,0 +1,44 @@ +tart + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlides.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlides.vue new file mode 100644 index 000000000..46790f372 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlides.vue @@ -0,0 +1,63 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerText.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerText.vue new file mode 100644 index 000000000..c004e00e4 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerText.vue @@ -0,0 +1,47 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/content/FallbackSlides.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/content/FallbackSlides.vue new file mode 100644 index 000000000..b5e4af29d --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/content/FallbackSlides.vue @@ -0,0 +1,27 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/content/FallbackText.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/content/FallbackText.vue new file mode 100644 index 000000000..5c14762e7 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/content/FallbackText.vue @@ -0,0 +1,25 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/event_map.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map.ts new file mode 100644 index 000000000..88eb4714e --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map.ts @@ -0,0 +1,47 @@ +import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; +import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; +import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; +import { CustomAmountChangedEvent } from '@src/tracking/events/CustomAmountChangedEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; +import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; +import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; +import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; +import { AlreadyDonatedShownEvent } from '@src/tracking/events/AlreadyDonatedShownEvent'; +import { FallbackBannerSubmitEvent } from '@src/tracking/events/FallbackBannerSubmitEvent'; +import { ShownEvent } from '@src/tracking/events/ShownEvent'; +import { mapShownEvent } from '@src/tracking/LegacyEventTracking/mapShownEvent'; +import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; + +export default new Map( [ + [ ShownEvent.EVENT_NAME, mapShownEvent ], + [ CloseEvent.EVENT_NAME, mapCloseEvent ], + [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], + [ CustomAmountChangedEvent.EVENT_NAME, + ( e: CustomAmountChangedEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.userChoice + '-amount', 1 ) + ], + [ AlreadyDonatedShownEvent.EVENT_NAME, ( e: AlreadyDonatedShownEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ], + [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], + [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { + switch ( e.feature ) { + case 'UpgradeToYearlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + case 'UpgradeToMonthlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + default: + return new WMDESizeIssueEvent( `submit`, createViewportInfo(), 1 ); + } + } ], + [ FallbackBannerSubmitEvent.EVENT_NAME, + ( e: FallbackBannerSubmitEvent ): WMDESizeIssueEvent => + new WMDESizeIssueEvent( e.eventName, createViewportInfo(), 1 ) + ], + [ BannerSubmitOnReturnEvent.EVENT_NAME, + ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) + ] +] ); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts new file mode 100644 index 000000000..c7eb259e7 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts @@ -0,0 +1,49 @@ +import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; +import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; +import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; +import { CustomAmountChangedEvent } from '@src/tracking/events/CustomAmountChangedEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; +import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; +import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; +import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; +import { AlreadyDonatedShownEvent } from '@src/tracking/events/AlreadyDonatedShownEvent'; +import { FallbackBannerSubmitEvent } from '@src/tracking/events/FallbackBannerSubmitEvent'; +import { ShownEvent } from '@src/tracking/events/ShownEvent'; +import { mapShownEvent } from '@src/tracking/LegacyEventTracking/mapShownEvent'; +import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; +import { CoverTransactionFeesEvent } from '@src/tracking/events/CoverTransactionFeesEvent'; + +export default new Map( [ + [ ShownEvent.EVENT_NAME, mapShownEvent ], + [ CloseEvent.EVENT_NAME, mapCloseEvent ], + [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], + [ CustomAmountChangedEvent.EVENT_NAME, + ( e: CustomAmountChangedEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.userChoice + '-amount', 1 ) + ], + [ AlreadyDonatedShownEvent.EVENT_NAME, ( e: AlreadyDonatedShownEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ], + [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], + [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { + switch ( e.feature ) { + case 'UpgradeToYearlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + case 'UpgradeToMonthlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + default: + return new WMDESizeIssueEvent( `submit`, createViewportInfo(), 1 ); + } + } ], + [ FallbackBannerSubmitEvent.EVENT_NAME, + ( e: FallbackBannerSubmitEvent ): WMDESizeIssueEvent => + new WMDESizeIssueEvent( e.eventName, createViewportInfo(), 1 ) + ], + [ BannerSubmitOnReturnEvent.EVENT_NAME, + ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) + ], + [ CoverTransactionFeesEvent.EVENT_NAME, ( e: CoverTransactionFeesEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.userChoice + 'cover-transaction-fee', 1 ) ] +] ); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/form_items.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/form_items.ts new file mode 100644 index 000000000..b70650d19 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/form_items.ts @@ -0,0 +1,23 @@ +import FormItemsBuilder from '@src/utils/FormItemsBuilder/FormItemsBuilder'; +import { Translator } from '@src/Translator'; +import { DonationFormItems } from '@src/utils/FormItemsBuilder/DonationFormItems'; +import { Intervals } from '@src/utils/FormItemsBuilder/fields/Intervals'; +import { PaymentMethods } from '@src/utils/FormItemsBuilder/fields/PaymentMethods'; +import { NumberFormatter } from '@src/utils/DynamicContent/formatters/NumberFormatter'; + +export function createFormItems( translations: Translator, amountFormatter: NumberFormatter ): DonationFormItems { + return new FormItemsBuilder( translations, amountFormatter ) + .setIntervals( + Intervals.ONCE, + Intervals.MONTHLY, + Intervals.QUARTERLY, + Intervals.YEARLY + ) + .setAmounts( 5, 10, 20, 25, 50, 100 ) + .setPaymentMethods( + PaymentMethods.PAYPAL, + PaymentMethods.BANK_TRANSFER, + PaymentMethods.CREDIT_CARD, + PaymentMethods.DIRECT_DEBIT + ).getItems(); +} diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/messages.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/messages.ts new file mode 100644 index 000000000..8bb2ea2d4 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/messages.ts @@ -0,0 +1,32 @@ +import CustomAmountFormDe from '@src/components/DonationForm/Forms/messages/CustomAmountForm.de'; +import DynamicCampaignTextDe from '@src/utils/DynamicContent/messages/DynamicCampaignText.de'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyDe from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.de'; +import AddressFormDe from '@src/components/DonationForm/Forms/messages/AddressForm.de'; +import FooterDe from '@src/components/Footer/messages/Footer.de'; +import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/MainDonationForm.de'; +import FallbackBanner from '@src/components/FallbackBanner/messages/FallbackBanner.de'; +import AlreadyDonatedModal from '@src/components/AlreadyDonatedModal/translations/AlreadyDonatedModal.de'; +import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; + +const messages: TranslationMessages = { + ...CustomAmountFormDe, + ...DynamicCampaignTextDe, + ...UpgradeToYearlyDe, + ...AddressFormDe, + ...FooterDe, + ...MainDonationFormDe, + ...AlreadyDonatedModal, + ...FallbackBanner, + ...SoftCloseDe, + 'already-donated-go-away-button': 'Im Moment nicht', + 'soft-close-prompt': 'Dürfen wir später nochmal fragen?', + 'upgrade-to-yearly-copy': `

Jedes Jahr sind wir auf Menschen wie Sie angewiesen. Jährliche Spenden helfen uns besonders und ermöglichen langfristige Weiterentwicklungen.

+

Sie gehen kein Risiko ein: Jederzeit formlos zu sofort kündbar.

`, + 'upgrade-to-yearly-no': 'Nein, ich spende einmalig {{amount}}', + 'upgrade-to-yearly-yes': 'Ja, ich spende {{amount}} jährlich', + 'campaign-day-only-n-days': 'Heute sind es nur noch {{days}} Tage bis zum Ende unserer Spendenkampagne.', + 'custom-amount-placeholder': 'Wahlbetrag' +}; + +export default messages; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts new file mode 100644 index 000000000..b7c246a89 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts @@ -0,0 +1,33 @@ +import CustomAmountFormDe from '@src/components/DonationForm/Forms/messages/CustomAmountForm.de'; +import DynamicCampaignTextDe from '@src/utils/DynamicContent/messages/DynamicCampaignText.de'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyDe from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.de'; +import AddressFormDe from '@src/components/DonationForm/Forms/messages/AddressForm.de'; +import FooterDe from '@src/components/Footer/messages/Footer.de'; +import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/MainDonationForm.de'; +import FallbackBanner from '@src/components/FallbackBanner/messages/FallbackBanner.de'; +import AlreadyDonatedModal from '@src/components/AlreadyDonatedModal/translations/AlreadyDonatedModal.de'; +import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; + +const messages: TranslationMessages = { + ...CustomAmountFormDe, + ...DynamicCampaignTextDe, + ...UpgradeToYearlyDe, + ...AddressFormDe, + ...FooterDe, + ...MainDonationFormDe, + ...AlreadyDonatedModal, + ...FallbackBanner, + ...SoftCloseDe, + 'already-donated-go-away-button': 'Im Moment nicht', + 'soft-close-prompt': 'Dürfen wir später nochmal fragen?', + 'upgrade-to-yearly-copy': `

Jedes Jahr sind wir auf Menschen wie Sie angewiesen. Jährliche Spenden helfen uns besonders und ermöglichen langfristige Weiterentwicklungen.

+

Sie gehen kein Risiko ein: Jederzeit formlos zu sofort kündbar.

`, + 'upgrade-to-yearly-no': 'Nein, ich spende einmalig {{amount}}', + 'upgrade-to-yearly-yes': 'Ja, ich spende {{amount}} jährlich', + 'campaign-day-only-n-days': 'Heute sind es nur noch {{days}} Tage bis zum Ende unserer Spendenkampagne.', + 'custom-amount-placeholder': 'Wahlbetrag', + 'cover-transaction-costs': 'Ich übernehme zusätzlich die Transaktionsgebühren von {{transactionCosts}}, damit 100% meiner Spende ankommt.' +}; + +export default messages; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/Banner.scss b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/Banner.scss new file mode 100644 index 000000000..1e7d13842 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/Banner.scss @@ -0,0 +1,22 @@ +@use 'src/themes/Svingle/variables/fonts'; + +.wmde-banner { + &-wrapper { + font-size: 14px; + font-family: fonts.$ui; + box-shadow: 0 3px 0.6em rgba( 60 60 60 / 40% ); + background-color: var( --main-background ); + } + + &--pending { + .wmde-banner-wrapper { + box-shadow: none; + } + } + + &--closed { + .wmde-banner-wrapper { + display: none; + } + } +} diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/FallbackBanner.scss b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/FallbackBanner.scss new file mode 100644 index 000000000..a0d40542d --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/FallbackBanner.scss @@ -0,0 +1,121 @@ +@use 'src/themes/Svingle/variables/fonts'; + +$breakpoint: 800px; + +.wmde-banner { + &-fallback { + width: 100%; + height: 150px; + display: flex; + flex-direction: column; + background: var( --fallback-background ); + box-shadow: 0 3px 0.6em rgba( 60 60 60 / 40% ); + + @media ( min-width: $breakpoint ) { + height: auto; + min-height: 250px; + padding: 4px; + } + + &-small, + &-large { + display: flex; + flex-direction: column; + flex: 1 1 auto; + } + + &-small { + align-items: center; + border: 4px solid var( --fallback-border ); + border-radius: 4px; + padding: 8px; + + .wmde-banner-selection-input-text, + .wmde-banner-selection-input-input { + font-family: fonts.$content; + font-size: 14px; + font-weight: normal; + } + } + + &-large { + align-items: stretch; + } + + &-usage-link { + color: var( --fallback-uof-link ); + } + + &-message { + flex: 1 1 auto; + display: flex; + flex-direction: column; + border: 4px solid var( --fallback-message-border ); + border-radius: 4px; + padding: 8px 0; + } + + &-bank-item { + display: block; + + &-label { + font-weight: bold; + } + } + + .wmde-banner-close { + height: 16px; + width: 16px; + top: 8px; + right: 8px; + + @media ( min-width: $breakpoint ) { + height: 30px; + width: 30px; + top: 12px; + right: 12px; + } + } + + .wmde-banner-message { + flex: 1 1 auto; + display: flex; + flex-direction: column; + padding: 8px 0; + color: var( --fallback-message-color ); + background-color: var( --fallback-message-background ); + margin: 15px; + + p { + margin-bottom: 0; + } + } + + .wmde-banner-slider-container { + padding: 0 0 8px; + margin: 0; + } + + .wmde-banner-slide-content { + font-size: 14px; + p { + margin-bottom: 8px; + } + } + + .wmde-banner-slider-navigation-previous, + .wmde-banner-slider-navigation-next { + align-items: end; + } + + .wmde-banner-slider-pagination-dot { + cursor: default; + } + } + + &--pending { + .wmde-banner-fallback { + box-shadow: none; + } + } +} diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/MainBanner.scss b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/MainBanner.scss new file mode 100644 index 000000000..a0bcd9bca --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/MainBanner.scss @@ -0,0 +1,53 @@ +$banner-height: 357px !default; +$form-width: 300px !default; + +.wmde-banner { + + .previous { + --slider-chevron: var( --previous-button-fill ); + } + + &-main { + min-height: $banner-height; + display: flex; + flex-direction: column; + padding: 12px 24px 0; + } + + &-content { + display: flex; + flex-direction: row; + flex-grow: 1; + } + + &-message { + padding: 3px 15px; + color: var( --message-color ); + background-color: var( --message-background ); + border: none; + border-radius: 9px; + margin-bottom: 15px; + } + + &-column-left { + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + flex: 1 1 auto; + margin-bottom: 0; + overflow-y: hidden; + margin-right: 30px; + padding: 0; + border: none; + } + + &-column-right { + order: 2; + flex: 0 0 $form-width; + display: flex; + flex-direction: column; + width: $form-width; + padding: 10px 0 0; + } +} diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles.scss b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles.scss new file mode 100644 index 000000000..ff644c870 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles.scss @@ -0,0 +1,54 @@ +// This is the file where we import the theme-specific component styles +@use '../../../../src/themes/Svingle/swatches/skin_default' with ( + $slider: true, + $select-group: true, + $upgrade-to-yearly: true, + $fallback-banner: true, + $progress-bar: true, + $soft-close: true, +); +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; +@use 'Banner'; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'MainBanner' with ( + $banner-height: 357px, + $form-width: 300px +); +@use 'src/themes/Svingle/defaults'; +@use 'src/themes/Svingle/ButtonClose/ButtonClose'; +@use 'src/themes/Svingle/ProgressBar/ProgressBar'; +@use 'src/themes/Svingle/DonationForm/DonationForm'; +@use 'src/themes/Svingle/DonationForm/MultiStepDonation'; +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectGroupRadios' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectCustomAmountRadio' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Svingle/DonationForm/Forms/MainDonationForm'; +@use 'src/themes/Svingle/DonationForm/Forms/UpgradeToYearlyButtonForm' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/Forms/CustomAmountForm'; +@use 'src/themes/Svingle/Footer/FooterAlreadyDonated'; +@use 'src/themes/Svingle/Footer/SelectionInput'; +@use 'src/themes/Svingle/Message/Message'; +@use 'src/themes/Svingle/SoftClose/SoftClose'; +@use 'src/themes/Svingle/Slider/KeenSlider'; + +/** + * Fallback banner with "Fijitiv" theme + * All selectors in Fijitiv theme are prefixed with the ".wmde-banner-fallback" class selector, + so they override the "default" styles with the same selector + */ +@use 'FallbackBanner'; +@use 'src/themes/Fijitiv/FallbackBanner/FallbackButton'; +@use 'src/themes/Fijitiv/FallbackBanner/LargeFooter'; +@use 'src/themes/Fijitiv/FallbackBanner/SmallFooter'; +@use 'src/themes/Fijitiv/ProgressBar/ProgressBar' as FallbackProgressBar with ( + $progress-bar-margin: 0 15px +); +@use 'src/themes/Fijitiv/Slider/KeenSlider' as FallbackSlider; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss new file mode 100644 index 000000000..3ac13e0af --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss @@ -0,0 +1,55 @@ +// This is the file where we import the theme-specific component styles +@use '../../../../src/themes/Svingle/swatches/skin_default' with ( + $slider: true, + $select-group: true, + $upgrade-to-yearly: true, + $fallback-banner: true, + $progress-bar: true, + $soft-close: true, +); +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; +@use 'Banner'; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'MainBanner' with ( + $banner-height: 357px, + $form-width: 300px +); +@use 'src/themes/Svingle/defaults'; +@use 'src/themes/Svingle/ButtonClose/ButtonClose'; +@use 'src/themes/Svingle/ProgressBar/ProgressBar'; +@use 'src/themes/Svingle/DonationForm/DonationForm'; +@use 'src/themes/Svingle/DonationForm/MultiStepDonation'; +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectGroupRadios' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectCustomAmountRadio' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Svingle/DonationForm/SubComponents/TransactionFees'; +@use 'src/themes/Svingle/DonationForm/Forms/MainDonationForm'; +@use 'src/themes/Svingle/DonationForm/Forms/UpgradeToYearlyButtonForm' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/Forms/CustomAmountForm'; +@use 'src/themes/Svingle/Footer/FooterAlreadyDonated'; +@use 'src/themes/Svingle/Footer/SelectionInput'; +@use 'src/themes/Svingle/Message/Message'; +@use 'src/themes/Svingle/SoftClose/SoftClose'; +@use 'src/themes/Svingle/Slider/KeenSlider'; + +/** + * Fallback banner with "Fijitiv" theme + * All selectors in Fijitiv theme are prefixed with the ".wmde-banner-fallback" class selector, + so they override the "default" styles with the same selector + */ +@use 'FallbackBanner'; +@use 'src/themes/Fijitiv/FallbackBanner/FallbackButton'; +@use 'src/themes/Fijitiv/FallbackBanner/LargeFooter'; +@use 'src/themes/Fijitiv/FallbackBanner/SmallFooter'; +@use 'src/themes/Fijitiv/ProgressBar/ProgressBar' as FallbackProgressBar with ( + $progress-bar-margin: 0 15px +); +@use 'src/themes/Fijitiv/Slider/KeenSlider' as FallbackSlider; diff --git a/campaign_info.toml b/campaign_info.toml index 6b302cad7..72b912a28 100644 --- a/campaign_info.toml +++ b/campaign_info.toml @@ -6,9 +6,9 @@ [desktop] name = "Desktop" icon = "desktop" -campaign = "C24_WMDE_Desktop_DE_13" -description = "Based on the CTRL banner of C24_WMDE_Desktop_DE_12, VAR uses transaction fees" -campaign_tracking = "13-ba-241113" +campaign = "C24_WMDE_Desktop_DE_14" +description = "Based on the CTRL banner of C24_WMDE_Desktop_DE_13, VAR adds additional copy, displays the '10 good reasons' overlay when the link in the added copy is clicked" +campaign_tracking = "14-ba-241119" preview_link = "/wiki/Wikipedia:Hauptseite?devbanner={{banner}}&banner=B22_WMDE_local_prototype" preview_link_darkmode = "/wiki/Wikipedia:Hauptseite?devbanner={{banner}}&banner=B22_WMDE_local_prototype&vectornightmode=1" preview_url = 'https://de.wikipedia.org/wiki/Wikipedia:Hauptseite?banner={{banner}}&devMode' @@ -17,14 +17,14 @@ use_of_funds_source = "MediaWiki:WMDE_Fundraising/UseOfFunds_2024_DE" # Banners of the campaign, key after "banners" can be anything [desktop.banners.ctrl] -filename = "./banners/desktop/C24_WMDE_Desktop_DE_13/banner_ctrl.ts" -pagename = "B24_WMDE_Desktop_DE_13_ctrl" -tracking = "org-13-241113-ctrl" +filename = "./banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts" +pagename = "B24_WMDE_Desktop_DE_14_ctrl" +tracking = "org-14-241119-ctrl" [desktop.banners.var] -filename = "./banners/desktop/C24_WMDE_Desktop_DE_13/banner_var.ts" -pagename = "B24_WMDE_Desktop_DE_13_var" -tracking = "org-13-241113-var" +filename = "./banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts" +pagename = "B24_WMDE_Desktop_DE_14_var" +tracking = "org-14-241119-var" [desktop.test_matrix] platform = ["edge", "firefox_win10", "chrome_win10", "safari", "firefox_macos", "chrome_macos", "firefox_linux", "chrome_linux"] diff --git a/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.spec.ts b/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.spec.ts new file mode 100644 index 000000000..f99dd53ba --- /dev/null +++ b/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.spec.ts @@ -0,0 +1,179 @@ +import { beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerCtrl.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { formItems } from '@test/banners/formItems'; +import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; +import { useOfFundsFeatures } from '@test/features/UseOfFunds'; +import { + bannerContentAnimatedTextFeatures, + bannerContentDateAndTimeFeatures, + bannerContentDisplaySwitchFeatures, + bannerContentFeatures +} from '@test/features/BannerContent'; +import { donationFormFeatures } from '@test/features/forms/MainDonation_UpgradeToYearlyButton'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { bannerAutoHideFeatures, bannerMainFeatures } from '@test/features/MainBanner'; +import { formActionSwitchFeatures } from '@test/features/form_action_switch/MainDonation_UpgradeToYearlyButton'; +import { softCloseFeatures } from '@test/features/SoftCloseDesktop'; +import { alreadyDonatedModalFeatures } from '@test/features/AlreadyDonatedModal'; +import { softCloseSubmitTrackingFeaturesDesktop } from '@test/features/SoftCloseSubmitTrackingDesktop'; +import { Tracker } from '@src/tracking/Tracker'; +import { TimerStub } from '@test/fixtures/TimerStub'; +import { Timer } from '@src/utils/Timer'; + +const formModel = useFormModel(); +const translator = ( key: string ): string => key; +let tracker: Tracker; + +describe( 'BannerCtrl.vue', () => { + + beforeEach( () => { + resetFormModel( formModel ); + tracker = { + trackEvent: vi.fn() + }; + } ); + + const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { + return mount( Banner, { + attachTo: document.body, + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + remainingImpressions: 10, + localCloseTracker: { + getItem: () => '', + setItem: () => {} + } + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + currentCampaignTimePercentage: 42, + formActions: { + donateWithAddressAction: 'https://example.com/with-address', + donateAnonymouslyAction: 'https://example.com/without-address' + }, + currencyFormatter: new CurrencyEn(), + formItems, + tracker, + timer: timer ?? new TimerStub() + } + } + } ); + }; + + describe( 'Main Banner', () => { + test.each( [ + [ 'expectDoesNotEmitCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await bannerMainFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectClosesBannerWhenWindowBecomesSmall' ] + ] )( '%s', async ( testName: string ) => { + await bannerAutoHideFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Content', () => { + test.each( [ + [ 'expectSlideShowPlaysWhenBecomesVisible' ], + [ 'expectSlideShowStopsOnFormInteraction' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectShowsSlideShowOnSmallSizes' ], + [ 'expectShowsMessageOnLargeSizes' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDisplaySwitchFeatures[ testName ]( getWrapper, 1300 ); + } ); + + test.each( [ + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + + test.each( [ + [ 'expectShowsLiveDateAndTimeInMessage' ], + [ 'expectShowsLiveDateAndTimeInSlideshow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectMainDonationFormSubmitsWithAddressForDirectDebit' ], + [ 'expectMainDonationFormSubmitsWithAddressForPayPal' ], + [ 'expectUpgradeToYearlyFormSubmitsWithAddressForDirectDebit' ], + [ 'expectUpgradeToYearlyFormSubmitsWithAddressForPayPal' ] + ] )( '%s', async ( testName: string ) => { + await formActionSwitchFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseMaybeLaterEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectShowsCloseIcon' ], + [ 'expectCloseIconEmitsCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Soft Close Submit Tracking', () => { + test.each( [ + [ 'expectEmitsBannerSubmitOnReturnEvent' ], + [ 'expectDoesNotEmitsBannerSubmitOnReturnEventWhenLocalStorageItemIsMissing' ] + ] )( '%s', async ( testName: string ) => { + await softCloseSubmitTrackingFeaturesDesktop[ testName ]( getWrapper(), tracker ); + } ); + } ); + + describe( 'Already Donated', () => { + test.each( [ + [ 'expectFiresMaybeLaterEventOnLinkClick' ] + ] )( '%s', async ( testName: string ) => { + await alreadyDonatedModalFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Use of Funds', () => { + test.each( [ + [ 'expectShowsUseOfFunds' ], + [ 'expectHidesUseOfFunds' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsFeatures[ testName ]( getWrapper() ); + } ); + } ); +} ); diff --git a/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.spec.ts b/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.spec.ts new file mode 100644 index 000000000..bd8057de4 --- /dev/null +++ b/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.spec.ts @@ -0,0 +1,190 @@ +import { beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { formItems } from '@test/banners/formItems'; +import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; +import { useOfFundsFeatures } from '@test/features/UseOfFunds'; +import { + bannerContentAnimatedTextFeatures, + bannerContentDateAndTimeFeatures, + bannerContentDisplaySwitchFeatures, + bannerContentFeatures +} from '@test/features/BannerContent'; +import { donationFormFeatures } from '@test/features/forms/MainDonation_UpgradeToYearlyButton'; +import { donationFormTransactionFeeFeatures } from '@test/features/forms/MainDonation_TransactionFee'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { bannerAutoHideFeatures, bannerMainFeatures } from '@test/features/MainBanner'; +import { formActionSwitchFeatures } from '@test/features/form_action_switch/MainDonation_UpgradeToYearlyButton'; +import { softCloseFeatures } from '@test/features/SoftCloseDesktop'; +import { alreadyDonatedModalFeatures } from '@test/features/AlreadyDonatedModal'; +import { softCloseSubmitTrackingFeaturesDesktop } from '@test/features/SoftCloseSubmitTrackingDesktop'; +import { Tracker } from '@src/tracking/Tracker'; +import { Timer } from '@src/utils/Timer'; +import { TimerStub } from '@test/fixtures/TimerStub'; + +const formModel = useFormModel(); +const translator = ( key: string, context: any ): string => context ? `${key} -- ${Object.entries( context )}` : key; +let tracker: Tracker; + +describe( 'BannerVar.vue', () => { + + beforeEach( () => { + resetFormModel( formModel ); + tracker = { + trackEvent: vi.fn() + }; + } ); + + const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { + return mount( Banner, { + attachTo: document.body, + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + remainingImpressions: 10, + localCloseTracker: { + getItem: () => '', + setItem: () => {} + } + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + currentCampaignTimePercentage: 42, + formActions: { + donateWithAddressAction: 'https://example.com/with-address', + donateAnonymouslyAction: 'https://example.com/without-address' + }, + currencyFormatter: new CurrencyEn(), + formItems, + tracker, + timer: timer ?? new TimerStub() + } + } + } ); + }; + + describe( 'Main Banner', () => { + test.each( [ + [ 'expectDoesNotEmitCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await bannerMainFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectClosesBannerWhenWindowBecomesSmall' ] + ] )( '%s', async ( testName: string ) => { + await bannerAutoHideFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Content', () => { + test.each( [ + [ 'expectSlideShowPlaysWhenBecomesVisible' ], + [ 'expectSlideShowStopsOnFormInteraction' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectShowsSlideShowOnSmallSizes' ], + [ 'expectShowsMessageOnLargeSizes' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDisplaySwitchFeatures[ testName ]( getWrapper, 1300 ); + } ); + + test.each( [ + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + + test.each( [ + [ 'expectShowsLiveDateAndTimeInMessage' ], + [ 'expectShowsLiveDateAndTimeInSlideshow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectMainDonationFormSubmitsWithAddressForDirectDebit' ], + [ 'expectMainDonationFormSubmitsWithAddressForPayPal' ], + [ 'expectUpgradeToYearlyFormSubmitsWithAddressForDirectDebit' ], + [ 'expectUpgradeToYearlyFormSubmitsWithAddressForPayPal' ] + ] )( '%s', async ( testName: string ) => { + await formActionSwitchFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Donation Form Transaction Fees', () => { + test.each( [ + [ 'expectMainDonationFormShowsTransactionFeeForPayPalAndCreditCard' ], + [ 'expectMainDonationFormSetsSubmitValuesWithTransactionFee' ], + [ 'expectUpsellFormHasTransactionFee' ] + ] )( '%s', async ( testName: string ) => { + await donationFormTransactionFeeFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseMaybeLaterEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectShowsCloseIcon' ], + [ 'expectCloseIconEmitsCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Soft Close Submit Tracking', () => { + test.each( [ + [ 'expectEmitsBannerSubmitOnReturnEvent' ], + [ 'expectDoesNotEmitsBannerSubmitOnReturnEventWhenLocalStorageItemIsMissing' ] + ] )( '%s', async ( testName: string ) => { + await softCloseSubmitTrackingFeaturesDesktop[ testName ]( getWrapper(), tracker ); + } ); + } ); + + describe( 'Already Donated', () => { + test.each( [ + [ 'expectFiresMaybeLaterEventOnLinkClick' ] + ] )( '%s', async ( testName: string ) => { + await alreadyDonatedModalFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Use of Funds', () => { + test.each( [ + [ 'expectShowsUseOfFunds' ], + [ 'expectHidesUseOfFunds' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsFeatures[ testName ]( getWrapper() ); + } ); + } ); +} ); diff --git a/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.spec.ts b/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.spec.ts new file mode 100644 index 000000000..9a4430d88 --- /dev/null +++ b/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.spec.ts @@ -0,0 +1,58 @@ +import { describe, test } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import FallbackBanner from '@banners/desktop/C24_WMDE_Desktop_DE_14/components/FallbackBanner.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { Tracker } from '@src/tracking/Tracker'; +import { TrackerStub } from '@test/fixtures/TrackerStub'; +import { fallbackBannerFeatures, submitFeatures } from '@test/features/FallbackBanner'; +import { Timer } from '@src/utils/Timer'; +import { TimerStub } from '@test/fixtures/TimerStub'; + +const translator = ( key: string ): string => key; + +describe( 'FallbackBanner.vue', () => { + const getWrapperAtWidth = ( width: number, dynamicContent: DynamicContent = null, tracker: Tracker = null, timer: Timer = null ): VueWrapper => { + Object.defineProperty( window, 'innerWidth', { writable: true, configurable: true, value: width } ); + return mount( FallbackBanner, { + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + donationLink: 'https://spenden.wikimedia.de' + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + tracker: tracker ?? new TrackerStub(), + timer: timer ?? new TimerStub() + } + } + } ); + }; + + test.each( [ + [ 'showsTheSmallBanner' ], + [ 'showsTheLargeBanner' ], + [ 'emitsTheBannerCloseEvent' ], + [ 'playsTheSlideshowWhenBecomesVisible' ], + [ 'showsUseOfFundsFromSmallBanner' ], + [ 'hidesUseOfFundsFromSmallBanner' ], + [ 'showsUseOfFundsFromLargeBanner' ], + [ 'hidesUseOfFundsFromLargeBanner' ] + ] )( '%s', async ( testName: string ) => { + await fallbackBannerFeatures[ testName ]( getWrapperAtWidth ); + } ); + + test.each( [ + [ 'submitsFromLargeBanner' ], + [ 'submitsFromSmallBanner' ] + ] )( '%s', async ( testName: string ) => { + await submitFeatures[ testName ]( getWrapperAtWidth ); + } ); +} ); From dd1e9be2ac092c8ff8e0b40ae3496721adf01804 Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Mon, 18 Nov 2024 12:16:17 +0100 Subject: [PATCH 7/9] Prepare CTRL for C24_WMDE_Desktop_DE_14 - is based on the control banner of desktop-de-13 Ticket: https://phabricator.wikimedia.org/T379950 --- .../C24_WMDE_Desktop_DE_14/banner_ctrl.ts | 3 +- .../C24_WMDE_Desktop_DE_14/banner_var.ts | 8 +- .../components/BannerVar.vue | 171 ------------------ .../C24_WMDE_Desktop_DE_14/event_map_var.ts | 49 ----- .../C24_WMDE_Desktop_DE_14/messages_var.ts | 33 ---- .../styles/styles_var.scss | 55 ------ 6 files changed, 5 insertions(+), 314 deletions(-) delete mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue delete mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts delete mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts delete mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts index c0b50d8ba..512ed5512 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_ctrl.ts @@ -59,8 +59,7 @@ app.use( DynamicTextPlugin, { date, formatters: localeFactory.getFormatters(), impressionCount, - translator, - urgencyMessageDaysLeft: 45 + translator } ); const currencyFormatter = localeFactory.getCurrencyFormatter(); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts index 4473f6217..2be3e1dd8 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts @@ -1,9 +1,9 @@ import { createVueApp } from '@src/createVueApp'; -import './styles/styles_var.scss'; +import './styles/styles.scss'; import BannerConductor from '@src/components/BannerConductor/FallbackBannerConductor.vue'; -import Banner from './components/BannerVar.vue'; +import Banner from './components/BannerCtrl.vue'; import FallbackBanner from './components/FallbackBanner.vue'; import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; import { WindowResizeHandler } from '@src/utils/ResizeHandler'; @@ -16,12 +16,12 @@ import { Translator } from '@src/Translator'; import DynamicTextPlugin from '@src/DynamicTextPlugin'; import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; -import eventMappings from './event_map_var'; +import eventMappings from './event_map'; import { createFallbackDonationURL } from '@src/createFallbackDonationURL'; import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; // Locale-specific imports -import messages from './messages_var'; +import messages from './messages'; import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; // Channel specific form setup diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue deleted file mode 100644 index 9b73613f5..000000000 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue +++ /dev/null @@ -1,171 +0,0 @@ - - - diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts deleted file mode 100644 index c7eb259e7..000000000 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; -import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; -import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; -import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; -import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; -import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; -import { CustomAmountChangedEvent } from '@src/tracking/events/CustomAmountChangedEvent'; -import { CloseEvent } from '@src/tracking/events/CloseEvent'; -import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; -import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; -import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; -import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; -import { AlreadyDonatedShownEvent } from '@src/tracking/events/AlreadyDonatedShownEvent'; -import { FallbackBannerSubmitEvent } from '@src/tracking/events/FallbackBannerSubmitEvent'; -import { ShownEvent } from '@src/tracking/events/ShownEvent'; -import { mapShownEvent } from '@src/tracking/LegacyEventTracking/mapShownEvent'; -import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; -import { CoverTransactionFeesEvent } from '@src/tracking/events/CoverTransactionFeesEvent'; - -export default new Map( [ - [ ShownEvent.EVENT_NAME, mapShownEvent ], - [ CloseEvent.EVENT_NAME, mapCloseEvent ], - [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], - [ CustomAmountChangedEvent.EVENT_NAME, - ( e: CustomAmountChangedEvent ): WMDELegacyBannerEvent => - new WMDELegacyBannerEvent( e.userChoice + '-amount', 1 ) - ], - [ AlreadyDonatedShownEvent.EVENT_NAME, ( e: AlreadyDonatedShownEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ], - [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], - [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { - switch ( e.feature ) { - case 'UpgradeToYearlyForm': - return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); - case 'UpgradeToMonthlyForm': - return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); - default: - return new WMDESizeIssueEvent( `submit`, createViewportInfo(), 1 ); - } - } ], - [ FallbackBannerSubmitEvent.EVENT_NAME, - ( e: FallbackBannerSubmitEvent ): WMDESizeIssueEvent => - new WMDESizeIssueEvent( e.eventName, createViewportInfo(), 1 ) - ], - [ BannerSubmitOnReturnEvent.EVENT_NAME, - ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => - new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) - ], - [ CoverTransactionFeesEvent.EVENT_NAME, ( e: CoverTransactionFeesEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.userChoice + 'cover-transaction-fee', 1 ) ] -] ); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts deleted file mode 100644 index b7c246a89..000000000 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts +++ /dev/null @@ -1,33 +0,0 @@ -import CustomAmountFormDe from '@src/components/DonationForm/Forms/messages/CustomAmountForm.de'; -import DynamicCampaignTextDe from '@src/utils/DynamicContent/messages/DynamicCampaignText.de'; -import { TranslationMessages } from '@src/Translator'; -import UpgradeToYearlyDe from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.de'; -import AddressFormDe from '@src/components/DonationForm/Forms/messages/AddressForm.de'; -import FooterDe from '@src/components/Footer/messages/Footer.de'; -import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/MainDonationForm.de'; -import FallbackBanner from '@src/components/FallbackBanner/messages/FallbackBanner.de'; -import AlreadyDonatedModal from '@src/components/AlreadyDonatedModal/translations/AlreadyDonatedModal.de'; -import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; - -const messages: TranslationMessages = { - ...CustomAmountFormDe, - ...DynamicCampaignTextDe, - ...UpgradeToYearlyDe, - ...AddressFormDe, - ...FooterDe, - ...MainDonationFormDe, - ...AlreadyDonatedModal, - ...FallbackBanner, - ...SoftCloseDe, - 'already-donated-go-away-button': 'Im Moment nicht', - 'soft-close-prompt': 'Dürfen wir später nochmal fragen?', - 'upgrade-to-yearly-copy': `

Jedes Jahr sind wir auf Menschen wie Sie angewiesen. Jährliche Spenden helfen uns besonders und ermöglichen langfristige Weiterentwicklungen.

-

Sie gehen kein Risiko ein: Jederzeit formlos zu sofort kündbar.

`, - 'upgrade-to-yearly-no': 'Nein, ich spende einmalig {{amount}}', - 'upgrade-to-yearly-yes': 'Ja, ich spende {{amount}} jährlich', - 'campaign-day-only-n-days': 'Heute sind es nur noch {{days}} Tage bis zum Ende unserer Spendenkampagne.', - 'custom-amount-placeholder': 'Wahlbetrag', - 'cover-transaction-costs': 'Ich übernehme zusätzlich die Transaktionsgebühren von {{transactionCosts}}, damit 100% meiner Spende ankommt.' -}; - -export default messages; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss deleted file mode 100644 index 3ac13e0af..000000000 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss +++ /dev/null @@ -1,55 +0,0 @@ -// This is the file where we import the theme-specific component styles -@use '../../../../src/themes/Svingle/swatches/skin_default' with ( - $slider: true, - $select-group: true, - $upgrade-to-yearly: true, - $fallback-banner: true, - $progress-bar: true, - $soft-close: true, -); -@use 'src/components/BannerConductor/banner-transition'; -@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; -@use 'Banner'; -@use 'src/themes/UseOfFunds/UseOfFunds'; -@use 'MainBanner' with ( - $banner-height: 357px, - $form-width: 300px -); -@use 'src/themes/Svingle/defaults'; -@use 'src/themes/Svingle/ButtonClose/ButtonClose'; -@use 'src/themes/Svingle/ProgressBar/ProgressBar'; -@use 'src/themes/Svingle/DonationForm/DonationForm'; -@use 'src/themes/Svingle/DonationForm/MultiStepDonation'; -@use 'src/themes/Svingle/DonationForm/SubComponents/SelectGroup'; -@use 'src/themes/Svingle/DonationForm/SubComponents/SelectGroupRadios' with ( - $font-size: 14px -); -@use 'src/themes/Svingle/DonationForm/SubComponents/SelectCustomAmountRadio' with ( - $font-size: 14px -); -@use 'src/themes/Svingle/DonationForm/SubComponents/SmsBox'; -@use 'src/themes/Svingle/DonationForm/SubComponents/TransactionFees'; -@use 'src/themes/Svingle/DonationForm/Forms/MainDonationForm'; -@use 'src/themes/Svingle/DonationForm/Forms/UpgradeToYearlyButtonForm' with ( - $font-size: 14px -); -@use 'src/themes/Svingle/DonationForm/Forms/CustomAmountForm'; -@use 'src/themes/Svingle/Footer/FooterAlreadyDonated'; -@use 'src/themes/Svingle/Footer/SelectionInput'; -@use 'src/themes/Svingle/Message/Message'; -@use 'src/themes/Svingle/SoftClose/SoftClose'; -@use 'src/themes/Svingle/Slider/KeenSlider'; - -/** - * Fallback banner with "Fijitiv" theme - * All selectors in Fijitiv theme are prefixed with the ".wmde-banner-fallback" class selector, - so they override the "default" styles with the same selector - */ -@use 'FallbackBanner'; -@use 'src/themes/Fijitiv/FallbackBanner/FallbackButton'; -@use 'src/themes/Fijitiv/FallbackBanner/LargeFooter'; -@use 'src/themes/Fijitiv/FallbackBanner/SmallFooter'; -@use 'src/themes/Fijitiv/ProgressBar/ProgressBar' as FallbackProgressBar with ( - $progress-bar-margin: 0 15px -); -@use 'src/themes/Fijitiv/Slider/KeenSlider' as FallbackSlider; From 38d1d602c8fa74bf37e0e992b9fd89140ef34e68 Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Mon, 18 Nov 2024 12:27:26 +0100 Subject: [PATCH 8/9] Prepare VAR for C24_WMDE_Desktop_DE_14 Ticket: https://phabricator.wikimedia.org/T379950 --- .../components/BannerVar.vue | 165 ++++++++++++++++++ .../content/BannerSlidesVar.vue | 63 +++++++ .../content/BannerTextVar.vue | 47 +++++ .../C24_WMDE_Desktop_DE_14/event_map_var.ts | 47 +++++ .../C24_WMDE_Desktop_DE_14/messages_var.ts | 32 ++++ .../styles/styles_var.scss | 54 ++++++ 6 files changed, 408 insertions(+) create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlidesVar.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerTextVar.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue new file mode 100644 index 000000000..54ea355f0 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue @@ -0,0 +1,165 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlidesVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlidesVar.vue new file mode 100644 index 000000000..46790f372 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlidesVar.vue @@ -0,0 +1,63 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerTextVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerTextVar.vue new file mode 100644 index 000000000..c004e00e4 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerTextVar.vue @@ -0,0 +1,47 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts new file mode 100644 index 000000000..88eb4714e --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts @@ -0,0 +1,47 @@ +import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; +import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; +import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; +import { CustomAmountChangedEvent } from '@src/tracking/events/CustomAmountChangedEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; +import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; +import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; +import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; +import { AlreadyDonatedShownEvent } from '@src/tracking/events/AlreadyDonatedShownEvent'; +import { FallbackBannerSubmitEvent } from '@src/tracking/events/FallbackBannerSubmitEvent'; +import { ShownEvent } from '@src/tracking/events/ShownEvent'; +import { mapShownEvent } from '@src/tracking/LegacyEventTracking/mapShownEvent'; +import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; + +export default new Map( [ + [ ShownEvent.EVENT_NAME, mapShownEvent ], + [ CloseEvent.EVENT_NAME, mapCloseEvent ], + [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], + [ CustomAmountChangedEvent.EVENT_NAME, + ( e: CustomAmountChangedEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.userChoice + '-amount', 1 ) + ], + [ AlreadyDonatedShownEvent.EVENT_NAME, ( e: AlreadyDonatedShownEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ], + [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], + [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { + switch ( e.feature ) { + case 'UpgradeToYearlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + case 'UpgradeToMonthlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + default: + return new WMDESizeIssueEvent( `submit`, createViewportInfo(), 1 ); + } + } ], + [ FallbackBannerSubmitEvent.EVENT_NAME, + ( e: FallbackBannerSubmitEvent ): WMDESizeIssueEvent => + new WMDESizeIssueEvent( e.eventName, createViewportInfo(), 1 ) + ], + [ BannerSubmitOnReturnEvent.EVENT_NAME, + ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) + ] +] ); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts new file mode 100644 index 000000000..8bb2ea2d4 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts @@ -0,0 +1,32 @@ +import CustomAmountFormDe from '@src/components/DonationForm/Forms/messages/CustomAmountForm.de'; +import DynamicCampaignTextDe from '@src/utils/DynamicContent/messages/DynamicCampaignText.de'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyDe from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.de'; +import AddressFormDe from '@src/components/DonationForm/Forms/messages/AddressForm.de'; +import FooterDe from '@src/components/Footer/messages/Footer.de'; +import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/MainDonationForm.de'; +import FallbackBanner from '@src/components/FallbackBanner/messages/FallbackBanner.de'; +import AlreadyDonatedModal from '@src/components/AlreadyDonatedModal/translations/AlreadyDonatedModal.de'; +import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; + +const messages: TranslationMessages = { + ...CustomAmountFormDe, + ...DynamicCampaignTextDe, + ...UpgradeToYearlyDe, + ...AddressFormDe, + ...FooterDe, + ...MainDonationFormDe, + ...AlreadyDonatedModal, + ...FallbackBanner, + ...SoftCloseDe, + 'already-donated-go-away-button': 'Im Moment nicht', + 'soft-close-prompt': 'Dürfen wir später nochmal fragen?', + 'upgrade-to-yearly-copy': `

Jedes Jahr sind wir auf Menschen wie Sie angewiesen. Jährliche Spenden helfen uns besonders und ermöglichen langfristige Weiterentwicklungen.

+

Sie gehen kein Risiko ein: Jederzeit formlos zu sofort kündbar.

`, + 'upgrade-to-yearly-no': 'Nein, ich spende einmalig {{amount}}', + 'upgrade-to-yearly-yes': 'Ja, ich spende {{amount}} jährlich', + 'campaign-day-only-n-days': 'Heute sind es nur noch {{days}} Tage bis zum Ende unserer Spendenkampagne.', + 'custom-amount-placeholder': 'Wahlbetrag' +}; + +export default messages; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss new file mode 100644 index 000000000..ff644c870 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss @@ -0,0 +1,54 @@ +// This is the file where we import the theme-specific component styles +@use '../../../../src/themes/Svingle/swatches/skin_default' with ( + $slider: true, + $select-group: true, + $upgrade-to-yearly: true, + $fallback-banner: true, + $progress-bar: true, + $soft-close: true, +); +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; +@use 'Banner'; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'MainBanner' with ( + $banner-height: 357px, + $form-width: 300px +); +@use 'src/themes/Svingle/defaults'; +@use 'src/themes/Svingle/ButtonClose/ButtonClose'; +@use 'src/themes/Svingle/ProgressBar/ProgressBar'; +@use 'src/themes/Svingle/DonationForm/DonationForm'; +@use 'src/themes/Svingle/DonationForm/MultiStepDonation'; +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectGroupRadios' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/SubComponents/SelectCustomAmountRadio' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Svingle/DonationForm/Forms/MainDonationForm'; +@use 'src/themes/Svingle/DonationForm/Forms/UpgradeToYearlyButtonForm' with ( + $font-size: 14px +); +@use 'src/themes/Svingle/DonationForm/Forms/CustomAmountForm'; +@use 'src/themes/Svingle/Footer/FooterAlreadyDonated'; +@use 'src/themes/Svingle/Footer/SelectionInput'; +@use 'src/themes/Svingle/Message/Message'; +@use 'src/themes/Svingle/SoftClose/SoftClose'; +@use 'src/themes/Svingle/Slider/KeenSlider'; + +/** + * Fallback banner with "Fijitiv" theme + * All selectors in Fijitiv theme are prefixed with the ".wmde-banner-fallback" class selector, + so they override the "default" styles with the same selector + */ +@use 'FallbackBanner'; +@use 'src/themes/Fijitiv/FallbackBanner/FallbackButton'; +@use 'src/themes/Fijitiv/FallbackBanner/LargeFooter'; +@use 'src/themes/Fijitiv/FallbackBanner/SmallFooter'; +@use 'src/themes/Fijitiv/ProgressBar/ProgressBar' as FallbackProgressBar with ( + $progress-bar-margin: 0 15px +); +@use 'src/themes/Fijitiv/Slider/KeenSlider' as FallbackSlider; From 6a0a29cb29d95ed30450411109b182a6e1bf44b9 Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Mon, 18 Nov 2024 12:59:35 +0100 Subject: [PATCH 9/9] Implement VAR for C24_WMDE_Desktop_DE_14 - adds additional copy - displays the "10 good reasons" overlay when the link in the added copy is clicked - adds styles for the "10 good reasons" button link Ticket: https://phabricator.wikimedia.org/T379953 --- .../C24_WMDE_Desktop_DE_14/banner_var.ts | 13 ++--- .../components/BannerVar.vue | 52 +++++++++++++++++-- .../content/BannerSlidesVar.vue | 21 ++++++-- .../content/BannerTextVar.vue | 37 +++++++++---- .../C24_WMDE_Desktop_DE_14/event_map_var.ts | 13 +++-- .../C24_WMDE_Desktop_DE_14/messages_var.ts | 2 + .../styles/styles_var.scss | 2 + src/themes/Svingle/Message/Message.scss | 16 ++++++ src/themes/Svingle/Slider/KeenSlider.scss | 16 ++++++ src/themes/Svingle/swatches/color_light.scss | 6 +++ .../components/BannerVar.spec.ts | 49 ++++++++++++----- 11 files changed, 187 insertions(+), 40 deletions(-) diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts index 2be3e1dd8..5e239316f 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/banner_var.ts @@ -1,9 +1,9 @@ import { createVueApp } from '@src/createVueApp'; -import './styles/styles.scss'; +import './styles/styles_var.scss'; import BannerConductor from '@src/components/BannerConductor/FallbackBannerConductor.vue'; -import Banner from './components/BannerCtrl.vue'; +import Banner from './components/BannerVar.vue'; import FallbackBanner from './components/FallbackBanner.vue'; import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; import { WindowResizeHandler } from '@src/utils/ResizeHandler'; @@ -16,18 +16,19 @@ import { Translator } from '@src/Translator'; import DynamicTextPlugin from '@src/DynamicTextPlugin'; import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; -import eventMappings from './event_map'; +import eventMappings from './event_map_var'; import { createFallbackDonationURL } from '@src/createFallbackDonationURL'; import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; // Locale-specific imports -import messages from './messages'; +import messages from './messages_var'; import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; // Channel specific form setup import { createFormItems } from './form_items'; import { createFormActions } from '@src/createFormActions'; import { WindowTimer } from '@src/utils/Timer'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; const date = new Date(); const localeFactory = new LocaleFactoryDe(); @@ -46,6 +47,7 @@ const app = createVueApp( BannerConductor, { }, bannerProps: { useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller(), remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'desktop' ) ), localCloseTracker: new LocalStorageCloseTracker(), donationLink: createFallbackDonationURL( page.getTracking(), impressionCount ) @@ -63,8 +65,7 @@ app.use( DynamicTextPlugin, { date, formatters: localeFactory.getFormatters(), impressionCount, - translator, - urgencyMessageDaysLeft: 45 + translator } ); const currencyFormatter = localeFactory.getCurrencyFormatter(); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue index 54ea355f0..3e7c152ad 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue @@ -10,14 +10,21 @@ + + @@ -81,8 +95,8 @@ import { inject, ref, watch } from 'vue'; import { UseOfFundsContent as useOfFundsContentInterface } from '@src/domain/UseOfFunds/UseOfFundsContent'; import MainBanner from './MainBanner.vue'; import FundsModal from '@src/components/UseOfFunds/FundsModal.vue'; -import BannerText from '../content/BannerText.vue'; -import BannerSlides from '../content/BannerSlides.vue'; +import BannerText from '../content/BannerTextVar.vue'; +import BannerSlides from '../content/BannerSlidesVar.vue'; import MultiStepDonation from '@src/components/DonationForm/MultiStepDonation.vue'; import MainDonationForm from '@src/components/DonationForm/Forms/MainDonationForm.vue'; import UpgradeToYearlyButtonForm from '@src/components/DonationForm/Forms/UpgradeToYearlyButtonForm.vue'; @@ -106,6 +120,11 @@ import { LocalCloseTracker } from '@src/utils/LocalCloseTracker'; import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; import { Tracker } from '@src/tracking/Tracker'; import { useBannerHider } from '@src/components/composables/useBannerHider'; +import { ReasonsToDonateShownEvent } from '@src/tracking/events/ReasonsToDonateShownEvent'; +import ReasonsToDonate from '@src/components/ReasonsToDonate/ReasonsToDonate.vue'; +import { ReasonsToDonateItemClickedEvent } from '@src/tracking/events/ReasonsToDonateItemClickedEvent'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; +import { ReasonsToDonateCTAClickedEvent } from '@src/tracking/events/ReasonsToDonateCTAClickedEvent'; enum ContentStates { Main = 'wmde-banner-wrapper--main', @@ -120,17 +139,19 @@ enum FormStepNames { interface Props { bannerState: BannerStates; useOfFundsContent: useOfFundsContentInterface; + pageScroller: PageScroller; remainingImpressions: number; localCloseTracker: LocalCloseTracker; } const props = defineProps(); -const emit = defineEmits( [ 'bannerClosed', 'bannerContentChanged' ] ); +const emit = defineEmits( [ 'bannerClosed', 'bannerContentChanged', 'reasonsToDonate' ] ); useBannerHider( 800, emit ); const tracker = inject( 'tracker' ); const isFundsModalVisible = ref( false ); +const isReasonsToDonateVisible = ref( false ); const contentState = ref( ContentStates.Main ); const formModel = useFormModel(); const stepControllers = [ @@ -150,6 +171,27 @@ const onSubmit = (): void => { } }; +const onShowReasonsToDonate = (): void => { + isReasonsToDonateVisible.value = true; + tracker.trackEvent( new ReasonsToDonateShownEvent() ); +}; +const onReasonsToDonateAccordionItemClicked = ( payload: { itemNumber: string } ): void => { + tracker.trackEvent( new ReasonsToDonateItemClickedEvent( payload.itemNumber ) ); +}; + +const onHideReasonsToDonate = (): void => { + isReasonsToDonateVisible.value = false; +}; + +const onReasonsToDonateCallToActionClicked = (): void => { + tracker.trackEvent( new ReasonsToDonateCTAClickedEvent() ); + + contentState.value = ContentStates.Main; + + props.pageScroller.scrollIntoView( '.wmde-banner-form' ); + isReasonsToDonateVisible.value = false; +}; + function onCloseMain(): void { if ( props.remainingImpressions > 0 ) { contentState.value = ContentStates.SoftClosing; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlidesVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlidesVar.vue index 46790f372..a648e683b 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlidesVar.vue +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/content/BannerSlidesVar.vue @@ -28,24 +28,32 @@

- Dann entscheiden Sie sich, eine der seltenen Ausnahmen zu sein, und geben Sie etwas zurück. Vielen Dank! + Dann entscheiden Sie sich, eine der seltenen Ausnahmen zu sein, und geben Sie etwas zurück. Falls Sie zögern, + + für eine Spende. Vielen Dank!

diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts index 88eb4714e..20ef6d038 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/event_map_var.ts @@ -15,6 +15,9 @@ import { FallbackBannerSubmitEvent } from '@src/tracking/events/FallbackBannerSu import { ShownEvent } from '@src/tracking/events/ShownEvent'; import { mapShownEvent } from '@src/tracking/LegacyEventTracking/mapShownEvent'; import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; +import { ReasonsToDonateShownEvent } from '@src/tracking/events/ReasonsToDonateShownEvent'; +import { ReasonsToDonateCTAClickedEvent } from '@src/tracking/events/ReasonsToDonateCTAClickedEvent'; +import { ReasonsToDonateItemClickedEvent } from '@src/tracking/events/ReasonsToDonateItemClickedEvent'; export default new Map( [ [ ShownEvent.EVENT_NAME, mapShownEvent ], @@ -41,7 +44,11 @@ export default new Map( [ new WMDESizeIssueEvent( e.eventName, createViewportInfo(), 1 ) ], [ BannerSubmitOnReturnEvent.EVENT_NAME, - ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => - new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) - ] + ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) + ], + [ ReasonsToDonateShownEvent.EVENT_NAME, ( e: ReasonsToDonateShownEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ], + [ ReasonsToDonateItemClickedEvent.EVENT_NAME, ( e: ReasonsToDonateItemClickedEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) + ], + [ ReasonsToDonateCTAClickedEvent.EVENT_NAME, ( e: ReasonsToDonateCTAClickedEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ] ] ); diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts index 8bb2ea2d4..009333f1d 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/messages_var.ts @@ -8,6 +8,7 @@ import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/Main import FallbackBanner from '@src/components/FallbackBanner/messages/FallbackBanner.de'; import AlreadyDonatedModal from '@src/components/AlreadyDonatedModal/translations/AlreadyDonatedModal.de'; import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; +import ReasonsToDonate from '@src/components/ReasonsToDonate/messages/ReasonsToDonate.de'; const messages: TranslationMessages = { ...CustomAmountFormDe, @@ -19,6 +20,7 @@ const messages: TranslationMessages = { ...AlreadyDonatedModal, ...FallbackBanner, ...SoftCloseDe, + ...ReasonsToDonate, 'already-donated-go-away-button': 'Im Moment nicht', 'soft-close-prompt': 'Dürfen wir später nochmal fragen?', 'upgrade-to-yearly-copy': `

Jedes Jahr sind wir auf Menschen wie Sie angewiesen. Jährliche Spenden helfen uns besonders und ermöglichen langfristige Weiterentwicklungen.

diff --git a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss index ff644c870..d0f316b14 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss +++ b/banners/desktop/C24_WMDE_Desktop_DE_14/styles/styles_var.scss @@ -52,3 +52,5 @@ $progress-bar-margin: 0 15px ); @use 'src/themes/Fijitiv/Slider/KeenSlider' as FallbackSlider; +@use 'src/components/ReasonsToDonate/styles/swatches/skin_default' as reasons-default; +@use 'src/components/ReasonsToDonate/styles/ReasonsToDonate'; diff --git a/src/themes/Svingle/Message/Message.scss b/src/themes/Svingle/Message/Message.scss index e9c27dd1b..54f08cb75 100644 --- a/src/themes/Svingle/Message/Message.scss +++ b/src/themes/Svingle/Message/Message.scss @@ -39,5 +39,21 @@ $font-sizes: ( breakpoints.$extra-small: 18px ) !default; text-align: center; padding-bottom: 15px; } + + button { + all: unset; + } + + button, + a { + color: var( --message-link ); + text-decoration: underline; + cursor: pointer; + + &:hover, + &:focus { + color: var( --message-link-hover ); + } + } } } diff --git a/src/themes/Svingle/Slider/KeenSlider.scss b/src/themes/Svingle/Slider/KeenSlider.scss index 37368198f..6fdd0e33d 100644 --- a/src/themes/Svingle/Slider/KeenSlider.scss +++ b/src/themes/Svingle/Slider/KeenSlider.scss @@ -47,6 +47,22 @@ $margin-bottom: 15px !default; p:last-child { margin: 0; } + + button { + all: unset; + } + + button, + a { + color: var( --message-link ); + text-decoration: underline; + cursor: pointer; + + &:hover, + &:focus { + color: var( --message-link-hover ); + } + } } &-title { diff --git a/src/themes/Svingle/swatches/color_light.scss b/src/themes/Svingle/swatches/color_light.scss index 491b138da..af7c99c8d 100644 --- a/src/themes/Svingle/swatches/color_light.scss +++ b/src/themes/Svingle/swatches/color_light.scss @@ -1,3 +1,6 @@ +$yellow100: #ffee00; +$yellow200: #ffef9d; + $white: #ffffff; $black: #000000; @@ -43,6 +46,9 @@ $blue700: #2a4b8d; --message-color: #{$white}; --message-border: #{$red600}; + --message-link: #{$yellow100}; + --message-link-hover: #{$yellow200}; + --color-error: #{$red600}; --button-close-fill: #{$grey600}; --button-background: #{$red600}; diff --git a/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.spec.ts b/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.spec.ts index bd8057de4..f32edeea5 100644 --- a/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.spec.ts +++ b/test/banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.spec.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, test, vi } from 'vitest'; +import { beforeEach, describe, Mock, test, vi } from 'vitest'; import { mount, VueWrapper } from '@vue/test-utils'; import Banner from '@banners/desktop/C24_WMDE_Desktop_DE_14/components/BannerVar.vue'; import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; @@ -14,7 +14,6 @@ import { bannerContentFeatures } from '@test/features/BannerContent'; import { donationFormFeatures } from '@test/features/forms/MainDonation_UpgradeToYearlyButton'; -import { donationFormTransactionFeeFeatures } from '@test/features/forms/MainDonation_TransactionFee'; import { useFormModel } from '@src/components/composables/useFormModel'; import { resetFormModel } from '@test/resetFormModel'; import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; @@ -26,18 +25,33 @@ import { softCloseSubmitTrackingFeaturesDesktop } from '@test/features/SoftClose import { Tracker } from '@src/tracking/Tracker'; import { Timer } from '@src/utils/Timer'; import { TimerStub } from '@test/fixtures/TimerStub'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; +import { useReasonsToDonateFeatures, useReasonsToDonateScrollFeatures } from '@test/features/ReasonsToDonate'; const formModel = useFormModel(); const translator = ( key: string, context: any ): string => context ? `${key} -- ${Object.entries( context )}` : key; +let pageScroller: PageScroller; let tracker: Tracker; describe( 'BannerVar.vue', () => { + let showCallback: Mock; + let closeCallback: Mock; beforeEach( () => { resetFormModel( formModel ); + pageScroller = { + scrollIntoView: vi.fn(), + scrollToTop: vi.fn() + }; tracker = { trackEvent: vi.fn() }; + + // for the reasonsToDonate feature + showCallback = vi.fn(); + closeCallback = vi.fn(); + HTMLDialogElement.prototype.showModal = showCallback; + HTMLDialogElement.prototype.close = closeCallback; } ); const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { @@ -46,6 +60,7 @@ describe( 'BannerVar.vue', () => { props: { bannerState: BannerStates.Pending, useOfFundsContent, + pageScroller, remainingImpressions: 10, localCloseTracker: { getItem: () => '', @@ -66,7 +81,7 @@ describe( 'BannerVar.vue', () => { }, currencyFormatter: new CurrencyEn(), formItems, - tracker, + tracker: tracker, timer: timer ?? new TimerStub() } } @@ -138,16 +153,6 @@ describe( 'BannerVar.vue', () => { } ); } ); - describe( 'Donation Form Transaction Fees', () => { - test.each( [ - [ 'expectMainDonationFormShowsTransactionFeeForPayPalAndCreditCard' ], - [ 'expectMainDonationFormSetsSubmitValuesWithTransactionFee' ], - [ 'expectUpsellFormHasTransactionFee' ] - ] )( '%s', async ( testName: string ) => { - await donationFormTransactionFeeFeatures[ testName ]( getWrapper() ); - } ); - } ); - describe( 'Soft Close', () => { test.each( [ [ 'expectShowsSoftClose' ], @@ -187,4 +192,22 @@ describe( 'BannerVar.vue', () => { await useOfFundsFeatures[ testName ]( getWrapper() ); } ); } ); + + describe( 'Reasons to Donate', () => { + test.each( [ + [ 'expectContainsReasonsToDonateDialogue' ], + [ 'expectTracksReasonsToDonateShownEvent' ], + [ 'expectTracksReasonsToDonateCTAClickedEvent' ], + [ 'expectTracksReasonsToDonateItemClickedEvent' ] + ] )( '%s', async ( testName: string ) => { + await useReasonsToDonateFeatures[ testName ]( getWrapper(), tracker ); + } ); + + test.each( [ + [ 'expectScrollsToFormWhenCallToActionIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await useReasonsToDonateScrollFeatures[ testName ]( getWrapper(), pageScroller ); + } ); + } ); + } );