This commit is contained in:
2025-11-27 18:56:03 +05:30
10 changed files with 590 additions and 166 deletions

View File

@@ -161,12 +161,12 @@ getPQQ_LastUpdatedQuestion:
path: /host/Activity_Hub/OnBoarding/get-latest-pqq-question-details
method: get
getAllActivity:
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllActivity.handler
getAllActivityType:
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllActivityType.handler
memorySize: 384
package:
patterns:
- 'src/modules/host/handlers/getActivity.*'
- 'src/modules/host/handlers/getActivityType.*'
- 'src/modules/host/services/**'
- ${file(./serverless/patterns/base.yml):pattern1}
- ${file(./serverless/patterns/base.yml):pattern2}
@@ -174,7 +174,23 @@ getAllActivity:
- ${file(./serverless/patterns/base.yml):pattern4}
events:
- httpApi:
path: /host/Activity_Hub/OnBoarding/get-activity
path: /host/Activity_Hub/OnBoarding/get-activity-type
method: get
getAllHostActivity:
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllHostActivity.handler
memorySize: 384
package:
patterns:
- 'src/modules/host/handlers/Activity_Hub/OnBoarding/getAllHostActivity.*'
- 'src/modules/host/services/**'
- ${file(./serverless/patterns/base.yml):pattern1}
- ${file(./serverless/patterns/base.yml):pattern2}
- ${file(./serverless/patterns/base.yml):pattern3}
- ${file(./serverless/patterns/base.yml):pattern4}
events:
- httpApi:
path: /host/Activity_Hub/OnBoarding/get-all-host-activity
method: get
acceptAggrement:
@@ -278,4 +294,19 @@ updatePQQ_LastAnswer:
events:
- httpApi:
path: /host/Activity_Hub/OnBoarding/submit-final-pqq-answer
method: post
method: post
getAllPQQwithSubmittedAns:
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllPQQwithSubmittedAns.handler
memorySize: 512
package:
patterns:
- 'src/modules/prepopulate/**'
- ${file(./serverless/patterns/base.yml):pattern1}
- ${file(./serverless/patterns/base.yml):pattern2}
- ${file(./serverless/patterns/base.yml):pattern3}
- ${file(./serverless/patterns/base.yml):pattern4}
events:
- httpApi:
path: /host/Activity_Hub/OnBoarding/get-all-pqq-ques-submited-ans
method: get

View File

@@ -94,8 +94,9 @@ updateMinglarProfile:
path: /minglaradmin/update-profile
method: patch
prepopulateTeammate:
handler: src/modules/minglaradmin/handlers/prepopulateTeammate.handler
prepopulateRole:
handler: src/modules/minglaradmin/handlers/prepopulateRole.handler
memorySize: 384
package:
patterns:
@@ -140,6 +141,22 @@ getAllHostApplication:
path: /minglaradmin/hosthub/hosts/get-all-host-applications-am
method: get
getAllHostActivityForAdmin:
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/getAllActivityOfHost.handler
memorySize: 384
package:
patterns:
- 'src/modules/minglaradmin/handlers/hosthub/onboarding/getAllActivityOfHost.handler.*'
- 'src/modules/minglaradmin/services/**'
- ${file(./serverless/patterns/base.yml):pattern1}
- ${file(./serverless/patterns/base.yml):pattern2}
- ${file(./serverless/patterns/base.yml):pattern3}
- ${file(./serverless/patterns/base.yml):pattern4}
events:
- httpApi:
path: /minglaradmin/get-all-activity-of-host/{id}
method: get
getAllOnboardingHostApplications:
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/getAllOnboardingHosts.handler
memorySize: 512
@@ -233,6 +250,21 @@ getAllInvitedCoadminAndAMDetails:
path: /minglaradmin/settings/teammates/get-all-invited-coadmin-am
method: get
getAmDetailsbyId:
handler: src/modules/minglaradmin/handlers/getAmDetail_ById.handler
memorySize: 384
package:
patterns:
- 'src/modules/minglaradmin/handlers/settings/**'
- ${file(./serverless/patterns/base.yml):pattern1}
- ${file(./serverless/patterns/base.yml):pattern2}
- ${file(./serverless/patterns/base.yml):pattern3}
- ${file(./serverless/patterns/base.yml):pattern4}
events:
- httpApi:
path: /minglaradmin/settings/teammates/get-am-details-by-id/{amXid}
method: get
assignAMToHost:
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/assignAM.handler
memorySize: 384

View File

@@ -0,0 +1,51 @@
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
import { PrismaService } from '../../../../../common/database/prisma.service';
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
import ApiError from '../../../../../common/utils/helper/ApiError';
import { HostService } from '../../../services/host.service';
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
const prismaService = new PrismaService();
const hostService = new HostService(prismaService);
const prePopulateService = new PrePopulateService(prismaService);
/**
* Add suggestion handler for host applications
* Allows Minglar Admin, Co_Admin, and Account Manager to add suggestions
* Types: Setup Profile, Review Account, Add Payment Details, Agreement
*/
export const handler = safeHandler(async (
event: APIGatewayProxyEvent,
context?: Context
): Promise<APIGatewayProxyResult> => {
// Verify authentication token
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
if (!token) {
throw new ApiError(401, 'This is a protected route. Please provide a valid token.');
}
// Verify token and get user info
const userInfo = await verifyHostToken(token);
// Read optional search query (supports ?search= or ?q=)
const search = event.queryStringParameters?.search || event.queryStringParameters?.q || undefined;
const data = await hostService.getAllActivityTypesWithInterest(search);
const frequencies = await prePopulateService.getAllFrequencies();
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Data retrieved successfully',
data,
frequencies
}),
};
});

View File

@@ -4,10 +4,13 @@ import { PrismaService } from '../../../../../common/database/prisma.service';
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
import ApiError from '../../../../../common/utils/helper/ApiError';
import { HostService } from '../../../services/host.service';
import { string } from 'zod';
const prismaService = new PrismaService();
const hostService = new HostService(prismaService);
/**
* Add suggestion handler for host applications
* Allows Minglar Admin, Co_Admin, and Account Manager to add suggestions
@@ -30,7 +33,8 @@ export const handler = safeHandler(async (
// Read optional search query (supports ?search= or ?q=)
const search = event.queryStringParameters?.search || event.queryStringParameters?.q || undefined;
const data = await hostService.getAllActivityTypesWithInterest(search);
const data = await hostService.getAllHostActivity(search ? String(search) : undefined, Number(userInfo.id));
return {
statusCode: 200,
@@ -42,6 +46,7 @@ export const handler = safeHandler(async (
success: true,
message: 'Data retrieved successfully',
data,
}),
};
});

View File

@@ -0,0 +1,41 @@
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
import { PrismaService } from '../../../../../common/database/prisma.service';
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
import ApiError from '../../../../../common/utils/helper/ApiError';
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
import { HostService } from '../../../services/host.service';
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
const prismaService = new PrismaService();
const hostService = new HostService(prismaService);
export const handler = safeHandler(async (
event: APIGatewayProxyEvent,
context?: Context
): Promise<APIGatewayProxyResult> => {
// Extract token from headers
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token']
if (!token) {
throw new ApiError(400, 'This is a protected route. Please provide a valid token.');
}
// Authenticate user using the shared authForHost function
await verifyMinglarAdminHostToken(token);
const result = await hostService.getAllPQQQuesAndSubmittedAns();
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Data retrieved successfully',
data: result,
}),
};
});

View File

@@ -1,15 +1,30 @@
// src/modules/host/services/host.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../../common/database/prisma.service';
import { AddPaymentDetailsDTO, CreateHostDto, UpdateHostDto } from '../dto/host.dto';
import {
AddPaymentDetailsDTO,
CreateHostDto,
UpdateHostDto,
} from '../dto/host.dto';
import * as bcrypt from 'bcryptjs';
import ApiError from '../../../common/utils/helper/ApiError';
import { User } from '@prisma/client';
import { z } from 'zod';
import { hostCompanyDetailsSchema } from '@/common/utils/validation/host/hostCompanyDetails.validation';
import { ACTIVITY_DISPLAY_STATUS, ACTIVITY_INTERNAL_STATUS, HOST_STATUS_DISPLAY, HOST_STATUS_INTERNAL, STEPPER } from '@/common/utils/constants/host.constant';
import { MINGLAR_STATUS_DISPLAY, MINGLAR_STATUS_INTERNAL } from '@/common/utils/constants/minglar.constant';
import { ROLE, ROLE_NAME, USER_STATUS } from '@/common/utils/constants/common.constant';
import {
ACTIVITY_DISPLAY_STATUS, ACTIVITY_INTERNAL_STATUS, HOST_STATUS_DISPLAY,
HOST_STATUS_INTERNAL,
STEPPER,
} from '@/common/utils/constants/host.constant';
import {
MINGLAR_STATUS_DISPLAY,
MINGLAR_STATUS_INTERNAL,
} from '@/common/utils/constants/minglar.constant';
import {
ROLE,
ROLE_NAME,
USER_STATUS,
} from '@/common/utils/constants/common.constant';
import { getPresignedUrl } from '@/common/middlewares/aws/getPreSignedUrl';
import config from '@/config/config';
@@ -24,7 +39,7 @@ interface HostDocumentInput {
@Injectable()
export class HostService {
constructor(private prisma: PrismaService) { }
constructor(private prisma: PrismaService) {}
async createHost(data: CreateHostDto) {
return this.prisma.user.create({ data });
@@ -59,7 +74,7 @@ export class HostService {
currencies: true,
states: true,
cities: true,
}
},
});
if (!host) {
@@ -76,8 +91,8 @@ export class HostService {
const filePath = doc.filePath;
// If full URL is saved, extract only key
const key = filePath.startsWith("http")
? filePath.split(".com/")[1]
const key = filePath.startsWith('http')
? filePath.split('.com/')[1]
: filePath;
(doc as any).presignedUrl = await getPresignedUrl(bucket, key);
@@ -162,7 +177,10 @@ export class HostService {
throw new ApiError(403, 'Access denied. Not a host user.');
}
const matchPassword = await bcrypt.compare(userPassword, existingUser.userPassword);
const matchPassword = await bcrypt.compare(
userPassword,
existingUser.userPassword,
);
if (!matchPassword) {
throw new ApiError(401, 'Invalid credentials');
}
@@ -190,7 +208,10 @@ export class HostService {
// Check if password already exists
if (user.userPassword) {
throw new ApiError(400, 'Password already exists. Use update password instead.');
throw new ApiError(
400,
'Password already exists. Use update password instead.',
);
}
// Hash the password
@@ -200,7 +221,11 @@ export class HostService {
// Update user with hashed password
await this.prisma.user.update({
where: { id: user.id },
data: { userPassword: hashedPassword, isEmailVerfied: true, userStatus: USER_STATUS.ACTIVE },
data: {
userPassword: hashedPassword,
isEmailVerfied: true,
userStatus: USER_STATUS.ACTIVE,
},
});
return true;
@@ -219,10 +244,24 @@ export class HostService {
await tx.hostHeader.update({
where: { id: data.hostXid },
data: {
stepper: STEPPER.BANK_DETAILS_UPDATED
}
})
})
stepper: STEPPER.BANK_DETAILS_UPDATED,
},
});
});
}
async getAllHostActivity(search?: string, hostXid?: number) {
return await this.prisma.activities.findMany({
where: {
isActive: true,
hostXid: hostXid,
},
include: {
ActivitiesMedia: true,
ActivityAmDetails: true,
activityType: true,
},
});
}
async acceptMinglarAgreement(user_xid: number) {
@@ -231,27 +270,31 @@ export class HostService {
select: {
id: true,
userXid: true,
}
})
},
});
await this.prisma.hostHeader.update({
where: { id: hostDetails.id },
data: {
stepper: STEPPER.AGREEMENT_ACCEPTED,
agreementAccepted: true,
}
})
},
});
}
async getPQQQuestionDetail(question_xid: number, activity_xid: number) {
return await this.prisma.activityPQQheader.findFirst({
where: { activityXid: activity_xid, pqqQuestionXid: question_xid, isActive: true },
where: {
activityXid: activity_xid,
pqqQuestionXid: question_xid,
isActive: true,
},
select: {
pqqQuestionXid: true,
pqqAnswerXid: true,
ActivityPQQSupportings: true,
ActivityPQQSuggestions: true
}
})
ActivityPQQSuggestions: true,
},
});
}
async getLatestQuestionDetailsPQQ(activity_xid: number) {
@@ -265,14 +308,14 @@ export class HostService {
pqqSubCategoryXid: true,
pqqSubCategories: {
select: {
categoryXid: true
}
}
}
}
categoryXid: true,
},
},
},
},
},
orderBy: { id: 'desc' }
})
orderBy: { id: 'desc' },
});
}
async addOrUpdateCompanyDetails(
@@ -281,7 +324,7 @@ export class HostService {
documents: HostDocumentInput[],
parentCompanyData?: any | null,
parentDocuments?: HostDocumentInput[],
isDraft: boolean = false // Add isDraft parameter with default false
isDraft: boolean = false, // Add isDraft parameter with default false
) {
return await this.prisma.$transaction(async (tx) => {
// Check if host already has a company
@@ -314,7 +357,11 @@ export class HostService {
const existingByPan = await tx.hostHeader.findFirst({
where: { panNumber: companyData.panNumber },
});
if (existingByPan) throw new ApiError(400, 'Company already exists with this pan/bin number');
if (existingByPan)
throw new ApiError(
400,
'Company already exists with this pan/bin number',
);
}
const refNumber = await this.generateHostRefNumber(tx);
@@ -429,7 +476,7 @@ export class HostService {
hostStatusInternal: hostStatusInternal,
hostStatusDisplay: hostStatusDisplay,
adminStatusInternal: minglarStatusInternal,
adminStatusDisplay: minglarStatusDisplay
adminStatusDisplay: minglarStatusDisplay,
},
});
@@ -513,7 +560,9 @@ export class HostService {
});
// replace parent docs
await tx.hostParenetDocuments.deleteMany({ where: { hostParentXid: parentRecord.id } });
await tx.hostParenetDocuments.deleteMany({
where: { hostParentXid: parentRecord.id },
});
if (parentDocuments?.length) {
const parentDocsData = parentDocuments.map((doc) => ({
hostParentXid: parentRecord.id,
@@ -528,18 +577,22 @@ export class HostService {
// If previously had a parent and now isSubsidairy=false -> optionally delete parent and its docs
const previousParent = (existingHostCompany as any).hostParent;
let prevParentId = null;
if (Array.isArray(previousParent) && previousParent.length) prevParentId = previousParent[0].id;
else if (previousParent && previousParent.id) prevParentId = previousParent.id;
if (Array.isArray(previousParent) && previousParent.length)
prevParentId = previousParent[0].id;
else if (previousParent && previousParent.id)
prevParentId = previousParent.id;
if (prevParentId) {
await tx.hostParenetDocuments.deleteMany({ where: { hostParentXid: prevParentId } });
await tx.hostParenetDocuments.deleteMany({
where: { hostParentXid: prevParentId },
});
await tx.hostParent.delete({ where: { id: prevParentId } });
}
}
const hostDetails = await this.prisma.hostHeader.findFirst({
where: { userXid: user_xid },
})
});
await this.prisma.hostTrack.create({
data: {
@@ -547,8 +600,8 @@ export class HostService {
updatedByRole: ROLE_NAME.HOST,
updatedByXid: user_xid,
trackStatus: hostDetails.hostStatusInternal,
}
})
},
});
return updatedHost;
});
@@ -563,16 +616,16 @@ export class HostService {
id: true,
emailAddress: true,
firstName: true,
}
},
},
accountManager: {
select: {
id: true,
emailAddress: true,
firstName: true,
}
}
}
},
},
},
});
if (!hostDetails) {
@@ -580,7 +633,7 @@ export class HostService {
}
const hostSuggestionDetails = await this.prisma.hostSuggestion.findMany({
where: { hostXid: hostDetails.id, isActive: true, isreviewed: false }
where: { hostXid: hostDetails.id, isActive: true, isreviewed: false },
});
if (hostSuggestionDetails) {
@@ -590,15 +643,13 @@ export class HostService {
isreviewed: true,
reviewedByXid: hostDetails.id,
reviewOn: new Date(),
}
})
},
});
}
return { hostSuggestionDetails, hostDetails };
}
async generateHostRefNumber(tx: any) {
const lastHost = await tx.hostHeader.findFirst({
orderBy: {
@@ -606,7 +657,7 @@ export class HostService {
},
select: {
id: true,
}
},
});
const nextId = lastHost ? lastHost.id + 1 : 1;
@@ -668,7 +719,6 @@ export class HostService {
// });
// }
async calculatePqqScoreForUser(activityXid: number) {
// 1. Get all headers for this activity (user's answers)
const answers = await this.prisma.activityPQQheader.findMany({
@@ -678,19 +728,19 @@ export class HostService {
include: {
pqqSubCategories: {
include: {
category: true
}
}
}
category: true,
},
},
},
},
pqqAnswers: true
}
pqqAnswers: true,
},
});
if (!answers.length) {
return {
overallPercentage: 0,
categoryWise: {}
categoryWise: {},
};
}
@@ -699,12 +749,15 @@ export class HostService {
let totalMaxPoints = 0;
// For category-wise scoring
const categories: Record<number, {
categoryId: number;
categoryName: string;
userPoints: number;
maxPoints: number;
}> = {};
const categories: Record<
number,
{
categoryId: number;
categoryName: string;
userPoints: number;
maxPoints: number;
}
> = {};
for (const item of answers) {
const question = item.pqqQuestions;
@@ -778,104 +831,107 @@ export class HostService {
// Return final score object
return {
overallPercentage,
categoryWise
categoryWise,
};
}
async createHeader(
activityXid: number,
pqqQuestionXid: number,
pqqAnswerXid: number,
comments?: string | null
comments?: string | null,
) {
return await this.prisma.activityPQQheader.create({
data: {
activityXid,
pqqQuestionXid,
pqqAnswerXid,
comments: comments || null // Handle null comments
}
comments: comments || null, // Handle null comments
},
});
}
async findHeaderByCompositeKey(
activityXid: number,
pqqQuestionXid: number,
pqqAnswerXid: number
pqqAnswerXid: number,
) {
return await this.prisma.activityPQQheader.findFirst({
where: {
activityXid,
pqqQuestionXid,
pqqAnswerXid
}
pqqAnswerXid,
},
});
}
async updateHeader(
headerId: number,
comments?: string | null
) {
async updateHeader(headerId: number, comments?: string | null) {
return await this.prisma.activityPQQheader.update({
where: {
id: headerId
id: headerId,
},
data: {
comments: comments || null, // Handle null comments
updatedAt: new Date()
}
updatedAt: new Date(),
},
});
}
async addSupportingFile(
headerId: number,
mimeType: string,
fileUrl: string
) {
async addSupportingFile(headerId: number, mimeType: string, fileUrl: string) {
return await this.prisma.activityPQQSupportings.create({
data: {
activityPqqHeaderXid: headerId,
mediaType: mimeType,
mediaFileName: fileUrl
}
mediaFileName: fileUrl,
},
});
}
async getSupportingFilesByHeaderId(headerId: number) {
return await this.prisma.activityPQQSupportings.findMany({
where: {
activityPqqHeaderXid: headerId
activityPqqHeaderXid: headerId,
},
orderBy: {
id: 'asc' // Maintain consistent order
}
id: 'asc', // Maintain consistent order
},
});
}
async updateSupportingFile(
supportingFileId: number,
mimeType: string,
fileUrl: string
fileUrl: string,
) {
return await this.prisma.activityPQQSupportings.update({
where: {
id: supportingFileId
id: supportingFileId,
},
data: {
mediaType: mimeType,
mediaFileName: fileUrl,
updatedAt: new Date()
}
updatedAt: new Date(),
},
});
}
async deleteSupportingFile(supportingFileId: number) {
return await this.prisma.activityPQQSupportings.delete({
where: {
id: supportingFileId
}
id: supportingFileId,
},
});
}
async getAllPQQQuesAndSubmittedAns() {
return await this.prisma.activityPQQheader.findMany({
where: { isActive: true },
include: {
pqqQuestions: true,
ActivityPQQSuggestions: true,
pqqAnswers: true,
ActivityPQQSupportings: true,
},
});
}
@@ -917,20 +973,26 @@ export class HostService {
frequenciesXid?: number,
) {
// Find host header for this user
const host = await this.prisma.hostHeader.findFirst({ where: { userXid: userId, isActive: true } });
const host = await this.prisma.hostHeader.findFirst({
where: { userXid: userId, isActive: true },
});
if (!host) {
throw new ApiError(404, 'Host not found for the user');
}
// Validate activityType exists
const activityType = await this.prisma.activityTypes.findUnique({ where: { id: activityTypeXid } });
const activityType = await this.prisma.activityTypes.findUnique({
where: { id: activityTypeXid },
});
if (!activityType) {
throw new ApiError(404, 'Activity type not found');
}
// Optionally validate frequency
if (frequenciesXid) {
const freq = await this.prisma.frequencies.findUnique({ where: { id: frequenciesXid } });
const freq = await this.prisma.frequencies.findUnique({
where: { id: frequenciesXid },
});
if (!freq) throw new ApiError(404, 'Frequency not found');
}
@@ -945,5 +1007,4 @@ export class HostService {
return created;
}
}

View File

@@ -0,0 +1,66 @@
import {
APIGatewayProxyEvent,
APIGatewayProxyResult,
Context,
} from 'aws-lambda';
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
import { PrismaService } from '../../../common/database/prisma.service';
import { MinglarService } from '../services/minglar.service';
import ApiError from '../../../common/utils/helper/ApiError';
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
const prismaService = new PrismaService();
const minglarService = new MinglarService(prismaService);
/**
* Get all host applications handler
* Returns host details with status, submission date, and account manager info
*/
export const handler = safeHandler(
async (
event: APIGatewayProxyEvent,
context?: Context,
): Promise<APIGatewayProxyResult> => {
// Verify authentication token
const token =
event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
if (!token) {
throw new ApiError(
401,
'This is a protected route. Please provide a valid token.',
);
}
await verifyMinglarAdminToken(token);
const amXid = event.pathParameters?.amXid;
if (!amXid) {
throw new ApiError(
400,
'Account Manager XID is required in path parameters.',
);
}
const amId = Number(amXid);
if (Number.isNaN(amId)) {
throw new ApiError(400, 'Account Manager XID must be a valid number.');
}
// Get all host applications from service based on user role
const getAmDetailsByid = await minglarService.getAMdetailById( amId );
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Host applications retrieved successfully',
data: getAmDetailsByid,
}),
};
},
);

View File

@@ -0,0 +1,53 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
import { PrismaService } from '../../../../../common/database/prisma.service';
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
import ApiError from '../../../../../common/utils/helper/ApiError';
import { string } from 'zod';
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
import { MinglarService } from '../../../services/minglar.service';
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
const prismaService = new PrismaService();
const minglarService = new MinglarService(prismaService);
const prePopulateService = new PrePopulateService(prismaService);
/**
* Add suggestion handler for host applications
* Allows Minglar Admin, Co_Admin, and Account Manager to add suggestions
* Types: Setup Profile, Review Account, Add Payment Details, Agreement
*/
export const handler = safeHandler(async (
event: APIGatewayProxyEvent,
context?: Context
): Promise<APIGatewayProxyResult> => {
// Verify authentication token
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
if (!token) {
throw new ApiError(401, 'This is a protected route. Please provide a valid token.');
}
// Verify token and get user info
const userInfo = await verifyMinglarAdminHostToken(token);
const hostXid = Number(event.pathParameters?.id)
// Read optional search query (supports ?search= or ?q=)
const search = event.queryStringParameters?.search || event.queryStringParameters?.q || undefined;
const data = await minglarService.getAllHostActivityForMinglar(search ? String(search) : undefined, hostXid);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Data retrieved successfully',
data,
}),
};
});

View File

@@ -0,0 +1,56 @@
import {
APIGatewayProxyEvent,
APIGatewayProxyResult,
Context,
} from 'aws-lambda';
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
import { PrismaService } from '../../../common/database/prisma.service';
import ApiError from '../../../common/utils/helper/ApiError';
import { ROLE } from '../../../common/utils/constants/common.constant';
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
const prismaService = new PrismaService();
export const handler = safeHandler(
async (
event: APIGatewayProxyEvent,
context?: Context,
): Promise<APIGatewayProxyResult> => {
// Extract token from headers
const token =
event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
if (!token) {
throw new ApiError(
400,
'This is a protected route. Please provide a valid token.',
);
}
// Verify token and get user info
await verifyMinglarAdminToken(token);
const roles = await prismaService.roles.findMany({
where: {
id: {
in: [ROLE.CO_ADMIN, ROLE.ACCOUNT_MANAGER],
},
},
select: {
id: true,
roleName: true,
},
});
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Roles retrieved successfully',
data: roles,
}),
};
},
);

View File

@@ -1,4 +1,8 @@
import { ROLE, ROLE_NAME, USER_STATUS } from '@/common/utils/constants/common.constant';
import {
ROLE,
ROLE_NAME,
USER_STATUS,
} from '@/common/utils/constants/common.constant';
import {
HOST_STATUS_DISPLAY,
HOST_STATUS_INTERNAL,
@@ -19,7 +23,7 @@ import { sendAMEmailForHostAssign } from './AMEmail.service';
@Injectable()
export class MinglarService {
constructor(private prisma: PrismaService) { }
constructor(private prisma: PrismaService) {}
async createPassword(user_xid: number, password: string): Promise<boolean> {
// Find user by id
@@ -198,6 +202,20 @@ export class MinglarService {
});
}
async getAllHostActivityForMinglar(search?: string, hostXid?: number) {
return await this.prisma.activities.findMany({
where: {
isActive: true,
hostXid: hostXid,
},
include: {
ActivitiesMedia: true,
ActivityAmDetails: true,
activityType: true,
},
});
}
async createUserRevenue(
userXid: number,
isFixedSalary: boolean,
@@ -557,15 +575,15 @@ export class MinglarService {
userId: number,
userRoleXid: number,
search?: string,
userStatus?: string
userStatus?: string,
) {
const filters: any = {
isActive: true,
user: {
roleXid: {
notIn: [ROLE.CO_ADMIN, ROLE.ACCOUNT_MANAGER]
}
}
notIn: [ROLE.CO_ADMIN, ROLE.ACCOUNT_MANAGER],
},
},
};
/** -----------------------------------
@@ -582,10 +600,10 @@ export class MinglarService {
filters.user = {
...filters.user,
OR: [
{ emailAddress: { contains: term, mode: "insensitive" } },
{ firstName: { contains: term, mode: "insensitive" } },
{ lastName: { contains: term, mode: "insensitive" } }
]
{ emailAddress: { contains: term, mode: 'insensitive' } },
{ firstName: { contains: term, mode: 'insensitive' } },
{ lastName: { contains: term, mode: 'insensitive' } },
],
};
}
}
@@ -595,7 +613,8 @@ export class MinglarService {
* ----------------------------------- */
if (
userStatus &&
userStatus.trim().toLowerCase() === MINGLAR_STATUS_DISPLAY.NEW.toLowerCase()
userStatus.trim().toLowerCase() ===
MINGLAR_STATUS_DISPLAY.NEW.toLowerCase()
) {
filters.adminStatusInternal = MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW;
}
@@ -633,8 +652,8 @@ export class MinglarService {
firstName: true,
lastName: true,
emailAddress: true,
mobileNumber: true
}
mobileNumber: true,
},
},
accountManager: {
select: {
@@ -643,17 +662,17 @@ export class MinglarService {
lastName: true,
emailAddress: true,
mobileNumber: true,
roleXid: true
}
}
roleXid: true,
},
},
},
orderBy: { createdAt: "desc" }
orderBy: { createdAt: 'desc' },
});
/** -----------------------------------
* TRANSFORM RESPONSE
* ----------------------------------- */
return results.map(h => ({
return results.map((h) => ({
hostId: h.id,
host: h.user,
hostStatusDisplay: h.hostStatusDisplay,
@@ -666,7 +685,7 @@ export class MinglarService {
city: h.cities || null,
state: h.states || null,
country: h.countries || null,
assignedOn: h.assignedOn || null
assignedOn: h.assignedOn || null,
}));
}
@@ -674,7 +693,7 @@ export class MinglarService {
return await this.prisma.hostHeader.findMany({
where: {
isActive: true,
hostStatusInternal: { notIn: [HOST_STATUS_INTERNAL.DRAFT] }
hostStatusInternal: { notIn: [HOST_STATUS_INTERNAL.DRAFT] },
},
select: {
id: true,
@@ -689,24 +708,26 @@ export class MinglarService {
id: true,
firstName: true,
lastName: true,
}
},
},
accountManager: {
select: {
id: true,
firstName: true,
lastName: true,
profileImage: true
}
}
}
})
profileImage: true,
},
},
},
});
}
async getAllOnboardingHostApplications_New() {
return await this.prisma.hostHeader.findMany({
where: { isActive: true, adminStatusInternal: MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW },
where: {
isActive: true,
adminStatusInternal: MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW,
},
select: {
id: true,
hostRefNumber: true,
@@ -718,41 +739,40 @@ export class MinglarService {
cities: {
select: {
id: true,
cityName: true
}
cityName: true,
},
},
countries: {
select: {
id: true,
countryName: true,
}
},
},
states: {
select: {
id: true,
stateName: true
}
stateName: true,
},
},
user: {
select: {
id: true,
firstName: true,
lastName: true,
}
},
},
accountManager: {
select: {
id: true,
firstName: true,
lastName: true,
profileImage: true
}
}
}
})
profileImage: true,
},
},
},
});
}
async getAllCoadminAndAM() {
// 1. Fetch all required users (Admin, Co-Admin, AM)
const users = await this.prisma.user.findMany({
@@ -852,7 +872,7 @@ export class MinglarService {
if (
hostDetails.adminStatusInternal !==
MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED &&
MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED &&
hostDetails.adminStatusDisplay !== MINGLAR_STATUS_DISPLAY.AM_NOT_ASSIGNED
) {
throw new ApiError(400, 'Invalid host status');
@@ -933,13 +953,12 @@ export class MinglarService {
return true;
}
async addPqqSuggestion(
title: string,
comments: string,
activity_pqq_header_xid: number,
reviewedByXid:number
reviewedByXid: number,
) {
// Check if host exists
const ActivityHeader = await this.prisma.activityPQQheader.findUnique({
@@ -959,7 +978,7 @@ export class MinglarService {
reviewedOn: new Date(),
isActive: true,
activityPqqHeaderXid: activity_pqq_header_xid,
reviewedByXid:reviewedByXid ,
reviewedByXid: reviewedByXid,
},
});
@@ -1040,11 +1059,9 @@ export class MinglarService {
updatedByRole: ROLE_NAME.ACCOUNT_MANAGER,
updatedByXid: user_xid,
trackStatus: MINGLAR_STATUS_INTERNAL.AM_APPROVED,
}
})
})
},
});
});
}
async acceptHostApplicationMinglarAdmin(host_xid: number, user_xid: number) {
@@ -1072,9 +1089,9 @@ export class MinglarService {
updatedByRole: ROLE_NAME.MINGLAR_ADMIN,
updatedByXid: user_xid,
trackStatus: MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED,
}
})
})
},
});
});
}
async rejectHostApplication(host_xid: number, user_xid: number) {
@@ -1106,8 +1123,8 @@ export class MinglarService {
updatedByRole: ROLE_NAME.MINGLAR_ADMIN,
updatedByXid: user_xid,
trackStatus: MINGLAR_STATUS_INTERNAL.ADMIN_REJECTED,
}
})
},
});
await tx.user.update({
where: { id: hostDetails.userXid },
@@ -1147,8 +1164,19 @@ export class MinglarService {
updatedByRole: ROLE_NAME.ACCOUNT_MANAGER,
updatedByXid: user_xid,
trackStatus: MINGLAR_STATUS_INTERNAL.AM_REJECTED,
}
})
})
},
});
});
}
async getAMdetailById(id: number) {
return this.prisma.user.findUnique({
where: { id: id, isActive: true, userStatus: USER_STATUS.ACTIVE },
include: {
userAddressDetails: true,
userDocuments: true,
userRevenues: true,
},
});
}
}