From b8a86350f63d2c90046f9d87eefb46f12c4a72b6 Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Thu, 5 Dec 2024 13:19:04 +0100 Subject: [PATCH 1/6] Prepare campaign for C24_WMDE_Desktop_DE_19 Ticket: https://phabricator.wikimedia.org/T380852 --- .../C24_WMDE_Desktop_DE_19/banner_ctrl.ts | 73 +++++++ .../C24_WMDE_Desktop_DE_19/banner_var.ts | 73 +++++++ .../components/BannerCtrl.vue | 170 +++++++++++++++++ .../components/BannerVar.vue | 170 +++++++++++++++++ .../components/FallbackBanner.vue | 108 +++++++++++ .../components/MainBanner.vue | 47 +++++ .../content/BannerSlides.vue | 48 +++++ .../content/BannerText.vue | 32 ++++ .../content/BannerTitle.vue | 19 ++ .../content/FallbackSlides.vue | 27 +++ .../content/FallbackText.vue | 25 +++ .../C24_WMDE_Desktop_DE_19/event_map.ts | 47 +++++ .../C24_WMDE_Desktop_DE_19/form_items.ts | 23 +++ .../C24_WMDE_Desktop_DE_19/messages.ts | 32 ++++ .../C24_WMDE_Desktop_DE_19/messages_var.ts | 33 ++++ .../C24_WMDE_Desktop_DE_19/styles/Banner.scss | 22 +++ .../styles/FallbackBanner.scss | 121 ++++++++++++ .../styles/MainBanner.scss | 58 ++++++ .../C24_WMDE_Desktop_DE_19/styles/styles.scss | 60 ++++++ campaign_info.toml | 18 +- .../components/BannerCtrl.spec.ts | 178 ++++++++++++++++++ .../components/BannerVar.spec.ts | 178 ++++++++++++++++++ .../components/FallbackBanner.spec.ts | 58 ++++++ 23 files changed, 1611 insertions(+), 9 deletions(-) create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/banner_ctrl.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/components/MainBanner.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerSlides.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerText.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerTitle.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/content/FallbackSlides.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/content/FallbackText.vue create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/event_map.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/form_items.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/messages.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/messages_var.ts create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/styles/Banner.scss create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/styles/FallbackBanner.scss create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/styles/MainBanner.scss create mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles.scss create mode 100644 test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.spec.ts create mode 100644 test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.spec.ts create mode 100644 test/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.spec.ts diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/banner_ctrl.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/banner_ctrl.ts new file mode 100644 index 000000000..512ed5512 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/banner_ctrl.ts @@ -0,0 +1,73 @@ +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 +} ); + +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_19/banner_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts new file mode 100644 index 000000000..7f9335664 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts @@ -0,0 +1,73 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles.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'; +import { createFallbackDonationURL } from '@src/createFallbackDonationURL'; +import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; +import messages from './messages_var'; +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 +} ); + +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_19/components/BannerCtrl.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue new file mode 100644 index 000000000..8387c894c --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue @@ -0,0 +1,170 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue new file mode 100644 index 000000000..8387c894c --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue @@ -0,0 +1,170 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue new file mode 100644 index 000000000..6550131fa --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue @@ -0,0 +1,108 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/components/MainBanner.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/MainBanner.vue new file mode 100644 index 000000000..20c886d6c --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/MainBanner.vue @@ -0,0 +1,47 @@ +tart + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerSlides.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerSlides.vue new file mode 100644 index 000000000..991443c11 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerSlides.vue @@ -0,0 +1,48 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerText.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerText.vue new file mode 100644 index 000000000..e7280312f --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerText.vue @@ -0,0 +1,32 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerTitle.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerTitle.vue new file mode 100644 index 000000000..ff61ed34e --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/content/BannerTitle.vue @@ -0,0 +1,19 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/content/FallbackSlides.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/content/FallbackSlides.vue new file mode 100644 index 000000000..b5e4af29d --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/content/FallbackSlides.vue @@ -0,0 +1,27 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/content/FallbackText.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/content/FallbackText.vue new file mode 100644 index 000000000..f3622de30 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/content/FallbackText.vue @@ -0,0 +1,25 @@ + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/event_map.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/event_map.ts new file mode 100644 index 000000000..88eb4714e --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/form_items.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/form_items.ts new file mode 100644 index 000000000..b70650d19 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/messages.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/messages.ts new file mode 100644 index 000000000..8bb2ea2d4 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/messages_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/messages_var.ts new file mode 100644 index 000000000..6719de775 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/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', + 'upgrade-to-yearly-header': 'Bitte spenden Sie {{amount}} jährlich!' +}; + +export default messages; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/styles/Banner.scss b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/Banner.scss new file mode 100644 index 000000000..1e7d13842 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/styles/FallbackBanner.scss b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/FallbackBanner.scss new file mode 100644 index 000000000..a0d40542d --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/styles/MainBanner.scss b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/MainBanner.scss new file mode 100644 index 000000000..1bf067da0 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/MainBanner.scss @@ -0,0 +1,58 @@ +$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 { + height: auto; + } + + &-message-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 11px; + } + + &-column-left { + display: flex; + flex-direction: column; + justify-content: center; + flex: 1 1 auto; + margin-bottom: 0; + overflow-y: hidden; + margin-right: 30px; + padding: 0 0 10px; + background: var( --message-background ); + border: 5px solid var( --message-border ); + border-radius: 9px; + } + + &-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_19/styles/styles.scss b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles.scss new file mode 100644 index 000000000..66b555cbc --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles.scss @@ -0,0 +1,60 @@ +// This is the file where we import the theme-specific component styles +@use 'src/themes/Treedip/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/Treedip/defaults'; +@use 'src/themes/Treedip/ButtonClose/ButtonClose'; +@use 'src/themes/Treedip/ProgressBar/ProgressBar' with ( + $progress-bar-margin: 0 15px +); +@use 'src/themes/Treedip/DonationForm/DonationForm'; +@use 'src/themes/Treedip/DonationForm/MultiStepDonation'; +@use 'src/themes/Treedip/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Treedip/DonationForm/SubComponents/SelectGroupRadios'; +@use 'src/themes/Treedip/DonationForm/SubComponents/SelectCustomAmountRadio'; +@use 'src/themes/Treedip/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Treedip/DonationForm/Forms/MainDonationForm'; +@use 'src/themes/Treedip/DonationForm/Forms/UpgradeToYearlyButtonForm' with ( + $font-size: 14px +); +@use 'src/themes/Treedip/DonationForm/Forms/CustomAmountForm'; +@use 'src/themes/Treedip/Footer/FooterAlreadyDonated'; +@use 'src/themes/Treedip/Footer/SelectionInput'; +@use 'src/themes/Treedip/Message/Message' with ( + $slider-main-headline-font-size: 25px, + $message-header-padding-bottom: 8px, + $message-header-small-up-padding-bottom: 8px, + $message-header-padding-top: 20px, + $message-header-small-up-padding-top: 20px +); +@use 'src/themes/Treedip/SoftClose/SoftClose'; +@use 'src/themes/Treedip/Slider/KeenSlider' with ( + $slider-padding: 0 +); + +/** + * 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 2d2c06dd8..0f66d09f7 100644 --- a/campaign_info.toml +++ b/campaign_info.toml @@ -6,9 +6,9 @@ [desktop] name = "Desktop" icon = "desktop" -campaign = "C24_WMDE_Desktop_DE_18" -description = "Based on ctrl 17, VAR has text change on second banner form page" -campaign_tracking = "18-ba-241202" +campaign = "C24_WMDE_Desktop_DE_19" +description = "Based on ----- of -----, VAR ----- " +campaign_tracking = "19-ba-241209" preview_link = "/wiki/Hamster?devbanner={{banner}}&banner=B22_WMDE_local_prototype" preview_link_darkmode = "/wiki/Hamster?devbanner={{banner}}&banner=B22_WMDE_local_prototype&vectornightmode=1" preview_url = 'https://de.wikipedia.org/wiki/Hamster?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_18/banner_ctrl.ts" -pagename = "B24_WMDE_Desktop_DE_18_ctrl" -tracking = "org-18-241202-ctrl" +filename = "./banners/desktop/C24_WMDE_Desktop_DE_19/banner_ctrl.ts" +pagename = "B24_WMDE_Desktop_DE_19_ctrl" +tracking = "org-19-241209-ctrl" [desktop.banners.var] -filename = "./banners/desktop/C24_WMDE_Desktop_DE_18/banner_var.ts" -pagename = "B24_WMDE_Desktop_DE_18_var" -tracking = "org-18-241202-var" +filename = "./banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts" +pagename = "B24_WMDE_Desktop_DE_19_var" +tracking = "org-19-241209-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_19/components/BannerCtrl.spec.ts b/test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.spec.ts new file mode 100644 index 000000000..f1b945138 --- /dev/null +++ b/test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.spec.ts @@ -0,0 +1,178 @@ +import { beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/desktop/C24_WMDE_Desktop_DE_19/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( [ + [ 'expectShowsLiveDateAndTimeInTitle' ] + ] )( '%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_19/components/BannerVar.spec.ts b/test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.spec.ts new file mode 100644 index 000000000..bef9b4697 --- /dev/null +++ b/test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.spec.ts @@ -0,0 +1,178 @@ +import { beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/desktop/C24_WMDE_Desktop_DE_19/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 { 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( [ + [ 'expectShowsLiveDateAndTimeInTitle' ] + ] )( '%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_19/components/FallbackBanner.spec.ts b/test/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.spec.ts new file mode 100644 index 000000000..ac52c2379 --- /dev/null +++ b/test/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/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 2284ed7cf3a9e1e1de4911cbfb7a1c932bdf25f7 Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Thu, 5 Dec 2024 14:19:15 +0100 Subject: [PATCH 2/6] Prepare CTRL for C24_WMDE_Desktop_DE_19 - The banner is based on the `VAR` banner of desktop-de-18 - Emit the event `modalOpened` when the use of funds modal is opened - Emit the event `modalClosed` when the use of funds modal is closed - Add fallback banner slider colors to Treedip - we might change that in the future Ticket: https://phabricator.wikimedia.org/T380852 --- .../C24_WMDE_Desktop_DE_19/banner_var.ts | 4 +- .../components/BannerCtrl.vue | 16 +- .../components/BannerVar.vue | 170 ----------------- .../C24_WMDE_Desktop_DE_19/messages.ts | 3 +- .../C24_WMDE_Desktop_DE_19/messages_var.ts | 33 ---- src/themes/Treedip/swatches/color_light.scss | 7 + .../components/BannerVar.spec.ts | 178 ------------------ 7 files changed, 24 insertions(+), 387 deletions(-) delete mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue delete mode 100644 banners/desktop/C24_WMDE_Desktop_DE_19/messages_var.ts delete mode 100644 test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.spec.ts diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts index 7f9335664..512ed5512 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts @@ -3,7 +3,7 @@ import { createVueApp } from '@src/createVueApp'; 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'; @@ -19,7 +19,7 @@ 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_var'; +import messages from './messages'; import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; import { createFormItems } from './form_items'; import { createFormActions } from '@src/createFormActions'; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue index 8387c894c..cfb4355b2 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue @@ -51,7 +51,7 @@ @@ -70,7 +70,7 @@ + + @@ -76,6 +83,13 @@ + + @@ -111,6 +125,12 @@ import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnRe import { Tracker } from '@src/tracking/Tracker'; import { useBannerHider } from '@src/components/composables/useBannerHider'; import BannerTitle from '@banners/desktop/C24_WMDE_Desktop_DE_15/content/BannerTitle.vue'; +import TenGoodReasonsSticker from '@banners/desktop/C24_WMDE_Desktop_DE_19/content/TenGoodReasonsSticker.vue'; +import ReasonsToDonate from '@src/components/ReasonsToDonate/ReasonsToDonate.vue'; +import { ReasonsToDonateShownEvent } from '@src/tracking/events/ReasonsToDonateShownEvent'; +import { ReasonsToDonateItemClickedEvent } from '@src/tracking/events/ReasonsToDonateItemClickedEvent'; +import { ReasonsToDonateCTAClickedEvent } from '@src/tracking/events/ReasonsToDonateCTAClickedEvent'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; enum ContentStates { Main = 'wmde-banner-wrapper--main', @@ -125,6 +145,7 @@ enum FormStepNames { interface Props { bannerState: BannerStates; useOfFundsContent: useOfFundsContentInterface; + pageScroller: PageScroller; remainingImpressions: number; localCloseTracker: LocalCloseTracker; } @@ -136,6 +157,7 @@ useBannerHider( 800, emit ); const tracker = inject( 'tracker' ); const isFundsModalVisible = ref( false ); +const isTenGoodReasonsModalVisible = ref( false ); const contentState = ref( ContentStates.Main ); const formModel = useFormModel(); const stepControllers = [ @@ -177,4 +199,26 @@ function onModalOpened(): void { emit( 'modalOpened' ); } +function onTenGoodReasonsModalOpened(): void { + isTenGoodReasonsModalVisible.value = true; + tracker.trackEvent( new ReasonsToDonateShownEvent() ); + emit( 'modalOpened' ); +} + +function onHideTenGoodReasonsModal(): void { + isTenGoodReasonsModalVisible.value = false; + emit( 'modalClosed' ); +} + +const onReasonsToDonateCallToActionClicked = (): void => { + isTenGoodReasonsModalVisible.value = false; + contentState.value = ContentStates.Main; + props.pageScroller.scrollIntoView( '.wmde-banner-form' ); + tracker.trackEvent( new ReasonsToDonateCTAClickedEvent() ); + emit( 'modalClosed' ); +}; + +const onReasonsToDonateAccordionItemClicked = ( payload: { itemNumber: string } ): void => { + tracker.trackEvent( new ReasonsToDonateItemClickedEvent( payload.itemNumber ) ); +}; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/components/MainBannerVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/MainBannerVar.vue index 28487b50b..c0f18f950 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/components/MainBannerVar.vue +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/MainBannerVar.vue @@ -11,6 +11,7 @@
+
diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/content/TenGoodReasonsSticker.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/content/TenGoodReasonsSticker.vue new file mode 100644 index 000000000..09fe2f849 --- /dev/null +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/content/TenGoodReasonsSticker.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/event_map_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/event_map_var.ts index 88eb4714e..20ef6d038 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/event_map_var.ts +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/messages_var.ts b/banners/desktop/C24_WMDE_Desktop_DE_19/messages_var.ts index 6719de775..2b7726d8b 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/messages_var.ts +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/styles/MainBannerVar.scss b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/MainBannerVar.scss index 1bf067da0..a17753a1e 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/styles/MainBannerVar.scss +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/MainBannerVar.scss @@ -54,5 +54,6 @@ $form-width: 300px !default; flex-direction: column; width: $form-width; padding: 10px 0 0; + position: relative; } } diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss index 0412c5b7e..59f607857 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss @@ -58,3 +58,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/campaign_info.toml b/campaign_info.toml index 0f66d09f7..08396ef98 100644 --- a/campaign_info.toml +++ b/campaign_info.toml @@ -7,8 +7,8 @@ name = "Desktop" icon = "desktop" campaign = "C24_WMDE_Desktop_DE_19" -description = "Based on ----- of -----, VAR ----- " -campaign_tracking = "19-ba-241209" +description = "Based on VAR of desktop-de-18, VAR has TenGoodReasonsSticker" +campaign_tracking = "19-ba-241210" preview_link = "/wiki/Hamster?devbanner={{banner}}&banner=B22_WMDE_local_prototype" preview_link_darkmode = "/wiki/Hamster?devbanner={{banner}}&banner=B22_WMDE_local_prototype&vectornightmode=1" preview_url = 'https://de.wikipedia.org/wiki/Hamster?banner={{banner}}&devMode' @@ -19,12 +19,12 @@ use_of_funds_source = "MediaWiki:WMDE_Fundraising/UseOfFunds_2024_DE" [desktop.banners.ctrl] filename = "./banners/desktop/C24_WMDE_Desktop_DE_19/banner_ctrl.ts" pagename = "B24_WMDE_Desktop_DE_19_ctrl" -tracking = "org-19-241209-ctrl" +tracking = "org-19-241210-ctrl" [desktop.banners.var] filename = "./banners/desktop/C24_WMDE_Desktop_DE_19/banner_var.ts" pagename = "B24_WMDE_Desktop_DE_19_var" -tracking = "org-19-241209-var" +tracking = "org-19-241210-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_19/components/BannerVar.spec.ts b/test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.spec.ts index d7ff708d7..dd1ae059f 100644 --- a/test/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.spec.ts +++ b/test/banners/desktop/C24_WMDE_Desktop_DE_19/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_19/components/BannerVar.vue'; import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; @@ -9,7 +9,6 @@ import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; import { useOfFundsFeatures } from '@test/features/UseOfFunds'; import { bannerContentAnimatedTextFeatures, - bannerContentDateAndTimeFeatures, bannerContentDisplaySwitchFeatures, bannerContentFeatures } from '@test/features/BannerContent'; @@ -23,20 +22,35 @@ 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'; +import { TimerStub } from '@test/fixtures/TimerStub'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; +import { useReasonsToDonateFeaturesUsingTenGoodReasonsSticker, useReasonsToDonateScrollFeaturesUsingTenGoodReasonsSticker } from '@test/features/ReasonsToDonate'; const formModel = useFormModel(); -const translator = ( key: string ): string => key; +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 => { @@ -45,6 +59,7 @@ describe( 'BannerVar.vue', () => { props: { bannerState: BannerStates.Pending, useOfFundsContent, + pageScroller, remainingImpressions: 10, localCloseTracker: { getItem: () => '', @@ -65,7 +80,7 @@ describe( 'BannerVar.vue', () => { }, currencyFormatter: new CurrencyEn(), formItems, - tracker, + tracker: tracker, timer: timer ?? new TimerStub() } } @@ -107,12 +122,6 @@ describe( 'BannerVar.vue', () => { ] )( '%s', async ( testName: string ) => { await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); } ); - - test.each( [ - [ 'expectShowsLiveDateAndTimeInTitle' ] - ] )( '%s', async ( testName: string ) => { - await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); - } ); } ); describe( 'Donation Form Happy Paths', () => { @@ -175,4 +184,22 @@ describe( 'BannerVar.vue', () => { await useOfFundsFeatures[ testName ]( getWrapper() ); } ); } ); + + describe( 'Reasons to Donate', () => { + test.each( [ + [ 'expectContainsReasonsToDonateDialogue' ], + [ 'expectTracksReasonsToDonateShownEventUsingTenGoodReasonsSticker' ], + [ 'expectTracksReasonsToDonateCTAClickedEventUsingTenGoodReasonsSticker' ], + [ 'expectTracksReasonsToDonateItemClickedEventUsingTenGoodReasonsSticker' ] + ] )( '%s', async ( testName: string ) => { + await useReasonsToDonateFeaturesUsingTenGoodReasonsSticker[ testName ]( getWrapper(), tracker ); + } ); + + test.each( [ + [ 'expectScrollsToFormWhenCallToActionIsClickedUsingTenGoodReasonsSticker' ] + ] )( '%s', async ( testName: string ) => { + await useReasonsToDonateScrollFeaturesUsingTenGoodReasonsSticker[ testName ]( getWrapper(), pageScroller ); + } ); + } ); + } ); diff --git a/test/features/ReasonsToDonate.ts b/test/features/ReasonsToDonate.ts index ca9593977..f282eaf6f 100644 --- a/test/features/ReasonsToDonate.ts +++ b/test/features/ReasonsToDonate.ts @@ -19,6 +19,14 @@ const expectScrollsToFormWhenCallToActionIsClicked = async ( wrapper: VueWrapper expect( pageScroller.scrollIntoView ).toHaveBeenCalledWith( '.wmde-banner-form' ); }; +const expectScrollsToFormWhenCallToActionIsClickedUsingTenGoodReasonsSticker = async ( wrapper: VueWrapper, pageScroller: PageScroller ): Promise => { + await wrapper.find( '.ten-good-reasons-sticker-text' ).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' ); @@ -27,6 +35,14 @@ const expectTracksReasonsToDonateShownEvent = async ( wrapper: VueWrapper, expect( tracker.trackEvent ).toHaveBeenCalledWith( new ReasonsToDonateShownEvent() ); }; +const expectTracksReasonsToDonateShownEventUsingTenGoodReasonsSticker = async ( wrapper: VueWrapper, tracker: Tracker ): Promise => { + + await wrapper.find( '.ten-good-reasons-sticker-text' ).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' ); @@ -36,6 +52,15 @@ const expectTracksReasonsToDonateCTAClickedEvent = async ( wrapper: VueWrapper, tracker: Tracker ): Promise => { + await wrapper.find( '.ten-good-reasons-sticker-text' ).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' ); @@ -45,14 +70,33 @@ const expectTracksReasonsToDonateItemClickedEvent = async ( wrapper: VueWrapper< expect( tracker.trackEvent ).toHaveBeenCalledWith( new ReasonsToDonateItemClickedEvent( itemNumber ) ); }; +const expectTracksReasonsToDonateItemClickedEventUsingTenGoodReasonsSticker = async ( wrapper: VueWrapper, tracker: Tracker ): Promise => { + await wrapper.find( '.ten-good-reasons-sticker-text' ).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 useReasonsToDonateFeaturesUsingTenGoodReasonsSticker: Record, tracker: Tracker ) => Promise> = { + expectContainsReasonsToDonateDialogue, + expectTracksReasonsToDonateShownEventUsingTenGoodReasonsSticker, + expectTracksReasonsToDonateCTAClickedEventUsingTenGoodReasonsSticker, + expectTracksReasonsToDonateItemClickedEventUsingTenGoodReasonsSticker }; export const useReasonsToDonateScrollFeatures: Record, pageScroller: PageScroller ) => Promise> = { expectScrollsToFormWhenCallToActionIsClicked }; + +export const useReasonsToDonateScrollFeaturesUsingTenGoodReasonsSticker: Record, pageScroller: PageScroller ) => Promise> = { + expectScrollsToFormWhenCallToActionIsClickedUsingTenGoodReasonsSticker +}; From ea7e7759a7a8da677deffb83fcd63e5f62f9b723 Mon Sep 17 00:00:00 2001 From: Corinna Hillebrand Date: Wed, 11 Dec 2024 15:06:06 +0100 Subject: [PATCH 5/6] Prepare C24_WMDE_Desktop_DE_19 for lateprogress - enable lateprogress in the local dev environment - use ProgressBarAlternative to show donation goal to the right of the bar - use ProgressBarAlternative in FallbackBanner as well https://phabricator.wikimedia.org/T381957 --- .../C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue | 2 +- .../C24_WMDE_Desktop_DE_19/components/BannerVar.vue | 2 +- .../C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue | 4 ++-- banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles.scss | 2 +- .../desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss | 2 +- dashboard/wpde-offline/index.html | 2 +- src/themes/Fijitiv/ProgressBar/ProgressBar.scss | 7 ++++--- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue index cfb4355b2..036ddaf9b 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerCtrl.vue @@ -104,7 +104,7 @@ import { TrackingFeatureName } from '@src/tracking/TrackingEvent'; import ButtonClose from '@src/components/ButtonClose/ButtonClose.vue'; import FooterAlreadyDonated from '@src/components/Footer/FooterAlreadyDonated.vue'; import WMDEFundsForwardingDE from '@src/components/UseOfFunds/Infographics/WMDEFundsForwardingDE.vue'; -import ProgressBar from '@src/components/ProgressBar/ProgressBar.vue'; +import ProgressBar from '@src/components/ProgressBar/ProgressBarAlternative.vue'; import SoftClose from '@src/components/SoftClose/SoftClose.vue'; import { LocalCloseTracker } from '@src/utils/LocalCloseTracker'; import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue index ce0ae5cc7..8e1873064 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/BannerVar.vue @@ -118,7 +118,7 @@ import { TrackingFeatureName } from '@src/tracking/TrackingEvent'; import ButtonClose from '@src/components/ButtonClose/ButtonClose.vue'; import FooterAlreadyDonated from '@src/components/Footer/FooterAlreadyDonated.vue'; import WMDEFundsForwardingDE from '@src/components/UseOfFunds/Infographics/WMDEFundsForwardingDE.vue'; -import ProgressBar from '@src/components/ProgressBar/ProgressBar.vue'; +import ProgressBar from '@src/components/ProgressBar/ProgressBarAlternative.vue'; import SoftClose from '@src/components/SoftClose/SoftClose.vue'; import { LocalCloseTracker } from '@src/utils/LocalCloseTracker'; import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue b/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue index 6550131fa..fb4324559 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/components/FallbackBanner.vue @@ -31,7 +31,7 @@
- +
@@ -71,7 +71,7 @@ import LargeFooter from '@src/components/FallbackBanner/LargeFooter.vue'; import { Tracker } from '@src/tracking/Tracker'; import { FallbackBannerSubmitEvent } from '@src/tracking/events/FallbackBannerSubmitEvent'; import WMDEFundsForwardingDE from '@src/components/UseOfFunds/Infographics/WMDEFundsForwardingDE.vue'; -import ProgressBar from '@src/components/ProgressBar/ProgressBar.vue'; +import ProgressBarAlternative from '@src/components/ProgressBar/ProgressBarAlternative.vue'; interface Props { bannerState: BannerStates; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles.scss b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles.scss index 66b555cbc..4e305ee1c 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles.scss +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles.scss @@ -17,7 +17,7 @@ ); @use 'src/themes/Treedip/defaults'; @use 'src/themes/Treedip/ButtonClose/ButtonClose'; -@use 'src/themes/Treedip/ProgressBar/ProgressBar' with ( +@use 'src/themes/Treedip/ProgressBar/ProgressBarAlternative' with ( $progress-bar-margin: 0 15px ); @use 'src/themes/Treedip/DonationForm/DonationForm'; diff --git a/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss index 59f607857..554c16338 100644 --- a/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss +++ b/banners/desktop/C24_WMDE_Desktop_DE_19/styles/styles_var.scss @@ -17,7 +17,7 @@ ); @use 'src/themes/Treedip/defaults'; @use 'src/themes/Treedip/ButtonClose/ButtonClose'; -@use 'src/themes/Treedip/ProgressBar/ProgressBar' with ( +@use 'src/themes/Treedip/ProgressBar/ProgressBarAlternative' with ( $progress-bar-margin: 0 15px ); @use 'src/themes/Treedip/DonationForm/DonationForm'; diff --git a/dashboard/wpde-offline/index.html b/dashboard/wpde-offline/index.html index 5ddf3e8f8..db49168e0 100644 --- a/dashboard/wpde-offline/index.html +++ b/dashboard/wpde-offline/index.html @@ -79,7 +79,7 @@

Wikimedia Deutschland e. V.

startDate: '2024-10-01', endDate: '2024-12-31', numberOfMembers: 73832, - isLateProgress: false, + isLateProgress: true, thankYouCampaign: { numberOfDonors: 350000, progressBarPercentage: 100 diff --git a/src/themes/Fijitiv/ProgressBar/ProgressBar.scss b/src/themes/Fijitiv/ProgressBar/ProgressBar.scss index 47a8220e3..fb115dac7 100644 --- a/src/themes/Fijitiv/ProgressBar/ProgressBar.scss +++ b/src/themes/Fijitiv/ProgressBar/ProgressBar.scss @@ -7,6 +7,8 @@ $progress-bar-height: 30px !default; $progress-bar-margin: 0 !default; .wmde-banner .wmde-banner-fallback { + @include ProgressBar.layout; + .wmde-banner { &-progress-bar { position: relative; @@ -69,19 +71,18 @@ $progress-bar-margin: 0 !default; &--late-progress { .wmde-banner-progress-bar-text-left { + color: var( --fallback-progressbar-color ); + @include breakpoints.extra-small-up { visibility: visible; } } - .wmde-banner-progress-bar-text-right { visibility: hidden; } - .wmde-banner-progress-bar-fill { min-width: 100px; } - .wmde-banner-progress-bar-target { flex: 0 0 auto; display: block; From 7ec68b23297dbff701cadb56f3f01c3b05c2c3d3 Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Wed, 11 Dec 2024 17:11:19 +0100 Subject: [PATCH 6/6] C24_WMDE_Desktop_DE_19 - Improve reasons to donate modal close button - Add curson pointer to the close button Ticket: https://phabricator.wikimedia.org/T380852 --- src/components/ReasonsToDonate/styles/ReasonsToDonate.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ReasonsToDonate/styles/ReasonsToDonate.scss b/src/components/ReasonsToDonate/styles/ReasonsToDonate.scss index 3311d6834..21ac36fb6 100644 --- a/src/components/ReasonsToDonate/styles/ReasonsToDonate.scss +++ b/src/components/ReasonsToDonate/styles/ReasonsToDonate.scss @@ -76,6 +76,7 @@ padding: 4px; border-radius: 50%; background: var( --close-button-background ); + cursor: pointer; } &-link {