From ad9e8e1a3fbfb5a004b6330070cae11e22c9ecff Mon Sep 17 00:00:00 2001 From: paritosh18 Date: Fri, 6 Mar 2026 15:49:25 +0530 Subject: [PATCH] Added remove api from interested --- serverless/functions/user.yml | 15 ++++ src/modules/host/services/host.service.ts | 16 +++-- .../activities/removeFromBucketInterested.ts | 71 +++++++++++++++++++ src/modules/user/services/user.service.ts | 65 +++++++++++++++++ 4 files changed, 161 insertions(+), 6 deletions(-) create mode 100644 src/modules/user/handlers/activities/removeFromBucketInterested.ts diff --git a/serverless/functions/user.yml b/serverless/functions/user.yml index eac6593..3989e57 100644 --- a/serverless/functions/user.yml +++ b/serverless/functions/user.yml @@ -361,4 +361,19 @@ addActivityToBucketInterested: events: - httpApi: path: /user/activities/add-to-bucket-interested + method: post + +removeActivityFromBucketInterested: + handler: src/modules/user/handlers/activities/removeFromBucketInterested.handler + memorySize: 384 + package: + patterns: + - 'src/modules/user/handlers/activities/**' + - ${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: /user/activities/remove-from-bucket-interested method: post \ No newline at end of file diff --git a/src/modules/host/services/host.service.ts b/src/modules/host/services/host.service.ts index 25ccfa0..d5224bd 100644 --- a/src/modules/host/services/host.service.ts +++ b/src/modules/host/services/host.service.ts @@ -177,8 +177,8 @@ function computeBasePriceAndTaxes( return { basePrice, taxDetails }; } -const normalize = (v?: string | null) => - v ? v.trim().toLowerCase() : null; +const normalize = (v?: string | null, maxLength: number = 50) => + v ? v.trim().toLowerCase().substring(0, maxLength) : null; async function renderAgreementPdf(vars: { effectiveDate: string; @@ -338,9 +338,11 @@ const findOrCreateState = async ( ) => { if (!stateName || !countryXid) return null; + const trimmedStateName = stateName.trim().substring(0, 50); + const state = await tx.states.findFirst({ where: { - stateName: { equals: stateName.trim(), mode: 'insensitive' }, + stateName: { equals: trimmedStateName, mode: 'insensitive' }, countryXid, isActive: true, }, @@ -350,7 +352,7 @@ const findOrCreateState = async ( const created = await tx.states.create({ data: { - stateName: stateName.trim(), + stateName: trimmedStateName, countryXid, }, }); @@ -365,9 +367,11 @@ const findOrCreateCity = async ( ) => { if (!cityName || !stateXid) return null; + const trimmedCityName = cityName.trim().substring(0, 50); + const city = await tx.cities.findFirst({ where: { - cityName: { equals: cityName.trim(), mode: 'insensitive' }, + cityName: { equals: trimmedCityName, mode: 'insensitive' }, stateXid, isActive: true, }, @@ -377,7 +381,7 @@ const findOrCreateCity = async ( const created = await tx.cities.create({ data: { - cityName: cityName.trim(), + cityName: trimmedCityName, stateXid, }, }); diff --git a/src/modules/user/handlers/activities/removeFromBucketInterested.ts b/src/modules/user/handlers/activities/removeFromBucketInterested.ts new file mode 100644 index 0000000..d3b050a --- /dev/null +++ b/src/modules/user/handlers/activities/removeFromBucketInterested.ts @@ -0,0 +1,71 @@ +import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; +import { prismaClient } from '../../../../common/database/prisma.lambda.service'; +import { verifyUserToken } from '../../../../common/middlewares/jwt/authForUser'; +import { safeHandler } from '../../../../common/utils/handlers/safeHandler'; +import ApiError from '../../../../common/utils/helper/ApiError'; +import { UserService } from '../../services/user.service'; + +const userService = new UserService(prismaClient); + +export const handler = safeHandler(async ( + event: APIGatewayProxyEvent, + context?: Context +): Promise => { + // 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 verifyUserToken + const userInfo = await verifyUserToken(token); + const userId = userInfo.id; + + if (Number.isNaN(userId)) { + throw new ApiError(400, 'User id must be a number'); + } + + const user = await userService.getUserById(userId); + if (!user) { + throw new ApiError(404, 'User not found'); + } + + // Parse request body + let body: { activityXid: number; isBucket: boolean; bucketTypeName: string; }; + + try { + body = event.body ? JSON.parse(event.body) : {}; + } catch (error) { + throw new ApiError(400, 'Invalid JSON in request body'); + } + + const { activityXid, isBucket, bucketTypeName } = body; + + // Validate required fields + if ( + typeof activityXid !== 'number' || + typeof isBucket !== 'boolean' || + !bucketTypeName + ) { + throw new ApiError(400, 'Required fields missing or invalid'); + } + + // Remove from bucket/interested + const counts = await userService.removeFromBucketInterested(userId, isBucket, bucketTypeName, activityXid); + + return { + statusCode: 200, + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }, + body: JSON.stringify({ + success: true, + message: `Activity removed from ${isBucket ? 'bucket' : 'interested'} successfully`, + data: { + bucketCount: counts.bucketCount, + interestedCount: counts.interestedCount, + } + }), + }; +}); diff --git a/src/modules/user/services/user.service.ts b/src/modules/user/services/user.service.ts index 32af889..143c422 100644 --- a/src/modules/user/services/user.service.ts +++ b/src/modules/user/services/user.service.ts @@ -2629,6 +2629,19 @@ export class UserService { select: { id: true, schoolCompanyName: true, + cities: { + select: { + id: true, + cityName: true, + states: { + select: { + id: true, + stateName: true + } + } + } + }, + isSchool: true, isActive: true, createdAt: true, @@ -3814,4 +3827,56 @@ export class UserService { }; } + async removeFromBucketInterested( + userXid: number, + isBucket: boolean, + bucketTypeName: string, + activityXid: number + ) { + const activityExists = await this.prisma.activities.findFirst({ + where: { id: activityXid, isActive: true }, + }); + + if (!activityExists) { + throw new ApiError(404, 'Activity not found'); + } + + const existing = await this.prisma.userBucketInterested.findFirst({ + where: { userXid, activityXid, isActive: true }, + }); + + if (!existing) { + throw new ApiError(400, 'Activity not found in bucket/interested list'); + } + + await this.prisma.userBucketInterested.update({ + where: { id: existing.id }, + data: { + isActive: false, + }, + }); + + // Get updated counts + const [bucketCount, interestedCount] = await Promise.all([ + this.prisma.userBucketInterested.count({ + where: { + userXid, + isBucket: true, + isActive: true, + }, + }), + this.prisma.userBucketInterested.count({ + where: { + userXid, + isBucket: false, + isActive: true, + }, + }), + ]); + + return { + bucketCount, + interestedCount, + }; + } } \ No newline at end of file