feat: email and calendar events for opportunities (#13613)

This commit is contained in:
neo773
2025-08-05 03:13:09 +05:30
committed by GitHub
parent 2a0c73d276
commit 19dbe28786
12 changed files with 284 additions and 6 deletions
@@ -36,6 +36,19 @@ class GetTimelineCalendarEventsFromCompanyIdArgs {
pageSize: number;
}
@ArgsType()
class GetTimelineCalendarEventsFromOpportunityIdArgs {
@Field(() => UUIDScalarType)
opportunityId: string;
@Field(() => Int)
page: number;
@Field(() => Int)
@Max(TIMELINE_CALENDAR_EVENTS_MAX_PAGE_SIZE)
pageSize: number;
}
@UseGuards(WorkspaceAuthGuard)
@Resolver(() => TimelineCalendarEventsWithTotal)
export class TimelineCalendarEventResolver {
@@ -76,4 +89,27 @@ export class TimelineCalendarEventResolver {
return timelineCalendarEvents;
}
@Query(() => TimelineCalendarEventsWithTotal)
async getTimelineCalendarEventsFromOpportunityId(
@Args()
{
opportunityId,
page,
pageSize,
}: GetTimelineCalendarEventsFromOpportunityIdArgs,
@AuthWorkspaceMemberId() workspaceMemberId: string,
) {
const timelineCalendarEvents =
await this.timelineCalendarEventService.getCalendarEventsFromOpportunityId(
{
currentWorkspaceMemberId: workspaceMemberId,
opportunityId,
page,
pageSize,
},
);
return timelineCalendarEvents;
}
}
@@ -9,6 +9,7 @@ import { TimelineCalendarEventsWithTotal } from 'src/engine/core-modules/calenda
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity';
import { OpportunityWorkspaceEntity } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
@Injectable()
@@ -199,4 +200,46 @@ export class TimelineCalendarEventService {
return calendarEvents;
}
async getCalendarEventsFromOpportunityId({
currentWorkspaceMemberId,
opportunityId,
page = 1,
pageSize = TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE,
}: {
currentWorkspaceMemberId: string;
opportunityId: string;
page: number;
pageSize: number;
}): Promise<TimelineCalendarEventsWithTotal> {
const opportunityRepository =
await this.twentyORMManager.getRepository<OpportunityWorkspaceEntity>(
'opportunity',
);
const opportunity = await opportunityRepository.findOne({
where: {
id: opportunityId,
},
select: {
companyId: true,
},
});
if (!opportunity?.companyId) {
return {
totalNumberOfCalendarEvents: 0,
timelineCalendarEvents: [],
};
}
const calendarEvents = await this.getCalendarEventsFromCompanyId({
currentWorkspaceMemberId,
companyId: opportunity.companyId,
page,
pageSize,
});
return calendarEvents;
}
}
@@ -5,6 +5,7 @@ import { TimelineThreadsWithTotal } from 'src/engine/core-modules/messaging/dtos
import { TimelineMessagingService } from 'src/engine/core-modules/messaging/services/timeline-messaging.service';
import { formatThreads } from 'src/engine/core-modules/messaging/utils/format-threads.util';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { OpportunityWorkspaceEntity } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
@Injectable()
@@ -98,4 +99,41 @@ export class GetMessagesService {
return messageThreads;
}
async getMessagesFromOpportunityId(
workspaceMemberId: string,
opportunityId: string,
page = 1,
pageSize: number = TIMELINE_THREADS_DEFAULT_PAGE_SIZE,
): Promise<TimelineThreadsWithTotal> {
const opportunityRepository =
await this.twentyORMManager.getRepository<OpportunityWorkspaceEntity>(
'opportunity',
);
const opportunity = await opportunityRepository.findOne({
where: {
id: opportunityId,
},
select: {
companyId: true,
},
});
if (!opportunity?.companyId) {
return {
totalNumberOfThreads: 0,
timelineThreads: [],
};
}
const messageThreads = await this.getMessagesFromCompanyId(
workspaceMemberId,
opportunity.companyId,
page,
pageSize,
);
return messageThreads;
}
}
@@ -41,6 +41,19 @@ class GetTimelineThreadsFromCompanyIdArgs {
pageSize: number;
}
@ArgsType()
class GetTimelineThreadsFromOpportunityIdArgs {
@Field(() => UUIDScalarType)
opportunityId: string;
@Field(() => Int)
page: number;
@Field(() => Int)
@Max(TIMELINE_THREADS_MAX_PAGE_SIZE)
pageSize: number;
}
@UseGuards(WorkspaceAuthGuard, UserAuthGuard)
@Resolver(() => TimelineThreadsWithTotal)
export class TimelineMessagingResolver {
@@ -100,4 +113,31 @@ export class TimelineMessagingResolver {
return timelineThreads;
}
@Query(() => TimelineThreadsWithTotal)
async getTimelineThreadsFromOpportunityId(
@AuthUser() user: User,
@AuthWorkspace() workspace: Workspace,
@Args()
{ opportunityId, page, pageSize }: GetTimelineThreadsFromOpportunityIdArgs,
) {
const workspaceMember = await this.userService.loadWorkspaceMember(
user,
workspace,
);
if (!workspaceMember) {
return;
}
const timelineThreads =
await this.getMessagesFromPersonIdsService.getMessagesFromOpportunityId(
workspaceMember.id,
opportunityId,
page,
pageSize,
);
return timelineThreads;
}
}