1 Commits

3 changed files with 266 additions and 1 deletions

View File

@@ -406,4 +406,19 @@ getAllBucketActivities:
events:
- httpApi:
path: /activities/get-all-bucket-activities
method: get
method: get
getUserItineraryDetails:
handler: src/modules/user/handlers/itinerary/getUserItineraryDetails.handler
memorySize: 512
package:
patterns:
- 'src/modules/user/**'
- ${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: /itinerary/get-user-itinerary-details
method: get

View File

@@ -0,0 +1,43 @@
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 { ItineraryService } from '../../services/itinerary.service';
const itineraryService = new ItineraryService(prismaClient);
export const handler = safeHandler(async (
event: APIGatewayProxyEvent,
context?: Context,
): Promise<APIGatewayProxyResult> => {
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.',
);
}
const userInfo = await verifyUserToken(token);
const userId = Number(userInfo.id);
if (!userId || isNaN(userId)) {
throw new ApiError(400, 'Invalid user ID');
}
const result = await itineraryService.getUserItineraryDetails(userId);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Itinerary details retrieved successfully',
data: result,
}),
};
});

View File

@@ -0,0 +1,207 @@
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { getPresignedUrl } from '../../../common/middlewares/aws/getPreSignedUrl';
import {
ACTIVITY_AM_INTERNAL_STATUS,
ACTIVITY_INTERNAL_STATUS,
} from '../../../common/utils/constants/host.constant';
import config from '@/config/config';
const bucket = config.aws.bucketName;
const attachPresignedUrl = async (file: string | null | undefined) => {
if (!file) return null;
const key = file.startsWith('http')
? new URL(file).pathname.replace(/^\/+/, '')
: file;
return getPresignedUrl(bucket, key);
};
const attachMediaWithPresignedUrl = async (
mediaArr: Array<{
id: number;
mediaType: string;
mediaFileName: string;
isCoverImage: boolean;
displayOrder: number;
}> = [],
) => {
return Promise.all(
mediaArr.map(async (media) => ({
id: media.id,
mediaType: media.mediaType,
mediaFileName: media.mediaFileName,
isCoverImage: media.isCoverImage,
displayOrder: media.displayOrder,
presignedUrl: await attachPresignedUrl(media.mediaFileName),
})),
);
};
@Injectable()
export class ItineraryService {
constructor(private prisma: PrismaClient) {}
async getUserItineraryDetails(userXid: number) {
const [userLocation, activityEntries, travellerType] = await Promise.all([
this.prisma.userAddressDetails.findFirst({
where: {
userXid,
isActive: true,
deletedAt: null,
},
orderBy: {
createdAt: 'desc',
},
select: {
id: true,
address1: true,
address2: true,
pinCode: true,
locationName: true,
locationAddress: true,
locationLat: true,
locationLong: true,
countryXid: true,
stateXid: true,
cityXid: true,
country: {
select: {
id: true,
countryName: true,
countryCode: true,
},
},
states: {
select: {
id: true,
stateName: true,
},
},
cities: {
select: {
id: true,
cityName: true,
},
},
},
}),
this.prisma.userBucketInterested.findMany({
where: {
userXid,
isActive: true,
deletedAt: null,
Activities: {
isActive: true,
deletedAt: null,
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
},
},
orderBy: {
createdAt: 'desc',
},
select: {
id: true,
isBucket: true,
bucketTypeName: true,
activityStatus: true,
createdAt: true,
activityXid: true,
Activities: {
select: {
id: true,
activityTitle: true,
activityDescription: true,
activityDurationMins: true,
checkInAddress: true,
checkInLat: true,
checkInLong: true,
ActivitiesMedia: {
where: {
isActive: true,
deletedAt: null,
},
orderBy: {
displayOrder: 'asc',
},
select: {
id: true,
mediaType: true,
mediaFileName: true,
isCoverImage: true,
displayOrder: true,
},
},
},
},
},
}),
this.prisma.allowedEntryTypes.findMany({
where: {
isActive: true,
deletedAt: null,
},
select: {
id: true,
allowedEntryTypeName: true,
},
orderBy: {
id: 'asc',
},
}),
]);
const formattedActivities = await Promise.all(
activityEntries.map(async (entry) => {
const coverImage =
entry.Activities?.ActivitiesMedia.find((media) => media.isCoverImage) ??
entry.Activities?.ActivitiesMedia[0] ??
null;
return {
id: entry.id,
activityXid: entry.activityXid,
isBucket: entry.isBucket,
bucketTypeName: entry.bucketTypeName,
activityStatus: entry.activityStatus,
addedOn: entry.createdAt,
activityDetails: {
id: entry.Activities?.id ?? null,
activityTitle: entry.Activities?.activityTitle ?? null,
activityDescription: entry.Activities?.activityDescription ?? null,
activityDurationMins: entry.Activities?.activityDurationMins ?? null,
checkInAddress: entry.Activities?.checkInAddress ?? null,
checkInLat: entry.Activities?.checkInLat ?? null,
checkInLong: entry.Activities?.checkInLong ?? null,
coverImage: coverImage?.mediaFileName ?? null,
coverImagePresignedUrl: await attachPresignedUrl(
coverImage?.mediaFileName,
),
media: await attachMediaWithPresignedUrl(
entry.Activities?.ActivitiesMedia ?? [],
),
},
};
}),
);
const latestAddedActivity = formattedActivities[0] ?? null;
return {
userLocation,
travellerType,
bucketCount: formattedActivities.filter((item) => item.isBucket).length,
interestedCount: formattedActivities.filter((item) => !item.isBucket).length,
latestAddedActivityCoverImage:
latestAddedActivity?.activityDetails.coverImage ?? null,
latestAddedActivityCoverImagePresignedUrl:
latestAddedActivity?.activityDetails.coverImagePresignedUrl ?? null,
bucketActivities: formattedActivities.filter((item) => item.isBucket),
interestedActivities: formattedActivities.filter((item) => !item.isBucket),
};
}
}