Skip to content

Commit

Permalink
feat: introduced API to close member interaction follow up
Browse files Browse the repository at this point in the history
  • Loading branch information
navneethkrish authored and madan-ideas2it committed Aug 13, 2024
1 parent 80ce6df commit d54ef20
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 236 deletions.
290 changes: 73 additions & 217 deletions .forestadmin-schema.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "MemberFollowUpStatus" ADD VALUE 'CLOSED';
1 change: 1 addition & 0 deletions apps/web-api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ enum PLEventType {
enum MemberFollowUpStatus {
PENDING
COMPLETED
CLOSED
}

enum MemberFeedbackResponseType {
Expand Down
57 changes: 50 additions & 7 deletions apps/web-api/src/office-hours/office-hours.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
CreateMemberFeedbackSchemaDto,
MemberFollowUpQueryParams,
ResponseMemberFollowUpWithRelationsSchema,
MemberFollowUpStatus
MemberFollowUpStatus,
MemberFollowUpType
} from 'libs/contracts/src/schema';
import { ApiQueryFromZod } from '../decorators/api-query-from-zod';
import { ApiOkResponseFromZod } from '../decorators/api-response-from-zod';
Expand All @@ -40,20 +41,33 @@ export class OfficeHoursController {
): Promise<any> {
const member: any = await this.memberService.findMemberByEmail(request["userEmail"]);
const interval = parseInt(process.env.INTERACTION_INTERVAL_DELAY_IN_MILLISECONDS || '1800000')
const result = await this.interactionService.findInteractions({
const result: any = await this.interactionService.findInteractions({
where: {
sourceMemberUid: member?.uid,
targetMemberUid: body?.targetMemberUid,
createdAt: {
gte: new Date(new Date().getTime() - interval)
}
},
include: {
interactionFollowUps: {
where: {
type: MemberFollowUpType.Enum.MEETING_INITIATED,
status: {
in: [ MemberFollowUpStatus.Enum.PENDING, MemberFollowUpStatus.Enum.CLOSED ]
}
}
}
},
orderBy: {
createdAt: 'desc'
}
});
if (result && result.length > 0) {
if (result && result.length > 0 && result[0]?.interactionFollowUps?.length > 0) {
throw new ForbiddenException(`Interaction with same user within ${interval / (60 * 1000)} minutes is forbidden`);
}
if (member.uid === body.targetMemberUid) {
throw new ForbiddenException('Interacte with yourself is forbidden');
throw new ForbiddenException('Interaction with yourself is forbidden');
}
return await this.interactionService.createInteraction(body as any, member);
}
Expand All @@ -69,6 +83,8 @@ export class OfficeHoursController {
const queryableFields = prismaQueryableFieldsFromZod(
ResponseMemberFollowUpWithRelationsSchema
);
const { status } : any = request.query;
delete request.query.status;
const builder = new PrismaQueryBuilder(queryableFields);
const builtQuery = builder.build(request.query);
const member: any = await this.memberService.findMemberByEmail(request["userEmail"]);
Expand All @@ -77,7 +93,7 @@ export class OfficeHoursController {
builtQuery.where,
{
createdBy: member?.uid,
status: MemberFollowUpStatus.Enum.PENDING
status: status ? { in: status.split(',') } : {}
},
this.followUpService.buildDelayedFollowUpQuery()
]
Expand All @@ -98,12 +114,39 @@ export class OfficeHoursController {
where: {
uid : interactionFollowUpUid,
createdBy: member?.uid,
status: MemberFollowUpStatus.Enum.PENDING
status: {
in: [ MemberFollowUpStatus.Enum.PENDING, MemberFollowUpStatus.Enum.CLOSED ]
}
}
});
console.log(followUps)
if (followUps && followUps.length === 0) {
throw new NotFoundException(`There is no follow-up associated with the given ID: ${interactionFollowUpUid}`);
}
return await this.interactionService.createInteractionFeedback(body as any, member, followUps?.[0]);
}
}

@Api(server.route.closeMemberInteractionFollowUp)
@UsePipes(ZodValidationPipe)
@UseGuards(UserTokenValidation)
async closeMemberInteractionFollowUp(
@Param('interactionUid') interactionUid: string,
@Param('followUpUid') followUpUid: string,
@Req() request: Request
): Promise<any> {
const member: any = await this.memberService.findMemberByEmail(request["userEmail"]);
const followUps = await this.followUpService.getFollowUps({
where: {
uid : followUpUid,
interactionUid,
createdBy: member?.uid,
status: MemberFollowUpStatus.Enum.PENDING
}
});
if (followUps && followUps.length === 0) {
throw new NotFoundException(`No pending follow-up found for the given ID: ${followUpUid}.
It may have been closed or does not exist.`);
}
return await this.interactionService.closeMemberInteractionFollowUpByID(followUpUid);
}
}
13 changes: 9 additions & 4 deletions apps/web-api/src/office-hours/office-hours.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@ export class OfficeHoursService {
async findInteractions(queryOptions: Prisma.MemberInteractionFindManyArgs) {
try {
return await this.prisma.memberInteraction.findMany({
...queryOptions,
include: {
interactionFollowUps: true
}
...queryOptions
});
} catch(exception) {
this.handleErrors(exception);
Expand Down Expand Up @@ -130,6 +127,14 @@ export class OfficeHoursService {
});
}

async closeMemberInteractionFollowUpByID(followUpUid) {
try {
return await this.followUpService.updateFollowUpStatusByUid(followUpUid, MemberFollowUpStatus.Enum.CLOSED);
} catch(error) {
this.handleErrors(error, followUpUid);
}
}

private handleErrors(error, message?) {
this.logger.error(error);
if (error instanceof Prisma.PrismaClientKnownRequestError) {
Expand Down
14 changes: 7 additions & 7 deletions apps/web-api/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,13 @@ export const PROJECT = 'Project';
export const TEAM = 'Team';

export const InteractionFailureReasons: { [key: string]: string } = {
"Broken Link": "IFR0001",
"Link is broken": "IFR0001",
"I plan to schedule soon": "IFR0002",
"Preferred slot not available": "IFR0003",
"Meeting yet to happen": "IFR0004",
"Got Rescheduled": "IFR0005",
"Got Cancelled" : "IFR0006",
"Preferred slot is not available": "IFR0003",
"Got rescheduled": "IFR0005",
"Got cancelled" : "IFR0006",
"Member didn’t show up": "IFR0007",
"I did not show up":"IFR0008",
"Other": "IFR0009"
"I could not make it":"IFR0008",
"Call quality issues": "IFR0009",
"Meeting link didn't work": "IFR00010"
};
9 changes: 9 additions & 0 deletions libs/contracts/src/lib/contract-member-interaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ export const apiMemberInteractions = contract.router({
},
summary: 'Get member interaction follow ups',
},
closeMemberInteractionFollowUp: {
method: 'PATCH',
path: `${getAPIVersionAsPath('1')}/members/:uid/interactions/:interactionUid/follow-ups/:followUpUid`,
body: contract.body<unknown>(),
responses: {
200: contract.response<unknown>(),
},
summary: 'close a member interaction follow up'
},
createMemberInteractionFeedback: {
method: 'POST',
path: `${getAPIVersionAsPath('1')}/members/:uid/follow-ups/:uid/feedbacks`,
Expand Down
2 changes: 1 addition & 1 deletion libs/contracts/src/schema/member-follow-up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const MemberFollowUpType = z.enum([
"MEETING_RESCHEDULED"
]);

export const MemberFollowUpStatus = z.enum(["PENDING", "COMPLETED"]);
export const MemberFollowUpStatus = z.enum(["PENDING", "COMPLETED", "CLOSED"]);

const MemberFollowUpSchema = z.object({
id: z.number().int(),
Expand Down

0 comments on commit d54ef20

Please sign in to comment.