Skip to content

Commit

Permalink
Bugfix: Make sure amount displayed on campaign page is dynamically ca…
Browse files Browse the repository at this point in the history
…lculated
  • Loading branch information
mkue committed Jan 12, 2025
1 parent 656d242 commit 12dd4d6
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 45 deletions.
22 changes: 6 additions & 16 deletions admin/src/collections/Campaigns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,45 +69,35 @@ export const campaignsCollection = buildAuditedCollection<Campaign>({
multiline: true,
},
link_website: {
title: 'Website Link',
name: 'Website Link',
dataType: 'string',
validation: { required: false },
description: 'The link to the website (optional)',
},
link_instagram: {
title: 'Instagram Link',
name: 'Instagram Link',
dataType: 'string',
validation: { required: false },
description: 'The link to the Instagram profile (optional)',
},
link_tiktok: {
title: 'TikTok Link',
name: 'TikTok Link',
dataType: 'string',
validation: { required: false },
description: 'The link to the TikTok profile (optional)',
},
link_facebook: {
title: 'Facebook Link',
name: 'Facebook Link',
dataType: 'string',
validation: { required: false },
description: 'The link to the Facebook profile (optional)',
},
link_x: {
title: 'X (formerly Twitter) Link',
name: 'X (formerly Twitter) Link',
dataType: 'string',
validation: { required: false },
description: 'The link to the X profile (optional)',
},
amount_collected_chf: {
dataType: 'number',
name: 'Collected amount in CHF',
readOnly: true,
},
contributions: {
dataType: 'number',
name: 'Contributions',
readOnly: true,
},
goal: {
dataType: 'number',
name: 'Optional Fundraising Goal',
Expand Down Expand Up @@ -152,7 +142,7 @@ export const campaignsCollection = buildAuditedCollection<Campaign>({
validation: {
required: true,
matches: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,
matchMessage: 'Slug must contain only lowercase letters, numbers, and hyphens',
matchesMessage: 'Slug must contain only lowercase letters, numbers, and hyphens',
},
description:
'URL-friendly version of the title. Must be unique and contain only lowercase letters, numbers, and hyphens.',
Expand Down
21 changes: 0 additions & 21 deletions shared/src/stripe/StripeEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,26 +139,6 @@ export class StripeEventHandler {
}
};

/**
* Increments the total donations of a campaign if the charge is associated with a campaignId.
*/
maybeUpdateCampaign = async (contribution: StripeContribution): Promise<void> => {
if (contribution.campaign_path) {
try {
const campaign = await contribution.campaign_path.get();
const current_contributions = campaign.data()?.contributions ?? 0;
const current_amount_chf = campaign.data()?.amount_collected_chf ?? 0;
await contribution.campaign_path.update({
contributions: current_contributions + 1,
amount_collected_chf: current_amount_chf + contribution.amount_chf,
});
console.log(`Campaign amount ${contribution.campaign_path} updated.`);
} catch (error) {
console.error(`Error updating campaign amount ${contribution.campaign_path}.`, error);
}
}
};

constructStatus = (status: Stripe.Charge.Status) => {
switch (status) {
case 'succeeded':
Expand Down Expand Up @@ -207,7 +187,6 @@ export class StripeEventHandler {
).doc(charge.id);
await contributionRef.set(contribution, { merge: true });
console.info(`Updated contribution document: ${contributionRef.path}`);
await this.maybeUpdateCampaign(contribution);
return contributionRef;
};
}
2 changes: 0 additions & 2 deletions shared/src/types/campaign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ export type Campaign = {
link_tiktok?: string;
link_facebook?: string;
link_x?: string;
amount_collected_chf: number; // automatically updated by incoming payments.
contributions: number; // automatically updated by incoming payments.
goal?: number;
goal_currency?: Currency;
end_date: Timestamp;
Expand Down
9 changes: 6 additions & 3 deletions shared/src/types/contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,24 @@ export enum StatusKey {

export type Contribution = StripeContribution | BankWireContribution;

/**
* Represents a contribution to Social Income. The amount that ends up on our account is amount_chf - fees_chf.
*/
type BaseContribution = {
source: ContributionSourceKey;
status: StatusKey;
created: Timestamp;
amount: number;
amount_chf: number;
fees_chf: number;
amount_chf: number; // Amount donated in CHF, including fees
fees_chf: number; // Transaction fees in CHF
currency: Currency;
campaign_path?: DocumentReference;
};

export type StripeContribution = BaseContribution & {
source: ContributionSourceKey.STRIPE;
monthly_interval: number;
reference_id: string; // stripe charge id
reference_id: string; // The stripe charge id, see: https://docs.stripe.com/api/charges
};

export type BankWireContribution = BaseContribution & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { firestoreAdmin } from '@/firebase-admin';
import { WebsiteLanguage, WebsiteRegion } from '@/i18n';
import { getMetadata } from '@/metadata';
import { Campaign, CAMPAIGN_FIRESTORE_PATH, CampaignStatus } from '@socialincome/shared/src/types/campaign';
import { Contribution } from '@socialincome/shared/src/types/contribution';
import { daysUntilTs } from '@socialincome/shared/src/utils/date';
import { getLatestExchangeRate } from '@socialincome/shared/src/utils/exchangeRates';
import { Translator } from '@socialincome/shared/src/utils/i18n';
Expand Down Expand Up @@ -85,8 +86,11 @@ export default async function Page({ params }: CampaignPageProps) {
? await getLatestExchangeRate(firestoreAdmin, campaign.goal_currency)
: 1.0;

const contributions = campaign.contributions ?? 0;
const amountCollected = Math.round((campaign.amount_collected_chf ?? 0) * exchangeRate);
const contributions = await firestoreAdmin
.collectionGroup<Contribution>('contributions')
.where('campaign_path', '==', firestoreAdmin.firestore.doc([CAMPAIGN_FIRESTORE_PATH, params.campaign].join('/')))
.get();
const amountCollected = (contributions.docs.reduce((sum, c) => sum + c.data().amount_chf, 0) ?? 0) * exchangeRate;
const percentageCollected = campaign.goal ? Math.round((amountCollected / campaign.goal) * 100) : undefined;
const daysLeft = daysUntilTs(campaign.end_date.toDate());

Expand Down Expand Up @@ -122,7 +126,7 @@ export default async function Page({ params }: CampaignPageProps) {
<Typography size="2xl" weight="medium" color="secondary">
{translator?.t('campaign.without-goal.collected', {
context: {
count: contributions,
count: contributions.size,
amount: amountCollected,
currency: campaign.goal_currency,
total: campaign.goal,
Expand Down

0 comments on commit 12dd4d6

Please sign in to comment.