Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add campaign progress bar to category page #5160

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .storybook/mock-data/thanks-page-data-mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ export const maleLoanData = {
}
}

const futureDate = new Date();
futureDate.setDate(futureDate.getDate() + 20);

export const femaleLoanData = {
"data": {
"shop": {
Expand Down Expand Up @@ -228,6 +231,15 @@ export const femaleLoanData = {
"totalCount": 1
}
},
"general": {
"kivaStats": {
"campaignStats": {
"currentBorrowerCount": 2298,
"targetBorrowerCount": 6000,
"targetEndDate": futureDate.toISOString(),
}
}
}
}
};

Expand Down
12 changes: 8 additions & 4 deletions .storybook/stories/KvProgressCampaign.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ const story = (args) => {
template: `
<div>
<kv-progress-campaign
:funded-loans="fundedLoans"
:total-loans="totalLoans"
:funded-borrowers="fundedBorrowers"
:total-borrowers="totalBorrowers"
:days-left="daysLeft"
:raised-money="raisedMoney"
:minimal-stats="minimalStats"
/>
</div>
`,
Expand All @@ -25,5 +25,9 @@ const story = (args) => {
};

export const Default = story({
raisedMoney: 345900, daysLeft: 29, totalLoans: 4000, fundedLoans: 462,
daysLeft: 29, totalBorrowers: 4000, fundedBorrowers: 462,
});

export const MinimalStats = story({
daysLeft: 29, totalBorrowers: 4000, fundedBorrowers: 462, minimalStats: true
});
47 changes: 47 additions & 0 deletions src/components/Iwd/IwdCategoryHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<div class="tw-flex tw-flex-col tw-w-full">
<div class="tw-flex tw-pt-2 md:tw-gap-6 lg:tw-gap-12">
<div>
<h1 style="line-height: 1;" class="md:tw-pb-3">
Help us fund 4,000 women for Women’s Day!
</h1>
<div class="tw-flex md:tw-hidden tw-py-0.5 tw-items-center">
<img :src="iWD2024Badge" alt="IWD Badge" style="width: 114px;">
<iwd-progress-campaign class="tw-pr-2" />
</div>
<!-- eslint-disable max-len -->
<p class="tw-pb-3">
To celebrate International Women’s Day, we’re aiming to fund 4,000 women this week. That’s 4,000 more women who could have the resources they need to thrive — and invest in their communities.
</p>
<p>We need you to make it happen. Help us reach our goal and earn your exclusive International Women’s Day badge!</p>
<!-- eslint-enable max-len -->
</div>
<div class="tw-shrink-0 tw-hidden md:tw-block">
<img :src="iWD2024Badge" alt="IWD Badge">
<iwd-progress-campaign />
</div>
</div>
<div class="tw-pt-2">
<activity-feed />
</div>
</div>
</template>

<script>
import ActivityFeed from '@/components/Iwd/ActivityFeed';
import iWD2024Badge from '@/assets/images/achievements/iwd_2024_badge.png';
import IwdProgressCampaign from '@/components/Iwd/IwdProgressCampaign';

export default {
name: 'IwdCategoryHeader',
components: {
ActivityFeed,
IwdProgressCampaign,
},
data() {
return {
iWD2024Badge,
};
},
};
</script>
69 changes: 69 additions & 0 deletions src/components/Iwd/IwdProgressCampaign.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<template>
<kv-progress-campaign
v-if="displayProgress"
:funded-borrowers="fundedBorrowers"
:total-borrowers="totalBorrowers"
:days-left="daysLeft"
:minimal-stats="minimalStats"
/>
<kv-loading-placeholder v-else class="tw-w-full tw-h-8" />
</template>

<script>
import KvProgressCampaign from '@/components/Kv/KvProgressCampaign';
import campaignStatsQuery from '@/graphql/query/campaignStats.graphql';
import logReadQueryError from '@/util/logReadQueryError';
import intervalToDuration from 'date-fns/intervalToDuration';
import KvLoadingPlaceholder from '~/@kiva/kv-components/vue/KvLoadingPlaceholder';

export default {
name: 'IwdProgressCampaign',
components: {
KvProgressCampaign,
KvLoadingPlaceholder,
},
inject: ['apollo', 'cookieStore'],
props: {
minimalStats: {
type: Boolean,
default: false,
},
},
data() {
return {
fundedBorrowers: undefined,
totalBorrowers: undefined,
daysLeft: undefined,
};
},
computed: {
displayProgress() {
return !!(typeof this.fundedBorrowers !== 'undefined'
&& typeof this.totalBorrowers !== 'undefined'
&& typeof this.daysLeft !== 'undefined');
},
},
async mounted() {
try {
const response = await this.apollo.query({
query: campaignStatsQuery,
variables: {
campaignKey: 'iwd2024',
filters: { gender: 'female' },
},
});
this.fundedBorrowers = response?.data?.general?.kivaStats?.campaignStats?.currentBorrowerCount;
this.totalBorrowers = response?.data?.general?.kivaStats?.campaignStats?.targetBorrowerCount;
const targetEndDate = response?.data?.general?.kivaStats?.campaignStats?.targetEndDate;
if (targetEndDate) {
this.daysLeft = intervalToDuration({
start: new Date(),
end: new Date(targetEndDate)
}).days;
}
} catch (e) {
logReadQueryError(e, 'IwdProgressCampaign campaignStatsQuery');
}
},
};
</script>
23 changes: 18 additions & 5 deletions src/components/Iwd/IwdThanksPageVariations.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
tw-rounded-b
md:tw-rounded-t
tw-p-1.5
tw-gap-1
tw-gap-2
tw-items-center
"
>
<div class="tw-shrink-0">
<div class="tw-shrink-0 tw-flex tw-flex-col md:tw-flex-row tw-gap-0.5 md:tw-gap-1 tw-items-center">
<img :src="iWD2024Badge" alt="IWD Badge" class="tw-w-10 md:tw-w-6">
<iwd-progress-campaign :minimal-stats="true" />
</div>
<div class="md:tw-font-medium">
<span>Thank you! Your support for </span>
Expand Down Expand Up @@ -104,7 +105,7 @@
</template>
<template v-else>
<div class="tw-flex tw-flex-col tw-w-full tw-pb-2">
<div class="tw-text-center tw-pt-1.5 tw-pb-2 tw-mx-auto" style="max-width: 685px;">
<div class="tw-text-center tw-pt-1.5 tw-px-2 tw-pb-2 tw-mx-auto" style="max-width: 685px;">
<h2 class="tw-pb-1.5">
Spread the word. Multiply your impact.
</h2>
Expand All @@ -122,7 +123,7 @@
tw-flex-col
md:tw-flex-row
tw-gap-1.5
md:tw-gap-3
md:tw-gap-8
"
>
<div class="tw-flex tw-flex-col tw-basis-auto md:tw-basis-1/2">
Expand Down Expand Up @@ -206,8 +207,18 @@
</button>
</div>
</div>
<div class="tw-basis-auto md:tw-basis-1/2">
<div
class="
tw-flex
md:tw-flex-col
tw-basis-auto
md:tw-basis-1/2
tw-items-center
md:tw-items-stretch
"
>
<img id="badge-image" :src="iWD2024Badge" alt="IWD Badge" class="tw-mx-0 md:tw-mx-auto">
<iwd-progress-campaign />
</div>
</div>
</div>
Expand All @@ -223,6 +234,7 @@ import socialSharingMixin from '@/plugins/social-sharing-mixin';
import KvIcon from '@/components/Kv/KvIcon';
import { mdiLink } from '@mdi/js';
import { getFullUrl } from '@/util/urlUtils';
import IwdProgressCampaign from '@/components/Iwd/IwdProgressCampaign';
import KvButton from '~/@kiva/kv-components/vue/KvButton';
import KvMaterialIcon from '~/@kiva/kv-components/vue/KvMaterialIcon';

Expand All @@ -235,6 +247,7 @@ export default {
KvButton,
KvIcon,
KvMaterialIcon,
IwdProgressCampaign,
},
inject: ['apollo', 'cookieStore'],
mixins: [socialSharingMixin],
Expand Down
42 changes: 16 additions & 26 deletions src/components/Kv/KvProgressCampaign.vue
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
<template>
<figure>
<figure class="tw-grow">
<div class="tw-flex tw-items-center tw-justify-between">
<p>
{{ fundedLoans }} loans funded
{{ fundedBorrowers }} funded
</p>
<p>
{{ loansLeft }} to go!
<p v-if="!minimalStats">
{{ borrowersLeft }} to go
</p>
</div>
<kv-progress-bar
class="tw-my-1"
class="tw-my-0.5"
aria-label="Percent the loan has funded"
:value="progressPercentage"
:bg-variant="bgVariant"
/>
<div class="">
<p>
{{ numeralRaised }} raised
</p>
<div v-if="!minimalStats">
<p>
{{ daysRemaining }}
{{ daysLeft }} days left
</p>
</div>
</figure>
</template>

<script>
import numeral from 'numeral';
import KvProgressBar from '~/@kiva/kv-components/vue/KvProgressBar';

export default {
Expand All @@ -35,21 +31,21 @@ export default {
KvProgressBar
},
props: {
fundedLoans: {
fundedBorrowers: {
type: Number,
required: true,
},
totalLoans: {
totalBorrowers: {
type: Number,
required: true,
},
daysLeft: {
type: Number,
required: true,
},
raisedMoney: {
type: Number,
required: true,
minimalStats: {
type: Boolean,
default: false,
},
},
data() {
Expand All @@ -58,19 +54,13 @@ export default {
};
},
computed: {
numeralRaised() {
return numeral(this.raisedMoney).format('$0,0');
},
daysRemaining() {
return `${this.daysLeft} days remaining`;
},
loansLeft() {
return this.totalLoans - this.fundedLoans > 0
? this.totalLoans - this.fundedLoans
borrowersLeft() {
return this.totalBorrowers - this.fundedBorrowers > 0
? this.totalBorrowers - this.fundedBorrowers
: 0;
},
progressPercentage() {
return (this.fundedLoans / this.totalLoans) * 100;
return (this.fundedBorrowers / this.totalBorrowers) * 100;
},
},
};
Expand Down
11 changes: 11 additions & 0 deletions src/graphql/query/campaignStats.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
query CampaignStats($campaignKey: String!, $filters: LoanSearchFiltersInput) {
general {
kivaStats {
campaignStats(campaignKey: $campaignKey, filters: $filters) {
currentBorrowerCount

Check warning on line 5 in src/graphql/query/campaignStats.graphql

View workflow job for this annotation

GitHub Actions / build

Cannot query field "currentBorrowerCount" on type "FundraisingCampaign"
targetBorrowerCount
targetEndDate
}
}
}
}
Loading
Loading