import { Injectable } from '@nestjs/common'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; import { Ticket, TicketValidationState, Tour } from '@prisma/client'; import { Interval } from 'date-fns'; import { PubSub } from 'graphql-subscriptions'; import { decodeOffsetCursor, encodeCursor, } from 'src/core/base/pagination.util'; import { DocumentInfoArgs, TicketFilterArgs } from './ticket-arg.types'; import { TicketLifecycleService } from './ticket-lifecycle.service'; import { TicketSystemEventTypes, TicketSystemValidatedEvent, } from './ticket-system.events'; import { PaginatedTicketObjectType, TicketStateKeyFiguresObjectType, TicketStateMetaObjectType, } from './ticket.object-type'; import { TicketRepository } from './ticket.repository'; @Injectable() export class TicketService { public readonly pubSub = new PubSub(); @OnEvent(TicketSystemEventTypes.Validated, { async: true }) notifyOnTicketsValidated(event: TicketSystemValidatedEvent): void { this.pubSub.publish('ticketsUpdated', { ticketsUpdated: { count: event.count }, }); } constructor( private readonly repository: TicketRepository, private readonly lifecycle: TicketLifecycleService, private readonly eventEmitter: EventEmitter2, ) {} async createTickets(interval: Interval): Promise { await this.lifecycle.createTickets(interval); this.eventEmitter.emit( TicketSystemEventTypes.Validated, new TicketSystemValidatedEvent(0), ); } async updateDocumentInfo(ticketId: string, documentInfo: DocumentInfoArgs) { return this.lifecycle.validateDocumentInfoUpdate(ticketId, documentInfo); } findById(id: string): Promise { return this.repository.findById(id); } findAll(): Promise { return this.repository.findAll() as Promise; } searchTickets(query: string): Promise { return this.repository.search(query); } async paginateTicketsByState( state: TicketValidationState, filter: TicketFilterArgs, take?: number, cursor?: string, ): Promise { const skip = cursor ? decodeOffsetCursor(cursor) : 0; const { tickets, total } = await this.repository.findByState( state, filter, take, skip, ); const prevPage = skip - take < 0 ? 0 : skip - take; const nextPage = skip + take < total ? skip + take : skip; return { nodes: tickets, prevCursor: encodeCursor(prevPage), endCursor: encodeCursor(nextPage), hasNextPage: nextPage !== skip, totalCount: total, }; } async getTicketStateMeta( ticketState: TicketValidationState, ): Promise { return this.repository.calculateTicketStateMeta(ticketState); } getTicketStateKeyFigures( ticketState: TicketValidationState, ): Promise { return this.repository.calculateTicketStateKeyFigures(ticketState); } findToursByTicketId(ticketId: string): Promise { return this.repository.findToursByTicketId(ticketId); } findStatesByTicketId(ticketId: string): Promise { return this.repository .findStatesByTicketId(ticketId) .then((states) => states.map(({ state }) => state)); } }