resolve todos in website

This commit is contained in:
2025-12-20 12:22:48 +01:00
parent a87cf27fb9
commit 20588e1c0b
39 changed files with 1238 additions and 359 deletions

View File

@@ -5,27 +5,24 @@
*/
// Use Cases
export * from './use-cases/SendNotificationUseCase';
export * from './use-cases/MarkNotificationReadUseCase';
export * from './use-cases/GetUnreadNotificationsUseCase';
export * from './use-cases/MarkNotificationReadUseCase';
export * from './use-cases/NotificationPreferencesUseCases';
export * from './use-cases/SendNotificationUseCase';
// Ports
export * from './ports/INotificationGateway';
export * from './ports/NotificationGateway';
// Re-export domain types for convenience
export type {
Notification,
NotificationProps,
NotificationStatus,
NotificationData,
NotificationUrgency,
NotificationAction,
Notification, NotificationAction, NotificationData, NotificationProps,
NotificationStatus, NotificationUrgency
} from '../domain/entities/Notification';
export type { NotificationPreference, NotificationPreferenceProps, ChannelPreference, TypePreference } from '../domain/entities/NotificationPreference';
export type { NotificationType, NotificationChannel } from '../domain/types/NotificationTypes';
export { getNotificationTypeTitle, getNotificationTypePriority, getChannelDisplayName, isExternalChannel, DEFAULT_ENABLED_CHANNELS, ALL_CHANNELS } from '../domain/types/NotificationTypes';
export type { ChannelPreference, NotificationPreference, NotificationPreferenceProps, TypePreference } from '../domain/entities/NotificationPreference';
export { ALL_CHANNELS, DEFAULT_ENABLED_CHANNELS, getChannelDisplayName, getNotificationTypePriority, getNotificationTypeTitle, isExternalChannel } from '../domain/types/NotificationTypes';
export type { NotificationChannel, NotificationType } from '../domain/types/NotificationTypes';
// Re-export repository interfaces
export type { INotificationPreferenceRepository } from '../domain/repositories/INotificationPreferenceRepository';
export type { INotificationRepository } from '../domain/repositories/INotificationRepository';
export type { INotificationPreferenceRepository } from '../domain/repositories/INotificationPreferenceRepository';

View File

@@ -19,7 +19,7 @@ export interface NotificationDeliveryResult {
attemptedAt: Date;
}
export interface INotificationGateway {
export interface NotificationGateway {
/**
* Send a notification through this gateway's channel
*/
@@ -45,21 +45,21 @@ export interface INotificationGateway {
* Registry for notification gateways
* Allows routing notifications to the appropriate gateway based on channel
*/
export interface INotificationGatewayRegistry {
export interface NotificationGatewayRegistry {
/**
* Register a gateway for a channel
*/
register(gateway: INotificationGateway): void;
register(gateway: NotificationGateway): void;
/**
* Get gateway for a specific channel
*/
getGateway(channel: NotificationChannel): INotificationGateway | null;
getGateway(channel: NotificationChannel): NotificationGateway | null;
/**
* Get all registered gateways
*/
getAllGateways(): INotificationGateway[];
getAllGateways(): NotificationGateway[];
/**
* Send notification through appropriate gateway

View File

@@ -1,5 +1,4 @@
import type { NotificationType } from '../../domain/types/NotificationTypes';
import type { NotificationChannel } from '../../domain/types/NotificationTypes';
import type { NotificationChannel, NotificationType } from '../../domain/types/NotificationTypes';
export interface NotificationData {
raceEventId?: string;
@@ -36,6 +35,6 @@ export interface SendNotificationCommand {
requiresResponse?: boolean;
}
export interface INotificationService {
export interface NotificationService {
sendNotification(command: SendNotificationCommand): Promise<void>;
}

View File

@@ -5,15 +5,14 @@
* based on their preferences.
*/
import type { AsyncUseCase, Logger } from '@core/shared/application';
import { v4 as uuid } from 'uuid';
import type { AsyncUseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/application';
import { Notification } from '../../domain/entities/Notification';
import type { NotificationData } from '../../domain/entities/Notification';
import type { INotificationRepository } from '../../domain/repositories/INotificationRepository';
import { Notification } from '../../domain/entities/Notification';
import type { INotificationPreferenceRepository } from '../../domain/repositories/INotificationPreferenceRepository';
import type { INotificationGatewayRegistry, NotificationDeliveryResult } from '../ports/INotificationGateway';
import type { NotificationType, NotificationChannel } from '../../domain/types/NotificationTypes';
import type { INotificationRepository } from '../../domain/repositories/INotificationRepository';
import type { NotificationChannel, NotificationType } from '../../domain/types/NotificationTypes';
import type { NotificationDeliveryResult, NotificationGatewayRegistry } from '../ports/NotificationGateway';
export interface SendNotificationCommand {
recipientId: string;
@@ -48,7 +47,7 @@ export class SendNotificationUseCase implements AsyncUseCase<SendNotificationCom
constructor(
private readonly notificationRepository: INotificationRepository,
private readonly preferenceRepository: INotificationPreferenceRepository,
private readonly gatewayRegistry: INotificationGatewayRegistry,
private readonly gatewayRegistry: NotificationGatewayRegistry,
private readonly logger: Logger,
) {
this.logger.debug('SendNotificationUseCase initialized.');

View File

@@ -1,16 +1,16 @@
import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { AcceptSponsorshipRequestUseCase } from './AcceptSponsorshipRequestUseCase';
import type { ISponsorshipRequestRepository } from '../../domain/repositories/ISponsorshipRequestRepository';
import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import type { INotificationService } from '@core/notifications/application/ports/INotificationService';
import type { NotificationService } from '@/notifications/application/ports/NotificationService';
import type { IWalletRepository } from '@core/payments/domain/repositories/IWalletRepository';
import type { ILeagueWalletRepository } from '../../domain/repositories/ILeagueWalletRepository';
import type { Logger } from '@core/shared/application';
import { SponsorshipRequest } from '../../domain/entities/SponsorshipRequest';
import { Season } from '../../domain/entities/Season';
import { beforeEach, describe, expect, it, Mock, vi } from 'vitest';
import { LeagueWallet } from '../../domain/entities/LeagueWallet';
import { Season } from '../../domain/entities/Season';
import { SponsorshipRequest } from '../../domain/entities/SponsorshipRequest';
import type { ILeagueWalletRepository } from '../../domain/repositories/ILeagueWalletRepository';
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
import type { ISponsorshipRequestRepository } from '../../domain/repositories/ISponsorshipRequestRepository';
import { Money } from '../../domain/value-objects/Money';
import { AcceptSponsorshipRequestUseCase } from './AcceptSponsorshipRequestUseCase';
describe('AcceptSponsorshipRequestUseCase', () => {
let mockSponsorshipRequestRepo: {
@@ -78,7 +78,7 @@ describe('AcceptSponsorshipRequestUseCase', () => {
mockSponsorshipRequestRepo as unknown as ISponsorshipRequestRepository,
mockSeasonSponsorshipRepo as unknown as ISeasonSponsorshipRepository,
mockSeasonRepo as unknown as ISeasonRepository,
mockNotificationService as unknown as INotificationService,
mockNotificationService as unknown as NotificationService,
processPayment,
mockWalletRepo as unknown as IWalletRepository,
mockLeagueWalletRepo as unknown as ILeagueWalletRepository,

View File

@@ -5,20 +5,19 @@
* This creates an active sponsorship and notifies the sponsor.
*/
import type { Logger } from '@core/shared/application';
import type { ISponsorshipRequestRepository } from '../../domain/repositories/ISponsorshipRequestRepository';
import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import type { INotificationService } from '@core/notifications/application/ports/INotificationService';
import type { NotificationService } from '@/notifications/application/ports/NotificationService';
import type { IWalletRepository } from '@core/payments/domain/repositories/IWalletRepository';
import type { ILeagueWalletRepository } from '../../domain/repositories/ILeagueWalletRepository';
import { SeasonSponsorship } from '../../domain/entities/SeasonSponsorship';
import type { AsyncUseCase } from '@core/shared/application';
import type { AsyncUseCase, Logger } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import { SeasonSponsorship } from '../../domain/entities/SeasonSponsorship';
import type { ILeagueWalletRepository } from '../../domain/repositories/ILeagueWalletRepository';
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
import type { ISponsorshipRequestRepository } from '../../domain/repositories/ISponsorshipRequestRepository';
import type { AcceptSponsorshipRequestDTO } from '../dto/AcceptSponsorshipRequestDTO';
import type { AcceptSponsorshipOutputPort } from '../ports/output/AcceptSponsorshipOutputPort';
import type { ProcessPaymentInputPort } from '../ports/input/ProcessPaymentInputPort';
import type { AcceptSponsorshipOutputPort } from '../ports/output/AcceptSponsorshipOutputPort';
import type { ProcessPaymentOutputPort } from '../ports/output/ProcessPaymentOutputPort';
export class AcceptSponsorshipRequestUseCase
@@ -27,7 +26,7 @@ export class AcceptSponsorshipRequestUseCase
private readonly sponsorshipRequestRepo: ISponsorshipRequestRepository,
private readonly seasonSponsorshipRepo: ISeasonSponsorshipRepository,
private readonly seasonRepository: ISeasonRepository,
private readonly notificationService: INotificationService,
private readonly notificationService: NotificationService,
private readonly paymentProcessor: (input: ProcessPaymentInputPort) => Promise<ProcessPaymentOutputPort>,
private readonly walletRepository: IWalletRepository,
private readonly leagueWalletRepository: ILeagueWalletRepository,

View File

@@ -1,15 +1,15 @@
import { describe, it, expect, vi } from 'vitest';
import { SendFinalResultsUseCase } from './SendFinalResultsUseCase';
import type { INotificationService } from '../../../notifications/application/ports/INotificationService';
import { describe, expect, it, vi } from 'vitest';
import type { NotificationService } from '../../../notifications/application/ports/NotificationService';
import type { RaceEventStewardingClosedEvent } from '../../domain/events/RaceEventStewardingClosed';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { RaceEventStewardingClosedEvent } from '../../domain/events/RaceEventStewardingClosed';
import { SendFinalResultsUseCase } from './SendFinalResultsUseCase';
describe('SendFinalResultsUseCase', () => {
it('sends final results notifications to all participating drivers', async () => {
const mockNotificationService = {
sendNotification: vi.fn(),
} as unknown as INotificationService;
} as unknown as NotificationService;
const mockRaceEvent = {
id: 'race-1',
@@ -107,7 +107,7 @@ describe('SendFinalResultsUseCase', () => {
it('skips sending notifications if race event not found', async () => {
const mockNotificationService = {
sendNotification: vi.fn(),
} as unknown as INotificationService;
} as unknown as NotificationService;
const mockRaceEventRepository = {
findById: vi.fn().mockResolvedValue(null),
@@ -146,7 +146,7 @@ describe('SendFinalResultsUseCase', () => {
it('skips sending notifications if no main race session', async () => {
const mockNotificationService = {
sendNotification: vi.fn(),
} as unknown as INotificationService;
} as unknown as NotificationService;
const mockRaceEvent = {
id: 'race-1',

View File

@@ -1,12 +1,12 @@
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { INotificationService } from '../../../notifications/application/ports/INotificationService';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { RaceEventStewardingClosedEvent } from '../../domain/events/RaceEventStewardingClosed';
import type { NotificationService } from '../../../notifications/application/ports/NotificationService';
import type { NotificationType } from '../../../notifications/domain/types/NotificationTypes';
import type { RaceEvent } from '../../domain/entities/RaceEvent';
import type { Result as RaceResult } from '../../domain/entities/Result';
import type { RaceEventStewardingClosedEvent } from '../../domain/events/RaceEventStewardingClosed';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
/**
* Use Case: SendFinalResultsUseCase
@@ -17,7 +17,7 @@ import type { Result as RaceResult } from '../../domain/entities/Result';
*/
export class SendFinalResultsUseCase {
constructor(
private readonly notificationService: INotificationService,
private readonly notificationService: NotificationService,
private readonly raceEventRepository: IRaceEventRepository,
private readonly resultRepository: IResultRepository,
) {}

View File

@@ -1,15 +1,15 @@
import { describe, it, expect, vi } from 'vitest';
import { SendPerformanceSummaryUseCase } from './SendPerformanceSummaryUseCase';
import type { INotificationService } from '../../../notifications/application/ports/INotificationService';
import { describe, expect, it, vi } from 'vitest';
import type { NotificationService } from '../../../notifications/application/ports/NotificationService';
import type { MainRaceCompletedEvent } from '../../domain/events/MainRaceCompleted';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { MainRaceCompletedEvent } from '../../domain/events/MainRaceCompleted';
import { SendPerformanceSummaryUseCase } from './SendPerformanceSummaryUseCase';
describe('SendPerformanceSummaryUseCase', () => {
it('sends performance summary notifications to all participating drivers', async () => {
const mockNotificationService = {
sendNotification: vi.fn(),
} as unknown as INotificationService;
} as unknown as NotificationService;
const mockRaceEvent = {
id: 'race-1',
@@ -106,7 +106,7 @@ describe('SendPerformanceSummaryUseCase', () => {
it('skips sending notifications if race event not found', async () => {
const mockNotificationService = {
sendNotification: vi.fn(),
} as unknown as INotificationService;
} as unknown as NotificationService;
const mockRaceEventRepository = {
findById: vi.fn().mockResolvedValue(null),

View File

@@ -1,12 +1,12 @@
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { INotificationService } from '../../../notifications/application/ports/INotificationService';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { MainRaceCompletedEvent } from '../../domain/events/MainRaceCompleted';
import type { NotificationService } from '../../../notifications/application/ports/NotificationService';
import type { NotificationType } from '../../../notifications/domain/types/NotificationTypes';
import type { RaceEvent } from '../../domain/entities/RaceEvent';
import type { Result as RaceResult } from '../../domain/entities/Result';
import type { MainRaceCompletedEvent } from '../../domain/events/MainRaceCompleted';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
/**
* Use Case: SendPerformanceSummaryUseCase
@@ -16,7 +16,7 @@ import type { Result as RaceResult } from '../../domain/entities/Result';
*/
export class SendPerformanceSummaryUseCase {
constructor(
private readonly notificationService: INotificationService,
private readonly notificationService: NotificationService,
private readonly raceEventRepository: IRaceEventRepository,
private readonly resultRepository: IResultRepository,
) {}