feat: add checkAvailabilityDetails API endpoint and implement schedule details retrieval logic
This commit is contained in:
113
src/modules/user/handlers/activities/checkAvailabilityDetails.ts
Normal file
113
src/modules/user/handlers/activities/checkAvailabilityDetails.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
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 { SchedulingService } from '../../../host/services/activityScheduling.service';
|
||||
import { UserService } from '../../services/user.service';
|
||||
|
||||
const userService = new UserService(prismaClient);
|
||||
const schedulingService = new SchedulingService(prismaClient);
|
||||
|
||||
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
|
||||
const userInfo = await verifyUserToken(token);
|
||||
const userId = Number(userInfo.id);
|
||||
|
||||
if (!userId || isNaN(userId)) {
|
||||
throw new ApiError(400, 'Invalid user ID');
|
||||
}
|
||||
|
||||
const activityXid = Number(event.pathParameters?.activity_xid);
|
||||
|
||||
if (!activityXid || isNaN(activityXid)) {
|
||||
throw new ApiError(400, 'Valid activityXid is required');
|
||||
}
|
||||
|
||||
// selected date may be passed as query param `selectedDate`
|
||||
const selectedDate =
|
||||
event.queryStringParameters?.selectedDate ||
|
||||
event.queryStringParameters?.date ||
|
||||
(event.body ? JSON.parse(event.body).selectedDate : undefined);
|
||||
|
||||
if (!selectedDate) {
|
||||
throw new ApiError(400, 'selectedDate query parameter is required');
|
||||
}
|
||||
|
||||
// Fetch activity details (basic) and schedule details for the selected date
|
||||
const activityDetails = await userService.getActivityDetailsById(userId, activityXid);
|
||||
const scheduleDetails = await schedulingService.getScheduleDetailsForDate(activityXid, selectedDate);
|
||||
// Shape response to match UI: only include fields shown in image
|
||||
const activity = activityDetails.activity;
|
||||
|
||||
// Rooms: combine ActivityVenues with schedule info per venue
|
||||
const rooms = (activity.ActivityVenues || []).map((v: any) => {
|
||||
// find schedule header for this venue
|
||||
const header = scheduleDetails.find((h: any) => h.activityVenue?.venueXid === v.id);
|
||||
const slotCount = header ? (header.slots || []).length : 0;
|
||||
|
||||
return {
|
||||
venueXid: v.id,
|
||||
venueName: v.venueName,
|
||||
venueLabel: v.venueLabel,
|
||||
venueCapacity: v.venueCapacity,
|
||||
availableSeats: v.availableSeats ?? null,
|
||||
price: v.ActivityPrices?.[0]?.sellPrice ?? null,
|
||||
slotsCount: slotCount,
|
||||
};
|
||||
});
|
||||
|
||||
// Slots: aggregate slots across scheduleDetails
|
||||
const slots: any[] = [];
|
||||
for (const h of scheduleDetails) {
|
||||
for (const s of h.slots || []) {
|
||||
// status heuristic based on maxCapacity
|
||||
let status = 'Available';
|
||||
if (s.maxCapacity === 0) status = 'Housefull';
|
||||
else if (s.maxCapacity <= 2) status = '2 Slots Left';
|
||||
else if (s.maxCapacity <= 5) status = 'Fast Filling';
|
||||
|
||||
slots.push({
|
||||
slotId: s.slotId,
|
||||
startTime: s.startTime,
|
||||
endTime: s.endTime,
|
||||
status,
|
||||
maxCapacity: s.maxCapacity,
|
||||
venueXid: h.activityVenue?.venueXid,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// derive check-in/out from slot times (earliest start, latest end)
|
||||
const startTimes = slots.map(s => s.startTime).filter(Boolean);
|
||||
const endTimes = slots.map(s => s.endTime).filter(Boolean);
|
||||
const checkInTime = startTimes.length ? startTimes.sort()[0] : null;
|
||||
const checkOutTime = endTimes.length ? endTimes.sort().reverse()[0] : null;
|
||||
|
||||
const responsePayload = {
|
||||
selectedDate,
|
||||
rooms,
|
||||
slots,
|
||||
checkInTime,
|
||||
checkOutTime,
|
||||
};
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({ success: true, data: responsePayload }),
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user