diff --git a/serverless/functions/host.yml b/serverless/functions/host.yml index 4368ed7..fc3d776 100644 --- a/serverless/functions/host.yml +++ b/serverless/functions/host.yml @@ -282,7 +282,7 @@ submitCompanyDetails: submitPQQ_Answer: handler: src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQQ_Answer.handler - memorySize: 384 + memorySize: 1024 package: patterns: - 'src/modules/host/handlers/submitPqqAns.*' diff --git a/src/common/utils/pagination/pagination.service.ts b/src/common/utils/pagination/pagination.service.ts new file mode 100644 index 0000000..62b5d89 --- /dev/null +++ b/src/common/utils/pagination/pagination.service.ts @@ -0,0 +1,66 @@ +// common/utils/pagination/pagination.service.ts +import { PaginationOptions, PaginationParams, PaginatedResponse } from './pagination.types'; + +export class PaginationService { + private readonly DEFAULT_PAGE = 1; + private readonly DEFAULT_LIMIT = 10; + private readonly MAX_LIMIT = 100; + + /** + * Parse and validate pagination parameters + */ + parsePaginationParams(params: PaginationParams): PaginationOptions { + let page = Number(params.page) || this.DEFAULT_PAGE; + let limit = Number(params.limit) || this.DEFAULT_LIMIT; + + // Validate and constrain values + page = Math.max(1, page); + limit = Math.max(1, Math.min(limit, this.MAX_LIMIT)); + + const skip = (page - 1) * limit; + + return { + page, + limit, + skip, + }; + } + + /** + * Create paginated response + */ + createPaginatedResponse( + data: T[], + totalCount: number, + paginationOptions: PaginationOptions, + ): PaginatedResponse { + const { page, limit } = paginationOptions; + const totalPages = Math.ceil(totalCount / limit); + + return { + data, + pagination: { + currentPage: page, + pageSize: limit, + totalCount, + totalPages, + hasNext: page < totalPages, + hasPrevious: page > 1, + }, + }; + } + + /** + * Extract pagination params from API Gateway event + */ + getPaginationFromEvent(event: any): PaginationParams { + const queryParams = event.queryStringParameters || {}; + + return { + page: queryParams.page, + limit: queryParams.limit, + }; + } +} + +export const paginationService = new PaginationService(); \ No newline at end of file diff --git a/src/common/utils/pagination/pagination.types.ts b/src/common/utils/pagination/pagination.types.ts new file mode 100644 index 0000000..a42f2d8 --- /dev/null +++ b/src/common/utils/pagination/pagination.types.ts @@ -0,0 +1,23 @@ +// common/utils/pagination/pagination.types.ts +export interface PaginationOptions { + page: number; + limit: number; + skip: number; +} + +export interface PaginatedResponse { + data: T[]; + pagination: { + currentPage: number; + pageSize: number; + totalCount: number; + totalPages: number; + hasNext: boolean; + hasPrevious: boolean; + }; +} + +export interface PaginationParams { + page?: string | number; + limit?: string | number; +} \ No newline at end of file diff --git a/src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQQ_Answer.ts b/src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQQ_Answer.ts index 8658c92..2f0e927 100644 --- a/src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQQ_Answer.ts +++ b/src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQQ_Answer.ts @@ -38,16 +38,25 @@ async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string let s3Key: string; // If existing URL provided, use the same S3 key to replace the file + // if (existingUrl) { + // s3Key = getS3KeyFromUrl(existingUrl); + // // Delete existing file first + // await deleteFromS3(s3Key); + // } else { + // // Generate new unique key for new file + // const uniqueKey = `${crypto.randomUUID()}_${originalName}`; + // s3Key = `${prefix}/${uniqueKey}`; + // } if (existingUrl) { - s3Key = getS3KeyFromUrl(existingUrl); - // Delete existing file first - await deleteFromS3(s3Key); - } else { - // Generate new unique key for new file - const uniqueKey = `${crypto.randomUUID()}_${originalName}`; - s3Key = `${prefix}/${uniqueKey}`; + // Delete old file, but DO NOT reuse its name + const oldKey = getS3KeyFromUrl(existingUrl); + await deleteFromS3(oldKey); } + // Create new key always + const uniqueKey = `${crypto.randomUUID()}_${originalName}`; + s3Key = `${prefix}/${uniqueKey}`; + // Upload new file (replaces existing if same key) await s3.upload({ Bucket: config.aws.bucketName, diff --git a/src/modules/minglaradmin/handlers/hosthub/hosts/getAllHostApplication.ts b/src/modules/minglaradmin/handlers/hosthub/hosts/getAllHostApplication.ts index 2481032..6bf25d5 100644 --- a/src/modules/minglaradmin/handlers/hosthub/hosts/getAllHostApplication.ts +++ b/src/modules/minglaradmin/handlers/hosthub/hosts/getAllHostApplication.ts @@ -4,13 +4,13 @@ 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'; +import { paginationService } from '../../../../../common/utils/pagination/pagination.service'; 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 + * Get all host applications handler with pagination */ export const handler = safeHandler(async ( event: APIGatewayProxyEvent, @@ -35,13 +35,29 @@ export const handler = safeHandler(async ( throw new ApiError(404, 'User not found'); } - // Get search query from query parameters + // Get query parameters const search = event.queryStringParameters?.search || ''; - // Extract userStatus (e.g. 'new') from query parameters const userStatus = event.queryStringParameters?.userStatus || ''; + + // Parse pagination parameters + const paginationParams = paginationService.getPaginationFromEvent(event); + const paginationOptions = paginationService.parsePaginationParams(paginationParams); - // Get all host applications from service based on user role - const hostApplications = await minglarService.getAllHostApplications(user.id, Number(user.roleXid), search, userStatus); + // Get paginated host applications + const { data, totalCount } = await minglarService.getAllHostApplications( + user.id, + Number(user.roleXid), + search, + userStatus, + paginationOptions + ); + + // Create paginated response + const paginatedResponse = paginationService.createPaginatedResponse( + data, + totalCount, + paginationOptions + ); return { statusCode: 200, @@ -52,7 +68,7 @@ export const handler = safeHandler(async ( body: JSON.stringify({ success: true, message: 'Host applications retrieved successfully', - data: hostApplications, + ...paginatedResponse, }), }; -}); +}); \ No newline at end of file diff --git a/src/modules/minglaradmin/services/minglar.service.ts b/src/modules/minglaradmin/services/minglar.service.ts index b5593a9..db60eaf 100644 --- a/src/modules/minglaradmin/services/minglar.service.ts +++ b/src/modules/minglaradmin/services/minglar.service.ts @@ -26,6 +26,7 @@ import { CreateMinglarDto, UpdateMinglarDto } from '../dto/minglar.dto'; import { sendAMEmailForHostAssign } from './AMEmail.service'; import { getPresignedUrl } from '@/common/middlewares/aws/getPreSignedUrl'; import config from '@/config/config'; +import { PaginationOptions } from '@/common/utils/pagination/pagination.types'; @Injectable() export class MinglarService { @@ -636,11 +637,13 @@ export class MinglarService { }); } + // Update your MinglarService method async getAllHostApplications( userId: number, userRoleXid: number, search?: string, userStatus?: string, + paginationOptions?: PaginationOptions, ) { const filters: any = { isActive: true, @@ -693,7 +696,14 @@ export class MinglarService { } /** ----------------------------------- - * MAIN QUERY + * COUNT TOTAL RECORDS + * ----------------------------------- */ + const totalCount = await this.prisma.hostHeader.count({ + where: filters, + }); + + /** ----------------------------------- + * MAIN QUERY WITH PAGINATION * ----------------------------------- */ const results = await this.prisma.hostHeader.findMany({ where: filters, @@ -732,12 +742,14 @@ export class MinglarService { }, }, orderBy: { createdAt: 'desc' }, + skip: paginationOptions?.skip || 0, + take: paginationOptions?.limit || 10, }); /** ----------------------------------- * TRANSFORM RESPONSE * ----------------------------------- */ - return results.map((h) => ({ + const transformedData = results.map((h) => ({ hostId: h.id, host: h.user, hostStatusDisplay: h.hostStatusDisplay, @@ -752,6 +764,11 @@ export class MinglarService { country: h.countries || null, assignedOn: h.assignedOn || null, })); + + return { + data: transformedData, + totalCount, + }; } async getAllOnboardingHostApplications() {