Skip to content

Commit

Permalink
feat: first IWD thanks page variation
Browse files Browse the repository at this point in the history
  • Loading branch information
dyersituations committed Feb 7, 2024
1 parent 96b6caa commit c5572b6
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 9 deletions.
19 changes: 19 additions & 0 deletions .storybook/mock-data/thanks-page-data-mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,25 @@ export const femaleLoanData = {
}
};

export const femaleLoanDataWithInviter = {
"data": {
...femaleLoanData.data,
"community": {
"lender": {
"id": 123,
"name": "Mary",
"image": {
"id": 123,
"url": "https://www-kiva-org-0.freetls.fastly.net/img/s100/4da4a17c4b35913d22114bf29bb1911b.jpg",
"width": 3264,
"height": 2448
},
"publicId": "mary19806605"
}
}
}
}

export const iwdExperiment = {
id: 'Experiment:iwd_header_2024',
version: 'b'
Expand Down
30 changes: 25 additions & 5 deletions .storybook/stories/ThanksPage.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,46 @@ import ThanksPage from '@/pages/Thanks/ThanksPage';
import apolloStoryMixin from '../mixins/apollo-story-mixin';
import cookieStoreStoryMixin from '../mixins/cookie-store-story-mixin';
import kvAuth0StoryMixin from '../mixins/kv-auth0-story-mixin';
import { maleLoanData, femaleLoanData, iwdExperiment } from '../mock-data/thanks-page-data-mock';
import {
maleLoanData,
femaleLoanData,
femaleLoanDataWithInviter,
iwdExperiment,
} from '../mock-data/thanks-page-data-mock';
import VueRouter from 'vue-router';

const routes = new VueRouter();

export default {
title: 'Page/ThanksPage',
component: ThanksPage,
decorators: [
(story, { args }) => {
// Ensure story iframe loads with expected query string
routes.replace(`/?${args.queryString}`).catch(() => { });
return story();
}
]
};

const story = (queryResult = {}, fragmentResult = {}) => {
const story = (queryResult = {}, fragmentResult = {}, queryString = '') => {
const template = () => ({
components: { ThanksPage },
mixins: [cookieStoreStoryMixin(), kvAuth0StoryMixin],
// Using provide ensures that apollo is not shared between stories
provide: apolloStoryMixin({ queryResult, fragmentResult }).provide,
routes,
template: '<thanks-page />',
})
});
template.args = { queryString };
return template;
};

export const Default = story(maleLoanData);

export const IWD = story(femaleLoanData, iwdExperiment);

export const IWDNoFemaleLoan = story(maleLoanData, iwdExperiment);

export const IWDInviterKiva = story(femaleLoanData, iwdExperiment, 'valet_inviter=kiva');

export const IWDInviterLender = story(femaleLoanDataWithInviter, iwdExperiment, 'valet_inviter=mary19806605');

178 changes: 178 additions & 0 deletions src/components/Iwd/IwdThanksPageVariations.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<template>
<div class="tw-bg-secondary">
<div class="row page-content !tw-pt-0">
<template v-if="iwdValetInviterId">
<div
class="
tw-flex
tw-bg-white
tw-shadow-lg
tw-mt-0
md:tw-mt-2
tw-rounded-b
md:tw-rounded-t
tw-p-1.5
tw-gap-1
tw-items-center
"
>
<div class="tw-shrink-0">
<img :src="iWD2024Badge" alt="IWD Badge" class="tw-w-10 md:tw-w-6">
</div>
<div class="md:tw-font-medium">
<span>Thank you! Your support for </span>
<span
v-if="iwdValetInviterName"
class="data-hj-suppress"
>
{{ iwdValetInviterName }} &
</span>
<!-- eslint-disable-next-line max-len -->
<span>Kiva is invaluable to our mission and to our borrowers around the world. We’ve sent a receipt to your email.</span>
</div>
</div>
<div
class="
tw-flex
tw-flex-col
md:tw-flex-row
tw-w-full
tw-pt-2
md:tw-pt-3
tw-gap-1.5
md:tw-gap-3.5
tw-items-normal
md:tw-items-center
tw-p-2
md:tw-p-0
"
>
<div v-if="iwdBorrowerName && iwdBorrowerLocation" class="tw-font-medium tw-block md:tw-hidden">
<span class="tw-text-brand">Meet </span>
<span class="tw-text-brand data-hj-suppress">{{ iwdBorrowerName }}</span>
<span> from the </span>
<!-- eslint-disable-next-line max-len -->
<span class="tw-text-brand">{{ iwdBorrowerLocation }}</span><span>, the borrower</span><span class="tw-text-brand"> you just lent to</span><span>! This loan is special because...</span>
</div>
<div class="iwd-borrower-image tw-basis-auto md:tw-basis-1/2 tw-overflow-hidden">
<borrower-image
v-if="iwdLoan"
class="tw-w-full tw-bg-black data-hj-suppress"
:alt="iwdBorrowerName"
:default-image="{ width: 548 }"
:hash="iwdLoanImageHash"
:images="[{ width: 548 }]"
/>
</div>
<div class="tw-flex tw-flex-col tw-basis-auto md:tw-basis-1/2 tw-gap-1.5">
<div v-if="iwdBorrowerName && iwdBorrowerLocation" class="tw-font-medium tw-hidden md:tw-block">
<span class="tw-text-brand">Meet </span>
<span class="tw-text-brand data-hj-suppress">{{ iwdBorrowerName }}</span>
<span> from the </span>
<!-- eslint-disable-next-line max-len -->
<span class="tw-text-brand">{{ iwdBorrowerLocation }}</span><span>, the borrower</span><span class="tw-text-brand"> you just lent to</span><span>! This loan is special because...</span>
</div>
<div class="tw-flex tw-flex-col md:tw-flex-row tw-gap-1 tw-px-2 md:tw-px-0">
<kv-button
v-if="iwdLoanId"
:href="`/lend/${iwdLoanId}`"
v-kv-track-event="['Thanks', 'click-read-borrower-story']"
>
<span>Read </span>
<span v-if="iwdBorrowerName" class="data-hj-suppress">
{{ `${iwdBorrowerName}'s ` }}
</span>
<span>story</span>
</kv-button>
<kv-button
href="/about/how"
variant="secondary"
v-kv-track-event="['Thanks', 'click-more-about-kiva']"
>
More about Kiva
</kv-button>
</div>
</div>
</div>
</template>
<template v-else>
<!-- TODO: content coming soon -->
</template>
</div>
</div>
</template>

<script>
import iWD2024Badge from '@/assets/images/achievements/iwd_2024_badge.png';
import BorrowerImage from '@/components/BorrowerProfile/BorrowerImage';
import KvButton from '~/@kiva/kv-components/vue/KvButton';
export const KIVA_INVITER_ID = 'KIVA';
export default {
name: 'IwdThanksPageVariations',
components: {
BorrowerImage,
KvButton,
},
data() {
return {
iWD2024Badge,
};
},
props: {
iwdValetInviterId: {
type: String,
default: undefined,
},
iwdValetInviter: {
type: Object,
default: () => ({}),
},
iwdLoan: {
type: Object,
default: () => ({}),
},
},
computed: {
iwdValetInviterName() {
return this.iwdValetInviter?.name ?? '';
},
iwdLoanId() {
return this.iwdLoan?.id ?? '';
},
iwdLoanImageHash() {
return this.iwdLoan?.image?.hash;
},
iwdBorrowerName() {
return this.iwdLoan?.name ?? '';
},
iwdBorrowerLocation() {
return this.iwdLoan?.geocode?.country?.name ?? '';
},
},
};
</script>
<style lang="scss" scoped>
// Using SCSS allows matching parent ThanksPage.vue component
@import 'settings';
.iwd-borrower-image {
height: 289px;
@include breakpoint(medium) {
height: 420px;
}
::v-deep img {
object-fit: cover;
height: 289px;
@include breakpoint(medium) {
height: 420px;
}
}
}
</style>
14 changes: 14 additions & 0 deletions src/graphql/query/lenderPublicProfile.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
query LenderPublicProfile ($publicId: String!) {
community {
lender(publicId: $publicId) {
id
name
image {
id
url
width
height
}
}
}
}
1 change: 1 addition & 0 deletions src/graphql/query/thanksPage.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ query checkoutReceipt($checkoutId: Int!, $visitorId: String) {
distributionModel
unreservedAmount @client
inPfp
gender
}
team {
id
Expand Down
49 changes: 45 additions & 4 deletions src/pages/Thanks/ThanksPage.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
<template>
<www-page data-testid="thanks-page">
<template v-if="isOnlyDonation">
<template v-if="iwdHeaderExpEnabled">
<iwd-thanks-page-variations
:iwd-valet-inviter-id="iwdValetInviterId"
:iwd-valet-inviter="iwdValetInviter"
:iwd-loan="iwdLoan"
/>
</template>
<template v-else-if="isOnlyDonation">
<thanks-page-donation-only
:monthly-donation-amount="monthlyDonationAmount"
/>
Expand Down Expand Up @@ -105,6 +112,7 @@ import numeral from 'numeral';
import { readBoolSetting } from '@/util/settingsUtils';
import logReadQueryError from '@/util/logReadQueryError';
import experimentAssignmentQuery from '@/graphql/query/experimentAssignment.graphql';
import lenderPublicProfile from '@/graphql/query/lenderPublicProfile.graphql';
import CheckoutReceipt from '@/components/Checkout/CheckoutReceipt';
import GuestUpsell from '@/components/Checkout/GuestUpsell';
import AutoDepositCTA from '@/components/Checkout/AutoDepositCTA';
Expand All @@ -123,6 +131,7 @@ import logFormatter from '@/util/logFormatter';
import { joinArray } from '@/util/joinArray';
import NotifyMe from '@/components/Thanks/NotifyMe';
import experimentVersionFragment from '@/graphql/fragments/experimentVersion.graphql';
import IwdThanksPageVariations, { KIVA_INVITER_ID } from '@/components/Iwd/IwdThanksPageVariations';
import KvButton from '~/@kiva/kv-components/vue/KvButton';
import { fetchGoals } from '../../util/teamsUtil';
import teamsGoalsQuery from '../../graphql/query/teamsGoals.graphql';
Expand Down Expand Up @@ -163,7 +172,8 @@ export default {
WwwPage,
ThanksPageCommentAndShare,
ThanksPageDonationOnly,
NotifyMe
NotifyMe,
IwdThanksPageVariations,
},
inject: ['apollo', 'cookieStore'],
metaInfo() {
Expand All @@ -188,6 +198,8 @@ export default {
goal: null,
showNotifyMe: false,
iwdHeaderExpEnabled: false,
iwdValetInviterId: undefined,
iwdValetInviter: {},
};
},
apollo: {
Expand All @@ -214,9 +226,14 @@ export default {
};
const limit = 1;
const valetInviterId = route?.query?.valet_inviter;
return Promise.all([
client.query({ query: experimentAssignmentQuery, variables: { id: 'share_ask_copy' } }),
teamId ? fetchGoals(client, limit, filters) : null
teamId ? fetchGoals(client, limit, filters) : null,
!!valetInviterId && valetInviterId?.toUpperCase() !== KIVA_INVITER_ID
? client.query({ query: lenderPublicProfile, variables: { publicId: valetInviterId } })
: null,
]);
}).catch(errorResponse => {
logFormatter(
Expand Down Expand Up @@ -305,6 +322,9 @@ export default {
teamPublicId() {
return this.loans?.[0]?.team?.teamPublicId;
},
iwdLoan() {
return (this.loans?.filter(l => l?.gender?.toUpperCase() === 'FEMALE') ?? [])?.[0];
},
},
created() {
// Retrieve and apply Page level data + experiment state
Expand Down Expand Up @@ -429,16 +449,37 @@ export default {
// When this is true, it will override all logic and show the thanks page v2
this.jumpToGuestUpsell = true;
},
getIwdInviter() {
this.iwdValetInviterId = this.$route?.query?.valet_inviter;
if (!!this.iwdValetInviterId && this.iwdValetInviterId?.toUpperCase() !== KIVA_INVITER_ID) {
try {
const data = this.apollo.readQuery({
query: lenderPublicProfile,
variables: {
checkoutId: lenderPublicProfile,
publicId: this.iwdValetInviterId,
}
});
this.iwdValetInviter = data?.community?.lender ?? {};
} catch (e) {
logReadQueryError(
e,
`Lender public profile readQuery failed: (publicId: ${this.iwdValetInviterId})`,
);
}
}
},
checkForIWD2024Experiment() {
const iwdHeaderExp = this.apollo.readFragment({
id: 'Experiment:iwd_header_2024',
fragment: experimentVersionFragment,
}) || {};
// Only show IWD content and track experiment if: 1) experiment enabled, and 2) "women" loan checked out
const EXPERIMENT_ENABLED_VERSION = 'b';
const womenLoanIncluded = (this.loans?.filter(l => l.gender.toUpperCase() === 'FEMALE')?.length ?? 0) > 0;
const womenLoanIncluded = !!this.iwdLoan;
this.iwdHeaderExpEnabled = iwdHeaderExp.version === EXPERIMENT_ENABLED_VERSION && womenLoanIncluded;
if (this.iwdHeaderExpEnabled) {
this.getIwdInviter();
this.$kvTrackEvent('Lending', 'EXP-IWDHeader2024', EXPERIMENT_ENABLED_VERSION);
}
},
Expand Down

0 comments on commit c5572b6

Please sign in to comment.