@@ -11,6 +11,7 @@ import { Repository } from 'typeorm';
1111import { CreateDonationRequest , Donation as DomainDonation } from './mappers' ;
1212import { Readable } from 'stream' ;
1313import { DonationsRepository } from './donations.repository' ;
14+ import { Goal } from './goal.entity' ;
1415
1516interface PaymentIntentSyncPayload {
1617 donationId ?: number ;
@@ -32,6 +33,10 @@ export class DonationsService {
3233 constructor (
3334 @InjectRepository ( Donation )
3435 private donationRepository : Repository < Donation > ,
36+
37+ @InjectRepository ( Goal )
38+ private goalRepository : Repository < Goal > ,
39+
3540 private readonly donationsRepository : DonationsRepository ,
3641 ) { }
3742
@@ -342,4 +347,83 @@ export class DonationsService {
342347
343348 return stream ;
344349 }
350+
351+ async getActiveGoalSummary ( ) {
352+ // --- TEMPORARY MOCK FOR TESTING ---
353+ return {
354+ goal : {
355+ id : 999 ,
356+ targetAmount : 50000 ,
357+ startDate : '2026-01-01' ,
358+ endDate : '2026-06-30' ,
359+ dateRangeLabel : 'January - June 2026' ,
360+ } ,
361+ amountRaised : 31336 ,
362+ progressPercent : 62.67 ,
363+ } ;
364+ /*
365+ const today = new Date().toISOString().split('T')[0];
366+
367+ // 1. find active goal
368+ const goal = await this.goalRepository
369+ .createQueryBuilder('goal')
370+ .where(':today BETWEEN goal.startDate AND goal.endDate', { today })
371+ .orderBy('goal.startDate', 'DESC')
372+ .getOne();
373+
374+ if (!goal) {
375+ return {
376+ goal: null,
377+ amountRaised: 0,
378+ progressPercent: 0,
379+ };
380+ }
381+
382+ // 2. sum donations in goal period
383+ const result = await this.donationRepository
384+ .createQueryBuilder('donation')
385+ .select('COALESCE(SUM(donation.amount), 0)', 'amount')
386+ .where('donation.status = :status', { status: DonationStatus.SUCCEEDED })
387+ .andWhere('donation.createdAt >= :startDate', {
388+ startDate: goal.startDate,
389+ })
390+ .andWhere('donation.createdAt <= :endDate', {
391+ endDate: `${goal.endDate} 23:59:59`,
392+ })
393+ .getRawOne<{ amount: string }>();
394+
395+ const amountRaised = Number(result?.amount ?? 0);
396+
397+ const progressPercent =
398+ goal.targetAmount > 0
399+ ? Math.min((amountRaised / goal.targetAmount) * 100, 100)
400+ : 0;
401+
402+ return {
403+ goal: {
404+ id: goal.id,
405+ targetAmount: goal.targetAmount,
406+ startDate: goal.startDate,
407+ endDate: goal.endDate,
408+ dateRangeLabel: this.formatDateRange(goal.startDate, goal.endDate),
409+ },
410+ amountRaised,
411+ progressPercent,
412+ };
413+ */
414+ }
415+
416+ private formatDateRange ( start : string , end : string ) : string {
417+ const startDate = new Date ( start ) ;
418+ const endDate = new Date ( end ) ;
419+
420+ const startMonth = startDate . toLocaleString ( 'en-US' , { month : 'long' } ) ;
421+ const endMonth = endDate . toLocaleString ( 'en-US' , { month : 'long' } ) ;
422+
423+ if ( startDate . getFullYear ( ) === endDate . getFullYear ( ) ) {
424+ return `${ startMonth } - ${ endMonth } ${ startDate . getFullYear ( ) } ` ;
425+ }
426+
427+ return `${ startMonth } ${ startDate . getFullYear ( ) } - ${ endMonth } ${ endDate . getFullYear ( ) } ` ;
428+ }
345429}
0 commit comments