From e62a11887d4d81c8682f2958d18381a6462ab6d3 Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Thu, 10 Oct 2024 12:19:30 +0200 Subject: [PATCH 1/5] Prepare campaign for C24_WPDE_Mobile_01 Ticket: https://phabricator.wikimedia.org/T376792 --- .../C24_WPDE_Mobile_01/FormController.ts | 0 .../C24_WPDE_Mobile_01/banner_ctrl.ts | 72 ++++++++ .../C24_WPDE_Mobile_01/banner_var.ts | 72 ++++++++ .../components/BannerCtrl.vue | 169 ++++++++++++++++++ .../components/BannerVar.vue | 164 +++++++++++++++++ .../components/FullPageBanner.vue | 40 +++++ .../components/MiniBanner.vue | 32 ++++ .../components/MiniBannerVar.vue | 32 ++++ .../content/BannerSlides.vue | 52 ++++++ .../content/BannerSlidesVar.vue | 52 ++++++ .../C24_WPDE_Mobile_01/content/BannerText.vue | 31 ++++ .../content/BannerTextVar.vue | 31 ++++ .../C24_WPDE_Mobile_01/event_map.ts | 15 ++ .../C24_WPDE_Mobile_01/form_items.ts | 23 +++ .../C24_WPDE_Mobile_01/messages.ts | 27 +++ .../C24_WPDE_Mobile_01/styles/Banner.scss | 55 ++++++ .../styles/FullPageBanner.scss | 105 +++++++++++ .../C24_WPDE_Mobile_01/styles/MiniBanner.scss | 133 ++++++++++++++ .../C24_WPDE_Mobile_01/styles/styles.scss | 24 +++ campaign_info.toml | 18 +- .../wpde_mobile/components/BannerCtrl.spec.ts | 2 +- .../wpde_mobile/components/BannerVar.spec.ts | 2 +- 22 files changed, 1140 insertions(+), 11 deletions(-) create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/FormController.ts create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/banner_ctrl.ts create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/FullPageBanner.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBanner.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlides.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerText.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/event_map.ts create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/form_items.ts create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/messages.ts create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/styles/Banner.scss create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/styles/FullPageBanner.scss create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/styles/MiniBanner.scss create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/styles/styles.scss diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/FormController.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/FormController.ts new file mode 100644 index 000000000..e69de29bb diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_ctrl.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_ctrl.ts new file mode 100644 index 000000000..3315f7c59 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_ctrl.ts @@ -0,0 +1,72 @@ +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 PageWPDE from '@src/page/PageWPDE'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; +import { TrackerWPDE } from '@src/tracking/TrackerWPDE'; +import eventMap from './event_map'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; + +// Channel specific form setup +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; + +// Content +import messages from './messages'; +import { LocaleFactoryWpDe } from '@src/utils/LocaleFactory/LocaleFactoryWpDe'; + +const localeFactory = new LocaleFactoryWpDe(); +const translator = new Translator( messages ); + +// Tracking placeholders will be replaced by webpack string-replace-loader +// using the campaign configuration ( campaign_info.toml ) for the correct values +const tracking = { + campaign: '!insert-campaign-here!', + keyword: '!insert-keyword-here!' +}; + +const page = new PageWPDE( tracking ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new TrackerWPDE( 'FundraisingTracker', page.getTracking().keyword, eventMap, runtimeEnvironment ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 0 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions() ) + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date: new 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 ) ); +app.provide( 'tracker', tracker ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts new file mode 100644 index 000000000..3811316ce --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts @@ -0,0 +1,72 @@ +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 PageWPDE from '@src/page/PageWPDE'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; +import { TrackerWPDE } from '@src/tracking/TrackerWPDE'; +import eventMap from './event_map'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; + +// Channel specific form setup +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; + +// Content +import messages from './messages'; +import { LocaleFactoryWpDe } from '@src/utils/LocaleFactory/LocaleFactoryWpDe'; + +const localeFactory = new LocaleFactoryWpDe(); +const translator = new Translator( messages ); + +// Tracking placeholders will be replaced by webpack string-replace-loader +// using the campaign configuration ( campaign_info.toml ) for the correct values +const tracking = { + campaign: '!insert-campaign-here!', + keyword: '!insert-keyword-here!' +}; + +const page = new PageWPDE( tracking ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new TrackerWPDE( 'FundraisingTracker', page.getTracking().keyword, eventMap, runtimeEnvironment ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 0 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions() ) + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date: new 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 ) ); +app.provide( 'tracker', tracker ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue new file mode 100644 index 000000000..f22afd109 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue @@ -0,0 +1,169 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue new file mode 100644 index 000000000..4fa2fa886 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue @@ -0,0 +1,164 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/FullPageBanner.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/FullPageBanner.vue new file mode 100644 index 000000000..89eb818a4 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/FullPageBanner.vue @@ -0,0 +1,40 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBanner.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBanner.vue new file mode 100644 index 000000000..66d511719 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBanner.vue @@ -0,0 +1,32 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue new file mode 100644 index 000000000..6d9d3c374 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue @@ -0,0 +1,32 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlides.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlides.vue new file mode 100644 index 000000000..8f15b7e93 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlides.vue @@ -0,0 +1,52 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue new file mode 100644 index 000000000..e56a0eef0 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue @@ -0,0 +1,52 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerText.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerText.vue new file mode 100644 index 000000000..c904d9742 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerText.vue @@ -0,0 +1,31 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue new file mode 100644 index 000000000..02a017b89 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue @@ -0,0 +1,31 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/event_map.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/event_map.ts new file mode 100644 index 000000000..ea0e58a98 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/event_map.ts @@ -0,0 +1,15 @@ +import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { ShownEvent } from '@src/tracking/events/ShownEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { CustomAmountChangedEvent } from '@src/tracking/events/CustomAmountChangedEvent'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; + +export default new Map( [ + [ MobileMiniBannerExpandedEvent.EVENT_NAME, 1 ], + [ CloseEvent.EVENT_NAME, 0.1 ], + [ ShownEvent.EVENT_NAME, 1 ], + [ FormStepShownEvent.EVENT_NAME, 1 ], + [ CustomAmountChangedEvent.EVENT_NAME, 1 ], + [ BannerSubmitEvent.EVENT_NAME, 1 ] +] ); diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/form_items.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/form_items.ts new file mode 100644 index 000000000..a3c657221 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/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( 5, 15, 25, 50, 100 ) + .setPaymentMethods( + PaymentMethods.PAYPAL, + PaymentMethods.CREDIT_CARD, + PaymentMethods.DIRECT_DEBIT, + PaymentMethods.BANK_TRANSFER, + PaymentMethods.SOFORT + ).getItems(); +} diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/messages.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/messages.ts new file mode 100644 index 000000000..a9655b585 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/messages.ts @@ -0,0 +1,27 @@ +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 SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.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'; + +const messages: TranslationMessages = { + ...CustomAmountFormDe, + ...DynamicCampaignTextDe, + ...UpgradeToYearlyDe, + ...SoftCloseDe, + ...AddressFormDe, + ...FooterDe, + ...MainDonationFormDe, + + // custom messages here + 'address-type-notice-full': 'Nur so können wir Ihnen eine Spendenquittung per Post zusenden. Außerdem erhalten ' + + 'Sie eine Bestätigung per E-Mail.', + 'address-type-notice-none': 'Sie verzichten sowohl auf eine Spendenquittung als auch auf eine Bestätigung ' + + 'per E-Mail. Sie erhalten von uns keine Information, wenn Wikipedia wieder Hilfe braucht.', + 'soft-close-prompt': 'Wikipedia später unterstützen?' +}; + +export default messages; diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/Banner.scss b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/Banner.scss new file mode 100644 index 000000000..124f9f157 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/Banner.scss @@ -0,0 +1,55 @@ +@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 { + .wmde-banner-wrapper { + display: none; + } + } +} diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/FullPageBanner.scss b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/FullPageBanner.scss new file mode 100644 index 000000000..a0fe64711 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/FullPageBanner.scss @@ -0,0 +1,105 @@ +@use '@src/themes/Mikings/variables/globals'; +@use '@src/themes/Mikings/variables/breakpoints'; + +.wmde-banner { + &-form-field-group { + border: 0; + } + + &-full { + position: fixed; + top: 0; + z-index: 1000; + border: 2px solid var( --full-border ); + background: var( --full-background ); + height: 100vh; + width: 100vw; + + &-content { + overflow-y: auto; + height: 100%; + width: 100%; + } + + p { + margin: 0; + padding-bottom: 16px; + line-height: 25px; + } + + &-close { + position: absolute; + top: 16px; + right: 16px; + height: 35px; + width: 35px; + padding: 5px; + background: var( --full-background ); + z-index: 99; + border-radius: 50%; + border: 0; + + &: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: 4px 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/wpde_mobile/C24_WPDE_Mobile_01/styles/MiniBanner.scss b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/MiniBanner.scss new file mode 100644 index 000000000..8b950d4db --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/MiniBanner.scss @@ -0,0 +1,133 @@ +@use '@src/themes/Mikings/variables/globals'; + +$height: 267px !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 { + margin-top: auto; + float: right; + height: 16px; + line-height: 16px; + width: 16px; + background: transparent; + z-index: 2; + border: 0; + + 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; + + @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 { + width: auto; + height: 40px; + line-height: 40px; + border-radius: 20px; + font-weight: bold; + background: var( --mini-button-background ); + color: var( --mini-button-color ); + margin: 0 16px; + border: 0; + + &:hover, + &:focus { + background: var( --mini-button-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/wpde_mobile/C24_WPDE_Mobile_01/styles/styles.scss b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/styles.scss new file mode 100644 index 000000000..79960925c --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/styles.scss @@ -0,0 +1,24 @@ +@use 'src/themes/Mikings/swatches/skin_default' with ( + $upgrade-to-yearly-button-form: true, + $progress-bar: true, + $soft-close: 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: 267px +); +@use './FullPageBanner'; +@use 'src/themes/Mikings/Footer/Footer'; +@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'; +@use 'src/themes/Mikings/ProgressBar/ProgressBar'; +@use 'src/themes/Mikings/SoftClose/SoftClose'; diff --git a/campaign_info.toml b/campaign_info.toml index cfc54b1c3..09bf49808 100644 --- a/campaign_info.toml +++ b/campaign_info.toml @@ -115,9 +115,9 @@ tracking = "wpde-01-241028-var" [wikipediade_mobile] name = "WPDE Mobile" icon = "mobile" -campaign = "C24_WPDE_Mobile_00" -description = "Based on C23_WPDE_Mobile_01" -campaign_tracking = "wpde-mob00-240619" +campaign = "C24_WPDE_Mobile_01" +description = "Based on the control banner of last year's mobile-wpde-01" +campaign_tracking = "wpde-mob01-241028" preview_link = "/wikipedia.de?devbanner={{banner}}&banner=dev-mode-wpde" preview_link_darkmode = "/wikipedia.de?devbanner={{banner}}&banner=dev-mode-wpde" wrapper_template = "wikipedia_de" @@ -125,14 +125,14 @@ wrap_in_wikitext = false preview_url = 'https://www.wikipedia.de/?banner={{banner}}' [wikipediade_mobile.banners.ctrl] -filename = "./banners/wpde_mobile/C24_WPDE_Mobile_00/banner_ctrl.ts" -pagename = "B24_WPDE_Mobile_00_ctrl" -tracking = "wpde-mob00-240619-ctrl" +filename = "./banners/wpde_mobile/C24_WPDE_Mobile_01/banner_ctrl.ts" +pagename = "B24_WPDE_Mobile_01_ctrl" +tracking = "wpde-mob01-241028-ctrl" [wikipediade_mobile.banners.var] -filename = "./banners/wpde_mobile/C24_WPDE_Mobile_00/banner_var.ts" -pagename = "B24_WPDE_Mobile_00_var" -tracking = "wpde-mob00-240619-var" +filename = "./banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts" +pagename = "B24_WPDE_Mobile_01_var" +tracking = "wpde-mob01-241028-var" diff --git a/test/banners/wpde_mobile/components/BannerCtrl.spec.ts b/test/banners/wpde_mobile/components/BannerCtrl.spec.ts index 6ee030f00..a147c709c 100644 --- a/test/banners/wpde_mobile/components/BannerCtrl.spec.ts +++ b/test/banners/wpde_mobile/components/BannerCtrl.spec.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, vi, test } from 'vitest'; import { mount, VueWrapper } from '@vue/test-utils'; -import Banner from '@banners/wpde_mobile/C24_WPDE_Mobile_00/components/BannerCtrl.vue'; +import Banner from '@banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue'; import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; import { PageScroller } from '@src/utils/PageScroller/PageScroller'; import { useOfFundsContent } from '@test/banners/useOfFundsContent'; diff --git a/test/banners/wpde_mobile/components/BannerVar.spec.ts b/test/banners/wpde_mobile/components/BannerVar.spec.ts index a54674779..a20068429 100644 --- a/test/banners/wpde_mobile/components/BannerVar.spec.ts +++ b/test/banners/wpde_mobile/components/BannerVar.spec.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, vi, test } from 'vitest'; import { mount, VueWrapper } from '@vue/test-utils'; -import Banner from '@banners/wpde_mobile/C24_WPDE_Mobile_00/components/BannerVar.vue'; +import Banner from '@banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue'; import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; import { PageScroller } from '@src/utils/PageScroller/PageScroller'; import { useOfFundsContent } from '@test/banners/useOfFundsContent'; From cc28e893c9e9c315fc864dbf8d69ad920396b21d Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Fri, 11 Oct 2024 14:18:12 +0200 Subject: [PATCH 2/5] Prepare CTRL for C24_WPDE_Mobile_01 - CTRL banner is based on the CTRL banner of last year's mobile-wpde-01 - It has a second button in the mobile mini banner - It still uses the soft close - It still shows the "Habe schon gespendet" button in the soft close - Clicking "Yes" in the soft close banner shouldn't set a banner display prevention cookie - Clicking "Habe schon gespendet" in the soft close banner should set a banner display prevention cookie valid for 4 weeks - It shows an additional paragraph on the second form page - Closing the modal banner shouldn't set a banner display prevention cookie Ticket: https://phabricator.wikimedia.org/T376792 --- .../C24_WPDE_Mobile_01/banner_var.ts | 2 +- .../components/BannerCtrl.vue | 53 +++++- .../components/BannerVar.vue | 164 ------------------ .../components/MiniBanner.vue | 14 +- .../components/MiniBannerVar.vue | 32 ---- .../content/BannerSlides.vue | 18 +- .../content/BannerSlidesVar.vue | 52 ------ .../C24_WPDE_Mobile_01/content/BannerText.vue | 26 ++- .../content/BannerTextVar.vue | 31 ---- .../C24_WPDE_Mobile_01/messages.ts | 8 +- .../C24_WPDE_Mobile_01/styles/MiniBanner.scss | 38 +++- .../SetAlreadyDonatedCookieImage.vue | 12 +- .../wpde_mobile/components/BannerCtrl.spec.ts | 7 +- .../wpde_mobile/components/BannerVar.spec.ts | 145 ---------------- test/features/SetCookieImageMobile.ts | 1 + 15 files changed, 134 insertions(+), 469 deletions(-) delete mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue delete mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue delete mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue delete mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue delete mode 100644 test/banners/wpde_mobile/components/BannerVar.spec.ts diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts index 3811316ce..3315f7c59 100644 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts @@ -3,7 +3,7 @@ import { createVueApp } from '@src/createVueApp'; import './styles/styles.scss'; import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; -import Banner from './components/BannerVar.vue'; +import Banner from './components/BannerCtrl.vue'; import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; import { WindowResizeHandler } from '@src/utils/ResizeHandler'; import PageWPDE from '@src/page/PageWPDE'; diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue index f22afd109..fb5386429 100644 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue @@ -1,9 +1,11 @@ diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue deleted file mode 100644 index 02a017b89..000000000 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue +++ /dev/null @@ -1,31 +0,0 @@ - - - diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/messages.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/messages.ts index a9655b585..b9601b241 100644 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/messages.ts +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/messages.ts @@ -21,7 +21,13 @@ const messages: TranslationMessages = { 'Sie eine Bestätigung per E-Mail.', 'address-type-notice-none': 'Sie verzichten sowohl auf eine Spendenquittung als auch auf eine Bestätigung ' + 'per E-Mail. Sie erhalten von uns keine Information, wenn Wikipedia wieder Hilfe braucht.', - 'soft-close-prompt': 'Wikipedia später unterstützen?' + 'soft-close-prompt': 'Wikipedia später unterstützen?', + 'soft-close-button-already-donated': 'Habe schon gespendet', + 'upgrade-to-yearly-copy': '

Jedes Jahr sind wir auf die Unterstützung von Menschen wie Ihnen angewiesen.' + + ' Jährliche Spenden helfen uns nachhaltig und ermöglichen langfristige Weiterentwicklungen.

' + + '

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

', + 'payment-sofort': 'Sofort', + 'payment-bank-transfer': 'Überweisung' }; export default messages; diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/MiniBanner.scss b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/MiniBanner.scss index 8b950d4db..9c11c7cbf 100644 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/MiniBanner.scss +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/styles/MiniBanner.scss @@ -24,14 +24,14 @@ $height: 267px !default; z-index: 2; &-button { + border: none; margin-top: auto; float: right; height: 16px; line-height: 16px; width: 16px; - background: transparent; + background: var( --mini-close-background ); z-index: 2; - border: 0; svg { height: 16px; @@ -80,6 +80,7 @@ $height: 267px !default; background: var( --mini-headline-background ); padding: 0 5px; z-index: 2; + white-space: nowrap; @media ( min-width: 330px ) { font-size: 16px; @@ -97,16 +98,30 @@ $height: 267px !default; flex: 1 1 auto; } - &-button { - width: auto; + &-button-group { + display: flex; + justify-content: center; + } + + &-button, + &-button-preselect { + width: 50%; height: 40px; - line-height: 40px; + border: none; border-radius: 20px; font-weight: bold; - background: var( --mini-button-background ); color: var( --mini-button-color ); margin: 0 16px; - border: 0; + font-size: 14px; + white-space: nowrap; + + @media ( min-width: 370px ) { + font-size: 16px; + } + } + + &-button { + background: var( --mini-button-background ); &:hover, &:focus { @@ -114,6 +129,15 @@ $height: 267px !default; } } + &-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; diff --git a/src/components/SetWPDECookieImage/SetAlreadyDonatedCookieImage.vue b/src/components/SetWPDECookieImage/SetAlreadyDonatedCookieImage.vue index ecd6c2e5e..e60be38a1 100644 --- a/src/components/SetWPDECookieImage/SetAlreadyDonatedCookieImage.vue +++ b/src/components/SetWPDECookieImage/SetAlreadyDonatedCookieImage.vue @@ -1,8 +1,8 @@ diff --git a/test/banners/wpde_mobile/components/BannerCtrl.spec.ts b/test/banners/wpde_mobile/components/BannerCtrl.spec.ts index a147c709c..4078fee64 100644 --- a/test/banners/wpde_mobile/components/BannerCtrl.spec.ts +++ b/test/banners/wpde_mobile/components/BannerCtrl.spec.ts @@ -76,8 +76,7 @@ describe( 'BannerCtrl.vue', () => { [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], [ 'expectMainDonationFormGoesToUpgrade' ], [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], - [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ], - [ 'expectUpgradeToYearlyFormGoesToMainDonation' ] + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] ] )( '%s', async ( testName: string ) => { await donationFormFeatures[ testName ]( getWrapper() ); } ); @@ -88,7 +87,6 @@ describe( 'BannerCtrl.vue', () => { [ 'expectShowsSoftCloseOnMiniBannerClose' ], [ 'expectDoesNotShowSoftCloseOnFullBannerClose' ], [ 'expectEmitsSoftCloseCloseEvent' ], - [ 'expectEmitsSoftCloseMaybeLaterEvent' ], [ 'expectEmitsSoftCloseTimeOutEvent' ], [ 'expectEmitsBannerContentChangedOnSoftClose' ], [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] @@ -100,8 +98,7 @@ describe( 'BannerCtrl.vue', () => { describe( 'Set Cookie Image', () => { test.each( [ [ 'expectSetsCookieImageOnSoftCloseClose' ], - [ 'expectSetsCookieImageOnSoftCloseTimeOut' ], - [ 'expectDoesNotSetCookieImageOnSoftCloseMaybeLater' ] + [ 'expectSetsCookieImageOnSoftCloseTimeOut' ] ] )( '%s', async ( testName: string ) => { await setCookieImageFeatures[ testName ]( getWrapper() ); } ); diff --git a/test/banners/wpde_mobile/components/BannerVar.spec.ts b/test/banners/wpde_mobile/components/BannerVar.spec.ts deleted file mode 100644 index a20068429..000000000 --- a/test/banners/wpde_mobile/components/BannerVar.spec.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { afterEach, beforeEach, describe, vi, test } from 'vitest'; -import { mount, VueWrapper } from '@vue/test-utils'; -import Banner from '@banners/wpde_mobile/C24_WPDE_Mobile_01/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 { TrackerStub } from '@test/fixtures/TrackerStub'; -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 { setCookieImageFeatures } from '@test/features/SetCookieImageMobile'; - -let pageScroller: PageScroller; -const formModel = useFormModel(); -const translator = ( key: string ): string => key; - -describe( 'BannerVar.vue', () => { - - let wrapper: VueWrapper; - beforeEach( () => { - resetFormModel( formModel ); - vi.useFakeTimers(); - - pageScroller = { - scrollIntoView: vi.fn(), - scrollToTop: vi.fn() - }; - } ); - - afterEach( () => { - wrapper.unmount(); - vi.restoreAllMocks(); - vi.useRealTimers(); - } ); - - const getWrapper = ( dynamicContent: DynamicContent = 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 - }, - global: { - mocks: { - $translate: translator - }, - provide: { - translator: { translate: translator }, - dynamicCampaignText: dynamicContent ?? newDynamicContent(), - formActions: { donateWithAddressAction: 'https://example.com', donateWithoutAddressAction: 'https://example.com' }, - currencyFormatter: new CurrencyEn(), - formItems, - tracker: new TrackerStub() - } - } - } ); - - return wrapper; - }; - - describe( 'Donation Form Happy Paths', () => { - test.each( [ - [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], - [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], - [ 'expectMainDonationFormGoesToUpgrade' ], - [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], - [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ], - [ 'expectUpgradeToYearlyFormGoesToMainDonation' ] - ] )( '%s', async ( testName: string ) => { - await donationFormFeatures[ testName ]( getWrapper() ); - } ); - } ); - - describe( 'Soft Close', () => { - test.each( [ - [ 'expectShowsSoftCloseOnMiniBannerClose' ], - [ 'expectDoesNotShowSoftCloseOnFullBannerClose' ], - [ 'expectEmitsSoftCloseCloseEvent' ], - [ 'expectEmitsSoftCloseMaybeLaterEvent' ], - [ 'expectEmitsSoftCloseTimeOutEvent' ], - [ 'expectEmitsBannerContentChangedOnSoftClose' ], - [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] - ] )( '%s', async ( testName: string ) => { - await softCloseFeatures[ testName ]( getWrapper() ); - } ); - } ); - - describe( 'Set Cookie Image', () => { - test.each( [ - [ 'expectSetsCookieImageOnSoftCloseClose' ], - [ 'expectSetsCookieImageOnSoftCloseTimeOut' ], - [ 'expectDoesNotSetCookieImageOnSoftCloseMaybeLater' ] - ] )( '%s', async ( testName: string ) => { - await setCookieImageFeatures[ testName ]( getWrapper() ); - } ); - } ); - - 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/features/SetCookieImageMobile.ts b/test/features/SetCookieImageMobile.ts index cac1a1104..fedf1eb2e 100644 --- a/test/features/SetCookieImageMobile.ts +++ b/test/features/SetCookieImageMobile.ts @@ -1,6 +1,7 @@ import { VueWrapper } from '@vue/test-utils'; import { expect, vi } from 'vitest'; +// This test does not make sense const expectSetsCookieImageOnSoftCloseClose = async ( wrapper: VueWrapper ): Promise => { await wrapper.find( '.wmde-banner-mini-button' ).trigger( 'click' ); await wrapper.find( '.wmde-banner-full-close' ).trigger( 'click' ); From a6b5b5a483b463004acaf0e302bc996dd658476f Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Fri, 11 Oct 2024 15:05:44 +0200 Subject: [PATCH 3/5] Implement VAR for C24_WPDE_Mobile_01 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - It has a second button in the mobile mini banner - It still uses the soft close - It still shows the "Habe schon gespendet" button in the soft close - The variant banner should use €15 in the headline, on the green button (and additionally in the first sentence on slide #4) - Closing the modal banner shouldn't set a banner display prevention cookie - Clicking "Yes" in the soft close banner shouldn't set a banner display prevention cookie. - Clicking "Habe schon gespendet" in the soft close banner should set a banner display prevention cookie valid for 4 weeks - It shows an additional paragraph on the second form page. - Update content repo Ticket: https://phabricator.wikimedia.org/T376792 --- .../C24_WPDE_Mobile_01/banner_var.ts | 2 +- .../components/BannerVar.vue | 210 ++++++++++++++++++ .../components/MiniBannerVar.vue | 36 +++ .../content/BannerSlidesVar.vue | 60 +++++ .../content/BannerTextVar.vue | 39 ++++ .../wpde_mobile/components/BannerVar.spec.ts | 142 ++++++++++++ 6 files changed, 488 insertions(+), 1 deletion(-) create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue create mode 100644 banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue create mode 100644 test/banners/wpde_mobile/components/BannerVar.spec.ts diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts b/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts index 3315f7c59..3811316ce 100644 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/banner_var.ts @@ -3,7 +3,7 @@ import { createVueApp } from '@src/createVueApp'; import './styles/styles.scss'; import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; -import Banner from './components/BannerCtrl.vue'; +import Banner from './components/BannerVar.vue'; import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; import { WindowResizeHandler } from '@src/utils/ResizeHandler'; import PageWPDE from '@src/page/PageWPDE'; diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue new file mode 100644 index 000000000..32ffd4f27 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue @@ -0,0 +1,210 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue new file mode 100644 index 000000000..19875a8ab --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/MiniBannerVar.vue @@ -0,0 +1,36 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue new file mode 100644 index 000000000..0bd9967c3 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerSlidesVar.vue @@ -0,0 +1,60 @@ + + + diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue new file mode 100644 index 000000000..5db864990 --- /dev/null +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/content/BannerTextVar.vue @@ -0,0 +1,39 @@ + + + diff --git a/test/banners/wpde_mobile/components/BannerVar.spec.ts b/test/banners/wpde_mobile/components/BannerVar.spec.ts new file mode 100644 index 000000000..076db6212 --- /dev/null +++ b/test/banners/wpde_mobile/components/BannerVar.spec.ts @@ -0,0 +1,142 @@ +import { afterEach, beforeEach, describe, vi, test } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/wpde_mobile/C24_WPDE_Mobile_01/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 { TrackerStub } from '@test/fixtures/TrackerStub'; +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 { setCookieImageFeatures } from '@test/features/SetCookieImageMobile'; + +let pageScroller: PageScroller; +const formModel = useFormModel(); +const translator = ( key: string ): string => key; + +describe( 'BannerVar.vue', () => { + + let wrapper: VueWrapper; + beforeEach( () => { + resetFormModel( formModel ); + vi.useFakeTimers(); + + pageScroller = { + scrollIntoView: vi.fn(), + scrollToTop: vi.fn() + }; + } ); + + afterEach( () => { + wrapper.unmount(); + vi.restoreAllMocks(); + vi.useRealTimers(); + } ); + + const getWrapper = ( dynamicContent: DynamicContent = 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 + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + formActions: { donateWithAddressAction: 'https://example.com', donateWithoutAddressAction: 'https://example.com' }, + currencyFormatter: new CurrencyEn(), + formItems, + tracker: new TrackerStub() + } + } + } ); + + return wrapper; + }; + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftCloseOnMiniBannerClose' ], + [ 'expectDoesNotShowSoftCloseOnFullBannerClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Set Cookie Image', () => { + test.each( [ + [ 'expectSetsCookieImageOnSoftCloseClose' ], + [ 'expectSetsCookieImageOnSoftCloseTimeOut' ] + ] )( '%s', async ( testName: string ) => { + await setCookieImageFeatures[ testName ]( getWrapper() ); + } ); + } ); + + 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 4750b89231c3fe8e28fe90b36e9f0759a5010047 Mon Sep 17 00:00:00 2001 From: Sperling-0 Date: Tue, 22 Oct 2024 12:44:10 +0200 Subject: [PATCH 4/5] Inline UoF infographic into Fundraising Banners - https://github.com/wmde/fundraising-banners/pull/563 Ticket: https://phabricator.wikimedia.org/T375848 Ticket: https://phabricator.wikimedia.org/T376792 --- .../C24_WPDE_Mobile_01/components/BannerCtrl.vue | 7 ++++++- .../C24_WPDE_Mobile_01/components/BannerVar.vue | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue index fb5386429..5338962a2 100644 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue @@ -82,7 +82,11 @@ :content="useOfFundsContent" :is-funds-modal-visible="isFundsModalVisible" @hideFundsModal="onHideFundsModal" - /> + > + + @@ -118,6 +122,7 @@ import { CloseEvent } from '@src/tracking/events/CloseEvent'; import { TrackingFeatureName } from '@src/tracking/TrackingEvent'; import ChevronLeftIcon from '@src/components/Icons/ChevronLeftIcon.vue'; import SetCookieImage from '@src/components/SetWPDECookieImage/SetCookieImage.vue'; +import WMDEFundsForwardingDE from '@src/components/UseOfFunds/Infographics/WMDEFundsForwardingDE.vue'; import SetAlreadyDonatedCookieImage from '@src/components/SetWPDECookieImage/SetAlreadyDonatedCookieImage.vue'; enum ContentStates { diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue index 32ffd4f27..0f96a81d1 100644 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerVar.vue @@ -82,7 +82,11 @@ :content="useOfFundsContent" :is-funds-modal-visible="isFundsModalVisible" @hideFundsModal="onHideFundsModal" - /> + > + + @@ -119,6 +123,7 @@ import { TrackingFeatureName } from '@src/tracking/TrackingEvent'; import ChevronLeftIcon from '@src/components/Icons/ChevronLeftIcon.vue'; import SetCookieImage from '@src/components/SetWPDECookieImage/SetCookieImage.vue'; import SetAlreadyDonatedCookieImage from '@src/components/SetWPDECookieImage/SetAlreadyDonatedCookieImage.vue'; +import WMDEFundsForwardingDE from '@src/components/UseOfFunds/Infographics/WMDEFundsForwardingDE.vue'; enum ContentStates { Mini = 'wmde-banner-wrapper--mini', From daa23994345dad462f8aa4486d77d66d6d5e8c8d Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Wed, 30 Oct 2024 12:43:03 +0100 Subject: [PATCH 5/5] Fix issues with tests - A timer wasn't being cleared properly causing the soft close timeout test to fail. - The cookie image check was using the wrong button classes to close the banner and was previously passing by coincidence. Ticket: https://phabricator.wikimedia.org/T376792 --- .../components/BannerCtrl.vue | 4 ++-- .../components/BannerVar.vue | 4 ++-- .../content/BannerSlides.vue | 13 ++++++++++--- .../content/BannerSlidesVar.vue | 12 +++++++++--- .../C24_WPDE_Mobile_01/content/BannerText.vue | 18 +++++++++++++++--- .../content/BannerTextVar.vue | 18 +++++++++++++++--- test/features/SetCookieImageMobile.ts | 8 ++++---- 7 files changed, 57 insertions(+), 20 deletions(-) diff --git a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue index 5338962a2..9a2291096 100644 --- a/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue +++ b/banners/wpde_mobile/C24_WPDE_Mobile_01/components/BannerCtrl.vue @@ -11,7 +11,7 @@ @@ -23,7 +23,7 @@ @close="() => onClose( 'FullPageBanner', CloseChoices.Hide )" > diff --git a/test/features/SetCookieImageMobile.ts b/test/features/SetCookieImageMobile.ts index fedf1eb2e..9c5e82c06 100644 --- a/test/features/SetCookieImageMobile.ts +++ b/test/features/SetCookieImageMobile.ts @@ -1,10 +1,9 @@ import { VueWrapper } from '@vue/test-utils'; import { expect, vi } from 'vitest'; -// This test does not make sense const expectSetsCookieImageOnSoftCloseClose = async ( wrapper: VueWrapper ): Promise => { - await wrapper.find( '.wmde-banner-mini-button' ).trigger( 'click' ); - await wrapper.find( '.wmde-banner-full-close' ).trigger( 'click' ); + await wrapper.find( '.wmde-banner-mini-close-button' ).trigger( 'click' ); + await wrapper.find( '.wmde-banner-soft-close-button-close' ).trigger( 'click' ); expect( wrapper.find( '.wmde-banner-set-cookie-image' ).exists() ).toBeTruthy(); }; @@ -13,7 +12,8 @@ const expectSetsCookieImageOnSoftCloseTimeOut = async ( wrapper: VueWrapper vi.useFakeTimers(); await wrapper.find( '.wmde-banner-mini-close-button' ).trigger( 'click' ); - await vi.runAllTimers(); + + await vi.runAllTimersAsync(); expect( wrapper.find( '.wmde-banner-set-cookie-image' ).exists() ).toBeTruthy();