Skip to content

Commit d755a69

Browse files
authored
Merge pull request #161 from wmde/C23_WMDE_Mobile_DE_02
C23_WMDE_Mobile_DE_02
2 parents abe6c3f + 35f6ae2 commit d755a69

File tree

31 files changed

+1238
-35
lines changed

31 files changed

+1238
-35
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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 getBannerDelay from '@src/utils/getBannerDelay';
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+
21+
// Locale-specific imports
22+
import messages from './messages';
23+
import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe';
24+
25+
// Channel specific form setup
26+
import { createFormItems } from './form_items';
27+
import { createFormActions } from '@src/createFormActions';
28+
29+
const localeFactory = new LocaleFactoryDe();
30+
const translator = new Translator( messages );
31+
const mediaWiki = new WindowMediaWiki();
32+
const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() );
33+
const impressionCount = new LocalImpressionCount( page.getTracking().keyword );
34+
const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings );
35+
36+
const app = createVueApp( BannerConductor, {
37+
page,
38+
bannerConfig: {
39+
delay: getBannerDelay( 7500 ),
40+
transitionDuration: 1000
41+
},
42+
bannerProps: {
43+
useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(),
44+
pageScroller: new WindowPageScroller()
45+
},
46+
resizeHandler: new WindowResizeHandler(),
47+
banner: Banner,
48+
impressionCount
49+
} );
50+
51+
app.use( TranslationPlugin, translator );
52+
app.use( DynamicTextPlugin, {
53+
campaignParameters: page.getCampaignParameters(),
54+
date: new Date(),
55+
formatters: localeFactory.getFormatters(),
56+
impressionCount,
57+
translator
58+
} );
59+
const currencyFormatter = localeFactory.getCurrencyFormatter();
60+
61+
app.provide( 'currencyFormatter', currencyFormatter );
62+
app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) );
63+
app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount ) );
64+
app.provide( 'tracker', tracker );
65+
66+
app.mount( page.getBannerContainer() );
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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/BannerCtrl.vue';
7+
import getBannerDelay from '@src/utils/getBannerDelay';
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+
21+
// Locale-specific imports
22+
import messages from './messages';
23+
import { LocaleFactoryDe } from '@src/utils/LocaleFactory/LocaleFactoryDe';
24+
25+
// Channel specific form setup
26+
import { createFormItems } from './form_items_var';
27+
import { createFormActions } from '@src/createFormActions';
28+
29+
const localeFactory = new LocaleFactoryDe();
30+
const translator = new Translator( messages );
31+
const mediaWiki = new WindowMediaWiki();
32+
const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker() );
33+
const impressionCount = new LocalImpressionCount( page.getTracking().keyword );
34+
const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings );
35+
36+
const app = createVueApp( BannerConductor, {
37+
page,
38+
bannerConfig: {
39+
delay: getBannerDelay( 7500 ),
40+
transitionDuration: 1000
41+
},
42+
bannerProps: {
43+
useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(),
44+
pageScroller: new WindowPageScroller()
45+
},
46+
resizeHandler: new WindowResizeHandler(),
47+
banner: Banner,
48+
impressionCount
49+
} );
50+
51+
app.use( TranslationPlugin, translator );
52+
app.use( DynamicTextPlugin, {
53+
campaignParameters: page.getCampaignParameters(),
54+
date: new Date(),
55+
formatters: localeFactory.getFormatters(),
56+
impressionCount,
57+
translator
58+
} );
59+
const currencyFormatter = localeFactory.getCurrencyFormatter();
60+
61+
app.provide( 'currencyFormatter', currencyFormatter );
62+
app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) );
63+
app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount ) );
64+
app.provide( 'tracker', tracker );
65+
66+
app.mount( page.getBannerContainer() );
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<template>
2+
<div class="wmde-banner-wrapper" :class="contentState">
3+
<MiniBanner
4+
@close="onCloseMiniBanner"
5+
@show-full-page-banner="onshowFullPageBanner"
6+
>
7+
<template #banner-slides>
8+
<KeenSlider :with-navigation="false" :play="slideshowShouldPlay" :interval="5000">
9+
10+
<template #slides="{ currentSlide }: any">
11+
<BannerSlides :currentSlide="currentSlide"/>
12+
</template>
13+
14+
</KeenSlider>
15+
</template>
16+
</MiniBanner>
17+
18+
<FullPageBanner
19+
@showFundsModal="isFundsModalVisible = true"
20+
@close="() => onClose( 'FullPageBanner', CloseChoices.Close )"
21+
>
22+
<template #banner-text>
23+
<BannerText/>
24+
</template>
25+
26+
<template #donation-form="{ formInteraction }: any">
27+
<MultiStepDonation :step-controllers="stepControllers" @form-interaction="formInteraction" :page-scroller="pageScroller">
28+
29+
<template #[FormStepNames.MainDonationFormStep]="{ pageIndex, submit, isCurrent, previous }: any">
30+
<MainDonationForm :page-index="pageIndex" @submit="submit" :is-current="isCurrent" @previous="previous"/>
31+
</template>
32+
33+
<template #[FormStepNames.UpgradeToYearlyFormStep]="{ pageIndex, submit, isCurrent, previous }: any">
34+
<UpgradeToYearlyButtonForm :page-index="pageIndex" @submit="submit" :is-current="isCurrent" @previous="previous">
35+
<template #back>
36+
<ChevronLeftIcon/> {{ $translate ( 'back-button' ) }}
37+
</template>
38+
</UpgradeToYearlyButtonForm>
39+
</template>
40+
41+
</MultiStepDonation>
42+
</template>
43+
44+
<template #footer>
45+
<BannerFooter :show-funds-link="false"/>
46+
</template>
47+
</FullPageBanner>
48+
49+
<SoftClose
50+
v-if="contentState === ContentStates.SoftClosing"
51+
@close="() => onClose( 'SoftClose', CloseChoices.Close )"
52+
@maybe-later="() => onClose( 'SoftClose', CloseChoices.MaybeLater )"
53+
@time-out-close="() => onClose( 'SoftClose', CloseChoices.TimeOut )"
54+
/>
55+
56+
<FundsModal
57+
:content="useOfFundsContent"
58+
:is-funds-modal-visible="isFundsModalVisible"
59+
@hideFundsModal="onHideFundsModal"
60+
/>
61+
</div>
62+
</template>
63+
64+
<script setup lang="ts">
65+
import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates';
66+
import SoftClose from '@src/components/SoftClose/SoftClose.vue';
67+
import { computed, inject, ref, watch } from 'vue';
68+
import FullPageBanner from './FullPageBanner.vue';
69+
import MiniBanner from './MiniBanner.vue';
70+
import FundsModal from '@src/components/UseOfFunds/FundsModal.vue';
71+
import { UseOfFundsContent as useOfFundsContentInterface } from '@src/domain/UseOfFunds/UseOfFundsContent';
72+
import { UseOfFundsCloseSources } from '@src/components/UseOfFunds/UseOfFundsCloseSources';
73+
import { PageScroller } from '@src/utils/PageScroller/PageScroller';
74+
import MainDonationForm from '@src/components/DonationForm/Forms/MainDonationForm.vue';
75+
import MultiStepDonation from '@src/components/DonationForm/MultiStepDonation.vue';
76+
import BannerText from '../content/BannerText.vue';
77+
import UpgradeToYearlyButtonForm from '@src/components/DonationForm/Forms/UpgradeToYearlyButtonForm.vue';
78+
import BannerSlides from '../content/BannerSlides.vue';
79+
import BannerFooter from '@src/components/Footer/BannerFooter.vue';
80+
import ChevronLeftIcon from '@src/components/Icons/ChevronLeftIcon.vue';
81+
import KeenSlider from '@src/components/Slider/KeenSlider.vue';
82+
import { Tracker } from '@src/tracking/Tracker';
83+
import { MobileMiniBannerExpandedEvent } from '@src/tracking/events/MobileMiniBannerExpandedEvent';
84+
import { useFormModel } from '@src/components/composables/useFormModel';
85+
import {
86+
createSubmittableMainDonationForm
87+
} from '@src/components/DonationForm/StepControllers/SubmittableMainDonationForm';
88+
import {
89+
createSubmittableUpgradeToYearly
90+
} from '@src/components/DonationForm/StepControllers/SubmittableUpgradeToYearly';
91+
import { CloseChoices } from '@src/domain/CloseChoices';
92+
import { CloseEvent } from '@src/tracking/events/CloseEvent';
93+
import { TrackingFeatureName } from '@src/tracking/TrackingEvent';
94+
95+
enum ContentStates {
96+
Mini = 'wmde-banner-wrapper--mini',
97+
FullPage = 'wmde-banner-wrapper--full-page',
98+
SoftClosing = 'wmde-banner-wrapper--soft-closing'
99+
}
100+
101+
enum FormStepNames {
102+
MainDonationFormStep = 'MainDonationForm',
103+
UpgradeToYearlyFormStep = 'UpgradeToYearlyForm'
104+
}
105+
106+
interface Props {
107+
bannerState: BannerStates;
108+
useOfFundsContent: useOfFundsContentInterface;
109+
pageScroller: PageScroller;
110+
}
111+
112+
const props = defineProps<Props>();
113+
const emit = defineEmits( [ 'bannerClosed', 'bannerContentChanged' ] );
114+
115+
const tracker = inject<Tracker>( 'tracker' );
116+
117+
const isFundsModalVisible = ref<boolean>( false );
118+
const slideShowStopped = ref<boolean>( false );
119+
const slideshowShouldPlay = computed( () => props.bannerState === BannerStates.Visible && !slideShowStopped.value );
120+
const contentState = ref<ContentStates>( ContentStates.Mini );
121+
const formModel = useFormModel();
122+
const stepControllers = [
123+
createSubmittableMainDonationForm( formModel, FormStepNames.UpgradeToYearlyFormStep ),
124+
createSubmittableUpgradeToYearly( formModel, FormStepNames.MainDonationFormStep, FormStepNames.MainDonationFormStep )
125+
];
126+
127+
watch( contentState, async () => {
128+
emit( 'bannerContentChanged' );
129+
} );
130+
131+
function onCloseMiniBanner(): void {
132+
contentState.value = ContentStates.SoftClosing;
133+
}
134+
135+
function onClose( feature: TrackingFeatureName, userChoice: CloseChoices ): void {
136+
emit( 'bannerClosed', new CloseEvent( feature, userChoice ) );
137+
}
138+
139+
function onshowFullPageBanner(): void {
140+
slideShowStopped.value = true;
141+
contentState.value = ContentStates.FullPage;
142+
tracker.trackEvent( new MobileMiniBannerExpandedEvent() );
143+
}
144+
145+
const onHideFundsModal = ( payload: { source: UseOfFundsCloseSources } ): void => {
146+
props.pageScroller.scrollIntoView( payload.source === UseOfFundsCloseSources.callToAction ?
147+
'.wmde-banner-form' :
148+
'.wmde-banner-full-small-print .wmde-banner-footer-usage-link'
149+
);
150+
isFundsModalVisible.value = false;
151+
};
152+
153+
</script>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<template>
2+
<div class="wmde-banner-full">
3+
<div class="wmde-banner-full-content">
4+
<button class="wmde-banner-full-close t-close-full-banner" @click.prevent="$emit( 'close' )">
5+
<CloseIconMobile/>
6+
</button>
7+
<div class="wmde-banner-full-info">
8+
<slot name="banner-text"/>
9+
</div>
10+
<div class="wmde-banner-full-call-to-action">
11+
Jetzt sind Sie <span class="wmde-banner-full-call-to-action-optional-text">in Deutschland</span> gefragt.
12+
</div>
13+
14+
<slot name="donation-form"/>
15+
16+
<div class="wmde-banner-full-small-print">
17+
<span>
18+
<a
19+
id="application-of-funds-link"
20+
class="wmde-banner-footer-usage-link t-use-of-funds-link"
21+
@click.prevent="$emit( 'showFundsModal' )"
22+
>
23+
{{ $translate( 'use-of-funds-link' ) }}
24+
</a>
25+
</span>
26+
</div>
27+
28+
<slot name="footer"/>
29+
</div>
30+
</div>
31+
</template>
32+
33+
<script setup lang="ts">
34+
35+
import CloseIconMobile from '@src/components/Icons/CloseIconMobile.vue';
36+
37+
defineEmits( [ 'close', 'showFundsModal' ] );
38+
39+
</script>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<template>
2+
<div class="wmde-banner-mini">
3+
<div class="wmde-banner-mini-close">
4+
<button class="wmde-banner-mini-close-button t-close-main-banner" @click.prevent="$emit( 'close' )">
5+
<CloseIconMobile/>
6+
</button>
7+
</div>
8+
9+
<header class="wmde-banner-mini-headline">
10+
<div class="wmde-banner-mini-headline-background">
11+
<span class="wmde-banner-mini-headline-content">Ist Ihnen Wikipedia 5&nbsp;€ wert?</span>
12+
</div>
13+
</header>
14+
15+
<div class="wmde-banner-mini-slideshow">
16+
<slot name="banner-slides"/>
17+
</div>
18+
19+
<button class="wmde-banner-mini-button" @click="$emit( 'showFullPageBanner' )">
20+
Jetzt spenden
21+
</button>
22+
23+
</div>
24+
</template>
25+
26+
<script setup lang="ts">
27+
28+
import CloseIconMobile from '@src/components/Icons/CloseIconMobile.vue';
29+
30+
defineEmits( [ 'showFullPageBanner', 'close' ] );
31+
32+
</script>

0 commit comments

Comments
 (0)