Skip to content

Commit d68bb00

Browse files
authored
Merge pull request #859 from wmde/WMDE_FR_2025_Mobile_DE_07
WMDE_FR_2025_Mobile_DE_07
2 parents 1ac6d5a + 55d10c0 commit d68bb00

File tree

28 files changed

+1916
-56
lines changed

28 files changed

+1916
-56
lines changed

banners/desktop/C25_WMDE_Desktop_DE_00/components/BannerCtrl.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
v-if="contentState === ContentStates.SoftClosing"
6868
:show-close-icon="true"
6969
@close="() => onClose( 'SoftClose', CloseChoices.Close )"
70+
@x-icon-close="() => onClose( 'SoftClose', CloseChoices.XIconClose )"
7071
@maybeLater="() => onClose( 'SoftClose', CloseChoices.MaybeLater )"
7172
@timeOutClose="() => onClose( 'SoftClose', CloseChoices.TimeOut )"
7273
@maybeLater7Days="() => onClose( 'SoftClose', CloseChoices.Close )"

banners/desktop/C25_WMDE_Desktop_DE_00/components/BannerVar.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
v-if="contentState === ContentStates.SoftClosing"
6969
:show-close-icon="true"
7070
@close="() => onClose( 'SoftClose', CloseChoices.Close )"
71+
@x-icon-close="() => onClose( 'SoftClose', CloseChoices.XIconClose )"
7172
@maybeLater="() => onClose( 'SoftClose', CloseChoices.MaybeLater )"
7273
@timeOutClose="() => onClose( 'SoftClose', CloseChoices.TimeOut )"
7374
@maybeLater7Days="() => onClose( 'SoftClose', CloseChoices.Close )"
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { createVueApp } from '@src/createVueApp';
2+
3+
import './styles/styles.scss';
4+
5+
import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue';
6+
import Banner from './components/BannerCtrl.vue';
7+
import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment';
8+
import { WindowResizeHandler } from '@src/utils/ResizeHandler';
9+
import PageWPORG from '@src/page/PageWPORG';
10+
import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki';
11+
import { SkinFactory } from '@src/page/skin/SkinFactory';
12+
import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker';
13+
import TranslationPlugin from '@src/TranslationPlugin';
14+
import { Translator } from '@src/Translator';
15+
import DynamicTextPlugin from '@src/DynamicTextPlugin';
16+
import { LocalImpressionCount } from '@src/utils/LocalImpressionCount';
17+
import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller';
18+
import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG';
19+
import eventMappings from './event_map';
20+
import messages from './messages';
21+
import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe';
22+
import { createFormItems } from './form_items';
23+
import { createFormActions } from '@src/createFormActions';
24+
import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker';
25+
import { WindowTimer } from '@src/utils/Timer';
26+
import { currentCampaignTimePercentage } from '@src/components/ProgressBar/currentCampaignTimePercentage';
27+
28+
const localeFactory = new LocaleFactoryDe();
29+
const translator = new Translator( messages );
30+
const mediaWiki = new WindowMediaWiki();
31+
const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() );
32+
const runtimeEnvironment = new UrlRuntimeEnvironment( window.location );
33+
const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment );
34+
const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment );
35+
const date = new Date();
36+
const currencyFormatter = localeFactory.getCurrencyFormatter();
37+
38+
const app = createVueApp( BannerConductor, {
39+
page,
40+
bannerConfig: {
41+
delay: runtimeEnvironment.getBannerDelay( 7500 ),
42+
transitionDuration: 1000
43+
},
44+
bannerCategory: 'fundraising',
45+
bannerProps: {
46+
useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(),
47+
pageScroller: new WindowPageScroller(),
48+
localCloseTracker: new LocalStorageCloseTracker()
49+
},
50+
resizeHandler: new WindowResizeHandler(),
51+
banner: Banner,
52+
impressionCount
53+
} );
54+
55+
app.use( TranslationPlugin, translator );
56+
app.use( DynamicTextPlugin, {
57+
campaignParameters: page.getCampaignParameters(),
58+
date,
59+
formatters: localeFactory.getFormatters(),
60+
impressionCount,
61+
translator
62+
} );
63+
64+
app.provide( 'currencyFormatter', currencyFormatter );
65+
app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) );
66+
app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount ) );
67+
app.provide( 'tracker', tracker );
68+
app.provide( 'timer', new WindowTimer() );
69+
app.provide( 'currentCampaignTimePercentage', currentCampaignTimePercentage( date, page.getCampaignParameters() ) );
70+
71+
app.mount( page.getBannerContainer() );
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { createVueApp } from '@src/createVueApp';
2+
3+
import './styles/styles_var.scss';
4+
5+
import BannerConductor from '@src/components/BannerConductor/BannerConductor.vue';
6+
import Banner from './components/BannerVar.vue';
7+
import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment';
8+
import { WindowResizeHandler } from '@src/utils/ResizeHandler';
9+
import PageWPORG from '@src/page/PageWPORG';
10+
import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki';
11+
import { SkinFactory } from '@src/page/skin/SkinFactory';
12+
import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker';
13+
import TranslationPlugin from '@src/TranslationPlugin';
14+
import { Translator } from '@src/Translator';
15+
import DynamicTextPlugin from '@src/DynamicTextPlugin';
16+
import { LocalImpressionCount } from '@src/utils/LocalImpressionCount';
17+
import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller';
18+
import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG';
19+
import eventMappings from './event_map';
20+
import messages from './messages';
21+
import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe';
22+
import { createFormItems } from './form_items';
23+
import { createFormActions } from '@src/createFormActions';
24+
import { LocalStorageCloseTracker } from '@src/utils/LocalCloseTracker';
25+
import { WindowTimer } from '@src/utils/Timer';
26+
import { currentCampaignTimePercentage } from '@src/components/ProgressBar/currentCampaignTimePercentage';
27+
28+
const localeFactory = new LocaleFactoryDe();
29+
const translator = new Translator( messages );
30+
const mediaWiki = new WindowMediaWiki();
31+
const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() );
32+
const runtimeEnvironment = new UrlRuntimeEnvironment( window.location );
33+
const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment );
34+
const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment );
35+
const date = new Date();
36+
const currencyFormatter = localeFactory.getCurrencyFormatter();
37+
38+
const app = createVueApp( BannerConductor, {
39+
page,
40+
bannerConfig: {
41+
delay: runtimeEnvironment.getBannerDelay( 7500 ),
42+
transitionDuration: 1000
43+
},
44+
bannerCategory: 'fundraising',
45+
bannerProps: {
46+
useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(),
47+
pageScroller: new WindowPageScroller(),
48+
remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'mobile' ) ),
49+
localCloseTracker: new LocalStorageCloseTracker()
50+
},
51+
resizeHandler: new WindowResizeHandler(),
52+
banner: Banner,
53+
impressionCount
54+
} );
55+
56+
app.use( TranslationPlugin, translator );
57+
app.use( DynamicTextPlugin, {
58+
campaignParameters: page.getCampaignParameters(),
59+
date,
60+
formatters: localeFactory.getFormatters(),
61+
impressionCount,
62+
translator
63+
} );
64+
65+
app.provide( 'currencyFormatter', currencyFormatter );
66+
app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) );
67+
app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount ) );
68+
app.provide( 'tracker', tracker );
69+
app.provide( 'timer', new WindowTimer() );
70+
app.provide( 'currentCampaignTimePercentage', currentCampaignTimePercentage( date, page.getCampaignParameters() ) );
71+
72+
app.mount( page.getBannerContainer() );
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
<template>
2+
<div class="wmde-banner-wrapper" :class="contentState">
3+
<MiniBanner
4+
@close="() => onClose( 'MiniBanner', CloseChoices.Close )"
5+
@show-full-page-banner="onshowFullPageBanner"
6+
@show-full-page-banner-preselected="onshowFullPageBannerPreselected"
7+
@showFundsModal="onShowFundsModal( 'MiniBanner' )"
8+
@already-donated-clicked="onClose( 'MiniBanner', CloseChoices.AlreadyDonated )"
9+
>
10+
<template #banner-slides>
11+
<KeenSlider :with-navigation="false" :play="slideshowShouldPlay" :interval="7000">
12+
13+
<template #slides="{ currentSlide }: any">
14+
<BannerSlides :currentSlide="currentSlide" :play-live-text="contentState === ContentStates.Mini">
15+
<template #progress><ProgressBar amount-to-show-on-right="TARGET"/></template>
16+
</BannerSlides>
17+
</template>
18+
19+
</KeenSlider>
20+
</template>
21+
</MiniBanner>
22+
23+
<FullPageBanner
24+
@showFundsModal="onShowFundsModal( 'FullPageBanner' )"
25+
@close="() => onClose( 'FullPageBanner', CloseChoices.Hide )"
26+
>
27+
<template #banner-text>
28+
<BannerText :play-live-text="contentState === ContentStates.FullPage"/>
29+
</template>
30+
31+
<template #progress>
32+
<ProgressBar amount-to-show-on-right="TARGET"/>
33+
</template>
34+
35+
<template #donation-form="{ formInteraction }: any">
36+
<MultiStepDonation
37+
:step-controllers="stepControllers"
38+
@form-interaction="formInteraction"
39+
:page-scroller="pageScroller"
40+
:submit-callback="onSubmit"
41+
>
42+
43+
<template #[FormStepNames.MainDonationFormStep]="{ pageIndex, submit, isCurrent, previous }: any">
44+
<MainDonationForm
45+
:page-index="pageIndex"
46+
@submit="submit"
47+
:is-current="isCurrent"
48+
@previous="previous"
49+
:dynamic-amounts="amountOptionsForForm"
50+
>
51+
52+
<template #button>
53+
<MainDonationFormButton/>
54+
</template>
55+
56+
</MainDonationForm>
57+
</template>
58+
59+
<template #[FormStepNames.UpgradeToYearlyFormStep]="{ pageIndex, submit, isCurrent, previous }: any">
60+
<UpgradeToYearlyButtonForm
61+
:page-index="pageIndex"
62+
@submit="submit"
63+
:is-current="isCurrent"
64+
@previous="previous"
65+
>
66+
<template #back>
67+
<ChevronLeftIcon/>
68+
{{ $translate( 'back-button' ) }}
69+
</template>
70+
</UpgradeToYearlyButtonForm>
71+
</template>
72+
73+
</MultiStepDonation>
74+
</template>
75+
76+
<template #footer>
77+
<BannerFooter :show-funds-link="false"/>
78+
</template>
79+
</FullPageBanner>
80+
81+
<FundsModal
82+
:content="useOfFundsContent"
83+
:visible="isFundsModalVisible"
84+
@hide="onHideFundsModal"
85+
@callToAction="onFundsModalCallToAction"
86+
/>
87+
</div>
88+
</template>
89+
90+
<script setup lang="ts">
91+
import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates';
92+
import { computed, inject, ref, watch } from 'vue';
93+
import FullPageBanner from './FullPageBanner.vue';
94+
import MiniBanner from './MiniBanner.vue';
95+
import FundsModal from '@src/components/UseOfFunds/UseOfFundsModal.vue';
96+
import { UseOfFundsContent as useOfFundsContentInterface } from '@src/domain/UseOfFunds/UseOfFundsContent';
97+
import { PageScroller } from '@src/utils/PageScroller/PageScroller';
98+
import MainDonationForm from '@src/components/DonationForm/Forms/MainDonationForm.vue';
99+
import MultiStepDonation from '@src/components/DonationForm/MultiStepDonation.vue';
100+
import BannerText from '../content/BannerText.vue';
101+
import BannerSlides from '../content/BannerSlides.vue';
102+
import BannerFooter from '@src/components/Footer/BannerFooter.vue';
103+
import KeenSlider from '@src/components/Slider/KeenSlider.vue';
104+
import { Tracker } from '@src/tracking/Tracker';
105+
import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent';
106+
import { useFormModel } from '@src/components/composables/useFormModel';
107+
import UpgradeToYearlyButtonForm from '@src/components/DonationForm/Forms/UpgradeToYearlyButtonForm.vue';
108+
import ChevronLeftIcon from '@src/components/Icons/ChevronLeftIcon.vue';
109+
import { CloseChoices } from '@src/domain/CloseChoices';
110+
import { CloseEvent } from '@src/tracking/events/CloseEvent';
111+
import { TrackingFeatureName } from '@src/tracking/TrackingEvent';
112+
import {
113+
createSubmittableMainDonationForm
114+
} from '@src/components/DonationForm/StepControllers/SubmittableMainDonationForm';
115+
import {
116+
createSubmittableUpgradeToYearly
117+
} from '@src/components/DonationForm/StepControllers/SubmittableUpgradeToYearly';
118+
import MainDonationFormButton
119+
from '@src/components/DonationForm/SubComponents/SubmitButtons/MainDonationFormButton.vue';
120+
import { LocalCloseTracker } from '@src/utils/LocalCloseTracker';
121+
import { BannerSubmitOnReturnEvent } from '@src/tracking/events/BannerSubmitOnReturnEvent';
122+
import { FormItem } from '@src/utils/FormItemsBuilder/FormItem';
123+
import FormItemsBuilder from '@src/utils/FormItemsBuilder/FormItemsBuilder';
124+
import { Translator } from '@src/Translator';
125+
import { Currency } from '@src/utils/DynamicContent/formatters/Currency';
126+
import { UseOfFundsShownEvent } from '@src/tracking/events/UseOfFundsShownEvent';
127+
import ProgressBar from '@src/components/ProgressBar/ProgressBar.vue';
128+
129+
enum ContentStates {
130+
Mini = 'wmde-banner-wrapper--mini',
131+
FullPage = 'wmde-banner-wrapper--full-page',
132+
SoftClosing = 'wmde-banner-wrapper--soft-closing'
133+
}
134+
135+
enum FormStepNames {
136+
MainDonationFormStep = 'MainDonationForm',
137+
UpgradeToYearlyFormStep = 'UpgradeToYearlyForm'
138+
}
139+
140+
interface Props {
141+
bannerState: BannerStates;
142+
useOfFundsContent: useOfFundsContentInterface;
143+
pageScroller: PageScroller;
144+
localCloseTracker: LocalCloseTracker;
145+
}
146+
147+
const props = defineProps<Props>();
148+
const emit = defineEmits( [ 'bannerClosed', 'bannerContentChanged', 'modalOpened', 'modalClosed' ] );
149+
150+
const tracker = inject<Tracker>( 'tracker' );
151+
152+
const isFundsModalVisible = ref<boolean>( false );
153+
const slideShowStopped = ref<boolean>( false );
154+
const slideshowShouldPlay = computed( () => props.bannerState === BannerStates.Visible && !slideShowStopped.value );
155+
const contentState = ref<ContentStates>( ContentStates.Mini );
156+
const formModel = useFormModel();
157+
const stepControllers = [
158+
createSubmittableMainDonationForm( formModel, FormStepNames.UpgradeToYearlyFormStep ),
159+
createSubmittableUpgradeToYearly( formModel, FormStepNames.MainDonationFormStep, FormStepNames.MainDonationFormStep )
160+
];
161+
162+
const localTranslator = inject<Translator>( 'translator' );
163+
const currencyFormatter = inject<Currency>( 'currencyFormatter' );
164+
165+
const localFormItemsBuilder = new FormItemsBuilder( localTranslator, currencyFormatter.euroAmount.bind( currencyFormatter ) );
166+
const amountOptionsFive = localFormItemsBuilder.setAmounts( 5, 15, 25, 50, 100 ).getItems().amounts;
167+
const amountOptionsTen = localFormItemsBuilder.setAmounts( 10, 15, 25, 50, 100 ).getItems().amounts;
168+
const amountOptionsForForm = ref<FormItem[]>( amountOptionsTen );
169+
170+
watch( contentState, async () => {
171+
emit( 'bannerContentChanged' );
172+
} );
173+
174+
function onClose( feature: TrackingFeatureName, userChoice: CloseChoices ): void {
175+
emit( 'bannerClosed', new CloseEvent( feature, userChoice ) );
176+
emit( 'modalClosed' );
177+
props.localCloseTracker.setItem( feature, userChoice );
178+
}
179+
180+
const onSubmit = (): void => {
181+
const closeChoice = props.localCloseTracker.getItem();
182+
if ( closeChoice !== '' ) {
183+
tracker.trackEvent( new BannerSubmitOnReturnEvent( closeChoice ) );
184+
}
185+
};
186+
187+
function onshowFullPageBanner(): void {
188+
slideShowStopped.value = true;
189+
contentState.value = ContentStates.FullPage;
190+
emit( 'modalOpened' );
191+
192+
amountOptionsForForm.value = amountOptionsFive;
193+
194+
tracker.trackEvent( new MobileMiniBannerExpandedEvent() );
195+
}
196+
197+
function onshowFullPageBannerPreselected(): void {
198+
slideShowStopped.value = true;
199+
200+
amountOptionsForForm.value = amountOptionsTen;
201+
202+
formModel.selectedAmount.value = '10';
203+
contentState.value = ContentStates.FullPage;
204+
tracker.trackEvent( new MobileMiniBannerExpandedEvent( 'preselected' ) );
205+
}
206+
207+
const onHideFundsModal = (): void => {
208+
isFundsModalVisible.value = false;
209+
210+
if ( contentState.value === ContentStates.Mini ) {
211+
emit( 'modalClosed' );
212+
}
213+
214+
if ( contentState.value === ContentStates.FullPage ) {
215+
props.pageScroller.scrollIntoView( '.wmde-banner-form' );
216+
}
217+
};
218+
219+
const onShowFundsModal = ( feature: TrackingFeatureName ): void => {
220+
isFundsModalVisible.value = true;
221+
tracker.trackEvent( new UseOfFundsShownEvent( feature ) );
222+
223+
if ( contentState.value === ContentStates.Mini ) {
224+
emit( 'modalOpened' );
225+
}
226+
};
227+
228+
const onFundsModalCallToAction = (): void => {
229+
isFundsModalVisible.value = false;
230+
231+
if ( contentState.value === ContentStates.Mini ) {
232+
onshowFullPageBanner();
233+
}
234+
235+
props.pageScroller.scrollIntoView( '.wmde-banner-form' );
236+
};
237+
238+
</script>

0 commit comments

Comments
 (0)