Skip to content

Commit 2752fcc

Browse files
authored
Merge pull request #887 from wmde/WMDE_FR_2025_Mobile_EN_02
WMDE_FR_2025_Mobile_EN_02
2 parents c648493 + eda4d7e commit 2752fcc

File tree

24 files changed

+1759
-10
lines changed

24 files changed

+1759
-10
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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 { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG';
15+
import eventMappings from './event_map';
16+
import { Translator } from '@src/Translator';
17+
import DynamicTextPlugin from '@src/DynamicTextPlugin';
18+
import { LocalImpressionCount } from '@src/utils/LocalImpressionCount';
19+
import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller';
20+
import { Locales } from '@src/domain/Locales';
21+
import { createFormItems } from './form_items';
22+
import { createFormActions } from '@src/createFormActions';
23+
import messages from './messages';
24+
import { LocaleFactoryEn } from '@src/utils/LocaleFactory/LocaleFactoryEn';
25+
import { WindowTimer } from '@src/utils/Timer';
26+
27+
const localeFactory = new LocaleFactoryEn();
28+
const translator = new Translator( messages );
29+
const mediaWiki = new WindowMediaWiki();
30+
const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() );
31+
const runtimeEnvironment = new UrlRuntimeEnvironment( window.location );
32+
const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment );
33+
const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment );
34+
const currencyFormatter = localeFactory.getCurrencyFormatter();
35+
36+
const app = createVueApp( BannerConductor, {
37+
page,
38+
bannerConfig: {
39+
delay: runtimeEnvironment.getBannerDelay( 7500 ),
40+
transitionDuration: 1000
41+
},
42+
bannerCategory: 'fundraising',
43+
bannerProps: {
44+
useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(),
45+
pageScroller: new WindowPageScroller(),
46+
remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'mobile_english' ) )
47+
},
48+
resizeHandler: new WindowResizeHandler(),
49+
banner: Banner,
50+
impressionCount
51+
} );
52+
53+
app.use( TranslationPlugin, translator );
54+
app.use( DynamicTextPlugin, {
55+
campaignParameters: page.getCampaignParameters(),
56+
date: new Date(),
57+
formatters: localeFactory.getFormatters(),
58+
impressionCount,
59+
translator
60+
} );
61+
62+
app.provide( 'currencyFormatter', currencyFormatter );
63+
app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) );
64+
app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { locale: Locales.EN } ) );
65+
app.provide( 'tracker', tracker );
66+
app.provide( 'timer', new WindowTimer() );
67+
68+
app.mount( page.getBannerContainer() );
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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 { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG';
15+
import eventMappings from './event_map';
16+
import { Translator } from '@src/Translator';
17+
import DynamicTextPlugin from '@src/DynamicTextPlugin';
18+
import { LocalImpressionCount } from '@src/utils/LocalImpressionCount';
19+
import { WindowPageScroller } from '@src/utils/PageScroller/WindowPageScroller';
20+
import { Locales } from '@src/domain/Locales';
21+
import { createFormItems } from './form_items';
22+
import { createFormActions } from '@src/createFormActions';
23+
import messages from './messages';
24+
import { LocaleFactoryEn } from '@src/utils/LocaleFactory/LocaleFactoryEn';
25+
import { WindowTimer } from '@src/utils/Timer';
26+
27+
const localeFactory = new LocaleFactoryEn();
28+
const translator = new Translator( messages );
29+
const mediaWiki = new WindowMediaWiki();
30+
const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() );
31+
const runtimeEnvironment = new UrlRuntimeEnvironment( window.location );
32+
const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment );
33+
const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment );
34+
const currencyFormatter = localeFactory.getCurrencyFormatter();
35+
36+
const app = createVueApp( BannerConductor, {
37+
page,
38+
bannerConfig: {
39+
delay: runtimeEnvironment.getBannerDelay( 7500 ),
40+
transitionDuration: 1000
41+
},
42+
bannerCategory: 'fundraising',
43+
bannerProps: {
44+
useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(),
45+
pageScroller: new WindowPageScroller(),
46+
remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'mobile_english' ) )
47+
},
48+
resizeHandler: new WindowResizeHandler(),
49+
banner: Banner,
50+
impressionCount
51+
} );
52+
53+
app.use( TranslationPlugin, translator );
54+
app.use( DynamicTextPlugin, {
55+
campaignParameters: page.getCampaignParameters(),
56+
date: new Date(),
57+
formatters: localeFactory.getFormatters(),
58+
impressionCount,
59+
translator
60+
} );
61+
62+
app.provide( 'currencyFormatter', currencyFormatter );
63+
app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) );
64+
app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { locale: Locales.EN } ) );
65+
app.provide( 'tracker', tracker );
66+
app.provide( 'timer', new WindowTimer() );
67+
68+
app.mount( page.getBannerContainer() );
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<template>
2+
<div class="wmde-banner-wrapper" :class="contentState">
3+
<MiniBanner
4+
@close="onCloseMiniBanner"
5+
@show-full-page-banner="onshowFullPageBanner"
6+
@show-full-page-banner-preselected-amount="onShowFullPageBannerPreselectedAmount"
7+
@show-use-of-funds="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>
16+
17+
</KeenSlider>
18+
</template>
19+
</MiniBanner>
20+
21+
<FullPageBanner
22+
@close="() => onClose( 'FullPageBanner', CloseChoices.Hide )"
23+
@show-use-of-funds="onShowFundsModal( 'FullPageBanner' )"
24+
>
25+
<template #banner-text>
26+
<BannerText :play-live-text="contentState === ContentStates.FullPage"/>
27+
</template>
28+
29+
<template #progress>
30+
<ProgressBar amount-to-show-on-right="TARGET"/>
31+
</template>
32+
33+
<template #donation-form="{ formInteraction }: any">
34+
<MultiStepDonation :step-controllers="stepControllers" @form-interaction="formInteraction" :page-scroller="pageScroller">
35+
36+
<template #[FormStepNames.MainDonationFormStep]="{ pageIndex, submit, previous, isCurrent }: any">
37+
<MainDonationForm
38+
:page-index="pageIndex"
39+
:is-current="isCurrent"
40+
@submit="submit"
41+
@previous="previous"
42+
custom-amount-placeholder-key="custom-amount-placeholder-short"
43+
>
44+
45+
<template #label-payment-ppl>
46+
<span class="wmde-banner-select-group-label with-logos paypal"><PayPalLogo/></span>
47+
</template>
48+
49+
<template #label-payment-mcp>
50+
<span class="wmde-banner-select-group-label with-logos credit-cards">
51+
<VisaLogo/>
52+
<MastercardLogo/>
53+
</span>
54+
</template>
55+
56+
</MainDonationForm>
57+
</template>
58+
59+
<template #[FormStepNames.UpgradeToYearlyFormStep]="{ pageIndex, submit, isCurrent, previous }: any">
60+
<UpgradeToYearlyButtonForm
61+
:page-index="pageIndex"
62+
:is-current="isCurrent"
63+
@submit="submit"
64+
@previous="previous"
65+
>
66+
<template #back>
67+
<ChevronLeftIcon/> {{ $translate( 'back-button' ) }}
68+
</template>
69+
</UpgradeToYearlyButtonForm>
70+
</template>
71+
72+
</MultiStepDonation>
73+
</template>
74+
75+
<template #footer>
76+
<BannerFooter @showFundsModal="onShowFundsModal( 'Footer' )" :showFundsLink="false"/>
77+
</template>
78+
</FullPageBanner>
79+
80+
<FundsModal
81+
:content="useOfFundsContent"
82+
:visible="isFundsModalVisible"
83+
@hide="onHideFundsModal"
84+
@callToAction="onFundsModalCallToAction"
85+
/>
86+
</div>
87+
</template>
88+
89+
<script setup lang="ts">
90+
import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates';
91+
import { computed, inject, ref, watch } from 'vue';
92+
import FullPageBanner from './FullPageBanner.vue';
93+
import MiniBanner from './MiniBanner.vue';
94+
import FundsModal from '@src/components/UseOfFunds/UseOfFundsModal.vue';
95+
import { UseOfFundsContent as useOfFundsContentInterface } from '@src/domain/UseOfFunds/UseOfFundsContent';
96+
import { PageScroller } from '@src/utils/PageScroller/PageScroller';
97+
import MainDonationForm from '@src/components/DonationForm/Forms/MainDonationForm.vue';
98+
import MultiStepDonation from '@src/components/DonationForm/MultiStepDonation.vue';
99+
import BannerText from '../content/BannerText.vue';
100+
import BannerSlides from '../content/BannerSlides.vue';
101+
import ProgressBar from '@src/components/ProgressBar/ProgressBar.vue';
102+
import BannerFooter from '@src/components/Footer/BannerFooter.vue';
103+
import KeenSlider from '@src/components/Slider/KeenSlider.vue';
104+
import MastercardLogo from '@src/components/PaymentLogos/MastercardLogo.vue';
105+
import VisaLogo from '@src/components/PaymentLogos/VisaLogo.vue';
106+
import PayPalLogo from '@src/components/PaymentLogos/PayPalLogo.vue';
107+
import { Tracker } from '@src/tracking/Tracker';
108+
import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent';
109+
import { CloseChoices } from '@src/domain/CloseChoices';
110+
import { CloseEvent } from '@src/tracking/events/CloseEvent';
111+
import { TrackingFeatureName } from '@src/tracking/TrackingEvent';
112+
import { useFormModel } from '@src/components/composables/useFormModel';
113+
import UpgradeToYearlyButtonForm from '@src/components/DonationForm/Forms/UpgradeToYearlyButtonForm.vue';
114+
import ChevronLeftIcon from '@src/components/Icons/ChevronLeftIcon.vue';
115+
import { createSubmittableMainDonationForm } from '@src/components/DonationForm/StepControllers/SubmittableMainDonationForm';
116+
import { createSubmittableUpgradeToYearly } from '@src/components/DonationForm/StepControllers/SubmittableUpgradeToYearly';
117+
import { UseOfFundsShownEvent } from '@src/tracking/events/UseOfFundsShownEvent';
118+
const formModel = useFormModel();
119+
120+
enum ContentStates {
121+
Mini = 'wmde-banner-wrapper--mini',
122+
FullPage = 'wmde-banner-wrapper--full-page',
123+
}
124+
125+
enum FormStepNames {
126+
MainDonationFormStep = 'MainDonationForm',
127+
UpgradeToYearlyFormStep = 'UpgradeToYearlyForm'
128+
}
129+
130+
interface Props {
131+
bannerState: BannerStates;
132+
useOfFundsContent: useOfFundsContentInterface;
133+
pageScroller: PageScroller;
134+
}
135+
136+
const props = defineProps<Props>();
137+
const emit = defineEmits( [ 'bannerClosed', 'bannerContentChanged', 'modalOpened', 'modalClosed' ] );
138+
139+
const tracker = inject<Tracker>( 'tracker' );
140+
141+
const isFundsModalVisible = ref<boolean>( false );
142+
const slideShowStopped = ref<boolean>( false );
143+
const slideshowShouldPlay = computed( () => props.bannerState === BannerStates.Visible && !slideShowStopped.value );
144+
const contentState = ref<ContentStates>( ContentStates.Mini );
145+
const stepControllers = [
146+
createSubmittableMainDonationForm( formModel, FormStepNames.UpgradeToYearlyFormStep ),
147+
createSubmittableUpgradeToYearly( formModel, FormStepNames.MainDonationFormStep, FormStepNames.MainDonationFormStep )
148+
];
149+
150+
watch( contentState, async () => {
151+
emit( 'bannerContentChanged' );
152+
} );
153+
154+
function onCloseMiniBanner(): void {
155+
onClose( 'MainBanner', CloseChoices.Close );
156+
}
157+
158+
function onClose( feature: TrackingFeatureName, userChoice: CloseChoices ): void {
159+
emit( 'bannerClosed', new CloseEvent( feature, userChoice ) );
160+
}
161+
162+
function onshowFullPageBanner(): void {
163+
slideShowStopped.value = true;
164+
contentState.value = ContentStates.FullPage;
165+
tracker.trackEvent( new MobileMiniBannerExpandedEvent( 'different-amount' ) );
166+
}
167+
168+
function onShowFullPageBannerPreselectedAmount(): void {
169+
slideShowStopped.value = true;
170+
formModel.selectedAmount.value = '10';
171+
contentState.value = ContentStates.FullPage;
172+
tracker.trackEvent( new MobileMiniBannerExpandedEvent( 'preselected' ) );
173+
}
174+
175+
const onShowFundsModal = ( feature: TrackingFeatureName ): void => {
176+
isFundsModalVisible.value = true;
177+
tracker.trackEvent( new UseOfFundsShownEvent( feature ) );
178+
179+
if ( contentState.value === ContentStates.Mini ) {
180+
emit( 'modalOpened' );
181+
}
182+
};
183+
184+
const onHideFundsModal = (): void => {
185+
isFundsModalVisible.value = false;
186+
187+
if ( contentState.value === ContentStates.Mini ) {
188+
emit( 'modalClosed' );
189+
}
190+
191+
if ( contentState.value === ContentStates.FullPage ) {
192+
props.pageScroller.scrollIntoView( '.wmde-banner-form' );
193+
}
194+
};
195+
196+
const onFundsModalCallToAction = (): void => {
197+
isFundsModalVisible.value = false;
198+
199+
if ( contentState.value === ContentStates.Mini ) {
200+
onshowFullPageBanner();
201+
}
202+
203+
props.pageScroller.scrollIntoView( '.wmde-banner-form' );
204+
};
205+
206+
</script>

0 commit comments

Comments
 (0)