From f727a247c44ed2832bb684ae2684ef0a6ee5dfaa Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Fri, 6 Oct 2023 07:37:21 +0200 Subject: [PATCH 1/3] Archive C23_WMDE_Mobile_DE_05 Ticket: https://phabricator.wikimedia.org/T346884 --- .../C23_WMDE_Mobile_DE_04/banner_ctrl.ts | 66 ++++++++ .../C23_WMDE_Mobile_DE_04/banner_var.ts | 66 ++++++++ .../components/BannerCtrl.vue | 153 ++++++++++++++++++ .../components/FullPageBanner.vue | 39 +++++ .../components/MiniBanner.vue | 32 ++++ .../content/BannerSlides.vue | 50 ++++++ .../content/BannerText.vue | 29 ++++ .../mobile/C23_WMDE_Mobile_DE_04/event_map.ts | 28 ++++ .../C23_WMDE_Mobile_DE_04/form_items.ts | 23 +++ .../mobile/C23_WMDE_Mobile_DE_04/messages.ts | 27 ++++ .../C23_WMDE_Mobile_DE_04/styles/Banner.scss | 56 +++++++ .../styles/FullPageBanner.scss | 99 ++++++++++++ .../styles/MiniBanner.scss | 132 +++++++++++++++ .../C23_WMDE_Mobile_DE_04/styles/styles.scss | 17 ++ 14 files changed, 817 insertions(+) create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/banner_ctrl.ts create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/banner_var.ts create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/components/BannerCtrl.vue create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/components/FullPageBanner.vue create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/components/MiniBanner.vue create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/content/BannerSlides.vue create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/content/BannerText.vue create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/event_map.ts create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/form_items.ts create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/messages.ts create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/styles/Banner.scss create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/styles/FullPageBanner.scss create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/styles/MiniBanner.scss create mode 100644 archive/mobile/C23_WMDE_Mobile_DE_04/styles/styles.scss diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/banner_ctrl.ts b/archive/mobile/C23_WMDE_Mobile_DE_04/banner_ctrl.ts new file mode 100644 index 000000000..7e9849df2 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/banner_ctrl.ts @@ -0,0 +1,66 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles.scss'; + +import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; +import Banner from './components/BannerCtrl.vue'; +import getBannerDelay from '@src/utils/getBannerDelay'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import eventMappings from './event_map'; + +// Locale-specific imports +import messages from './messages'; +import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; + +// Channel specific form setup +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; + +const localeFactory = new LocaleFactoryDe(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller() + }, + 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, { ast: '0' } ) ); +app.provide( 'tracker', tracker ); + +app.mount( page.getBannerContainer() ); diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/banner_var.ts b/archive/mobile/C23_WMDE_Mobile_DE_04/banner_var.ts new file mode 100644 index 000000000..bd35396d9 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/banner_var.ts @@ -0,0 +1,66 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles.scss'; + +import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; +import Banner from './components/BannerCtrl.vue'; +import getBannerDelay from '@src/utils/getBannerDelay'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import eventMappings from './event_map'; + +// Locale-specific imports +import messages from './messages'; +import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; + +// Channel specific form setup +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; + +const localeFactory = new LocaleFactoryDe(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller() + }, + 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, { ast: '2' } ) ); +app.provide( 'tracker', tracker ); + +app.mount( page.getBannerContainer() ); diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/components/BannerCtrl.vue b/archive/mobile/C23_WMDE_Mobile_DE_04/components/BannerCtrl.vue new file mode 100644 index 000000000..9de7e676f --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/components/BannerCtrl.vue @@ -0,0 +1,153 @@ + + + diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/components/FullPageBanner.vue b/archive/mobile/C23_WMDE_Mobile_DE_04/components/FullPageBanner.vue new file mode 100644 index 000000000..973467b02 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/components/FullPageBanner.vue @@ -0,0 +1,39 @@ + + + diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/components/MiniBanner.vue b/archive/mobile/C23_WMDE_Mobile_DE_04/components/MiniBanner.vue new file mode 100644 index 000000000..926554f9f --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/components/MiniBanner.vue @@ -0,0 +1,32 @@ + + + diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/content/BannerSlides.vue b/archive/mobile/C23_WMDE_Mobile_DE_04/content/BannerSlides.vue new file mode 100644 index 000000000..ac0252c38 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/content/BannerSlides.vue @@ -0,0 +1,50 @@ + + + diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/content/BannerText.vue b/archive/mobile/C23_WMDE_Mobile_DE_04/content/BannerText.vue new file mode 100644 index 000000000..c553f50b6 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/content/BannerText.vue @@ -0,0 +1,29 @@ + + + diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/event_map.ts b/archive/mobile/C23_WMDE_Mobile_DE_04/event_map.ts new file mode 100644 index 000000000..8596b1635 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/event_map.ts @@ -0,0 +1,28 @@ +import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; +import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; +import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; +import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; +import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; +import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; + +export default new Map( [ + [ CloseEvent.EVENT_NAME, mapCloseEvent ], + [ MobileMiniBannerExpandedEvent.EVENT_NAME, + ( e: MobileMiniBannerExpandedEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ], + [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], + [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], + + [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { + switch ( e.feature ) { + case 'UpgradeToYearlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, null, 1 ); + default: + return new WMDESizeIssueEvent( `submit`, null, 1 ); + } + } ] +] ); diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/form_items.ts b/archive/mobile/C23_WMDE_Mobile_DE_04/form_items.ts new file mode 100644 index 000000000..97d35b6a7 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/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.DIRECT_DEBIT, + PaymentMethods.BANK_TRANSFER, + PaymentMethods.CREDIT_CARD, + PaymentMethods.SOFORT + ).getItems(); +} diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/messages.ts b/archive/mobile/C23_WMDE_Mobile_DE_04/messages.ts new file mode 100644 index 000000000..a9655b585 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/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/archive/mobile/C23_WMDE_Mobile_DE_04/styles/Banner.scss b/archive/mobile/C23_WMDE_Mobile_DE_04/styles/Banner.scss new file mode 100644 index 000000000..faf723a8b --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/styles/Banner.scss @@ -0,0 +1,56 @@ +@use 'src/themes/Mikings/variables/globals'; +@use 'src/themes/Mikings/variables/fonts'; +@use 'src/themes/Mikings/variables/colors'; + +@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: colors.$white; + + &--full-page { + .wmde-banner-mini { + animation: hide-mini 500ms; + } + .wmde-banner-full { + visibility: visible; + opacity: 1; + transform: scale( 1 ); + } + } + + &--soft-closing { + .wmde-banner-mini { + display: none; + } + } + } + + &--closed, + &--not-shown { + .wmde-banner-wrapper { + display: none; + } + } +} diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/styles/FullPageBanner.scss b/archive/mobile/C23_WMDE_Mobile_DE_04/styles/FullPageBanner.scss new file mode 100644 index 000000000..22ef61757 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/styles/FullPageBanner.scss @@ -0,0 +1,99 @@ +@use '@src/themes/Mikings/variables/colors'; +@use '@src/themes/Mikings/variables/globals'; +@use '@src/themes/Mikings/variables/_breakpoints.scss'; + +.wmde-banner { + &-full { + border: 2px solid colors.$primary; + background: colors.$white; + position: fixed; + top: 0; + z-index: 1000; + height: 100vh; + width: 100vw; + + &-content { + overflow-y: auto; + height: 100%; + width: 100%; + } + + p { + padding-bottom: 16px; + } + + &-close { + position: absolute; + top: 16px; + right: 16px; + height: 35px; + width: 35px; + padding: 5px; + background: colors.$white; + z-index: 99; + border-radius: 50%; + + &:hover { + cursor: pointer; + } + + .close-button { + text-decoration: underline; + } + } + + &-info { + padding: 16px; + } + + &-call-to-action { + position: relative; + color: colors.$white; + background: colors.$primary; + 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: colors.$primary transparent transparent transparent; + } + } + + .banner-text-title { + margin-right: 30px; + } + + &-small-print { + text-align: center; + font-size: 12px; + margin-bottom: 16px; + + a { + color: colors.$gray; + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/styles/MiniBanner.scss b/archive/mobile/C23_WMDE_Mobile_DE_04/styles/MiniBanner.scss new file mode 100644 index 000000000..8879a9e14 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/styles/MiniBanner.scss @@ -0,0 +1,132 @@ +@use '@src/themes/Mikings/variables/colors'; +@use '@src/themes/Mikings/variables/globals'; + +$height: 288px !default; + +.wmde-banner { + &-mini { + display: flex; + flex-direction: column; + min-height: $height; + padding: 16px 0; + position: relative; + border: 2px solid colors.$primary; + background: colors.$white; + + &-close { + position: absolute; + height: 36px; + width: 36px; + top: 11px; + right: 16px; + text-align: center; + background: colors.$white; + padding: 10px; + z-index: 2; + + &-button { + margin-top: auto; + float: right; + height: 16px; + line-height: 16px; + width: 16px; + background: colors.$white; + z-index: 2; + + svg { + height: 16px; + width: 16px; + } + + &:hover { + cursor: pointer; + } + } + } + + &-headline { + height: 25px; + text-align: center; + margin: 0 16px 16px; + + &-background { + position: relative; + text-align: left; + + @media ( min-width: 400px ) { + text-align: center; + } + + /* single line above container */ + &::before { + content: ''; + display: block; + background: colors.$primary; + 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: colors.$black; + background: colors.$white; + 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; + color: colors.$white; + background: colors.$secondary; + margin: 0 16px; + + &:hover, + &:focus { + background: colors.$secondary-hover; + } + } + + .smallprint-mini { + text-align: center; + font-size: 11px; + margin-top: 12px; + margin-bottom: -5px; + + a { + color: colors.$gray; + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/archive/mobile/C23_WMDE_Mobile_DE_04/styles/styles.scss b/archive/mobile/C23_WMDE_Mobile_DE_04/styles/styles.scss new file mode 100644 index 000000000..d5b476cb7 --- /dev/null +++ b/archive/mobile/C23_WMDE_Mobile_DE_04/styles/styles.scss @@ -0,0 +1,17 @@ +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Mikings/defaults'; +@use './Banner'; +@use './MiniBanner' with ( + $height: 288px +); +@use './FullPageBanner'; +@use 'src/themes/Mikings/Footer/Footer'; +@use 'src/themes/Mikings/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/SoftClose/SoftClose'; From 0193b8d3b1a76486ad8695e71984b3cb0c831887 Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Fri, 6 Oct 2023 07:55:34 +0200 Subject: [PATCH 2/3] Prepare campaign for C23_WMDE_Mobile_DE_05 Ticket: https://phabricator.wikimedia.org/T346884 --- banners/mobile/banner_ctrl.ts | 2 +- banners/mobile/banner_var.ts | 2 +- campaign_info.toml | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/banners/mobile/banner_ctrl.ts b/banners/mobile/banner_ctrl.ts index 7e9849df2..94a2a8fb9 100644 --- a/banners/mobile/banner_ctrl.ts +++ b/banners/mobile/banner_ctrl.ts @@ -60,7 +60,7 @@ const currencyFormatter = localeFactory.getCurrencyFormatter(); app.provide( 'currencyFormatter', currencyFormatter ); app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) ); -app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { ast: '0' } ) ); +app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount ) ); app.provide( 'tracker', tracker ); app.mount( page.getBannerContainer() ); diff --git a/banners/mobile/banner_var.ts b/banners/mobile/banner_var.ts index bd35396d9..94a2a8fb9 100644 --- a/banners/mobile/banner_var.ts +++ b/banners/mobile/banner_var.ts @@ -60,7 +60,7 @@ const currencyFormatter = localeFactory.getCurrencyFormatter(); app.provide( 'currencyFormatter', currencyFormatter ); app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) ); -app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { ast: '2' } ) ); +app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount ) ); app.provide( 'tracker', tracker ); app.mount( page.getBannerContainer() ); diff --git a/campaign_info.toml b/campaign_info.toml index 5aeb8c40e..11be00643 100644 --- a/campaign_info.toml +++ b/campaign_info.toml @@ -33,9 +33,9 @@ resolution = ["800x600", "1024x768", "1280x960", "1600x1200", "1920x1200", "2560 [mobile] name = "Mobile" icon = "mobile" -campaign = "C23_WMDE_Mobile_DE_04" -description = "based on VAR 02, has all payment types as text, VAR leads to different address page" -campaign_tracking = "mob-de-04-ba-230914" +campaign = "C23_WMDE_Mobile_DE_05" +description = "based on CTRL 04, VAR has an extra button" +campaign_tracking = "mob-de-05-ba-231009" preview_link = "/mobile/wiki/Wikipedia:Hauptseite?devbanner={{banner}}&banner=B22_WMDE_local_prototype&useskin=minerva" preview_url = 'https://de.m.wikipedia.org/wiki/Wikipedia:Hauptseite?banner={{banner}}&useskin=minerva&devMode' wrapper_template = "wikipedia_org" @@ -44,13 +44,13 @@ use_of_funds_source = "MediaWiki:WMDE_Fundraising/UseOfFunds_2023_DE" # Banners of the campaign, key after "banners" can be anything [mobile.banners.ctrl] filename = "./banners/mobile/banner_ctrl.ts" -pagename = "B23_WMDE_Mobile_DE_04_ctrl" -tracking = "org-mob04-230914-ctrl" +pagename = "B23_WMDE_Mobile_DE_05_ctrl" +tracking = "org-mob05-231009-ctrl" [mobile.banners.var] filename = "./banners/mobile/banner_var.ts" -pagename = "B23_WMDE_Mobile_DE_04_var" -tracking = "org-mob04-230914-var" +pagename = "B23_WMDE_Mobile_DE_05_var" +tracking = "org-mob05-231009-var" [mobile.test_matrix] device = [ 'samsung_s10', 'iphone_xs_max', 'iphone_5s', 'iphone_se', "iphone_8", "iphone_12_mini", "iphone_7_plus", "iphone_11_pro_max"] From c3990fa89946a502e08d4d188196145639e79ebc Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Fri, 6 Oct 2023 09:04:03 +0200 Subject: [PATCH 3/3] Implement VAR for C23_WMDE_Mobile_DE_05 Var banner has 2 buttons, the new one preselects the amount 5 in the form. Ticket: https://phabricator.wikimedia.org/T346884 --- banners/mobile/banner_var.ts | 4 +- banners/mobile/components/BannerVar.vue | 161 ++++++++++++++++++ banners/mobile/components/MiniBannerVar.vue | 37 ++++ banners/mobile/content/BannerSlides.vue | 6 +- banners/mobile/content/BannerText.vue | 6 +- banners/mobile/event_map.ts | 2 +- banners/mobile/messages.ts | 3 +- banners/mobile/styles/MiniBannerVar.scss | 158 +++++++++++++++++ banners/mobile/styles/styles_var.scss | 17 ++ .../events/MobileMiniBannerExpandedEvent.ts | 4 + .../mobile/components/BannerVar.spec.ts | 156 +++++++++++++++++ test/features/MiniBannerPreselect.ts | 29 ++++ 12 files changed, 571 insertions(+), 12 deletions(-) create mode 100644 banners/mobile/components/BannerVar.vue create mode 100644 banners/mobile/components/MiniBannerVar.vue create mode 100644 banners/mobile/styles/MiniBannerVar.scss create mode 100644 banners/mobile/styles/styles_var.scss create mode 100644 test/banners/mobile/components/BannerVar.spec.ts create mode 100644 test/features/MiniBannerPreselect.ts diff --git a/banners/mobile/banner_var.ts b/banners/mobile/banner_var.ts index 94a2a8fb9..5a0378743 100644 --- a/banners/mobile/banner_var.ts +++ b/banners/mobile/banner_var.ts @@ -1,9 +1,9 @@ import { createVueApp } from '@src/createVueApp'; -import './styles/styles.scss'; +import './styles/styles_var.scss'; import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; -import Banner from './components/BannerCtrl.vue'; +import Banner from './components/BannerVar.vue'; import getBannerDelay from '@src/utils/getBannerDelay'; import { WindowResizeHandler } from '@src/utils/ResizeHandler'; import PageWPORG from '@src/page/PageWPORG'; diff --git a/banners/mobile/components/BannerVar.vue b/banners/mobile/components/BannerVar.vue new file mode 100644 index 000000000..c8d84a3bc --- /dev/null +++ b/banners/mobile/components/BannerVar.vue @@ -0,0 +1,161 @@ + + + diff --git a/banners/mobile/components/MiniBannerVar.vue b/banners/mobile/components/MiniBannerVar.vue new file mode 100644 index 000000000..9643cb180 --- /dev/null +++ b/banners/mobile/components/MiniBannerVar.vue @@ -0,0 +1,37 @@ + + + diff --git a/banners/mobile/content/BannerSlides.vue b/banners/mobile/content/BannerSlides.vue index ac0252c38..a3500535d 100644 --- a/banners/mobile/content/BannerSlides.vue +++ b/banners/mobile/content/BannerSlides.vue @@ -11,10 +11,8 @@

- - Millionen Menschen nutzen Wikipedia, aber 99 % spenden nicht – sie übergehen diesen Aufruf. - - Die meisten Menschen spenden, weil sie Wikipedia nützlich finden.

+ Millionen Menschen nutzen Wikipedia, aber 99 % spenden nicht + – sie übergehen diesen Aufruf. Die meisten Menschen spenden, weil sie Wikipedia nützlich finden.

diff --git a/banners/mobile/content/BannerText.vue b/banners/mobile/content/BannerText.vue index c553f50b6..0f6481d48 100644 --- a/banners/mobile/content/BannerText.vue +++ b/banners/mobile/content/BannerText.vue @@ -7,10 +7,8 @@

vielleicht kommen wir gerade ungelegen, aber dennoch: Klicken Sie jetzt bitte nicht weg! Am heutigen {{ currentDayName }} bitten wir Sie bescheiden, die Unabhängigkeit von Wikipedia zu - unterstützen. - - Millionen Menschen nutzen Wikipedia, aber 99 % spenden nicht – sie übergehen diesen Aufruf. - + unterstützen. Millionen Menschen nutzen Wikipedia, + aber 99 % spenden nicht – sie übergehen diesen Aufruf. Die meisten Menschen spenden, weil sie Wikipedia nützlich finden. Die durchschnittliche Spende beträgt 22,25 €, doch bereits 5 € helfen uns weiter. Hat Wikipedia Ihnen in diesem Jahr Wissen im Wert einer Tasse Kaffee geschenkt? Dann entscheiden Sie sich, eine der diff --git a/banners/mobile/event_map.ts b/banners/mobile/event_map.ts index 8596b1635..5e57ef7a5 100644 --- a/banners/mobile/event_map.ts +++ b/banners/mobile/event_map.ts @@ -13,7 +13,7 @@ import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; export default new Map( [ [ CloseEvent.EVENT_NAME, mapCloseEvent ], [ MobileMiniBannerExpandedEvent.EVENT_NAME, - ( e: MobileMiniBannerExpandedEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName, 1 ) ], + ( e: MobileMiniBannerExpandedEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ], [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], diff --git a/banners/mobile/messages.ts b/banners/mobile/messages.ts index a9655b585..f24a88452 100644 --- a/banners/mobile/messages.ts +++ b/banners/mobile/messages.ts @@ -21,7 +21,8 @@ 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?', + 'use-of-funds-link': 'Was Ihre Spende bewirkt' }; export default messages; diff --git a/banners/mobile/styles/MiniBannerVar.scss b/banners/mobile/styles/MiniBannerVar.scss new file mode 100644 index 000000000..48e0cd732 --- /dev/null +++ b/banners/mobile/styles/MiniBannerVar.scss @@ -0,0 +1,158 @@ +@use '@src/themes/Mikings/variables/colors'; +@use '@src/themes/Mikings/variables/globals'; +@use 'sass:color'; + +$height: 288px !default; +$green: #6e9e00; + +.wmde-banner { + &-mini { + display: flex; + flex-direction: column; + min-height: $height; + padding: 16px 0; + position: relative; + border: 2px solid colors.$primary; + background: colors.$white; + + &-close { + position: absolute; + height: 36px; + width: 36px; + top: 11px; + right: 16px; + text-align: center; + background: colors.$white; + padding: 10px; + z-index: 2; + + &-button { + margin-top: auto; + float: right; + height: 16px; + line-height: 16px; + width: 16px; + background: colors.$white; + z-index: 2; + + svg { + height: 16px; + width: 16px; + } + + &:hover { + cursor: pointer; + } + } + } + + &-headline { + height: 25px; + text-align: center; + margin: 0 16px 16px; + + &-background { + position: relative; + text-align: left; + + @media ( min-width: 400px ) { + text-align: center; + } + + /* single line above container */ + &::before { + content: ''; + display: block; + background: colors.$primary; + 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: colors.$black; + background: colors.$white; + 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-group { + display: flex; + justify-content: center; + } + + &-button, + &-button-preselect { + width: 50%; + height: 40px; + line-height: 40px; + border-radius: 20px; + font-weight: bold; + color: colors.$white; + margin: 0 16px; + font-size: 14px; + white-space: nowrap; + + @media ( min-width: 370px ) { + font-size: 16px; + } + } + + &-button { + background: colors.$secondary; + + &:hover, + &:focus { + background: colors.$secondary-hover; + } + } + + &-button-preselect { + background: $green; + + &:hover, + &:focus { + background: color.adjust( $green, $lightness: -5% ); + } + } + + .smallprint-mini { + text-align: center; + font-size: 11px; + margin-top: 12px; + margin-bottom: -5px; + + a { + color: colors.$gray; + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/banners/mobile/styles/styles_var.scss b/banners/mobile/styles/styles_var.scss new file mode 100644 index 000000000..c8599e22e --- /dev/null +++ b/banners/mobile/styles/styles_var.scss @@ -0,0 +1,17 @@ +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Mikings/defaults'; +@use './Banner'; +@use './MiniBannerVar' with ( + $height: 288px +); +@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/SoftClose/SoftClose'; diff --git a/src/tracking/events/MobileMiniBannerExpandedEvent.ts b/src/tracking/events/MobileMiniBannerExpandedEvent.ts index b1b6fbf00..90b83bb9d 100644 --- a/src/tracking/events/MobileMiniBannerExpandedEvent.ts +++ b/src/tracking/events/MobileMiniBannerExpandedEvent.ts @@ -8,4 +8,8 @@ export class MobileMiniBannerExpandedEvent implements TrackingEvent { public readonly customData: Record = {}; public readonly feature: TrackingFeatureName = 'MiniBanner'; public readonly userChoice: string = ''; + + public constructor( userChoice: string = '' ) { + this.userChoice = userChoice; + } } diff --git a/test/banners/mobile/components/BannerVar.spec.ts b/test/banners/mobile/components/BannerVar.spec.ts new file mode 100644 index 000000000..4ec71f2a0 --- /dev/null +++ b/test/banners/mobile/components/BannerVar.spec.ts @@ -0,0 +1,156 @@ +import { afterEach, beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '../../../../banners/mobile/components/BannerVar.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; +import { formItems } from '@test/banners/formItems'; +import { softCloseFeatures } from '@test/features/SoftCloseMobile'; +import { useOfFundsFeatures, useOfFundsScrollFeatures } from '@test/features/UseOfFunds'; +import { miniBannerFeatures } from '@test/features/MiniBanner'; +import { donationFormFeatures } from '@test/features/forms/MainDonation_UpgradeToYearlyButton'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { bannerContentAnimatedTextFeatures } from '@test/features/BannerContent'; +import { fullPageBannerFeatures } from '@test/features/FullPageBanner'; +import { miniBannerPreselectFeatures } from '@test/features/MiniBannerPreselect'; +import { Tracker } from '@src/tracking/Tracker'; + +let pageScroller: PageScroller; +let tracker: Tracker; +const formModel = useFormModel(); +const translator = ( key: string ): string => key; +describe( 'BannerVar.vue', () => { + + let wrapper: VueWrapper; + beforeEach( () => { + resetFormModel( formModel ); + + pageScroller = { + scrollIntoView: vi.fn(), + scrollToTop: vi.fn() + }; + + tracker = { + trackEvent: vi.fn() + }; + } ); + + 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 + }, + 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 + } + } + } ); + + return wrapper; + }; + + afterEach( () => { + wrapper.unmount(); + } ); + + // skipped because the sentence is not part of the current test + describe.skip( 'Content', () => { + test.each( [ + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInSlideShow' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + } ); + + 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' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ 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() ); + } ); + + test.each( [ + [ 'expectShowsFullPageWhenPreselectIsClicked' ], + [ 'expectPreselectsAmountWhenPreselectIsClicked' ], + [ 'expectTrackingEventIsFiredWhenPreselectIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await miniBannerPreselectFeatures[ testName ]( getWrapper(), tracker ); + } ); + + } ); + + describe( 'Full Page Banner', () => { + test.each( [ + [ 'expectEmitsCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await fullPageBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); + +} ); diff --git a/test/features/MiniBannerPreselect.ts b/test/features/MiniBannerPreselect.ts new file mode 100644 index 000000000..b56322fc8 --- /dev/null +++ b/test/features/MiniBannerPreselect.ts @@ -0,0 +1,29 @@ +import { VueWrapper } from '@vue/test-utils'; +import { expect } from 'vitest'; +import { Tracker } from '@src/tracking/Tracker'; +import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent'; + +const expectShowsFullPageWhenPreselectIsClicked = async ( wrapper: VueWrapper ): Promise => { + await wrapper.find( '.wmde-banner-mini-button-preselect' ).trigger( 'click' ); + + expect( wrapper.classes() ).toContain( 'wmde-banner-wrapper--full-page' ); +}; + +const expectPreselectsAmountWhenPreselectIsClicked = async ( wrapper: VueWrapper ): Promise => { + await wrapper.find( '.wmde-banner-mini-button-preselect' ).trigger( 'click' ); + + expect( wrapper.find( '.wmde-banner-select-group-input:checked' ).element.value ).toStrictEqual( '5' ); +}; + +const expectTrackingEventIsFiredWhenPreselectIsClicked = async ( wrapper: VueWrapper, tracker: Tracker ): Promise => { + await wrapper.find( '.wmde-banner-mini-button-preselect' ).trigger( 'click' ); + + expect( tracker.trackEvent ).toHaveBeenCalledOnce(); + expect( tracker.trackEvent ).toHaveBeenCalledWith( new MobileMiniBannerExpandedEvent( 'preselected' ) ); +}; + +export const miniBannerPreselectFeatures: Record, tracker: Tracker ) => Promise> = { + expectShowsFullPageWhenPreselectIsClicked, + expectPreselectsAmountWhenPreselectIsClicked, + expectTrackingEventIsFiredWhenPreselectIsClicked +};