sending the connection interest count and generating the activity ref number
This commit is contained in:
@@ -61,7 +61,8 @@ interface HostDocumentInput {
|
||||
export async function generateActivityRefNumber(
|
||||
tx: any,
|
||||
hostXid: number,
|
||||
activityTypeXid: number
|
||||
activityTypeXid: number,
|
||||
hostRefNumber: string
|
||||
) {
|
||||
// 1️⃣ Get ActivityType with Interest
|
||||
const activityType = await tx.activityTypes.findUnique({
|
||||
@@ -131,7 +132,7 @@ export async function generateActivityRefNumber(
|
||||
|
||||
const nextActivityTypeSequence = activityTypeCount + 1;
|
||||
|
||||
return `E-${interestCode}${String(interestSequence).padStart(
|
||||
return `${hostRefNumber}-E-${interestCode}${String(interestSequence).padStart(
|
||||
3,
|
||||
"0"
|
||||
)}-${String(nextActivityTypeSequence).padStart(2, "0")}`;
|
||||
@@ -2763,6 +2764,18 @@ export class HostService {
|
||||
frequenciesXid: number,
|
||||
) {
|
||||
return await this.prisma.$transaction(async (tx) => {
|
||||
|
||||
const hostUserDetail = await tx.user.findFirst({
|
||||
where: { id: userId, isActive: true},
|
||||
select: {
|
||||
id: true,
|
||||
userRefNumber: true,
|
||||
}
|
||||
})
|
||||
|
||||
if(!hostUserDetail) {
|
||||
throw new ApiError(404, 'User not found');
|
||||
}
|
||||
const host = await tx.hostHeader.findFirst({
|
||||
where: { userXid: userId, isActive: true },
|
||||
});
|
||||
@@ -2770,6 +2783,10 @@ export class HostService {
|
||||
|
||||
const activityType = await tx.activityTypes.findUnique({
|
||||
where: { id: activityTypeXid },
|
||||
include: {
|
||||
interests: true, // ✅ correct
|
||||
energyLevel: true, // ✅ this is correct already
|
||||
},
|
||||
});
|
||||
if (!activityType) throw new ApiError(404, 'Activity type not found');
|
||||
|
||||
@@ -2780,7 +2797,7 @@ export class HostService {
|
||||
if (!freq) throw new ApiError(404, 'Frequency not found');
|
||||
}
|
||||
|
||||
const referenceNumber = await generateActivityRefNumber(tx, host.id, activityTypeXid);
|
||||
const referenceNumber = await generateActivityRefNumber(tx, host.id, activityTypeXid, hostUserDetail.userRefNumber);
|
||||
|
||||
const created = await tx.activities.create({
|
||||
data: {
|
||||
|
||||
@@ -193,6 +193,7 @@ async function rankAndPaginateActivities(
|
||||
whereClause: any,
|
||||
page: number,
|
||||
limit: number,
|
||||
connectionInterestMap
|
||||
) {
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
@@ -330,6 +331,8 @@ async function rankAndPaginateActivities(
|
||||
// activityDurationMins: activity.activityDurationMins,
|
||||
// sustainabilityScore: activity.sustainabilityScore,
|
||||
// cheapestPrice,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(activity.id) ?? 0,
|
||||
energyLevel: activity.activityType.energyLevel
|
||||
? {
|
||||
...activity.activityType.energyLevel,
|
||||
@@ -704,6 +707,45 @@ export class UserService {
|
||||
};
|
||||
}
|
||||
|
||||
const userConnectionDetails = await tx.connectDetails.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
schoolCompanyXid: true,
|
||||
}
|
||||
})
|
||||
|
||||
const otherConnectionUsers = await tx.connectDetails.findMany({
|
||||
where: { userXid: { notIn: [userId] }, isActive: true, schoolCompanyXid: { in: userConnectionDetails.map((u) => u.schoolCompanyXid) } },
|
||||
select: {
|
||||
id: true,
|
||||
userXid: true,
|
||||
}
|
||||
})
|
||||
|
||||
const connectionUserIds =
|
||||
otherConnectionUsers.length > 0
|
||||
? otherConnectionUsers.map(u => u.userXid)
|
||||
: [-1]; // impossible user id
|
||||
|
||||
const connectionInterestByActivity = await tx.userBucketInterested.groupBy({
|
||||
by: ['activityXid'],
|
||||
where: {
|
||||
userXid: { in: connectionUserIds },
|
||||
isActive: true,
|
||||
},
|
||||
_count: {
|
||||
activityXid: true,
|
||||
},
|
||||
});
|
||||
|
||||
const connectionInterestMap = new Map(
|
||||
connectionInterestByActivity.map(item => [
|
||||
item.activityXid,
|
||||
item._count.activityXid,
|
||||
])
|
||||
);
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
/* =====================================================
|
||||
@@ -890,6 +932,8 @@ export class UserService {
|
||||
mostHypedSorted.map(async (activity) => ({
|
||||
activityId: activity.id,
|
||||
activityTitle: activity.activityTitle,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(activity.id) ?? 0,
|
||||
hypeCount: activity.hypeCount,
|
||||
energyLevel: activity.activityType.energyLevel
|
||||
? {
|
||||
@@ -926,6 +970,7 @@ export class UserService {
|
||||
newArrivalsWhere,
|
||||
page,
|
||||
limit,
|
||||
connectionInterestMap
|
||||
);
|
||||
|
||||
/* =====================================================
|
||||
@@ -949,7 +994,76 @@ export class UserService {
|
||||
otherStatesWhere,
|
||||
page,
|
||||
limit,
|
||||
connectionInterestMap
|
||||
);
|
||||
// =====================================================
|
||||
// 6️⃣ RANDOM ACTIVITIES (5 ONLY - SIMPLE)
|
||||
// =====================================================
|
||||
|
||||
const totalActiveCount = await tx.activities.count({
|
||||
where: {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
deletedAt: null,
|
||||
},
|
||||
});
|
||||
|
||||
let randomActivities: any[] = [];
|
||||
|
||||
if (totalActiveCount > 0) {
|
||||
const takeCount = Math.min(5, totalActiveCount);
|
||||
|
||||
const randomOffsets = new Set<number>();
|
||||
while (randomOffsets.size < takeCount) {
|
||||
randomOffsets.add(Math.floor(Math.random() * totalActiveCount));
|
||||
}
|
||||
|
||||
const randomFetched = await Promise.all(
|
||||
Array.from(randomOffsets).map((offset) =>
|
||||
tx.activities.findFirst({
|
||||
skip: offset,
|
||||
where: {
|
||||
isActive: true,
|
||||
activityInternalStatus:
|
||||
ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus:
|
||||
ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
deletedAt: null,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
ActivitiesMedia: {
|
||||
where: { isActive: true, isCoverImage: true },
|
||||
orderBy: { displayOrder: 'asc' },
|
||||
take: 1,
|
||||
select: {
|
||||
mediaFileName: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
randomActivities = await Promise.all(
|
||||
randomFetched
|
||||
.filter(Boolean)
|
||||
.map(async (activity) => {
|
||||
const cover = activity!.ActivitiesMedia?.[0];
|
||||
|
||||
return {
|
||||
activityId: activity!.id,
|
||||
activityTitle: activity!.activityTitle,
|
||||
coverImage: cover?.mediaFileName ?? null,
|
||||
coverImagePresignedUrl: cover?.mediaFileName
|
||||
? await attachPresignedUrl(cover.mediaFileName)
|
||||
: null,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/* =====================================================
|
||||
5️⃣ OVERSEAS ACTIVITIES (RANKED)
|
||||
@@ -969,6 +1083,7 @@ export class UserService {
|
||||
overseasWhere,
|
||||
page,
|
||||
limit,
|
||||
connectionInterestMap
|
||||
);
|
||||
|
||||
const formattedActivities = await Promise.all(
|
||||
@@ -982,6 +1097,8 @@ export class UserService {
|
||||
return {
|
||||
interestXid: activity.activityType.interestXid,
|
||||
activityId: activity.id,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(activity.id) ?? 0,
|
||||
activityTitle: activity.activityTitle,
|
||||
activityDurationMins: activity.activityDurationMins,
|
||||
sustainabilityScore: activity.sustainabilityScore,
|
||||
@@ -1024,14 +1141,16 @@ export class UserService {
|
||||
|
||||
return {
|
||||
userAddressDetails,
|
||||
experiencesLogged: 25,
|
||||
citiesDiscovered: 10,
|
||||
experiencesLogged: 0,
|
||||
citiesDiscovered: 0,
|
||||
loggedInNetworkCount: 0,
|
||||
citiesInNetworkCount: 0,
|
||||
rating: 0,
|
||||
pagination: {
|
||||
page,
|
||||
limit,
|
||||
},
|
||||
randomActivities,
|
||||
interests: interestsWithActivities,
|
||||
otherStatesActivities: formattedOtherStatesActivities,
|
||||
overSeasActivities: formattedOverSeasActivities,
|
||||
@@ -1112,6 +1231,51 @@ export class UserService {
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
/* =====================================================
|
||||
CONNECTION INTEREST MAP
|
||||
===================================================== */
|
||||
|
||||
const userConnectionDetails = await tx.connectDetails.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: { schoolCompanyXid: true },
|
||||
});
|
||||
|
||||
const otherConnectionUsers = await tx.connectDetails.findMany({
|
||||
where: {
|
||||
userXid: { not: userId },
|
||||
isActive: true,
|
||||
schoolCompanyXid: {
|
||||
in: userConnectionDetails.map((u) => u.schoolCompanyXid),
|
||||
},
|
||||
},
|
||||
select: { userXid: true },
|
||||
});
|
||||
|
||||
// Prevent empty IN crash
|
||||
const connectionUserIds =
|
||||
otherConnectionUsers.length > 0
|
||||
? otherConnectionUsers.map((u) => u.userXid)
|
||||
: [-1];
|
||||
|
||||
// Only bucket = true (important!)
|
||||
const connectionInterestByActivity =
|
||||
await tx.userBucketInterested.groupBy({
|
||||
by: ['activityXid'],
|
||||
where: {
|
||||
userXid: { in: connectionUserIds },
|
||||
isActive: true,
|
||||
isBucket: true,
|
||||
},
|
||||
_count: { activityXid: true },
|
||||
});
|
||||
|
||||
const connectionInterestMap = new Map(
|
||||
connectionInterestByActivity.map((item) => [
|
||||
item.activityXid,
|
||||
item._count.activityXid,
|
||||
]),
|
||||
);
|
||||
|
||||
/* =====================================================
|
||||
3️⃣ OTHER INTERESTS (GROUPED WITH ACTIVITIES)
|
||||
===================================================== */
|
||||
@@ -1157,6 +1321,8 @@ export class UserService {
|
||||
otherInterestActivities.map(async (a) => ({
|
||||
interestXid: a.activityType.interestXid,
|
||||
activityId: a.id,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(a.id) ?? 0,
|
||||
activityTitle: a.activityTitle,
|
||||
energyLevel: {
|
||||
...a.activityType.energyLevel,
|
||||
@@ -1234,6 +1400,8 @@ export class UserService {
|
||||
activityId: act.id,
|
||||
activityTitle: act.activityTitle,
|
||||
hypeCount: g._count.activityXid,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(act.id) ?? 0,
|
||||
energyLevel: {
|
||||
...act.activityType.energyLevel,
|
||||
presignedUrl: await attachPresignedUrl(
|
||||
@@ -1264,6 +1432,7 @@ export class UserService {
|
||||
take: limit,
|
||||
orderBy: { id: 'desc' },
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
activityType: { select: { energyLevel: true } },
|
||||
ActivitiesMedia: {
|
||||
@@ -1303,6 +1472,7 @@ export class UserService {
|
||||
skip,
|
||||
take: limit,
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
activityType: { select: { energyLevel: true } },
|
||||
ActivitiesMedia: {
|
||||
@@ -1316,6 +1486,7 @@ export class UserService {
|
||||
skip,
|
||||
take: limit,
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
activityType: { select: { energyLevel: true } },
|
||||
ActivitiesMedia: {
|
||||
@@ -1349,6 +1520,8 @@ export class UserService {
|
||||
activities: await Promise.all(
|
||||
newArrivalsRaw.map(async (a) => ({
|
||||
activityTitle: a.activityTitle,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(a.id) ?? 0,
|
||||
energyLevel: {
|
||||
...a.activityType.energyLevel,
|
||||
presignedUrl: await attachPresignedUrl(
|
||||
@@ -1368,6 +1541,8 @@ export class UserService {
|
||||
activities: await Promise.all(
|
||||
otherStatesRaw.map(async (a) => ({
|
||||
activityTitle: a.activityTitle,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(a.id) ?? 0,
|
||||
energyLevel: {
|
||||
...a.activityType.energyLevel,
|
||||
presignedUrl: await attachPresignedUrl(
|
||||
@@ -1387,6 +1562,8 @@ export class UserService {
|
||||
activities: await Promise.all(
|
||||
overseasRaw.map(async (a) => ({
|
||||
activityTitle: a.activityTitle,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(a.id) ?? 0,
|
||||
energyLevel: {
|
||||
...a.activityType.energyLevel,
|
||||
presignedUrl: await attachPresignedUrl(
|
||||
@@ -1735,13 +1912,47 @@ export class UserService {
|
||||
);
|
||||
}
|
||||
|
||||
// 🔹 Get connection users
|
||||
const userConnectionDetails = await tx.connectDetails.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: { schoolCompanyXid: true },
|
||||
});
|
||||
|
||||
const schoolCompanyXids = userConnectionDetails.map(
|
||||
(c) => c.schoolCompanyXid,
|
||||
);
|
||||
|
||||
const connectionUsers = await tx.connectDetails.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
schoolCompanyXid: {
|
||||
in: schoolCompanyXids.length ? schoolCompanyXids : [-1],
|
||||
},
|
||||
userXid: { not: userId },
|
||||
},
|
||||
select: { userXid: true },
|
||||
});
|
||||
|
||||
const connectionUserIds = connectionUsers.map((u) => u.userXid);
|
||||
|
||||
const interestedCount = await tx.userBucketInterested.count({
|
||||
where: {
|
||||
activityXid,
|
||||
isBucket: false,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
const connectionInterestedCount = connectionUserIds.length
|
||||
? await tx.userBucketInterested.count({
|
||||
where: {
|
||||
activityXid,
|
||||
userXid: { in: connectionUserIds },
|
||||
isActive: true,
|
||||
},
|
||||
})
|
||||
: 0;
|
||||
|
||||
const prices = activity.ActivityVenues.flatMap((v) =>
|
||||
v.ActivityPrices.map((p) => p.sellPrice),
|
||||
).filter((p) => p !== null) as number[];
|
||||
@@ -1755,6 +1966,7 @@ export class UserService {
|
||||
return {
|
||||
activity,
|
||||
interestedCount,
|
||||
connectionInterestedCount,
|
||||
cheapestPrice,
|
||||
totalCapacity,
|
||||
rating: 0, // ⭐ Placeholder, implement rating logic as needed
|
||||
@@ -1898,6 +2110,27 @@ export class UserService {
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// 0.5️⃣ Get connection users
|
||||
const userConnectionDetails = await this.prisma.connectDetails.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: { schoolCompanyXid: true },
|
||||
});
|
||||
|
||||
const schoolCompanyXids = userConnectionDetails.map(
|
||||
(c) => c.schoolCompanyXid,
|
||||
);
|
||||
|
||||
const connectionUsers = await this.prisma.connectDetails.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
schoolCompanyXid: { in: schoolCompanyXids.length ? schoolCompanyXids : [-1] },
|
||||
userXid: { not: userId },
|
||||
},
|
||||
select: { userXid: true },
|
||||
});
|
||||
|
||||
const connectionUserIds = connectionUsers.map((u) => u.userXid);
|
||||
|
||||
// 0️⃣ Get user's interests and map to activity types
|
||||
const userInterests = await this.prisma.userInterests.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
@@ -2012,6 +2245,31 @@ export class UserService {
|
||||
.filter((a) => a.distanceKm <= radiusKm)
|
||||
.sort((a, b) => a.distanceKm - b.distanceKm);
|
||||
|
||||
const nearbyActivityIds = withDistance.map((a) => a.id);
|
||||
|
||||
let connectionInterestMap = new Map<number, number>();
|
||||
|
||||
if (nearbyActivityIds.length && connectionUserIds.length) {
|
||||
const connectionInterestCounts =
|
||||
await this.prisma.userBucketInterested.groupBy({
|
||||
by: ['activityXid'],
|
||||
where: {
|
||||
activityXid: { in: nearbyActivityIds },
|
||||
userXid: { in: connectionUserIds },
|
||||
isActive: true,
|
||||
isBucket: true, // ✅ only real interest
|
||||
},
|
||||
_count: { activityXid: true },
|
||||
});
|
||||
|
||||
connectionInterestMap = new Map(
|
||||
connectionInterestCounts.map((item) => [
|
||||
item.activityXid,
|
||||
item._count.activityXid,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
const totalCount = withDistance.length;
|
||||
const paged = withDistance.slice(skip, skip + limit);
|
||||
|
||||
@@ -2026,8 +2284,11 @@ export class UserService {
|
||||
return {
|
||||
activityId: activity.id,
|
||||
activityTitle: activity.activityTitle,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(activity.id) ?? 0,
|
||||
activityDurationMins: activity.activityDurationMins,
|
||||
sustainabilityScore: activity.sustainabilityScore,
|
||||
rating: 0,
|
||||
distanceKm: activity.distanceKm,
|
||||
cheapestPrice,
|
||||
energyLevel: activity.activityType.energyLevel
|
||||
@@ -2343,6 +2604,42 @@ export class UserService {
|
||||
const effectiveCountryXid = effectiveLocation?.countryXid ?? null;
|
||||
const effectiveStateXid = effectiveLocation?.stateXid ?? null;
|
||||
|
||||
const userConnectionDetails = await tx.connectDetails.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
schoolCompanyXid: true,
|
||||
}
|
||||
})
|
||||
|
||||
const otherConnectionUsers = await tx.connectDetails.findMany({
|
||||
where: { userXid: { notIn: [userId] }, isActive: true, schoolCompanyXid: { in: userConnectionDetails.map((u) => u.schoolCompanyXid) } },
|
||||
select: {
|
||||
id: true,
|
||||
userXid: true,
|
||||
}
|
||||
})
|
||||
|
||||
const connectionUserIds = otherConnectionUsers.map(u => u.userXid);
|
||||
|
||||
const connectionInterestByActivity = await tx.userBucketInterested.groupBy({
|
||||
by: ['activityXid'],
|
||||
where: {
|
||||
userXid: { in: connectionUserIds },
|
||||
isActive: true,
|
||||
},
|
||||
_count: {
|
||||
activityXid: true,
|
||||
},
|
||||
});
|
||||
|
||||
const connectionInterestMap = new Map(
|
||||
connectionInterestByActivity.map(item => [
|
||||
item.activityXid,
|
||||
item._count.activityXid,
|
||||
])
|
||||
);
|
||||
|
||||
/* =====================================================
|
||||
1️⃣ FETCH ALL CANDIDATES FOR INTERESTS (SIMPLE SORT)
|
||||
===================================================== */
|
||||
@@ -2563,7 +2860,7 @@ export class UserService {
|
||||
createdAt: { gte: new Date(Date.now() - 31 * 24 * 60 * 60 * 1000) }
|
||||
};
|
||||
|
||||
const formattedNewArrivalsActivities = await rankAndPaginateActivities(tx, newArrivalsWhere, page, limit);
|
||||
const formattedNewArrivalsActivities = await rankAndPaginateActivities(tx, newArrivalsWhere, page, limit, connectionInterestMap);
|
||||
|
||||
/* =====================================================
|
||||
4️⃣ OTHER STATES ACTIVITIES (RANKED)
|
||||
@@ -2582,7 +2879,7 @@ export class UserService {
|
||||
otherStatesWhere.checkInStateXid = { not: effectiveStateXid };
|
||||
}
|
||||
|
||||
const formattedOtherStatesActivities = await rankAndPaginateActivities(tx, otherStatesWhere, page, limit);
|
||||
const formattedOtherStatesActivities = await rankAndPaginateActivities(tx, otherStatesWhere, page, limit, connectionInterestMap);
|
||||
|
||||
|
||||
/* =====================================================
|
||||
@@ -2599,7 +2896,7 @@ export class UserService {
|
||||
overseasWhere.checkInCountryXid = { not: effectiveCountryXid };
|
||||
}
|
||||
|
||||
const formattedOverSeasActivities = await rankAndPaginateActivities(tx, overseasWhere, page, limit);
|
||||
const formattedOverSeasActivities = await rankAndPaginateActivities(tx, overseasWhere, page, limit, connectionInterestMap);
|
||||
|
||||
|
||||
const formattedActivities = await Promise.all(
|
||||
@@ -2614,8 +2911,11 @@ export class UserService {
|
||||
interestXid: activity.activityType.interestXid,
|
||||
activityId: activity.id,
|
||||
activityTitle: activity.activityTitle,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(activity.id) ?? 0,
|
||||
activityDurationMins: activity.activityDurationMins,
|
||||
sustainabilityScore: activity.sustainabilityScore,
|
||||
rating: 0,
|
||||
cheapestPrice,
|
||||
energyLevel: activity.activityType.energyLevel
|
||||
? {
|
||||
@@ -2841,6 +3141,42 @@ export class UserService {
|
||||
const effectiveCountryXid = effectiveLocation?.countryXid ?? null;
|
||||
const effectiveStateXid = effectiveLocation?.stateXid ?? null;
|
||||
|
||||
const userConnectionDetails = await tx.connectDetails.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
schoolCompanyXid: true,
|
||||
}
|
||||
})
|
||||
|
||||
const otherConnectionUsers = await tx.connectDetails.findMany({
|
||||
where: { userXid: { notIn: [userId] }, isActive: true, schoolCompanyXid: { in: userConnectionDetails.map((u) => u.schoolCompanyXid) } },
|
||||
select: {
|
||||
id: true,
|
||||
userXid: true,
|
||||
}
|
||||
})
|
||||
|
||||
const connectionUserIds = otherConnectionUsers.map(u => u.userXid);
|
||||
|
||||
const connectionInterestByActivity = await tx.userBucketInterested.groupBy({
|
||||
by: ['activityXid'],
|
||||
where: {
|
||||
userXid: { in: connectionUserIds },
|
||||
isActive: true,
|
||||
},
|
||||
_count: {
|
||||
activityXid: true,
|
||||
},
|
||||
});
|
||||
|
||||
const connectionInterestMap = new Map(
|
||||
connectionInterestByActivity.map(item => [
|
||||
item.activityXid,
|
||||
item._count.activityXid,
|
||||
])
|
||||
);
|
||||
|
||||
/* =======================================================
|
||||
SWITCH BASED VIEW MORE TYPE
|
||||
======================================================= */
|
||||
@@ -2874,7 +3210,7 @@ export class UserService {
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
};
|
||||
|
||||
return await rankAndPaginateActivities(tx, where, page, limit);
|
||||
return await rankAndPaginateActivities(tx, where, page, limit, connectionInterestMap);
|
||||
}
|
||||
|
||||
/* ==========================================
|
||||
@@ -2891,7 +3227,7 @@ export class UserService {
|
||||
},
|
||||
};
|
||||
|
||||
return await rankAndPaginateActivities(tx, where, page, limit);
|
||||
return await rankAndPaginateActivities(tx, where, page, limit, connectionInterestMap);
|
||||
}
|
||||
|
||||
/* ==========================================
|
||||
@@ -2913,7 +3249,7 @@ export class UserService {
|
||||
where.checkInStateXid = { not: effectiveStateXid };
|
||||
}
|
||||
|
||||
return await rankAndPaginateActivities(tx, where, page, limit);
|
||||
return await rankAndPaginateActivities(tx, where, page, limit, connectionInterestMap);
|
||||
}
|
||||
|
||||
/* ==========================================
|
||||
@@ -2931,7 +3267,7 @@ export class UserService {
|
||||
where.checkInCountryXid = { not: effectiveCountryXid };
|
||||
}
|
||||
|
||||
return await rankAndPaginateActivities(tx, where, page, limit);
|
||||
return await rankAndPaginateActivities(tx, where, page, limit, connectionInterestMap);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -3021,7 +3357,7 @@ export class UserService {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
ActivitiesMedia: {
|
||||
where: {
|
||||
where: {
|
||||
isActive: true,
|
||||
},
|
||||
select: {
|
||||
@@ -3063,4 +3399,84 @@ export class UserService {
|
||||
});
|
||||
}
|
||||
|
||||
async getFiveRandomActivities() {
|
||||
return await this.prisma.$transaction(async (tx) => {
|
||||
|
||||
// Step 1: Count eligible activities
|
||||
const totalCount = await tx.activities.count({
|
||||
where: {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
deletedAt: null,
|
||||
},
|
||||
});
|
||||
|
||||
if (totalCount === 0) return [];
|
||||
|
||||
// Step 2: Generate 5 unique random offsets
|
||||
const takeCount = Math.min(5, totalCount);
|
||||
const randomOffsets = new Set<number>();
|
||||
|
||||
while (randomOffsets.size < takeCount) {
|
||||
randomOffsets.add(Math.floor(Math.random() * totalCount));
|
||||
}
|
||||
|
||||
// Step 3: Fetch activities using skip (efficient for small limit like 5)
|
||||
const activities = await Promise.all(
|
||||
Array.from(randomOffsets).map((offset) =>
|
||||
tx.activities.findFirst({
|
||||
skip: offset,
|
||||
where: {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
deletedAt: null,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
ActivitiesMedia: {
|
||||
where: {
|
||||
isActive: true,
|
||||
},
|
||||
orderBy: {
|
||||
displayOrder: 'asc',
|
||||
},
|
||||
take: 1,
|
||||
select: {
|
||||
mediaFileName: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// Step 4: Attach presigned URLs
|
||||
const result = await Promise.all(
|
||||
activities
|
||||
.filter(Boolean)
|
||||
.map(async (activity) => {
|
||||
const media = activity!.ActivitiesMedia?.[0];
|
||||
|
||||
let presignedUrl = null;
|
||||
|
||||
if (media?.mediaFileName) {
|
||||
presignedUrl = await attachPresignedUrl(media.mediaFileName);
|
||||
}
|
||||
|
||||
return {
|
||||
id: activity!.id,
|
||||
title: activity!.activityTitle,
|
||||
coverImage: media?.mediaFileName ?? null,
|
||||
coverImagePresignedUrl: presignedUrl,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user