From 6a868bd3a91e2dd46eea8584cefef1925eece47e Mon Sep 17 00:00:00 2001 From: Ben Petrillo Date: Sun, 28 Sep 2025 21:21:15 -0400 Subject: [PATCH 1/3] feat(donations): add donation DTOs and mappers --- .../src/donations/dtos/create-donation-dto.ts | 106 +++++++ .../donations/dtos/donation-response-dto.ts | 101 +++++++ .../src/donations/dtos/public-donation-dto.ts | 66 ++++ apps/backend/src/donations/mappers.spec.ts | 283 ++++++++++++++++++ apps/backend/src/donations/mappers.ts | 122 ++++++++ 5 files changed, 678 insertions(+) create mode 100644 apps/backend/src/donations/dtos/create-donation-dto.ts create mode 100644 apps/backend/src/donations/dtos/donation-response-dto.ts create mode 100644 apps/backend/src/donations/dtos/public-donation-dto.ts create mode 100644 apps/backend/src/donations/mappers.spec.ts create mode 100644 apps/backend/src/donations/mappers.ts diff --git a/apps/backend/src/donations/dtos/create-donation-dto.ts b/apps/backend/src/donations/dtos/create-donation-dto.ts new file mode 100644 index 0000000..4a1e935 --- /dev/null +++ b/apps/backend/src/donations/dtos/create-donation-dto.ts @@ -0,0 +1,106 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { + IsString, + IsEmail, + IsNumber, + IsBoolean, + IsEnum, + IsOptional, + Min, + IsNotEmpty, +} from 'class-validator'; + +export enum DonationType { + ONE_TIME = 'one_time', + RECURRING = 'recurring', +} + +export enum RecurringInterval { + WEEKLY = 'weekly', + MONTHLY = 'monthly', + BIMONTHLY = 'bimonthly', + QUARTERLY = 'quarterly', + ANNUALLY = 'annually', +} + +export class CreateDonationDto { + @ApiProperty({ + description: 'donor first name', + example: 'John', + }) + @IsString() + @IsNotEmpty() + firstName: string; + + @ApiProperty({ + description: 'donor last name', + example: 'Smith', + }) + @IsString() + @IsNotEmpty() + lastName: string; + + @ApiProperty({ + description: 'donor email address', + example: 'john.smith@example.com', + }) + @IsEmail() + @IsNotEmpty() + email: string; + + @ApiProperty({ + description: 'the donation amount in dollars', + example: 100.0, + minimum: 0.01, + }) + @IsNumber() + @Min(0.01) + amount: number; + + @ApiProperty({ + description: 'whether the donation should be anonymous', + example: false, + required: false, + default: false, + }) + @IsBoolean() + @IsOptional() + isAnonymous?: boolean = false; + + @ApiProperty({ + description: 'the type of donation', + enum: DonationType, + example: DonationType.ONE_TIME, + }) + @IsEnum(DonationType) + donationType: DonationType; + + @ApiProperty({ + description: 'recurring interval for recurring donations', + enum: RecurringInterval, + required: false, + example: RecurringInterval.MONTHLY, + }) + @IsEnum(RecurringInterval) + @IsOptional() + recurringInterval?: RecurringInterval; + + @ApiProperty({ + description: 'optional dedication message', + example: 'for the Fenway community', + required: false, + }) + @IsString() + @IsOptional() + dedicationMessage?: string; + + @ApiProperty({ + description: 'whether to show dedication message publicly', + example: false, + required: false, + default: false, + }) + @IsBoolean() + @IsOptional() + showDedicationPublicly?: boolean = false; +} diff --git a/apps/backend/src/donations/dtos/donation-response-dto.ts b/apps/backend/src/donations/dtos/donation-response-dto.ts new file mode 100644 index 0000000..0d02df0 --- /dev/null +++ b/apps/backend/src/donations/dtos/donation-response-dto.ts @@ -0,0 +1,101 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { DonationType, RecurringInterval } from './create-donation-dto'; + +export enum DonationStatus { + PENDING = 'pending', + COMPLETED = 'completed', + FAILED = 'failed', + CANCELLED = 'cancelled', +} + +export class DonationResponseDto { + @ApiProperty({ + description: 'Unique donation identifier', + example: '123e4567-e89b-12d3-a456-426614174000', + }) + id: string; + + @ApiProperty({ + description: 'donor first name', + example: 'John', + }) + firstName: string; + + @ApiProperty({ + description: 'donor last name', + example: 'Smith', + }) + lastName: string; + + @ApiProperty({ + description: 'donor email address', + example: 'john.smith@example.com', + }) + email: string; + + @ApiProperty({ + description: 'donation amount in dollars', + example: 100.0, + }) + amount: number; + + @ApiProperty({ + description: 'whether the donation is anonymous', + example: false, + }) + isAnonymous: boolean; + + @ApiProperty({ + description: 'the type of donation', + enum: DonationType, + example: DonationType.ONE_TIME, + }) + donationType: DonationType; + + @ApiProperty({ + description: 'the recurring interval for recurring donations', + enum: RecurringInterval, + required: false, + example: RecurringInterval.MONTHLY, + }) + recurringInterval?: RecurringInterval; + + @ApiProperty({ + description: 'optional dedication message', + example: 'for the Fenway community', + required: false, + }) + dedicationMessage?: string; + + @ApiProperty({ + description: 'whether to show dedication message publicly', + example: false, + }) + showDedicationPublicly: boolean; + + @ApiProperty({ + description: 'the current donation status', + enum: DonationStatus, + example: DonationStatus.COMPLETED, + }) + status: DonationStatus; + + @ApiProperty({ + description: 'timestamp when donation was created', + example: '2024-01-15T10:30:00Z', + }) + createdAt: Date; + + @ApiProperty({ + description: 'timestamp when donation was last updated', + example: '2024-01-15T10:35:00Z', + }) + updatedAt: Date; + + @ApiProperty({ + description: 'payment processor transaction ID', + example: 'txn_1234567890', + required: false, + }) + transactionId?: string; +} diff --git a/apps/backend/src/donations/dtos/public-donation-dto.ts b/apps/backend/src/donations/dtos/public-donation-dto.ts new file mode 100644 index 0000000..bba89a5 --- /dev/null +++ b/apps/backend/src/donations/dtos/public-donation-dto.ts @@ -0,0 +1,66 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { DonationType, RecurringInterval } from './create-donation-dto'; +import { DonationStatus } from './donation-response-dto'; + +export class PublicDonationDto { + @ApiProperty({ + description: 'unique donation identifier', + example: '123e4567-e89b-12d3-a456-426614174000', + }) + id: string; + + @ApiProperty({ + description: 'donor name, hidden if anonymous', + example: 'John Smith', + required: false, + }) + donorName?: string; + + @ApiProperty({ + description: 'donation amount, in dollars', + example: 100.0, + }) + amount: number; + + @ApiProperty({ + description: 'whether or not the donation is anonymous', + example: false, + }) + isAnonymous: boolean; + + @ApiProperty({ + description: 'the type of donation', + enum: DonationType, + example: DonationType.ONE_TIME, + }) + donationType: DonationType; + + @ApiProperty({ + description: 'the recurring interval for recurring donations', + enum: RecurringInterval, + required: false, + example: RecurringInterval.MONTHLY, + }) + recurringInterval?: RecurringInterval; + + @ApiProperty({ + description: + 'the dedication message, shown if showDedicationPublicly is true', + example: 'for the Fenway community', + required: false, + }) + dedicationMessage?: string; + + @ApiProperty({ + description: 'the current donation status', + enum: DonationStatus, + example: DonationStatus.COMPLETED, + }) + status: DonationStatus; + + @ApiProperty({ + description: 'timestamp when donation was created', + example: '2024-01-15T10:30:00Z', + }) + createdAt: Date; +} diff --git a/apps/backend/src/donations/mappers.spec.ts b/apps/backend/src/donations/mappers.spec.ts new file mode 100644 index 0000000..7938071 --- /dev/null +++ b/apps/backend/src/donations/mappers.spec.ts @@ -0,0 +1,283 @@ +import { validate } from 'class-validator'; +import { + CreateDonationDto, + DonationType, + RecurringInterval, +} from './dtos/create-donation-dto'; +import { DonationStatus } from './dtos/donation-response-dto'; +import { PublicDonationDto } from './dtos/public-donation-dto'; +import { DonationMappers, Donation } from './mappers'; + +describe('DonationMappers', () => { + const mockDonation: Donation = { + id: '123e4567-e89b-12d3-a456-426614174000', + firstName: 'John', + lastName: 'Smith', + email: 'john.smith@example.com', + amount: 100.0, + isAnonymous: false, + donationType: 'one_time', + dedicationMessage: 'for the Fenway community', + showDedicationPublicly: true, + status: 'completed', + createdAt: new Date('2024-01-15T10:30:00Z'), + updatedAt: new Date('2024-01-15T10:35:00Z'), + transactionId: 'txn_1234567890', + }; + + const mockCreateDto: CreateDonationDto = { + firstName: 'John', + lastName: 'Smith', + email: 'john.smith@example.com', + amount: 100.0, + isAnonymous: false, + donationType: DonationType.ONE_TIME, + dedicationMessage: 'for the Fenway community', + showDedicationPublicly: true, + }; + + const mockPublicDonation: PublicDonationDto = { + id: '123e4567-e89b-12d3-a456-426614174000', + donorName: 'John Smith', + amount: 100.0, + isAnonymous: false, + donationType: DonationType.ONE_TIME, + recurringInterval: undefined, + dedicationMessage: 'for the Fenway community', + status: DonationStatus.COMPLETED, + createdAt: new Date('2024-01-15T10:30:00Z'), + }; + + describe('toCreateDonationRequest', () => { + it('should map CreateDonationDto to CreateDonationRequest correctly', () => { + const result = DonationMappers.toCreateDonationRequest(mockCreateDto); + + expect(result).toEqual({ + firstName: 'John', + lastName: 'Smith', + email: 'john.smith@example.com', + amount: 100.0, + isAnonymous: false, + donationType: 'one_time', + dedicationMessage: 'for the Fenway community', + showDedicationPublicly: true, + }); + }); + + it('should apply default values for optional fields', () => { + const minimalDto: CreateDonationDto = { + firstName: 'Jane', + lastName: 'Doe', + email: 'jane.doe@example.com', + amount: 50.0, + donationType: DonationType.ONE_TIME, + }; + + const result = DonationMappers.toCreateDonationRequest(minimalDto); + + expect(result.isAnonymous).toBe(false); + expect(result.showDedicationPublicly).toBe(false); + expect(result.recurringInterval).toBeUndefined(); + expect(result.dedicationMessage).toBeUndefined(); + }); + + it('should handle recurring donations with interval', () => { + const recurringDto: CreateDonationDto = { + ...mockCreateDto, + donationType: DonationType.RECURRING, + recurringInterval: RecurringInterval.MONTHLY, + }; + + const result = DonationMappers.toCreateDonationRequest(recurringDto); + + expect(result.donationType).toBe('recurring'); + expect(result.recurringInterval).toBe('monthly'); + }); + }); + + describe('toDonationResponseDto', () => { + it('should map Donation to DonationResponseDto correctly', () => { + const result = DonationMappers.toDonationResponseDto(mockDonation); + + expect(result.id).toBe(mockDonation.id); + expect(result.firstName).toBe(mockDonation.firstName); + expect(result.lastName).toBe(mockDonation.lastName); + expect(result.email).toBe(mockDonation.email); + expect(result.amount).toBe(mockDonation.amount); + expect(result.isAnonymous).toBe(mockDonation.isAnonymous); + expect(result.donationType).toBe(mockDonation.donationType); + expect(result.dedicationMessage).toBe(mockDonation.dedicationMessage); + expect(result.showDedicationPublicly).toBe( + mockDonation.showDedicationPublicly, + ); + expect(result.status).toBe(mockDonation.status); + expect(result.createdAt).toBe(mockDonation.createdAt); + expect(result.updatedAt).toBe(mockDonation.updatedAt); + expect(result.transactionId).toBe(mockDonation.transactionId); + }); + }); + + describe('toPublicDonationDto', () => { + it('should include donor name when not anonymous', () => { + const result = DonationMappers.toPublicDonationDto(mockDonation); + + expect(result.donorName).toBe('John Smith'); + expect(result.dedicationMessage).toBe('for the Fenway community'); + }); + + it('should exclude donor name when anonymous', () => { + const anonymousDonation: Donation = { + ...mockDonation, + isAnonymous: true, + }; + + const result = DonationMappers.toPublicDonationDto(anonymousDonation); + + expect(result.donorName).toBeUndefined(); + expect(result.isAnonymous).toBe(true); + }); + + it('should exclude dedication message when showDedicationPublicly is false', () => { + const privateDedication: Donation = { + ...mockDonation, + showDedicationPublicly: false, + }; + + const result = DonationMappers.toPublicDonationDto(privateDedication); + + expect(result.dedicationMessage).toBeUndefined(); + }); + + it('should exclude dedication message when it is empty even if showDedicationPublicly is true', () => { + const noDedication: Donation = { + ...mockDonation, + dedicationMessage: undefined, + showDedicationPublicly: true, + }; + + const result = DonationMappers.toPublicDonationDto(noDedication); + + expect(result.dedicationMessage).toBeUndefined(); + }); + + it('should not include email or sensitive fields', () => { + const result = DonationMappers.toPublicDonationDto(mockDonation); + + expect(result.id).toBe(mockPublicDonation.id); + expect(result.donorName).toBe(mockPublicDonation.donorName); + expect(result.amount).toBe(mockPublicDonation.amount); + expect(result.isAnonymous).toBe(mockPublicDonation.isAnonymous); + expect(result.donationType).toBe(mockPublicDonation.donationType); + expect(result.recurringInterval).toBe( + mockPublicDonation.recurringInterval, + ); + expect(result.dedicationMessage).toBe( + mockPublicDonation.dedicationMessage, + ); + expect(result.status).toBe(mockPublicDonation.status); + expect(result.createdAt).toEqual(mockPublicDonation.createdAt); + + expect(result).not.toHaveProperty('email'); + expect(result).not.toHaveProperty('firstName'); + expect(result).not.toHaveProperty('lastName'); + expect(result).not.toHaveProperty('transactionId'); + expect(result).not.toHaveProperty('updatedAt'); + expect(result).not.toHaveProperty('showDedicationPublicly'); + }); + }); + + describe('array mapping methods', () => { + it('should map array of donations to response DTOs', () => { + const donations = [mockDonation, { ...mockDonation, id: 'different-id' }]; + const result = DonationMappers.toDonationResponseDtos(donations); + + expect(result).toHaveLength(2); + expect(result[0].id).toBe(mockDonation.id); + expect(result[1].id).toBe('different-id'); + }); + + it('should map array of donations to public DTOs', () => { + const donations = [ + mockDonation, + { ...mockDonation, id: 'different-id', isAnonymous: true }, + ]; + const result = DonationMappers.toPublicDonationDtos(donations); + + expect(result).toHaveLength(2); + expect(result[0].donorName).toBe('John Smith'); + expect(result[1].donorName).toBeUndefined(); + }); + }); +}); + +describe('CreateDonationDto Validation', () => { + it('should validate a valid DTO', async () => { + const dto = new CreateDonationDto(); + dto.firstName = 'John'; + dto.lastName = 'Smith'; + dto.email = 'john.smith@example.com'; + dto.amount = 100.0; + dto.donationType = DonationType.ONE_TIME; + + const errors = await validate(dto); + expect(errors).toHaveLength(0); + }); + + it('should fail validation for invalid email', async () => { + const dto = new CreateDonationDto(); + dto.firstName = 'John'; + dto.lastName = 'Smith'; + dto.email = 'invalid-email'; + dto.amount = 100.0; + dto.donationType = DonationType.ONE_TIME; + + const errors = await validate(dto); + expect(errors.length).toBeGreaterThan(0); + expect(errors.some((error) => error.property === 'email')).toBe(true); + }); + + it('should fail validation for empty required fields', async () => { + const dto = new CreateDonationDto(); + dto.firstName = ''; + dto.lastName = ''; + dto.email = ''; + dto.amount = 0; + dto.donationType = DonationType.ONE_TIME; + + const errors = await validate(dto); + expect(errors.length).toBeGreaterThan(0); + + const errorProperties = errors.map((error) => error.property); + expect(errorProperties).toContain('firstName'); + expect(errorProperties).toContain('lastName'); + expect(errorProperties).toContain('email'); + expect(errorProperties).toContain('amount'); + }); + + it('should fail validation for amount too low', async () => { + const dto = new CreateDonationDto(); + dto.firstName = 'John'; + dto.lastName = 'Smith'; + dto.email = 'john.smith@example.com'; + dto.amount = 0.005; // Below minimum + dto.donationType = DonationType.ONE_TIME; + + const errors = await validate(dto); + expect(errors.some((error) => error.property === 'amount')).toBe(true); + }); + + it('should fail validation for invalid recurring interval', async () => { + const dto = new CreateDonationDto(); + dto.firstName = 'John'; + dto.lastName = 'Smith'; + dto.email = 'john.smith@example.com'; + dto.amount = 100.0; + dto.donationType = DonationType.RECURRING; + dto.recurringInterval = 'invalid' as RecurringInterval; + + const errors = await validate(dto); + expect(errors.some((error) => error.property === 'recurringInterval')).toBe( + true, + ); + }); +}); diff --git a/apps/backend/src/donations/mappers.ts b/apps/backend/src/donations/mappers.ts new file mode 100644 index 0000000..7ecd4cb --- /dev/null +++ b/apps/backend/src/donations/mappers.ts @@ -0,0 +1,122 @@ +import { + CreateDonationDto, + DonationType, + RecurringInterval, +} from './dtos/create-donation-dto'; +import { + DonationResponseDto, + DonationStatus, +} from './dtos/donation-response-dto'; +import { PublicDonationDto } from './dtos/public-donation-dto'; + +export interface CreateDonationRequest { + firstName: string; + lastName: string; + email: string; + amount: number; + isAnonymous: boolean; + donationType: 'one_time' | 'recurring'; + recurringInterval?: + | 'weekly' + | 'monthly' + | 'bimonthly' + | 'quarterly' + | 'annually'; + dedicationMessage?: string; + showDedicationPublicly: boolean; +} + +export interface Donation { + id: string; + firstName: string; + lastName: string; + email: string; + amount: number; + isAnonymous: boolean; + donationType: 'one_time' | 'recurring'; + recurringInterval?: + | 'weekly' + | 'monthly' + | 'bimonthly' + | 'quarterly' + | 'annually'; + dedicationMessage?: string; + showDedicationPublicly: boolean; + status: 'pending' | 'completed' | 'failed' | 'cancelled'; + createdAt: Date; + updatedAt: Date; + transactionId?: string; +} + +export class DonationMappers { + static toCreateDonationRequest( + dto: CreateDonationDto, + ): CreateDonationRequest { + return { + firstName: dto.firstName, + lastName: dto.lastName, + email: dto.email, + amount: dto.amount, + isAnonymous: dto.isAnonymous ?? false, + donationType: dto.donationType as 'one_time' | 'recurring', + recurringInterval: dto.recurringInterval as + | 'weekly' + | 'monthly' + | 'bimonthly' + | 'quarterly' + | 'annually' + | undefined, + dedicationMessage: dto.dedicationMessage, + showDedicationPublicly: dto.showDedicationPublicly ?? false, + }; + } + + static toDonationResponseDto(donation: Donation): DonationResponseDto { + return { + id: donation.id, + firstName: donation.firstName, + lastName: donation.lastName, + email: donation.email, + amount: donation.amount, + isAnonymous: donation.isAnonymous, + donationType: donation.donationType as DonationType, + recurringInterval: donation.recurringInterval as RecurringInterval, + dedicationMessage: donation.dedicationMessage, + showDedicationPublicly: donation.showDedicationPublicly, + status: donation.status as DonationStatus, + createdAt: donation.createdAt, + updatedAt: donation.updatedAt, + transactionId: donation.transactionId, + }; + } + + static toPublicDonationDto(donation: Donation): PublicDonationDto { + const publicDto: PublicDonationDto = { + id: donation.id, + amount: donation.amount, + isAnonymous: donation.isAnonymous, + donationType: donation.donationType as DonationType, + recurringInterval: donation.recurringInterval as RecurringInterval, + status: donation.status as DonationStatus, + createdAt: donation.createdAt, + }; + + if (!donation.isAnonymous) { + publicDto.donorName = `${donation.firstName} ${donation.lastName}`; + } + + if (donation.showDedicationPublicly && donation.dedicationMessage) { + publicDto.dedicationMessage = donation.dedicationMessage; + } + + return publicDto; + } + + static toDonationResponseDtos(donations: Donation[]): DonationResponseDto[] { + return donations.map((donation) => this.toDonationResponseDto(donation)); + } + + static toPublicDonationDtos(donations: Donation[]): PublicDonationDto[] { + return donations.map((donation) => this.toPublicDonationDto(donation)); + } +} From a18ddd32a4a0cb6afc896f952b878d42437ac69c Mon Sep 17 00:00:00 2001 From: thaninbew Date: Mon, 29 Sep 2025 23:44:55 -0400 Subject: [PATCH 2/3] Make fields consistent with latest commits --- apps/backend/src/donations/donation.entity.ts | 3 +++ .../src/donations/dtos/donation-response-dto.ts | 4 ++-- apps/backend/src/donations/dtos/public-donation-dto.ts | 4 ++-- apps/backend/src/donations/mappers.spec.ts | 10 +++++----- apps/backend/src/donations/mappers.ts | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/backend/src/donations/donation.entity.ts b/apps/backend/src/donations/donation.entity.ts index 73d3ddb..3ca60f9 100644 --- a/apps/backend/src/donations/donation.entity.ts +++ b/apps/backend/src/donations/donation.entity.ts @@ -44,6 +44,9 @@ export class Donation { @Column({ nullable: true }) dedicationMessage: string; + @Column({ default: false }) + showDedicationPublicly: boolean; + @Column() createdAt: Date; diff --git a/apps/backend/src/donations/dtos/donation-response-dto.ts b/apps/backend/src/donations/dtos/donation-response-dto.ts index 0d02df0..16e43c8 100644 --- a/apps/backend/src/donations/dtos/donation-response-dto.ts +++ b/apps/backend/src/donations/dtos/donation-response-dto.ts @@ -11,9 +11,9 @@ export enum DonationStatus { export class DonationResponseDto { @ApiProperty({ description: 'Unique donation identifier', - example: '123e4567-e89b-12d3-a456-426614174000', + example: 123, }) - id: string; + id: number; @ApiProperty({ description: 'donor first name', diff --git a/apps/backend/src/donations/dtos/public-donation-dto.ts b/apps/backend/src/donations/dtos/public-donation-dto.ts index bba89a5..308c817 100644 --- a/apps/backend/src/donations/dtos/public-donation-dto.ts +++ b/apps/backend/src/donations/dtos/public-donation-dto.ts @@ -5,9 +5,9 @@ import { DonationStatus } from './donation-response-dto'; export class PublicDonationDto { @ApiProperty({ description: 'unique donation identifier', - example: '123e4567-e89b-12d3-a456-426614174000', + example: 123, }) - id: string; + id: number; @ApiProperty({ description: 'donor name, hidden if anonymous', diff --git a/apps/backend/src/donations/mappers.spec.ts b/apps/backend/src/donations/mappers.spec.ts index 7938071..7e34743 100644 --- a/apps/backend/src/donations/mappers.spec.ts +++ b/apps/backend/src/donations/mappers.spec.ts @@ -10,7 +10,7 @@ import { DonationMappers, Donation } from './mappers'; describe('DonationMappers', () => { const mockDonation: Donation = { - id: '123e4567-e89b-12d3-a456-426614174000', + id: 123, firstName: 'John', lastName: 'Smith', email: 'john.smith@example.com', @@ -37,7 +37,7 @@ describe('DonationMappers', () => { }; const mockPublicDonation: PublicDonationDto = { - id: '123e4567-e89b-12d3-a456-426614174000', + id: 123, donorName: 'John Smith', amount: 100.0, isAnonymous: false, @@ -188,18 +188,18 @@ describe('DonationMappers', () => { describe('array mapping methods', () => { it('should map array of donations to response DTOs', () => { - const donations = [mockDonation, { ...mockDonation, id: 'different-id' }]; + const donations = [mockDonation, { ...mockDonation, id: 456 }]; const result = DonationMappers.toDonationResponseDtos(donations); expect(result).toHaveLength(2); expect(result[0].id).toBe(mockDonation.id); - expect(result[1].id).toBe('different-id'); + expect(result[1].id).toBe(456); }); it('should map array of donations to public DTOs', () => { const donations = [ mockDonation, - { ...mockDonation, id: 'different-id', isAnonymous: true }, + { ...mockDonation, id: 456, isAnonymous: true }, ]; const result = DonationMappers.toPublicDonationDtos(donations); diff --git a/apps/backend/src/donations/mappers.ts b/apps/backend/src/donations/mappers.ts index 7ecd4cb..2583d1e 100644 --- a/apps/backend/src/donations/mappers.ts +++ b/apps/backend/src/donations/mappers.ts @@ -27,7 +27,7 @@ export interface CreateDonationRequest { } export interface Donation { - id: string; + id: number; firstName: string; lastName: string; email: string; From db0c8de2b7c277536b8a2f2a5ad3615015e8ecfa Mon Sep 17 00:00:00 2001 From: thaninbew Date: Tue, 30 Sep 2025 00:02:01 -0400 Subject: [PATCH 3/3] fix recurringInterval mismatch --- apps/backend/src/donations/donation.entity.ts | 6 +++--- apps/backend/src/donations/test.ts | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 apps/backend/src/donations/test.ts diff --git a/apps/backend/src/donations/donation.entity.ts b/apps/backend/src/donations/donation.entity.ts index 3ca60f9..dbb2e3a 100644 --- a/apps/backend/src/donations/donation.entity.ts +++ b/apps/backend/src/donations/donation.entity.ts @@ -6,11 +6,11 @@ export enum donationType { } export enum recurringInterval { - 'monthly', - 'yearly', 'weekly', + 'monthly', 'bimonthly', - 'biweekly', + 'quarterly', + 'annually', } @Entity() diff --git a/apps/backend/src/donations/test.ts b/apps/backend/src/donations/test.ts deleted file mode 100644 index 0ae040b..0000000 --- a/apps/backend/src/donations/test.ts +++ /dev/null @@ -1 +0,0 @@ -//test