diff --git a/src/modules/host/services/sendOTPEmail.service.ts b/src/modules/host/services/sendOTPEmail.service.ts index 9d2dc36..ccd71f6 100644 --- a/src/modules/host/services/sendOTPEmail.service.ts +++ b/src/modules/host/services/sendOTPEmail.service.ts @@ -51,18 +51,18 @@ export async function sendWelcomeEmailToHost( const subject = "Get Started as a Minglar Host"; const htmlContent = ` -

Hi ${emailAddress}



-

We’re excited to have you join Minglar as a host. Welcome aboard! 🌟



-

To get started and bring your activities live, here’s what comes next:



+

Hi ${emailAddress}


+

We’re excited to have you join Minglar as a host. Welcome aboard! 🌟


+

To get started and bring your activities live, here’s what comes next:


Your next steps:


1. Complete your host profile


2. Complete the pre-qualification process for all your activities


3. Submit your activity details for review


-

4. Go live and start receiving bookings



+

4. Go live and start receiving bookings


👉 Access your Host Portal:


-

${config.HOST_LINK}




-

If you need any support along the way, our team is always here to help. You can reach us anytime at info@minglargroup.com.



-

We’re looking forward to seeing your experiences come to life on Minglar.



+

${config.HOST_LINK}



+

If you need any support along the way, our team is always here to help. You can reach us anytime at info@minglargroup.com.


+

We’re looking forward to seeing your experiences come to life on Minglar.


Warm regards,
Team Minglar

`; diff --git a/src/modules/user/handlers/itinerary/saveUserItinerary.ts b/src/modules/user/handlers/itinerary/saveUserItinerary.ts index 92a20ec..30b0e78 100644 --- a/src/modules/user/handlers/itinerary/saveUserItinerary.ts +++ b/src/modules/user/handlers/itinerary/saveUserItinerary.ts @@ -44,6 +44,35 @@ export const handler = safeHandler(async ( ); } + if ( + body.startLocationAddress === undefined || + body.startLocationAddress === null || + body.startLocationLat === undefined || + body.startLocationLat === null || + body.startLocationLong === undefined || + body.startLocationLong === null || + body.endLocationAddress === undefined || + body.endLocationAddress === null || + body.endLocationLat === undefined || + body.endLocationLat === null || + body.endLocationLong === undefined || + body.endLocationLong === null + ) { + throw new ApiError( + 400, + 'startLocationAddress, startLocationLat, startLocationLong, endLocationAddress, endLocationLat and endLocationLong are required.', + ); + } + + if ( + (typeof body.startLocationAddress === 'string' && + !body.startLocationAddress.trim()) || + (typeof body.endLocationAddress === 'string' && + !body.endLocationAddress.trim()) + ) { + throw new ApiError(400, 'Location addresses cannot be empty.'); + } + if (!activities.length) { throw new ApiError(400, 'At least one activity is required.'); } @@ -107,6 +136,24 @@ export const handler = safeHandler(async ( endDate: body.endDate, startTime: body.startTime, endTime: body.endTime, + startLocationAddress: body.startLocationAddress, + startLocationLat: + body.startLocationLat !== null && body.startLocationLat !== undefined + ? Number(body.startLocationLat) + : undefined, + startLocationLong: + body.startLocationLong !== null && body.startLocationLong !== undefined + ? Number(body.startLocationLong) + : undefined, + endLocationAddress: body.endLocationAddress, + endLocationLat: + body.endLocationLat !== null && body.endLocationLat !== undefined + ? Number(body.endLocationLat) + : undefined, + endLocationLong: + body.endLocationLong !== null && body.endLocationLong !== undefined + ? Number(body.endLocationLong) + : undefined, activities: activities.map((activity: any) => { const itineraryType = typeof activity.itineraryType === 'string' @@ -188,6 +235,10 @@ export const handler = safeHandler(async ( Number.isNaN(activity.locationLat)) || (activity.locationLong !== undefined && Number.isNaN(activity.locationLong)), + Number.isNaN(payload.startLocationLat) || + Number.isNaN(payload.startLocationLong) || + Number.isNaN(payload.endLocationLat) || + Number.isNaN(payload.endLocationLong), ) ) { throw new ApiError(400, 'One or more numeric itinerary values are invalid.'); diff --git a/src/modules/user/services/itinerary.service.ts b/src/modules/user/services/itinerary.service.ts index 4e48997..94695e0 100644 --- a/src/modules/user/services/itinerary.service.ts +++ b/src/modules/user/services/itinerary.service.ts @@ -459,6 +459,12 @@ export class ItineraryService { endDate: string; startTime: string; endTime: string; + startLocationAddress: unknown; + startLocationLat: number; + startLocationLong: number; + endLocationAddress: unknown; + endLocationLat: number; + endLocationLong: number; activities: Array<{ activityXid?: number; venueXid?: number; @@ -540,6 +546,41 @@ export class ItineraryService { }, }); + const startLocationDetails = await tx.itineraryStartStopDetails.create({ + data: { + itineraryHeaderXid: itineraryHeader.id, + itineraryMemberXid: ownerMember.id, + dateValue: itineraryStartDate, + timeValue: payload.startTime, + isStartPoint: true, + locationLat: payload.startLocationLat, + locationLong: payload.startLocationLong, + locationAddress: + payload.startLocationAddress as Prisma.InputJsonValue, + travelMode: null, + kmForNextPoint: null, + timeForNextPointMins: null, + isActive: true, + }, + }); + + const endLocationDetails = await tx.itineraryStartStopDetails.create({ + data: { + itineraryHeaderXid: itineraryHeader.id, + itineraryMemberXid: ownerMember.id, + dateValue: itineraryEndDate, + timeValue: payload.endTime, + isStartPoint: false, + locationLat: payload.endLocationLat, + locationLong: payload.endLocationLong, + locationAddress: payload.endLocationAddress as Prisma.InputJsonValue, + travelMode: null, + kmForNextPoint: null, + timeForNextPointMins: null, + isActive: true, + }, + }); + const createdActivities = await Promise.all( payload.activities.map(async (activityItem) => { const itineraryType = @@ -961,6 +1002,8 @@ export class ItineraryService { memberStatus: ownerMember.memberStatus, }, ], + startLocationDetails, + endLocationDetails, activities: createdActivities, }; }); @@ -1034,6 +1077,29 @@ export class ItineraryService { }, }, }, + ItineraryStartStopDetails: { + where: { + isActive: true, + deletedAt: null, + }, + orderBy: { + createdAt: 'asc', + }, + select: { + id: true, + itineraryMemberXid: true, + dateValue: true, + timeValue: true, + isStartPoint: true, + locationLat: true, + locationLong: true, + locationAddress: true, + travelMode: true, + kmForNextPoint: true, + timeForNextPointMins: true, + createdAt: true, + }, + }, ItineraryActivities: { where: { isActive: true, @@ -1482,6 +1548,23 @@ export class ItineraryService { }), ); + const startStopDetails = itinerary.ItineraryStartStopDetails.map( + (detail) => ({ + id: detail.id, + itineraryMemberXid: detail.itineraryMemberXid, + dateValue: detail.dateValue, + timeValue: detail.timeValue, + isStartPoint: detail.isStartPoint, + locationLat: detail.locationLat, + locationLong: detail.locationLong, + locationAddress: detail.locationAddress, + travelMode: detail.travelMode, + kmForNextPoint: detail.kmForNextPoint, + timeForNextPointMins: detail.timeForNextPointMins, + createdAt: detail.createdAt, + }), + ); + return { itineraryHeaderXid: itinerary.id, itineraryNo: itinerary.itineraryNo, @@ -1506,6 +1589,7 @@ export class ItineraryService { membersCount: members.length, activitiesCount: activities.length, members, + startStopDetails, activities, }; }),