From cd14f585e38e8561627cb9dc5c97e82ef9288951 Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Fri, 6 Dec 2024 15:10:25 +0100 Subject: [PATCH 1/4] Prepare campaign for C24_WMDE_Mobile_DE_12 Ticket: https://phabricator.wikimedia.org/T381398 --- .../MainDonationForm_changesAmountOptions.vue | 133 +++++++++ .../C24_WMDE_Mobile_DE_12/banner_ctrl.ts | 70 +++++ .../C24_WMDE_Mobile_DE_12/banner_var.ts | 70 +++++ .../components/BannerCtrl.vue | 255 +++++++++++++++++ .../components/BannerVar.vue | 261 ++++++++++++++++++ .../components/FullPageBanner.vue | 43 +++ .../components/FullPageBannerVar.vue | 46 +++ .../components/MiniBanner.vue | 37 +++ .../components/MiniBannerVar.vue | 36 +++ .../components/MinimisedBanner.vue | 32 +++ .../content/BannerSlides.vue | 75 +++++ .../content/BannerText.vue | 50 ++++ .../mobile/C24_WMDE_Mobile_DE_12/event_map.ts | 33 +++ .../C24_WMDE_Mobile_DE_12/form_items.ts | 22 ++ .../mobile/C24_WMDE_Mobile_DE_12/messages.ts | 30 ++ .../C24_WMDE_Mobile_DE_12/styles/Banner.scss | 56 ++++ .../styles/BannerVar.scss | 56 ++++ .../styles/FullPageBanner.scss | 100 +++++++ .../styles/FullPageBannerVar.scss | 116 ++++++++ .../styles/MiniBanner.scss | 163 +++++++++++ .../styles/MiniBannerVar.scss | 178 ++++++++++++ .../styles/MinimisedBanner.scss | 96 +++++++ .../C24_WMDE_Mobile_DE_12/styles/styles.scss | 30 ++ .../styles/styles_var.scss | 28 ++ campaign_info.toml | 18 +- .../components/BannerCtrl.spec.ts | 183 ++++++++++++ .../components/BannerVar.spec.ts | 183 ++++++++++++ 27 files changed, 2391 insertions(+), 9 deletions(-) create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/MainDonationForm_changesAmountOptions.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/banner_ctrl.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBanner.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBannerVar.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBanner.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBannerVar.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/MinimisedBanner.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/content/BannerSlides.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/content/BannerText.vue create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/event_map.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/form_items.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/messages.ts create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/Banner.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/BannerVar.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBanner.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBannerVar.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBanner.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBannerVar.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/MinimisedBanner.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles.scss create mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles_var.scss create mode 100644 test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.spec.ts create mode 100644 test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.spec.ts diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/MainDonationForm_changesAmountOptions.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/MainDonationForm_changesAmountOptions.vue new file mode 100644 index 000000000..dd5e7ab31 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/MainDonationForm_changesAmountOptions.vue @@ -0,0 +1,133 @@ + + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/banner_ctrl.ts b/banners/mobile/C24_WMDE_Mobile_DE_12/banner_ctrl.ts new file mode 100644 index 000000000..1c138885f --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/banner_ctrl.ts @@ -0,0 +1,70 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles.scss'; + +import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; +import Banner from './components/BannerCtrl.vue'; +import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import eventMappings from './event_map'; +import messages from './messages'; +import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; +import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; +import { WindowTimer } from '@src/utils/Timer'; + +const localeFactory = new LocaleFactoryDe(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment ); + +const currencyFormatter = localeFactory.getCurrencyFormatter(); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'mobile' ) ), + localCloseTracker: new LocalStorageCloseTracker() + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date: new Date(), + formatters: localeFactory.getFormatters(), + impressionCount, + translator, + urgencyMessageDaysLeft: 45 +} ); + +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.provide( 'timer', new WindowTimer() ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts new file mode 100644 index 000000000..94cd4a000 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts @@ -0,0 +1,70 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles_var.scss'; + +import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; +import Banner from './components/BannerVar.vue'; +import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import eventMappings from './event_map'; +import messages from './messages'; +import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe'; +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; +import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker'; +import { WindowTimer } from '@src/utils/Timer'; + +const localeFactory = new LocaleFactoryDe(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment ); + +const currencyFormatter = localeFactory.getCurrencyFormatter(); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + pageScroller: new WindowPageScroller(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'mobile' ) ), + localCloseTracker: new LocalStorageCloseTracker() + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date: new Date(), + formatters: localeFactory.getFormatters(), + impressionCount, + translator, + urgencyMessageDaysLeft: 45 +} ); + +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.provide( 'timer', new WindowTimer() ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.vue new file mode 100644 index 000000000..e28a0d24c --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.vue @@ -0,0 +1,255 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.vue new file mode 100644 index 000000000..0c405a056 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.vue @@ -0,0 +1,261 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBanner.vue new file mode 100644 index 000000000..d75bb5b68 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBanner.vue @@ -0,0 +1,43 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBannerVar.vue new file mode 100644 index 000000000..7350fbfa1 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBannerVar.vue @@ -0,0 +1,46 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBanner.vue new file mode 100644 index 000000000..7ab1e5afd --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBanner.vue @@ -0,0 +1,37 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBannerVar.vue new file mode 100644 index 000000000..dcbe339c0 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBannerVar.vue @@ -0,0 +1,36 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/MinimisedBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/MinimisedBanner.vue new file mode 100644 index 000000000..7678ce7c6 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/MinimisedBanner.vue @@ -0,0 +1,32 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/content/BannerSlides.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/content/BannerSlides.vue new file mode 100644 index 000000000..48524e525 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/content/BannerSlides.vue @@ -0,0 +1,75 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/content/BannerText.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/content/BannerText.vue new file mode 100644 index 000000000..c0b3d6b27 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/content/BannerText.vue @@ -0,0 +1,50 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/event_map.ts b/banners/mobile/C24_WMDE_Mobile_DE_12/event_map.ts new file mode 100644 index 000000000..d7a00a5dd --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/event_map.ts @@ -0,0 +1,33 @@ +import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; +import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; +import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; +import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; +import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; +import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; +import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; +import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent'; + +export default new Map( [ + [ CloseEvent.EVENT_NAME, mapCloseEvent ], + [ MobileMiniBannerExpandedEvent.EVENT_NAME, + ( e: MobileMiniBannerExpandedEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ], + [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], + [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], + + [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { + switch ( e.feature ) { + case 'MiniBanner': + case 'UpgradeToYearlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + default: + return new WMDESizeIssueEvent( `submit`, createViewportInfo(), 1 ); + } + } ], + [ BannerSubmitOnReturnEvent.EVENT_NAME, + ( e: BannerSubmitOnReturnEvent ): WMDELegacyBannerEvent => new WMDELegacyBannerEvent( e.eventName + ( e.userChoice !== '' ? `-${e.userChoice}` : '' ), 1 ) ] +] ); diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/form_items.ts b/banners/mobile/C24_WMDE_Mobile_DE_12/form_items.ts new file mode 100644 index 000000000..5156a352e --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/form_items.ts @@ -0,0 +1,22 @@ +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 + ) + .setPaymentMethods( + PaymentMethods.PAYPAL, + PaymentMethods.DIRECT_DEBIT, + PaymentMethods.BANK_TRANSFER, + PaymentMethods.CREDIT_CARD, + PaymentMethods.SOFORT + ).getItems(); +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/messages.ts b/banners/mobile/C24_WMDE_Mobile_DE_12/messages.ts new file mode 100644 index 000000000..930f9b38f --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/messages.ts @@ -0,0 +1,30 @@ +import DynamicCampaignTextDe from '@src/utils/DynamicContent/messages/DynamicCampaignText.de'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyDe from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.de'; +import FooterDe from '@src/components/Footer/messages/Footer.de'; +import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/MainDonationForm.de'; +import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; + +const messages: TranslationMessages = { + ...DynamicCampaignTextDe, + ...FooterDe, + ...MainDonationFormDe, + ...UpgradeToYearlyDe, + ...SoftCloseDe, + + // custom messages here + 'use-of-funds-link': 'Was Ihre Spende bewirkt', + 'payment-bank-transfer': 'Überweisung', + 'payment-sofort': 'Sofort', + 'upgrade-to-yearly-copy': '

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

' + + '

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

', + 'upgrade-to-yearly-no': 'Nein, ich spende einmalig {{amount}}', + 'upgrade-to-yearly-yes': 'Ja, ich spende {{amount}} jährlich', + 'campaign-day-only-n-days': 'Heute sind es nur noch {{days}} Tage bis zum Ende unserer Spendenkampagne.', + 'soft-close-prompt': 'Wikipedia später unterstützen?', + 'soft-close-button-already-donated': 'Habe schon gespendet', + 'amount-total': '' +}; + +export default messages; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/Banner.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/Banner.scss new file mode 100644 index 000000000..ef5ca15ed --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/Banner.scss @@ -0,0 +1,56 @@ +@use 'src/themes/Mikings/variables/globals'; +@use 'src/themes/Mikings/variables/fonts'; + +@keyframes hide-mini { + 0% { + opacity: 1; + } + 99% { + opacity: 0; + } + 100% { + display: none; + } +} + +.wmde-banner { + + &-full { + visibility: hidden; + opacity: 0; + transform: scale( 1.1 ); + transition: opacity 500ms globals.$banner-easing, transform 500ms globals.$banner-easing; + } + + &-wrapper { + font-size: 16px; + font-family: fonts.$ui; + box-shadow: 0 3px 0.6em rgba( 60 60 60 / 40% ); + background-color: var( --main-background ); + color: var( --main-color ); + + &--full-page { + .wmde-banner-mini { + animation: hide-mini 500ms; + } + .wmde-banner-full { + visibility: visible; + opacity: 1; + transform: scale( 1 ); + } + } + + &--soft-closing { + .wmde-banner-mini { + display: none; + } + } + } + + &--closed, + &--not-shown { + .wmde-banner-wrapper { + display: none; + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/BannerVar.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/BannerVar.scss new file mode 100644 index 000000000..5ff1ecbab --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/BannerVar.scss @@ -0,0 +1,56 @@ +@use 'src/themes/Modo/variables/globals'; +@use 'src/themes/Modo/variables/fonts'; + +@keyframes hide-mini { + 0% { + opacity: 1; + } + 99% { + opacity: 0; + } + 100% { + display: none; + } +} + +.wmde-banner { + + &-full { + visibility: hidden; + opacity: 0; + transform: scale( 1.1 ); + transition: opacity 500ms globals.$banner-easing, transform 500ms globals.$banner-easing; + } + + &-wrapper { + font-size: 16px; + font-family: fonts.$ui; + box-shadow: 0 3px 0.6em rgba( 60 60 60 / 40% ); + background-color: var( --main-background ); + color: var( --main-color ); + + &--full-page { + .wmde-banner-mini { + animation: hide-mini 500ms; + } + .wmde-banner-full { + visibility: visible; + opacity: 1; + transform: scale( 1 ); + } + } + + &--soft-closing { + .wmde-banner-mini { + display: none; + } + } + } + + &--closed, + &--not-shown { + .wmde-banner-wrapper { + display: none; + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBanner.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBanner.scss new file mode 100644 index 000000000..f0fa8fbdd --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBanner.scss @@ -0,0 +1,100 @@ +@use '@src/themes/Mikings/variables/globals'; +@use '@src/themes/Mikings/variables/breakpoints'; + +.wmde-banner { + &-full { + border: 2px solid var( --full-border ); + background: var( --full-background ); + position: fixed; + top: 0; + z-index: 1000; + height: 100vh; + height: -webkit-fill-available; + width: 100vw; + + &-content { + overflow-y: auto; + height: 100%; + width: 100%; + } + + p { + padding-bottom: 16px; + } + + &-close { + position: absolute; + top: 16px; + right: 16px; + height: 35px; + width: 35px; + padding: 5px; + background: var( --full-background ); + z-index: 99; + border: none; + border-radius: 50%; + + &:hover { + cursor: pointer; + } + + .close-button { + text-decoration: underline; + } + } + + &-info { + padding: 16px; + } + + &-call-to-action { + position: relative; + color: var( --full-cta-color ); + background: var( --full-cta-background ); + font-weight: bold; + height: 31px; + line-height: 31px; + text-align: center; + + &-optional-text { + display: none; + + @include breakpoints.tablet-portrait-up { + display: inline; + } + } + + &::after { + content: ''; + position: absolute; + bottom: -4px; + left: 50%; + margin-left: -4px; + width: 0; + height: 0; + border-style: solid; + border-width: 5px 4px 0; + border-color: var( --full-cta-background ) transparent transparent transparent; + } + } + + .banner-text-title { + margin-right: 30px; + } + + &-small-print { + text-align: center; + font-size: 12px; + margin-bottom: 16px; + + a { + color: var( --full-smallprint-color ); + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBannerVar.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBannerVar.scss new file mode 100644 index 000000000..74e0d4eb9 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBannerVar.scss @@ -0,0 +1,116 @@ +@use '@src/themes/Modo/variables/globals'; +@use '@src/themes/Modo/variables/breakpoints'; + +.wmde-banner { + &-full { + background: var( --full-background ); + position: fixed; + top: 0; + z-index: 1000; + height: 100vh; + height: -webkit-fill-available; + width: 100vw; + + &-content { + overflow-y: auto; + height: 100%; + width: 100%; + padding: 12px; + } + + p { + padding-bottom: 16px; + } + + &-close { + position: absolute; + top: 0; + right: 0; + height: 36px; + width: 36px; + padding: 5px 3px 5px 7px; + background: transparent; + z-index: 99; + border: none; + + svg { + height: 15px; + width: 15px; + background: var( --full-close-background ); + border-radius: 16px; + box-sizing: content-box; + border: solid 5px var( --full-close-background ); + } + + &:hover { + cursor: pointer; + } + } + + &-info { + padding: 12px; + background: var( --full-info-background ); + border-radius: 16px; + color: var( --info-color ); + } + + &-content-below-info { + background: var( --full-content-below-info-background ); + border-radius: 16px; + } + + &-call-to-action { + position: relative; + color: var( --full-cta-color ); + background: var( --full-cta-background ); + font-weight: bold; + font-size: 14px; + height: 25px; + line-height: 25px; + text-align: center; + border-radius: 16px; + margin-bottom: 10px; + margin-top: 10px; + + &-optional-text { + display: none; + + @include breakpoints.tablet-portrait-up { + display: inline; + } + } + + &::after { + content: ''; + position: absolute; + bottom: -4px; + left: 50%; + margin-left: -4px; + width: 0; + height: 0; + border-style: solid; + border-width: 5px 4px 0; + border-color: var( --full-cta-background ) transparent transparent transparent; + } + } + + .banner-text-title { + margin-right: 30px; + } + + &-small-print { + text-align: center; + font-size: 12px; + margin-bottom: 16px; + + a { + color: var( --full-smallprint-color ); + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBanner.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBanner.scss new file mode 100644 index 000000000..a910fa7d5 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBanner.scss @@ -0,0 +1,163 @@ +@use '@src/themes/Mikings/variables/globals'; +@use '@src/themes/Mikings/variables/breakpoints'; + +$height: 336px !default; +$height-l-up: 288px !default; + +.wmde-banner { + &-mini { + display: flex; + flex-direction: column; + min-height: $height; + padding: 16px 0; + position: relative; + border: 2px solid var( --mini-border ); + background: var( --mini-background ); + + @include breakpoints.phone-l-up { + min-height: $height-l-up; + } + + &-close { + position: absolute; + height: 36px; + width: 36px; + top: 11px; + right: 16px; + text-align: center; + background: var( --mini-close-background ); + padding: 10px; + z-index: 2; + + &-button { + border: none; + margin-top: auto; + float: right; + height: 16px; + line-height: 16px; + width: 16px; + background: var( --mini-close-background ); + z-index: 2; + + svg { + height: 16px; + width: 16px; + } + + &:hover { + cursor: pointer; + } + } + } + + &-headline { + height: 25px; + text-align: center; + margin: 0 16px 16px; + + &-background { + position: relative; + text-align: left; + + @media ( min-width: 400px ) { + text-align: center; + } + + /* single line above container */ + &::before { + content: ''; + display: block; + background: var( --mini-headline-line ); + width: 100%; + height: 1px; + position: absolute; + top: 50%; + z-index: 1; + } + } + + &-content { + position: relative; + display: inline-block; + font-weight: bold; + font-size: 14px; + line-height: 25px; + color: var( --mini-headline-color ); + background: var( --mini-headline-background ); + padding: 0 5px; + z-index: 2; + white-space: nowrap; + + @media ( min-width: 330px ) { + font-size: 16px; + } + + @media ( min-width: 360px ) { + font-size: 18px; + } + } + } + + &-slideshow { + display: flex; + flex-direction: column; + flex: 1 1 auto; + } + + &-button-group { + display: flex; + justify-content: center; + } + + &-button, + &-button-preselect { + width: 50%; + height: 40px; + border: none; + border-radius: 20px; + font-weight: bold; + color: var( --mini-button-color ); + margin: 0 16px; + font-size: 14px; + white-space: nowrap; + + @media ( min-width: 370px ) { + font-size: 16px; + } + } + + &-button { + background: var( --mini-button-background ); + + &:hover, + &:focus { + background: var( --mini-button-background-hover ); + } + } + + &-button-preselect { + background: var( --mini-button-alt-background ); + + &:hover, + &:focus { + background: var( --mini-button-alt-background-hover ); + } + } + + .smallprint-mini { + text-align: center; + font-size: 11px; + margin-top: 12px; + margin-bottom: -5px; + + a { + color: var( --mini-smallprint-color ); + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBannerVar.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBannerVar.scss new file mode 100644 index 000000000..3b6fb5289 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBannerVar.scss @@ -0,0 +1,178 @@ +@use '@src/themes/Modo/variables/globals'; +@use '@src/themes/Modo/variables/breakpoints'; + +$height: 336px !default; +$height-l-up: 288px !default; + +.wmde-banner { + &-mini { + display: flex; + flex-direction: column; + min-height: $height; + padding: 6px; + position: relative; + background: var( --mini-background ); + color: var( --info-color ); + + @include breakpoints.phone-l-up { + min-height: $height-l-up; + padding: 12px; + } + + &-info { + background: var( --mini-info-background ); + border-radius: 16px; + margin-bottom: 6px; + display: flex; + flex-direction: column; + flex: 1 1 auto; + + @include breakpoints.phone-l-up { + margin-bottom: 12px; + } + } + + &-close { + top: -3px; + right: -3px; + position: absolute; + height: 36px; + width: 36px; + padding: 5px 3px 5px 7px; + background: transparent; + z-index: 99; + border: none; + + svg { + height: 15px; + width: 15px; + background: var( --mini-close-background ); + border-radius: 16px; + box-sizing: content-box; + border: solid 5px var( --mini-close-background ); + } + + &:hover { + cursor: pointer; + } + } + + &-headline { + height: 25px; + text-align: center; + margin: 16px 16px 12px; + + &-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; + background: var( --mini-headline-background ); + padding: 0 5px; + z-index: 2; + white-space: nowrap; + + @media ( min-width: 330px ) { + font-size: 16px; + } + + @media ( min-width: 360px ) { + font-size: 18px; + } + } + } + + &-slideshow { + display: flex; + flex-direction: column; + flex: 1 1 auto; + } + + &-button-group { + display: flex; + justify-content: center; + margin: 0 -6px; + + @include breakpoints.phone-l-up { + margin: 0 -12px; + } + } + + &-button, + &-button-preselect { + width: 50%; + height: 40px; + border: none; + border-radius: 20px; + font-weight: bold; + color: var( --mini-button-color ); + font-size: 14px; + white-space: nowrap; + margin: 0 6px; + + @include breakpoints.phone-l-up { + margin: 0 12px; + } + + @media ( min-width: 370px ) { + font-size: 16px; + } + } + + &-button { + background: var( --mini-button-background ); + + &:hover, + &:focus { + background: var( --mini-button-background-hover ); + } + } + + &-button-preselect { + background: var( --mini-button-alt-background ); + + &:hover, + &:focus { + background: var( --mini-button-alt-background-hover ); + } + } + + .smallprint-mini { + text-align: center; + font-size: 11px; + margin-top: 12px; + margin-bottom: -5px; + + a { + color: var( --mini-smallprint-color ); + + &:hover, + &:focus { + text-decoration: underline; + } + } + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MinimisedBanner.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MinimisedBanner.scss new file mode 100644 index 000000000..71c9abf8d --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/MinimisedBanner.scss @@ -0,0 +1,96 @@ +$transition-easing: cubic-bezier( 0.555, 0.155, 0.14, 0.945 ) !default; + +.wmde-banner { + &-minimised { + + height: 82px; + + &-inner { + flex: 1 0 auto; + display: flex; + flex-direction: column; + padding: 16px 0 18px; + position: relative; + border: 2px solid var( --mini-border ); + background: var( --mini-background ); + height: auto; + box-shadow: none; + } + + &-headline, + &-content { + padding: 0 16px; + margin-right: 26px; + } + + &-headline { + font-weight: bold; + } + + &-highlighted-text { + background: var( --minimise-text-highlight-background ); + font-weight: bold; + } + + &-close { + position: absolute; + height: 36px; + width: 36px; + top: 2px; + right: 6px; + text-align: center; + background: var( --mini-close-background ); + padding: 10px; + z-index: 2; + + &-button { + border: none; + margin-top: auto; + float: right; + height: 16px; + line-height: 16px; + width: 16px; + background: var( --mini-close-background ); + z-index: 2; + + svg { + height: 16px; + width: 16px; + } + + &:hover { + cursor: pointer; + } + } + } + + &-maximise { + height: 16px; + display: flex; + justify-content: center; + transition: height $transition-easing var( --wmde-banner-transition-duration ); + + &-tab { + height: 16px; + border: 2px solid var( --mini-border ); + border-top: none; + border-radius: 0 0 3px 3px; + box-shadow: var( --mini-box-shadow ); + } + + &-button { + border: none; + border-radius: 2px; + background: var( --mini-background ); + color: var( --minimise-color ); + position: relative; + height: 32px; + top: -18px; + cursor: pointer; + font-size: 14px; + font-weight: bold; + width: 175px; + } + } + } +} diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles.scss new file mode 100644 index 000000000..376688038 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles.scss @@ -0,0 +1,30 @@ +@use 'src/themes/Mikings/swatches/skin_default' with ( + $upgrade-to-yearly-button-form: true, + $progress-bar: true, + $soft-close: true, + $thank-you-box: true +); +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Mikings/defaults'; +@use './Banner'; +@use './MiniBanner' with ( + $height: 336px, + $height-l-up: 306px +); +@use './FullPageBanner'; +@use 'src/themes/Mikings/Footer/Footer'; +@use 'src/themes/Mikings/ThankYouBox/ThankYouBox'; +@use 'src/themes/Mikings/Footer/SelectionInput'; +@use 'src/themes/Mikings/DonationForm/MultiStepDonation'; +@use 'src/themes/Mikings/DonationForm/Forms/UpgradeToYearlyButtonForm'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SelectCustomAmount'; +@use 'src/themes/Mikings/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Mikings/Slider/Slider' with ( + $pagination-padding: 10px, + $pagination-height: 40px +); +@use 'src/themes/Mikings/SoftClose/SoftClose'; +@use 'src/themes/Mikings/ProgressBar/ProgressBar'; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles_var.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles_var.scss new file mode 100644 index 000000000..5bbdb69d1 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles_var.scss @@ -0,0 +1,28 @@ +@use 'src/themes/Modo/swatches/skin_default' with ( + $upgrade-to-yearly-button-form: true, + $progress-bar: true, + $soft-close: true, + $thank-you-box: true +); +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Modo/defaults'; +@use './BannerVar'; +@use './MiniBannerVar' with ( + $height: 336px, + $height-l-up: 306px +); +@use './FullPageBannerVar'; +@use 'src/themes/Modo/Footer/Footer'; +@use 'src/themes/Modo/ThankYouBox/ThankYouBox'; +@use 'src/themes/Modo/Footer/SelectionInput'; +@use 'src/themes/Modo/DonationForm/MultiStepDonation'; +@use 'src/themes/Modo/DonationForm/Forms/UpgradeToYearlyButtonForm'; +@use 'src/themes/Modo/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Modo/DonationForm/SubComponents/SelectCustomAmount'; +@use 'src/themes/Modo/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Modo/Slider/Slider'; +@use 'src/themes/Modo/SoftClose/SoftClose'; +@use 'src/themes/Modo/ProgressBar/ProgressBar'; +@use 'src/themes/Modo/Message/Message'; diff --git a/campaign_info.toml b/campaign_info.toml index fe8063f62..f38fd23fb 100644 --- a/campaign_info.toml +++ b/campaign_info.toml @@ -34,9 +34,9 @@ resolution = ["800x600", "1024x768", "1280x960", "1600x1200", "1920x1200", "2560 [mobile] name = "Mobile" icon = "mobile" -campaign = "C24_WMDE_Mobile_DE_11" -description = " based on CTRL of C24_WMDE_Mobile_DE_10, VAR uses a new theme" -campaign_tracking = "mob-de-11-ba-241203" +campaign = "C24_WMDE_Mobile_DE_12" +description = " based on VAR of C24_WMDE_Mobile_DE_11, VAR has a double progress bar" +campaign_tracking = "mob-de-12-ba-241210" preview_link = "/mobile/wiki/Wikipedia:Hauptseite?devbanner={{banner}}&banner=B22_WMDE_local_prototype&useskin=minerva" preview_link_darkmode = "/mobile/wiki/Wikipedia:Hauptseite?devbanner={{banner}}&banner=B22_WMDE_local_prototype&useskin=minerva&minervanightmode=1" preview_url = 'https://de.m.wikipedia.org/wiki/Wikipedia:Hauptseite?banner={{banner}}&useskin=minerva&devMode' @@ -45,14 +45,14 @@ use_of_funds_source = "MediaWiki:WMDE_Fundraising/UseOfFunds_2024_DE" # Banners of the campaign, key after "banners" can be anything [mobile.banners.ctrl] -filename = "./banners/mobile/C24_WMDE_Mobile_DE_11/banner_ctrl.ts" -pagename = "B24_WMDE_Mobile_DE_11_ctrl" -tracking = "org-mob11-241203-ctrl" +filename = "./banners/mobile/C24_WMDE_Mobile_DE_12/banner_ctrl.ts" +pagename = "B24_WMDE_Mobile_DE_12_ctrl" +tracking = "org-mob12-241210-ctrl" [mobile.banners.var] -filename = "./banners/mobile/C24_WMDE_Mobile_DE_11/banner_var.ts" -pagename = "B24_WMDE_Mobile_DE_11_var" -tracking = "org-mob11-241203-var" +filename = "./banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts" +pagename = "B24_WMDE_Mobile_DE_12_var" +tracking = "org-mob12-241210-var" [mobile.test_matrix] device = [ 'samsung_s10', 'iphone_xs_max', 'iphone_5s', 'iphone_se', "iphone_8", "iphone_12_mini", "iphone_7_plus", "iphone_11_pro_max"] diff --git a/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.spec.ts b/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.spec.ts new file mode 100644 index 000000000..556651194 --- /dev/null +++ b/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.spec.ts @@ -0,0 +1,183 @@ +import { afterEach, beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerCtrl.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { PageScroller } from '@src/utils/PageScroller/PageScroller'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { CurrencyDe } from '@src/utils/DynamicContent/formatters/CurrencyDe'; +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_changesAmountOptions'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { fullPageBannerFeatures } from '@test/features/FullPageBanner'; +import { formActionSwitchFeatures } from '@test/features/form_action_switch/MainDonation_UpgradeToYearlyButton'; +import { Tracker } from '@src/tracking/Tracker'; +import { bannerContentAnimatedTextFeatures, bannerContentDateAndTimeFeatures } from '@test/features/BannerContent'; +import { softCloseSubmitTrackingFeatures } from '@test/features/SoftCloseSubmitTracking'; +import { Timer } from '@src/utils/Timer'; +import { TimerStub } from '@test/fixtures/TimerStub'; + +let pageScroller: PageScroller; +let tracker: Tracker; +const formModel = useFormModel(); +const translator = ( key: string ): string => key; +describe( 'BannerCtrl.vue', () => { + + let wrapper: VueWrapper; + beforeEach( () => { + resetFormModel( formModel ); + + pageScroller = { + scrollIntoView: vi.fn(), + scrollToTop: vi.fn() + }; + + tracker = { + trackEvent: vi.fn() + }; + } ); + + afterEach( () => { + wrapper.unmount(); + } ); + + const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { + // attachTo the document body to fix an issue with Vue Test Utils where + // clicking a submit button in a form does not fire the submit event + wrapper = mount( Banner, { + attachTo: document.body, + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + pageScroller, + remainingImpressions: 10, + localCloseTracker: { + getItem: () => '', + setItem: () => {} + } + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + formActions: { donateWithAddressAction: 'https://example.com/with-address', donateAnonymouslyAction: 'https://example.com/without-address' }, + currencyFormatter: new CurrencyDe(), + formItems, + tracker, + timer: timer ?? new TimerStub() + } + } + } ); + + return wrapper; + }; + + describe( 'Content', () => { + test.each( [ + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + + test.each( [ + [ 'expectShowsLiveDateAndTimeInMiniBanner' ], + [ 'expectShowsLiveDateAndTimeInFullPageBanner' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectMainDonationFormSubmitsWithAddressForDirectDebit' ], + [ 'expectUpgradeToYearlyFormSubmitsWithAddressForDirectDebit' ] + ] )( '%s', async ( testName: string ) => { + await formActionSwitchFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftCloseOnMiniBannerClose' ], + [ 'expectDoesNotShowSoftCloseOnFullBannerClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseMaybeLaterEvent' ], + [ 'expectEmitsSoftCloseAlreadyDonatedEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Soft Close Submit Tracking', () => { + test.each( [ + [ 'expectStoresMaybeLateCloseChoice' ], + [ 'expectStoresCloseCloseChoice' ], + [ 'expectStoresAlreadyDonatedCloseChoice' ], + [ 'expectEmitsBannerSubmitOnReturnEvent' ], + [ 'expectDoesNotEmitsBannerSubmitOnReturnEventWhenLocalStorageItemIsMissing' ] + ] )( '%s', async ( testName: string ) => { + await softCloseSubmitTrackingFeatures[ testName ]( getWrapper(), tracker ); + } ); + } ); + + describe( 'Use of Funds', () => { + test.each( [ + [ 'expectShowsUseOfFunds' ], + [ 'expectHidesUseOfFunds' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectScrollsToFormWhenCallToActionIsClicked' ], + [ 'expectScrollsToLinkWhenCloseIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsScrollFeatures[ testName ]( getWrapper(), pageScroller ); + } ); + } ); + + describe( 'Mini Banner', () => { + test.each( [ + [ 'expectSlideShowPlaysWhenMiniBannerBecomesVisible' ], + [ 'expectSlideShowStopsWhenFullBannerBecomesVisible' ], + [ 'expectShowsFullPageWhenCallToActionIsClicked' ], + [ 'expectEmitsBannerContentChangedEventWhenCallToActionIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await miniBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Full Page Banner', () => { + test.each( [ + [ 'expectEmitsCloseEvent' ], + [ 'expectEmitsModalOpenedEvent' ], + [ 'expectEmitsModalClosedEvent' ] + ] )( '%s', async ( testName: string ) => { + await fullPageBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); +} ); diff --git a/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.spec.ts b/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.spec.ts new file mode 100644 index 000000000..a3216e878 --- /dev/null +++ b/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.spec.ts @@ -0,0 +1,183 @@ +import { afterEach, beforeEach, describe, test, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/mobile/C24_WMDE_Mobile_DE_12/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 { CurrencyDe } from '@src/utils/DynamicContent/formatters/CurrencyDe'; +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_changesAmountOptions'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { fullPageBannerFeatures } from '@test/features/FullPageBanner'; +import { formActionSwitchFeatures } from '@test/features/form_action_switch/MainDonation_UpgradeToYearlyButton'; +import { Tracker } from '@src/tracking/Tracker'; +import { bannerContentAnimatedTextFeatures, bannerContentDateAndTimeFeatures } from '@test/features/BannerContent'; +import { softCloseSubmitTrackingFeatures } from '@test/features/SoftCloseSubmitTracking'; +import { Timer } from '@src/utils/Timer'; +import { TimerStub } from '@test/fixtures/TimerStub'; + +let pageScroller: PageScroller; +let tracker: Tracker; +const formModel = useFormModel(); +const translator = ( key: string ): string => key; +describe( 'BannerVar.vue', () => { + + let wrapper: VueWrapper; + beforeEach( () => { + resetFormModel( formModel ); + + pageScroller = { + scrollIntoView: vi.fn(), + scrollToTop: vi.fn() + }; + + tracker = { + trackEvent: vi.fn() + }; + } ); + + afterEach( () => { + wrapper.unmount(); + } ); + + const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { + // attachTo the document body to fix an issue with Vue Test Utils where + // clicking a submit button in a form does not fire the submit event + wrapper = mount( Banner, { + attachTo: document.body, + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + pageScroller, + remainingImpressions: 10, + localCloseTracker: { + getItem: () => '', + setItem: () => {} + } + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + formActions: { donateWithAddressAction: 'https://example.com/with-address', donateAnonymouslyAction: 'https://example.com/without-address' }, + currencyFormatter: new CurrencyDe(), + formItems, + tracker, + timer: timer ?? new TimerStub() + } + } + } ); + + return wrapper; + }; + + describe( 'Content', () => { + test.each( [ + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectHidesAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + + test.each( [ + [ 'expectShowsLiveDateAndTimeInMiniBanner' ], + [ 'expectShowsLiveDateAndTimeInFullPageBanner' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectMainDonationFormSubmitsWithAddressForDirectDebit' ], + [ 'expectUpgradeToYearlyFormSubmitsWithAddressForDirectDebit' ] + ] )( '%s', async ( testName: string ) => { + await formActionSwitchFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftCloseOnMiniBannerClose' ], + [ 'expectDoesNotShowSoftCloseOnFullBannerClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseMaybeLaterEvent' ], + [ 'expectEmitsSoftCloseAlreadyDonatedEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Soft Close Submit Tracking', () => { + test.each( [ + [ 'expectStoresMaybeLateCloseChoice' ], + [ 'expectStoresCloseCloseChoice' ], + [ 'expectStoresAlreadyDonatedCloseChoice' ], + [ 'expectEmitsBannerSubmitOnReturnEvent' ], + [ 'expectDoesNotEmitsBannerSubmitOnReturnEventWhenLocalStorageItemIsMissing' ] + ] )( '%s', async ( testName: string ) => { + await softCloseSubmitTrackingFeatures[ testName ]( getWrapper(), tracker ); + } ); + } ); + + describe( 'Use of Funds', () => { + test.each( [ + [ 'expectShowsUseOfFunds' ], + [ 'expectHidesUseOfFunds' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectScrollsToFormWhenCallToActionIsClicked' ], + [ 'expectScrollsToLinkWhenCloseIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsScrollFeatures[ testName ]( getWrapper(), pageScroller ); + } ); + } ); + + describe( 'Mini Banner', () => { + test.each( [ + [ 'expectSlideShowPlaysWhenMiniBannerBecomesVisible' ], + [ 'expectSlideShowStopsWhenFullBannerBecomesVisible' ], + [ 'expectShowsFullPageWhenCallToActionIsClicked' ], + [ 'expectEmitsBannerContentChangedEventWhenCallToActionIsClicked' ] + ] )( '%s', async ( testName: string ) => { + await miniBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Full Page Banner', () => { + test.each( [ + [ 'expectEmitsCloseEvent' ], + [ 'expectEmitsModalOpenedEvent' ], + [ 'expectEmitsModalClosedEvent' ] + ] )( '%s', async ( testName: string ) => { + await fullPageBannerFeatures[ testName ]( getWrapper() ); + } ); + } ); +} ); From 8468a73b27dce04c291d9ef3ea02ed13f13f3bab Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Fri, 6 Dec 2024 15:22:45 +0100 Subject: [PATCH 2/4] Prepare CTRL for C24_WMDE_Mobile_DE_12 - Decrease button font size on very small screens Ticket: https://phabricator.wikimedia.org/T381398 --- .../C24_WMDE_Mobile_DE_12/banner_var.ts | 2 +- .../components/BannerVar.vue | 10 +- .../components/FullPageBanner.vue | 31 +-- .../components/FullPageBannerVar.vue | 46 ----- .../components/MiniBanner.vue | 21 +-- .../components/MiniBannerVar.vue | 36 ---- .../components/MinimisedBanner.vue | 32 ---- .../C24_WMDE_Mobile_DE_12/styles/Banner.scss | 4 +- .../styles/BannerVar.scss | 56 ------ .../styles/FullPageBanner.scss | 50 +++-- .../styles/FullPageBannerVar.scss | 116 ------------ .../styles/MiniBanner.scss | 75 +++++--- .../styles/MiniBannerVar.scss | 178 ------------------ .../styles/MinimisedBanner.scss | 96 ---------- .../C24_WMDE_Mobile_DE_12/styles/styles.scss | 36 ++-- .../styles/styles_var.scss | 28 --- .../Modo/DonationForm/MultiStepDonation.scss | 7 +- 17 files changed, 133 insertions(+), 691 deletions(-) delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBannerVar.vue delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBannerVar.vue delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/components/MinimisedBanner.vue delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/BannerVar.scss delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/FullPageBannerVar.scss delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/MiniBannerVar.scss delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/MinimisedBanner.scss delete mode 100644 banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles_var.scss diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts index 94cd4a000..2835b1e97 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/banner_var.ts @@ -1,6 +1,6 @@ import { createVueApp } from '@src/createVueApp'; -import './styles/styles_var.scss'; +import './styles/styles.scss'; import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue'; import Banner from './components/BannerVar.vue'; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.vue index 0c405a056..e28a0d24c 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.vue @@ -98,11 +98,6 @@ {{ $translate( 'soft-close-button-already-donated' ) }} - import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; import { computed, inject, ref, watch } from 'vue'; -import FullPageBanner from './FullPageBannerVar.vue'; -import MiniBanner from './MiniBannerVar.vue'; +import FullPageBanner from './FullPageBanner.vue'; +import MiniBanner from './MiniBanner.vue'; import FundsModal from '@src/components/UseOfFunds/FundsModal.vue'; import { UseOfFundsContent as useOfFundsContentInterface } from '@src/domain/UseOfFunds/UseOfFundsContent'; import { UseOfFundsCloseSources } from '@src/components/UseOfFunds/UseOfFundsCloseSources'; @@ -156,7 +151,6 @@ import { FormItem } from '@src/utils/FormItemsBuilder/FormItem'; import FormItemsBuilder from '@src/utils/FormItemsBuilder/FormItemsBuilder'; import { Translator } from '@src/Translator'; import { Currency } from '@src/utils/DynamicContent/formatters/Currency'; -import CloseIconMobile from '@src/components/Icons/CloseIconMobile.vue'; enum ContentStates { Mini = 'wmde-banner-wrapper--mini', diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBanner.vue index d75bb5b68..7350fbfa1 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBanner.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBanner.vue @@ -8,27 +8,30 @@ +
Jetzt sind Sie in Deutschland gefragt.
- + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBannerVar.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBannerVar.vue deleted file mode 100644 index 7350fbfa1..000000000 --- a/banners/mobile/C24_WMDE_Mobile_DE_12/components/FullPageBannerVar.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBanner.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBanner.vue index 7ab1e5afd..dcbe339c0 100644 --- a/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBanner.vue +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/components/MiniBanner.vue @@ -1,21 +1,20 @@ - + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/content/ProgressBar.vue b/banners/mobile/C24_WMDE_Mobile_DE_12/content/ProgressBar.vue new file mode 100644 index 000000000..54bed9a88 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/content/ProgressBar.vue @@ -0,0 +1,30 @@ + + + diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/messages_var.ts b/banners/mobile/C24_WMDE_Mobile_DE_12/messages_var.ts new file mode 100644 index 000000000..29192b85b --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/messages_var.ts @@ -0,0 +1,32 @@ +import DynamicCampaignTextDe from '@src/utils/DynamicContent/messages/DynamicCampaignText.de'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyDe from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.de'; +import FooterDe from '@src/components/Footer/messages/Footer.de'; +import MainDonationFormDe from '@src/components/DonationForm/Forms/messages/MainDonationForm.de'; +import SoftCloseDe from '@src/components/SoftClose/messages/SoftClose.de'; +import DoubleProgressBarDe from '@src/components/ProgressBar/messages/DoubleProgressBar.de'; + +const messages: TranslationMessages = { + ...DynamicCampaignTextDe, + ...FooterDe, + ...MainDonationFormDe, + ...UpgradeToYearlyDe, + ...SoftCloseDe, + ...DoubleProgressBarDe, + + // custom messages here + 'use-of-funds-link': 'Was Ihre Spende bewirkt', + 'payment-bank-transfer': 'Überweisung', + 'payment-sofort': 'Sofort', + 'upgrade-to-yearly-copy': '

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

' + + '

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

', + 'upgrade-to-yearly-no': 'Nein, ich spende einmalig {{amount}}', + 'upgrade-to-yearly-yes': 'Ja, ich spende {{amount}} jährlich', + 'campaign-day-only-n-days': 'Heute sind es nur noch {{days}} Tage bis zum Ende unserer Spendenkampagne.', + 'soft-close-prompt': 'Wikipedia später unterstützen?', + 'soft-close-button-already-donated': 'Habe schon gespendet', + 'amount-total': '' +}; + +export default messages; diff --git a/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles_var.scss b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles_var.scss new file mode 100644 index 000000000..82cffc1b4 --- /dev/null +++ b/banners/mobile/C24_WMDE_Mobile_DE_12/styles/styles_var.scss @@ -0,0 +1,28 @@ +@use 'src/themes/Modo/swatches/skin_default' with ( + $upgrade-to-yearly-button-form: true, + $double-progress-bar: true, + $soft-close: true, + $thank-you-box: true +); +@use 'src/components/BannerConductor/banner-transition'; +@use 'src/themes/UseOfFunds/swatches/skin_default' as uof-default; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Modo/defaults'; +@use 'Banner'; +@use 'MiniBanner' with ( + $height: 336px, + $height-l-up: 306px +); +@use 'FullPageBanner'; +@use 'src/themes/Modo/Footer/Footer'; +@use 'src/themes/Modo/ThankYouBox/ThankYouBox'; +@use 'src/themes/Modo/Footer/SelectionInput'; +@use 'src/themes/Modo/DonationForm/MultiStepDonation'; +@use 'src/themes/Modo/DonationForm/Forms/UpgradeToYearlyButtonForm'; +@use 'src/themes/Modo/DonationForm/SubComponents/SelectGroup'; +@use 'src/themes/Modo/DonationForm/SubComponents/SelectCustomAmount'; +@use 'src/themes/Modo/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Modo/Slider/Slider'; +@use 'src/themes/Modo/SoftClose/SoftClose'; +@use 'src/themes/Modo/ProgressBar/DoubleProgressBar'; +@use 'src/themes/Modo/Message/Message'; diff --git a/src/components/ProgressBar/ConfigurableDoubleProgressBar.vue b/src/components/ProgressBar/ConfigurableDoubleProgressBar.vue new file mode 100644 index 000000000..9456c1367 --- /dev/null +++ b/src/components/ProgressBar/ConfigurableDoubleProgressBar.vue @@ -0,0 +1,60 @@ + + + diff --git a/src/components/ProgressBar/Icons/HandIcon.vue b/src/components/ProgressBar/Icons/HandIcon.vue new file mode 100644 index 000000000..f1b49c7a0 --- /dev/null +++ b/src/components/ProgressBar/Icons/HandIcon.vue @@ -0,0 +1,6 @@ + diff --git a/src/components/ProgressBar/Icons/TimerIcon.vue b/src/components/ProgressBar/Icons/TimerIcon.vue new file mode 100644 index 000000000..42cd4c430 --- /dev/null +++ b/src/components/ProgressBar/Icons/TimerIcon.vue @@ -0,0 +1,6 @@ + diff --git a/src/themes/Modo/ProgressBar/DoubleProgressBar.scss b/src/themes/Modo/ProgressBar/DoubleProgressBar.scss new file mode 100644 index 000000000..dbea0737d --- /dev/null +++ b/src/themes/Modo/ProgressBar/DoubleProgressBar.scss @@ -0,0 +1,81 @@ +@use 'src/components/ProgressBar/DoubleProgressBar'; +@use 'transitionsDouble'; + +.wmde-banner { + @include DoubleProgressBar.layout; + + .wmde-banner { + &-double-progress { + margin: 0; + font-size: 12px; + + &-labels { + display: flex; + justify-content: space-between; + font-weight: bold; + margin-bottom: 6px; + } + + &-amount, + &-time { + height: 16px; + line-height: 16px; + padding-right: 10px; + border-radius: 12px; + + &-fill, + &-difference { + color: var( --double-progress-color ); + height: 100%; + padding: 0 10px; + } + + &-fill { + display: flex; + justify-content: space-between; + } + } + + &-right-text { + float: right; + color: var( --double-progress-right-text-color ); + } + + &-amount { + margin-bottom: 10px; + background: var( --double-progress-time-background ); + + &-fill, + &-difference { + border-radius: 12px; + } + + &-fill { + background: var( --double-progress-time-fill-background ); + z-index: 2; + } + + &-difference { + background: var( --double-progress-difference-background ); + z-index: 1; + text-align: right; + color: var( --double-progress-difference-color ); + } + + svg { + position: relative; + top: 2px; + } + } + + &-time { + background: var( --double-progress-amount-background ); + + &-fill { + border-radius: 12px; + background: var( --double-progress-amount-fill-background ); + } + } + } + } +} diff --git a/src/themes/Modo/ProgressBar/_transitionsDouble.scss b/src/themes/Modo/ProgressBar/_transitionsDouble.scss new file mode 100644 index 000000000..d5015aec0 --- /dev/null +++ b/src/themes/Modo/ProgressBar/_transitionsDouble.scss @@ -0,0 +1,49 @@ +@use '../variables/globals'; + +.wmde-banner { + &-double-progress-amount-difference, + &-double-progress-time-fill, + &-double-progress-amount-fill { + transition: width 3000ms globals.$banner-easing; + width: 0; + max-width: 100%; + } + + &-double-progress .text-fade { + opacity: 0; + transition: opacity 300ms globals.$banner-easing; + transition-delay: 3000ms; + } + + &--visible { + .wmde-banner-mini { + .wmde-banner-double-progress-amount-difference, + .wmde-banner-double-progress-time-fill { + width: var( --wmde-banner-progress-bar-time-width ); + } + + .wmde-banner-double-progress-amount-fill { + width: var( --wmde-banner-progress-bar-width ); + } + + .wmde-banner-double-progress .text-fade { + opacity: 1; + } + } + } + + &-wrapper--full-page { + .wmde-banner-double-progress-amount-difference, + .wmde-banner-double-progress-time-fill { + width: var( --wmde-banner-progress-bar-time-width ); + } + + .wmde-banner-double-progress-amount-fill { + width: var( --wmde-banner-progress-bar-width ); + } + + .wmde-banner-double-progress .text-fade { + opacity: 1; + } + } +} diff --git a/src/themes/Modo/swatches/color_light.scss b/src/themes/Modo/swatches/color_light.scss index 5bb64a0b4..2040e4e93 100644 --- a/src/themes/Modo/swatches/color_light.scss +++ b/src/themes/Modo/swatches/color_light.scss @@ -10,8 +10,10 @@ $grey700: #54595d; $grey400: #a2a9b1; $grey350: #c8ccd1; $grey100: #eaecf0; -$grey90: #eeeeee; +$grey75: #e8e8e8; +$grey50: #eeeeee; +$blue300: #66cfff; $blue400: #5d9fd0; $blue500: #648196; $blue600: #386d94; @@ -37,11 +39,15 @@ $green800: #1d865b; $purple10: #ebe2fc; $purple100: #6b4ba1; +$red200: #f17678; +$red300: #ff5233; + @mixin swatch( $address-type-button-form: false, $upgrade-to-yearly-button-form: false, $select-group-image-label: false, $progress-bar: false, + $double-progress-bar: false, $soft-close: false, $subscription-form: false, $thank-you-box: false @@ -57,7 +63,7 @@ $purple100: #6b4ba1; --mini-info-background: #{$green800}; --mini-box-shadow: 0 3px 0.6em rgba( 60 60 60 / 40% ); - --mini-close-background: #{$grey90}; + --mini-close-background: #{$grey50}; --mini-headline-line: #{$yellow200}; --mini-headline-background: #{$green800}; @@ -82,7 +88,7 @@ $purple100: #6b4ba1; --full-smallprint-color: #{$grey700}; - --full-close-background: #{$grey90}; + --full-close-background: #{$grey50}; --slider-pagination-background: #{$grey350}; --slider-pagination-background-active: #{$white}; @@ -148,6 +154,21 @@ $purple100: #6b4ba1; --progress-bar-color: #{$black}; } + @if $double-progress-bar { + --double-progress-color: #{$black}; + --double-progress-time-background: #{$grey75}; + --double-progress-time-fill-background: #{$yellow200}; + --double-progress-difference-background: #{$red300}; + --double-progress-difference-color: #{$white}; + + --double-progress-amount-background: #{$grey75}; + --double-progress-amount-fill-background: #{$blue300}; + --double-progress-right-text-color: #{$black}; + + --double-progress-hand-fill: #{$black}; + --double-progress-timer-fill: #{$black}; + } + @if $soft-close { --soft-close-background: #{$white}; --soft-close-box-shadow: 0 3px 0.6em rgba( 60 60 60 / 40% ); @@ -155,7 +176,7 @@ $purple100: #6b4ba1; --soft-close-prompt-color: #{$white}; --soft-close-prompt-background: #{$green800}; - --soft-close-close-button-background: #{$grey90}; + --soft-close-close-button-background: #{$grey50}; --soft-close-button-background: #{$blue700}; --soft-close-button-color: #{$white}; diff --git a/src/themes/Modo/swatches/skin_default.scss b/src/themes/Modo/swatches/skin_default.scss index ea2f5b9bb..0ea568f4a 100644 --- a/src/themes/Modo/swatches/skin_default.scss +++ b/src/themes/Modo/swatches/skin_default.scss @@ -4,6 +4,7 @@ $address-type-button-form: false !default; $upgrade-to-yearly-button-form: false !default; $select-group-image-label: false !default; $progress-bar: false !default; +$double-progress-bar: false !default; $soft-close: false !default; $subscription-form: false !default; $thank-you-box: false !default; @@ -14,6 +15,7 @@ $thank-you-box: false !default; $upgrade-to-yearly-button-form, $select-group-image-label, $progress-bar, + $double-progress-bar, $soft-close, $subscription-form, $thank-you-box diff --git a/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.spec.ts b/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.spec.ts index a3216e878..24deaec0f 100644 --- a/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.spec.ts +++ b/test/banners/mobile/C24_WMDE_Mobile_DE_12/components/BannerVar.spec.ts @@ -72,7 +72,8 @@ describe( 'BannerVar.vue', () => { currencyFormatter: new CurrencyDe(), formItems, tracker, - timer: timer ?? new TimerStub() + timer: timer ?? new TimerStub(), + currentCampaignTimePercentage: 42 } } } ); diff --git a/test/components/ProgressBar/ConfigurableDoubleProgressBar.spec.ts b/test/components/ProgressBar/ConfigurableDoubleProgressBar.spec.ts new file mode 100644 index 000000000..86b8b5db7 --- /dev/null +++ b/test/components/ProgressBar/ConfigurableDoubleProgressBar.spec.ts @@ -0,0 +1,54 @@ +import { mount } from '@vue/test-utils'; +import { describe, it, expect, beforeEach } from 'vitest'; +import ProgressBar from '@src/components/ProgressBar/ConfigurableDoubleProgressBar.vue'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { DateAndTime } from '@src/utils/DynamicContent/DateAndTime'; + +describe( 'ConfigurableDoubleProgressBar.vue', () => { + let dynamicCampaignContent: DynamicContent; + + beforeEach( () => { + dynamicCampaignContent = { + campaignDaySentence: '', + currentDate: '', + getCurrentDateAndTime(): DateAndTime { + return { currentDate: '', currentTime: '' }; + }, + currentDayName: '', + daysLeftSentence: 'daysLeftSentence', + daysPassedSentence: 'daysPassedSentence', + donorsNeededSentence: '', + goalDonationSum: '', + remainingDonationSum: '', + overallImpressionCount: 0, + progressBarContent: { + percentageTowardsTarget: 42, + donationTarget: 'donationTarget', + donationTargetAmount: 'donationTargetAmount', + amountDonated: 'amountDonated', + amountNeeded: 'amountNeeded', + isLateProgress: false + }, + visitorsVsDonorsSentence: '', + averageDonation: '' + }; + } ); + + it( 'should add the donation percentages as css variables', () => { + const wrapper = mount( ProgressBar, { + props: { amountToShowOnRight: 'TARGET' }, + global: { + mocks: { + $translate: ( key: string ) => key + }, + provide: { + dynamicCampaignText: dynamicCampaignContent, + currentCampaignTimePercentage: 66 + } + } + } ); + + expect( wrapper.attributes( 'style' ) ).toContain( '--wmde-banner-progress-bar-width: 42%' ); + expect( wrapper.attributes( 'style' ) ).toContain( '--wmde-banner-progress-bar-time-width: 66%' ); + } ); +} ); From 50987047e3b6fdf45dc7977cbfcd7380f736c9c4 Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Tue, 10 Dec 2024 16:38:32 +0100 Subject: [PATCH 4/4] Fix late progress on CTRL banner There was some weird styles being added to the single progress bar once late progress was activated that are now fixed. Ticket: https://phabricator.wikimedia.org/T381398 --- src/environment/dev/CampaignParameterOverride.ts | 2 +- src/themes/Modo/ProgressBar/ProgressBar.scss | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/environment/dev/CampaignParameterOverride.ts b/src/environment/dev/CampaignParameterOverride.ts index 9e6099926..f3ad1d316 100644 --- a/src/environment/dev/CampaignParameterOverride.ts +++ b/src/environment/dev/CampaignParameterOverride.ts @@ -17,6 +17,6 @@ export function getCampaignParameterOverride( campaignParameters: CampaignParame ...campaignParameters, startDate: '2024-10-28', endDate: '2024-12-31', - isLateProgress: false + isLateProgress: true }; } diff --git a/src/themes/Modo/ProgressBar/ProgressBar.scss b/src/themes/Modo/ProgressBar/ProgressBar.scss index 5145da920..f55a461b6 100644 --- a/src/themes/Modo/ProgressBar/ProgressBar.scss +++ b/src/themes/Modo/ProgressBar/ProgressBar.scss @@ -32,7 +32,7 @@ &-fill-wrapper { height: 18px; - line-height: 18px; + line-height: 15px; width: 100%; border: 2px solid var( --progress-bar-border ); border-radius: 13px; @@ -55,17 +55,12 @@ &--late-progress { .wmde-banner-progress-bar-text { - margin-bottom: 0; font-size: 12px; @media ( min-width: 360px ) { font-size: 14px; } } - .wmde-banner-progress-bar-fill-wrapper { - height: 26px; - line-height: 22px; - } .wmde-banner-progress-bar-fill-text { display: inline; }