Compare commits
4 Commits
testingonl
...
split-sche
| Author | SHA1 | Date | |
|---|---|---|---|
| 50f93bbeae | |||
| 3ce9d1d180 | |||
| cb819088a0 | |||
| 8f5f01c287 |
@@ -1,5 +1,5 @@
|
|||||||
# Legacy monolith config. For new deployments use serverless.*.yml files.
|
# Legacy monolith config. For new deployments use serverless.*.yml files.
|
||||||
service: minglarDev
|
service: minglar
|
||||||
|
|
||||||
|
|
||||||
useDotenv: true
|
useDotenv: true
|
||||||
|
|||||||
@@ -13,6 +13,40 @@ const hostService = new HostService(prismaClient);
|
|||||||
|
|
||||||
const s3 = new AWS.S3({ region: config.aws.region });
|
const s3 = new AWS.S3({ region: config.aws.region });
|
||||||
|
|
||||||
|
function parseMultipartFieldValue(val: string) {
|
||||||
|
if (val === '' || val === 'null' || val === 'undefined') return null;
|
||||||
|
|
||||||
|
const cleaned = val.trim();
|
||||||
|
const looksLikeJson =
|
||||||
|
(cleaned.startsWith('{') && cleaned.endsWith('}')) ||
|
||||||
|
(cleaned.startsWith('[') && cleaned.endsWith(']')) ||
|
||||||
|
(cleaned.startsWith('"') && cleaned.endsWith('"'));
|
||||||
|
|
||||||
|
if (!looksLikeJson) return val;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(cleaned);
|
||||||
|
} catch {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeComments(comments: unknown): string | null {
|
||||||
|
if (comments === null || comments === undefined || comments === '') return null;
|
||||||
|
|
||||||
|
const value = String(comments).trim();
|
||||||
|
if (!value) return null;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(value.startsWith('"') && value.endsWith('"')) ||
|
||||||
|
(value.startsWith("'") && value.endsWith("'"))
|
||||||
|
) {
|
||||||
|
return value.slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// Function to extract S3 key from URL
|
// Function to extract S3 key from URL
|
||||||
function getS3KeyFromUrl(url: string): string {
|
function getS3KeyFromUrl(url: string): string {
|
||||||
const bucketBaseUrl = `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/`;
|
const bucketBaseUrl = `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/`;
|
||||||
@@ -122,22 +156,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
|
|
||||||
bb.on("field", (fieldname, val) => {
|
bb.on("field", (fieldname, val) => {
|
||||||
console.log(`FIELD RAW: ${fieldname} =`, val);
|
console.log(`FIELD RAW: ${fieldname} =`, val);
|
||||||
if (val === '' || val === 'null' || val === 'undefined') fields[fieldname] = null;
|
fields[fieldname] = parseMultipartFieldValue(val);
|
||||||
else {
|
|
||||||
try {
|
|
||||||
const cleaned = val.trim();
|
|
||||||
|
|
||||||
// If it starts and ends with quotes, remove them
|
|
||||||
const withoutQuotes =
|
|
||||||
(cleaned.startsWith('"') && cleaned.endsWith('"'))
|
|
||||||
? cleaned.slice(1, -1)
|
|
||||||
: cleaned;
|
|
||||||
|
|
||||||
fields[fieldname] = JSON.parse(withoutQuotes);
|
|
||||||
} catch {
|
|
||||||
fields[fieldname] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
bb.on("close", () => resolve());
|
bb.on("close", () => resolve());
|
||||||
@@ -154,7 +173,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
const activityXid = Number(fields.activityXid);
|
const activityXid = Number(fields.activityXid);
|
||||||
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
||||||
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
||||||
const comments = fields.comments || null;
|
const comments = normalizeComments(fields.comments);
|
||||||
|
|
||||||
if (!activityXid || isNaN(activityXid)) throw new ApiError(400, "Please provide a valid activity");
|
if (!activityXid || isNaN(activityXid)) throw new ApiError(400, "Please provide a valid activity");
|
||||||
if (!pqqQuestionXid || isNaN(pqqQuestionXid)) throw new ApiError(400, "Please select a valid question");
|
if (!pqqQuestionXid || isNaN(pqqQuestionXid)) throw new ApiError(400, "Please select a valid question");
|
||||||
|
|||||||
@@ -142,6 +142,10 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
|
|
||||||
const deletedFiles = normalizeJsonField(fields, "deletedFiles") || [];
|
const deletedFiles = normalizeJsonField(fields, "deletedFiles") || [];
|
||||||
const parentDeletedFiles = normalizeJsonField(fields, "parentDeletedFiles") || [];
|
const parentDeletedFiles = normalizeJsonField(fields, "parentDeletedFiles") || [];
|
||||||
|
const deleteCompanyLogo =
|
||||||
|
fields.deleteCompanyLogo === 'true' || fields.deleteCompanyLogo === true;
|
||||||
|
const deleteParentCompanyLogo =
|
||||||
|
fields.deleteParentCompanyLogo === 'true' || fields.deleteParentCompanyLogo === true;
|
||||||
|
|
||||||
/** 4) Extract and clean isDraft flag */
|
/** 4) Extract and clean isDraft flag */
|
||||||
const isDraft = fields.isDraft === 'true' || fields.isDraft === true;
|
const isDraft = fields.isDraft === 'true' || fields.isDraft === true;
|
||||||
@@ -379,6 +383,63 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DELETE EXISTING LOGO IF REQUESTED */
|
||||||
|
if (deleteCompanyLogo) {
|
||||||
|
const existingHost = await prismaClient.hostHeader.findFirst({
|
||||||
|
where: { userXid: userInfo.id },
|
||||||
|
select: { logoPath: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingHost?.logoPath) {
|
||||||
|
try {
|
||||||
|
const s3Key = getS3KeyFromUrl(existingHost.logoPath);
|
||||||
|
await deleteFromS3(s3Key);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('S3 delete failed for company logo:', existingHost.logoPath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedCompany.logoPath = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DELETE EXISTING PARENT COMPANY LOGO IF REQUESTED */
|
||||||
|
if (deleteParentCompanyLogo && parsedCompany.isSubsidairy) {
|
||||||
|
const existingHost = await prismaClient.hostHeader.findFirst({
|
||||||
|
where: { userXid: userInfo.id },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
hostParent: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
logoPath: true,
|
||||||
|
},
|
||||||
|
take: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const existingParent = Array.isArray(existingHost?.hostParent)
|
||||||
|
? existingHost.hostParent[0]
|
||||||
|
: existingHost?.hostParent;
|
||||||
|
|
||||||
|
if (existingParent?.logoPath) {
|
||||||
|
try {
|
||||||
|
const s3Key = getS3KeyFromUrl(existingParent.logoPath);
|
||||||
|
await deleteFromS3(s3Key);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('S3 delete failed for parent company logo:', existingParent.logoPath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedParentCompany) {
|
||||||
|
parsedParentCompany.logoPath = null;
|
||||||
|
} else {
|
||||||
|
parsedParentCompany = {
|
||||||
|
logoPath: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** UPLOAD LOGO (if provided) */
|
/** UPLOAD LOGO (if provided) */
|
||||||
const logoFile = files.find(
|
const logoFile = files.find(
|
||||||
(f) => f.fieldName === 'companyLogo' || f.fieldName === 'companyLogoFile'
|
(f) => f.fieldName === 'companyLogo' || f.fieldName === 'companyLogoFile'
|
||||||
@@ -449,6 +510,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
parsedParentCompany,
|
parsedParentCompany,
|
||||||
uploadedParentDocs,
|
uploadedParentDocs,
|
||||||
isDraft,
|
isDraft,
|
||||||
|
{ deleteCompanyLogo, deleteParentCompanyLogo },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!createdOrUpdated) throw new ApiError(400, 'Failed to add/update company details.');
|
if (!createdOrUpdated) throw new ApiError(400, 'Failed to add/update company details.');
|
||||||
|
|||||||
@@ -518,6 +518,7 @@ export class HostService {
|
|||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
emailAddress: true,
|
emailAddress: true,
|
||||||
|
dateOfBirth: true,
|
||||||
firstName: true,
|
firstName: true,
|
||||||
lastName: true,
|
lastName: true,
|
||||||
mobileNumber: true,
|
mobileNumber: true,
|
||||||
@@ -1390,6 +1391,10 @@ export class HostService {
|
|||||||
parentCompanyData?: any | null,
|
parentCompanyData?: any | null,
|
||||||
parentDocuments?: HostDocumentInput[],
|
parentDocuments?: HostDocumentInput[],
|
||||||
isDraft: boolean = false,
|
isDraft: boolean = false,
|
||||||
|
options?: {
|
||||||
|
deleteCompanyLogo?: boolean;
|
||||||
|
deleteParentCompanyLogo?: boolean;
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
return await this.prisma.$transaction(async (tx) => {
|
return await this.prisma.$transaction(async (tx) => {
|
||||||
// Check if host already has a company
|
// Check if host already has a company
|
||||||
@@ -1650,7 +1655,9 @@ export class HostService {
|
|||||||
? { connect: { id: Number(companyData.countryXid) } }
|
? { connect: { id: Number(companyData.countryXid) } }
|
||||||
: undefined,
|
: undefined,
|
||||||
pinCode: companyData.pinCode,
|
pinCode: companyData.pinCode,
|
||||||
logoPath: companyData.logoPath || existingHostCompany.logoPath,
|
logoPath: options?.deleteCompanyLogo
|
||||||
|
? companyData.logoPath ?? null
|
||||||
|
: companyData.logoPath || existingHostCompany.logoPath,
|
||||||
isSubsidairy: companyData.isSubsidairy,
|
isSubsidairy: companyData.isSubsidairy,
|
||||||
registrationNumber: companyData.registrationNumber,
|
registrationNumber: companyData.registrationNumber,
|
||||||
panNumber: companyData.panNumber,
|
panNumber: companyData.panNumber,
|
||||||
@@ -1791,10 +1798,11 @@ export class HostService {
|
|||||||
? { connect: { id: Number(parentCompanyData.countryXid) } }
|
? { connect: { id: Number(parentCompanyData.countryXid) } }
|
||||||
: undefined,
|
: undefined,
|
||||||
pinCode: parentCompanyData.pinCode || null,
|
pinCode: parentCompanyData.pinCode || null,
|
||||||
logoPath:
|
logoPath: options?.deleteParentCompanyLogo
|
||||||
parentCompanyData?.logoPath ||
|
? parentCompanyData?.logoPath ?? null
|
||||||
existingParentCompany?.logoPath ||
|
: parentCompanyData?.logoPath ||
|
||||||
null,
|
existingParentCompany?.logoPath ||
|
||||||
|
null,
|
||||||
registrationNumber: parentCompanyData.registrationNumber || null,
|
registrationNumber: parentCompanyData.registrationNumber || null,
|
||||||
panNumber: parentCompanyData.panNumber || null,
|
panNumber: parentCompanyData.panNumber || null,
|
||||||
gstNumber: parentCompanyData.gstNumber || null,
|
gstNumber: parentCompanyData.gstNumber || null,
|
||||||
@@ -1849,10 +1857,11 @@ export class HostService {
|
|||||||
? { connect: { id: Number(parentCompanyData.countryXid) } }
|
? { connect: { id: Number(parentCompanyData.countryXid) } }
|
||||||
: undefined,
|
: undefined,
|
||||||
pinCode: parentCompanyData.pinCode || null,
|
pinCode: parentCompanyData.pinCode || null,
|
||||||
logoPath:
|
logoPath: options?.deleteParentCompanyLogo
|
||||||
parentCompanyData?.logoPath ||
|
? parentCompanyData?.logoPath ?? null
|
||||||
existingParentCompany?.logoPath ||
|
: parentCompanyData?.logoPath ||
|
||||||
null,
|
existingParentCompany?.logoPath ||
|
||||||
|
null,
|
||||||
registrationNumber: parentCompanyData.registrationNumber || null,
|
registrationNumber: parentCompanyData.registrationNumber || null,
|
||||||
panNumber: parentCompanyData.panNumber || null,
|
panNumber: parentCompanyData.panNumber || null,
|
||||||
gstNumber: parentCompanyData.gstNumber || null,
|
gstNumber: parentCompanyData.gstNumber || null,
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ const getUniqueDatesForScheduleDetail = (
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ItineraryService {
|
export class ItineraryService {
|
||||||
constructor(private prisma: PrismaClient) {}
|
constructor(private prisma: PrismaClient) { }
|
||||||
|
|
||||||
async getUserItineraryDetails(userXid: number) {
|
async getUserItineraryDetails(userXid: number) {
|
||||||
const [userLocation, activityEntries, travellerType, energyLevel] = await Promise.all([
|
const [userLocation, activityEntries, travellerType, energyLevel] = await Promise.all([
|
||||||
@@ -398,15 +398,15 @@ export class ItineraryService {
|
|||||||
),
|
),
|
||||||
energyLevel: entry.Activities?.activityType?.energyLevel
|
energyLevel: entry.Activities?.activityType?.energyLevel
|
||||||
? {
|
? {
|
||||||
id: entry.Activities.activityType.energyLevel.id,
|
id: entry.Activities.activityType.energyLevel.id,
|
||||||
energyLevelName:
|
energyLevelName:
|
||||||
entry.Activities.activityType.energyLevel.energyLevelName,
|
entry.Activities.activityType.energyLevel.energyLevelName,
|
||||||
energyIcon:
|
energyIcon:
|
||||||
entry.Activities.activityType.energyLevel.energyIcon,
|
entry.Activities.activityType.energyLevel.energyIcon,
|
||||||
energyIconPresignedUrl: await attachPresignedUrl(
|
energyIconPresignedUrl: await attachPresignedUrl(
|
||||||
entry.Activities.activityType.energyLevel.energyIcon,
|
entry.Activities.activityType.energyLevel.energyIcon,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
media: await attachMediaWithPresignedUrl(
|
media: await attachMediaWithPresignedUrl(
|
||||||
entry.Activities?.ActivitiesMedia ?? [],
|
entry.Activities?.ActivitiesMedia ?? [],
|
||||||
@@ -640,9 +640,9 @@ export class ItineraryService {
|
|||||||
|
|
||||||
const slotEnd = scheduleHeader.activity.activityDurationMins
|
const slotEnd = scheduleHeader.activity.activityDurationMins
|
||||||
? addMinutes(
|
? addMinutes(
|
||||||
slotStart,
|
slotStart,
|
||||||
scheduleHeader.activity.activityDurationMins,
|
scheduleHeader.activity.activityDurationMins,
|
||||||
)
|
)
|
||||||
: combineDateAndTime(slotDate, slot.endTime);
|
: combineDateAndTime(slotDate, slot.endTime);
|
||||||
|
|
||||||
if (!slotEnd) {
|
if (!slotEnd) {
|
||||||
@@ -665,7 +665,7 @@ export class ItineraryService {
|
|||||||
if (
|
if (
|
||||||
activityItem.occurenceDate &&
|
activityItem.occurenceDate &&
|
||||||
formatDateKey(slotDate) !==
|
formatDateKey(slotDate) !==
|
||||||
formatDateKey(parseDateValue(activityItem.occurenceDate))
|
formatDateKey(parseDateValue(activityItem.occurenceDate))
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -879,6 +879,97 @@ export class ItineraryService {
|
|||||||
checkInAddress: true,
|
checkInAddress: true,
|
||||||
checkInLat: true,
|
checkInLat: true,
|
||||||
checkInLong: true,
|
checkInLong: true,
|
||||||
|
foodAvailable: true,
|
||||||
|
foodIsChargeable: true,
|
||||||
|
trainerAvailable: true,
|
||||||
|
trainerIsChargeable: true,
|
||||||
|
inActivityAvailable: true,
|
||||||
|
inActivityIsChargeable: true,
|
||||||
|
pickUpDropAvailable: true,
|
||||||
|
pickUpDropIsChargeable: true,
|
||||||
|
activityFoodTypes: {
|
||||||
|
where: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
foodTypeXid: true,
|
||||||
|
foodType: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
foodTypeName: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ActivityFoodCost: {
|
||||||
|
where: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
baseAmount: true,
|
||||||
|
totalAmount: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ActivityTrainers: {
|
||||||
|
where: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
baseAmount: true,
|
||||||
|
totalAmount: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ActivityNavigationModes: {
|
||||||
|
where: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
navigationModeName: true,
|
||||||
|
isInActivityChargeable: true,
|
||||||
|
navigationModesBasePrice: true,
|
||||||
|
navigationModesTotalPrice: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ActivityPickUpDetails: {
|
||||||
|
where: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
isPickUp: true,
|
||||||
|
locationLat: true,
|
||||||
|
locationLong: true,
|
||||||
|
locationAddress: true,
|
||||||
|
transportBasePrice: true,
|
||||||
|
transportTotalPrice: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
activityPickUpTransports: {
|
||||||
|
where: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
transportModeXid: true,
|
||||||
|
transportMode: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
transportModeName: true,
|
||||||
|
transportModeIcon: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
ActivitiesMedia: {
|
ActivitiesMedia: {
|
||||||
where: {
|
where: {
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -921,9 +1012,8 @@ export class ItineraryService {
|
|||||||
|
|
||||||
const formattedItineraries = await Promise.all(
|
const formattedItineraries = await Promise.all(
|
||||||
itineraries.map(async (itinerary) => {
|
itineraries.map(async (itinerary) => {
|
||||||
const ownerFullName = `${itinerary.owner.firstName ?? ''} ${
|
const ownerFullName = `${itinerary.owner.firstName ?? ''} ${itinerary.owner.lastName ?? ''
|
||||||
itinerary.owner.lastName ?? ''
|
}`.trim();
|
||||||
}`.trim();
|
|
||||||
|
|
||||||
const members = await Promise.all(
|
const members = await Promise.all(
|
||||||
itinerary.ItineraryMembers.map(async (member) => ({
|
itinerary.ItineraryMembers.map(async (member) => ({
|
||||||
@@ -932,9 +1022,8 @@ export class ItineraryService {
|
|||||||
memberRole: member.memberRole,
|
memberRole: member.memberRole,
|
||||||
memberStatus: member.memberStatus,
|
memberStatus: member.memberStatus,
|
||||||
invitedByXid: member.invitedByXid,
|
invitedByXid: member.invitedByXid,
|
||||||
fullName: `${member.member.firstName ?? ''} ${
|
fullName: `${member.member.firstName ?? ''} ${member.member.lastName ?? ''
|
||||||
member.member.lastName ?? ''
|
}`.trim(),
|
||||||
}`.trim(),
|
|
||||||
firstName: member.member.firstName,
|
firstName: member.member.firstName,
|
||||||
lastName: member.member.lastName,
|
lastName: member.member.lastName,
|
||||||
profileImage: member.member.profileImage,
|
profileImage: member.member.profileImage,
|
||||||
@@ -985,6 +1074,80 @@ export class ItineraryService {
|
|||||||
media: await attachMediaWithPresignedUrl(
|
media: await attachMediaWithPresignedUrl(
|
||||||
item.activity.ActivitiesMedia,
|
item.activity.ActivitiesMedia,
|
||||||
),
|
),
|
||||||
|
foodDetails: {
|
||||||
|
foodAvailable: item.activity.foodAvailable,
|
||||||
|
foodIsChargeable: item.activity.foodIsChargeable,
|
||||||
|
foodTypes: item.activity.activityFoodTypes.map((foodType) => ({
|
||||||
|
id: foodType.id,
|
||||||
|
foodTypeXid: foodType.foodTypeXid,
|
||||||
|
foodType: foodType.foodType,
|
||||||
|
})),
|
||||||
|
foodCost: item.activity.ActivityFoodCost.map((foodCost) => ({
|
||||||
|
id: foodCost.id,
|
||||||
|
baseAmount: foodCost.baseAmount,
|
||||||
|
totalAmount: foodCost.totalAmount,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
trainerDetails: {
|
||||||
|
trainerAvailable: item.activity.trainerAvailable,
|
||||||
|
trainerIsChargeable: item.activity.trainerIsChargeable,
|
||||||
|
trainerCost: item.activity.ActivityTrainers.map((trainer) => ({
|
||||||
|
id: trainer.id,
|
||||||
|
baseAmount: trainer.baseAmount,
|
||||||
|
totalAmount: trainer.totalAmount,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
navigationDetails: {
|
||||||
|
inActivityAvailable: item.activity.inActivityAvailable,
|
||||||
|
inActivityIsChargeable: item.activity.inActivityIsChargeable,
|
||||||
|
navigationModes: item.activity.ActivityNavigationModes.map(
|
||||||
|
(navigationMode) => ({
|
||||||
|
id: navigationMode.id,
|
||||||
|
navigationModeName: navigationMode.navigationModeName,
|
||||||
|
isInActivityChargeable:
|
||||||
|
navigationMode.isInActivityChargeable,
|
||||||
|
navigationModesBasePrice:
|
||||||
|
navigationMode.navigationModesBasePrice,
|
||||||
|
navigationModesTotalPrice:
|
||||||
|
navigationMode.navigationModesTotalPrice,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
pickUpDetails: {
|
||||||
|
pickUpDropAvailable: item.activity.pickUpDropAvailable,
|
||||||
|
pickUpDropIsChargeable:
|
||||||
|
item.activity.pickUpDropIsChargeable,
|
||||||
|
details: item.activity.ActivityPickUpDetails.map(
|
||||||
|
(pickUpDetail) => ({
|
||||||
|
id: pickUpDetail.id,
|
||||||
|
isPickUp: pickUpDetail.isPickUp,
|
||||||
|
locationLat: pickUpDetail.locationLat,
|
||||||
|
locationLong: pickUpDetail.locationLong,
|
||||||
|
locationAddress: pickUpDetail.locationAddress,
|
||||||
|
transportBasePrice: pickUpDetail.transportBasePrice,
|
||||||
|
transportTotalPrice: pickUpDetail.transportTotalPrice,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
transportModes: await Promise.all(
|
||||||
|
item.activity.activityPickUpTransports.map(
|
||||||
|
async (transport) => ({
|
||||||
|
id: transport.id,
|
||||||
|
transportModeXid: transport.transportModeXid,
|
||||||
|
transportMode: {
|
||||||
|
id: transport.transportMode.id,
|
||||||
|
transportModeName:
|
||||||
|
transport.transportMode.transportModeName,
|
||||||
|
transportModeIcon:
|
||||||
|
transport.transportMode.transportModeIcon,
|
||||||
|
transportModeIconPresignedUrl:
|
||||||
|
await attachPresignedUrl(
|
||||||
|
transport.transportMode.transportModeIcon,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
venue: item.venue,
|
venue: item.venue,
|
||||||
scheduleHeader: item.scheduledHeader,
|
scheduleHeader: item.scheduledHeader,
|
||||||
@@ -1150,6 +1313,7 @@ export class ItineraryService {
|
|||||||
id: true,
|
id: true,
|
||||||
activityTitle: true,
|
activityTitle: true,
|
||||||
activityDurationMins: true,
|
activityDurationMins: true,
|
||||||
|
activityDescription: true,
|
||||||
checkInLat: true,
|
checkInLat: true,
|
||||||
checkInLong: true,
|
checkInLong: true,
|
||||||
checkInAddress: true,
|
checkInAddress: true,
|
||||||
@@ -1246,6 +1410,17 @@ export class ItineraryService {
|
|||||||
venueName: true,
|
venueName: true,
|
||||||
venueLabel: true,
|
venueLabel: true,
|
||||||
venueCapacity: true,
|
venueCapacity: true,
|
||||||
|
ActivityVenueArtifacts: {
|
||||||
|
where: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
mediaType: true,
|
||||||
|
mediaFileName: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
availableSeats: true,
|
availableSeats: true,
|
||||||
ScheduleHeader: {
|
ScheduleHeader: {
|
||||||
where: {
|
where: {
|
||||||
@@ -1411,6 +1586,8 @@ export class ItineraryService {
|
|||||||
venueXid: venue.id,
|
venueXid: venue.id,
|
||||||
venueName: venue.venueName,
|
venueName: venue.venueName,
|
||||||
venueLabel: venue.venueLabel,
|
venueLabel: venue.venueLabel,
|
||||||
|
mediaFileName: venue.ActivityVenueArtifacts[0]?.mediaFileName ?? null,
|
||||||
|
mediaType: venue.ActivityVenueArtifacts[0]?.mediaType ?? null,
|
||||||
venueCapacity: venue.venueCapacity,
|
venueCapacity: venue.venueCapacity,
|
||||||
availableSeats: venue.availableSeats,
|
availableSeats: venue.availableSeats,
|
||||||
slotDate: formatDateKey(slotDate),
|
slotDate: formatDateKey(slotDate),
|
||||||
@@ -1430,11 +1607,27 @@ export class ItineraryService {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!availableSlots.length) {
|
const sanitizedAvailableSlots = availableSlots.filter(
|
||||||
|
(
|
||||||
|
slot,
|
||||||
|
): slot is NonNullable<(typeof availableSlots)[number]> =>
|
||||||
|
Boolean(slot),
|
||||||
|
);
|
||||||
|
|
||||||
|
const availableSlotsWithPresignedUrl = await Promise.all(
|
||||||
|
sanitizedAvailableSlots.map(async (slot) => ({
|
||||||
|
...slot,
|
||||||
|
mediaFileNamePresignedUrl: await attachPresignedUrl(
|
||||||
|
slot.mediaFileName,
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!availableSlotsWithPresignedUrl.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
availableSlots.sort(
|
availableSlotsWithPresignedUrl.sort(
|
||||||
(first, second) =>
|
(first, second) =>
|
||||||
new Date(first!.startDateTime).getTime() -
|
new Date(first!.startDateTime).getTime() -
|
||||||
new Date(second!.startDateTime).getTime(),
|
new Date(second!.startDateTime).getTime(),
|
||||||
@@ -1454,29 +1647,30 @@ export class ItineraryService {
|
|||||||
bucketTypeName: entry.bucketTypeName,
|
bucketTypeName: entry.bucketTypeName,
|
||||||
distance,
|
distance,
|
||||||
activityTitle: activity.activityTitle,
|
activityTitle: activity.activityTitle,
|
||||||
|
activityDescription: activity.activityDescription,
|
||||||
activityDurationMins,
|
activityDurationMins,
|
||||||
activityCoverImage: coverImage?.mediaFileName ?? null,
|
activityCoverImage: coverImage?.mediaFileName ?? null,
|
||||||
activityCoverImagePresignedUrl: await attachPresignedUrl(
|
activityCoverImagePresignedUrl: await attachPresignedUrl(
|
||||||
coverImage?.mediaFileName,
|
coverImage?.mediaFileName,
|
||||||
),
|
),
|
||||||
venue: availableSlots[0]
|
venue: availableSlotsWithPresignedUrl[0]
|
||||||
? {
|
? {
|
||||||
venueXid: availableSlots[0].venueXid,
|
venueXid: availableSlotsWithPresignedUrl[0].venueXid,
|
||||||
venueName: availableSlots[0].venueName,
|
venueName: availableSlotsWithPresignedUrl[0].venueName,
|
||||||
venueLabel: availableSlots[0].venueLabel,
|
venueLabel: availableSlotsWithPresignedUrl[0].venueLabel,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
availableSlots,
|
availableSlots: availableSlotsWithPresignedUrl,
|
||||||
entryType: activity.ActivityAllowedEntry[0]?.allowedEntryType ?? null,
|
entryType: activity.ActivityAllowedEntry[0]?.allowedEntryType ?? null,
|
||||||
energyLevel: energyLevel
|
energyLevel: energyLevel
|
||||||
? {
|
? {
|
||||||
energyLevelXid: energyLevel.id,
|
energyLevelXid: energyLevel.id,
|
||||||
energyLevelName: energyLevel.energyLevelName,
|
energyLevelName: energyLevel.energyLevelName,
|
||||||
energyLevelIcon: energyLevel.energyIcon,
|
energyLevelIcon: energyLevel.energyIcon,
|
||||||
energyLevelIconPresignedUrl: await attachPresignedUrl(
|
energyLevelIconPresignedUrl: await attachPresignedUrl(
|
||||||
energyLevel.energyIcon,
|
energyLevel.energyIcon,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
checkInAddress: activity.checkInAddress,
|
checkInAddress: activity.checkInAddress,
|
||||||
checkInCity: activity.checkInCity,
|
checkInCity: activity.checkInCity,
|
||||||
@@ -1486,9 +1680,9 @@ export class ItineraryService {
|
|||||||
checkInLong: activity.checkInLong,
|
checkInLong: activity.checkInLong,
|
||||||
interest: activity.activityType?.interests
|
interest: activity.activityType?.interests
|
||||||
? {
|
? {
|
||||||
id: activity.activityType.interests.id,
|
id: activity.activityType.interests.id,
|
||||||
interestName: activity.activityType.interests.interestName,
|
interestName: activity.activityType.interests.interestName,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user