Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 47x 882x 986x 882x 1291x 161423x 19270x 1291x 531x 531x 4418x 531x 1291x 23x 1268x 882x 882x 882x 1268x 522x 882x 882x 882x | import dayjs from "dayjs";
import { partition } from "remeda";
import { config } from "shared/config";
import { DirectSignupsForProgramItem } from "server/features/direct-signup/directSignupTypes";
import { User } from "shared/types/models/user";
import { EventLogAction } from "shared/types/models/eventLog";
import { ProgramItem } from "shared/types/models/programItem";
import { DIRECT_SIGNUP_PRIORITY } from "shared/constants/signups";
export const getAssignmentBonus = (
attendeeGroup: User[],
lotteryParticipantDirectSignups: readonly DirectSignupsForProgramItem[],
lotterySignupProgramItems: readonly ProgramItem[],
assignmentTime: string,
): number => {
/** First time bonus */
// A re-run must not count its own results as "previous" (which would strip the bonus and
// change outcomes): ignore lottery wins (priority > 0) and NEW_ASSIGNMENT events at the
// current assignmentTime, but keep genuine first-come-first-served direct signups
const isCurrentAssignment = (startTime: string): boolean =>
dayjs(startTime).isSame(dayjs(assignmentTime), "minute");
// Get group members with previous direct signups or NEW_ASSIGNMENT event log items
const [groupMembersWithDirectSignups, groupMembersWithoutDirectSignups] =
partition(attendeeGroup, (groupMember) => {
const previousDirectSignup = lotteryParticipantDirectSignups.find(
(programItem) => {
return programItem.userSignups.find(
(userSignup) =>
userSignup.username === groupMember.username &&
// Exclude this lottery's own win (priority > 0) at the current time, but keep
// first-come-first-served (priority 0) signups counting as "previous"
!(
isCurrentAssignment(userSignup.signedToStartTime) &&
userSignup.priority !== DIRECT_SIGNUP_PRIORITY
),
);
},
);
const newAssignmentEvent = groupMember.eventLogItems.find(
(eventLogItem) => {
const previousAssignment =
eventLogItem.action === EventLogAction.NEW_ASSIGNMENT;
const programItemExists = lotterySignupProgramItems.some(
(programItem) =>
programItem.programItemId === eventLogItem.programItemId,
);
return (
previousAssignment &&
programItemExists &&
!isCurrentAssignment(eventLogItem.programItemStartTime)
);
},
);
if (previousDirectSignup ?? newAssignmentEvent) {
return true;
}
return false;
});
// Give first time bonus to the whole group if half of the group members don't have previous direct signups
const averagePreviousDirectSignups =
groupMembersWithDirectSignups.length / attendeeGroup.length;
const firstTimeBonus =
averagePreviousDirectSignups <= 0.5 ? config.server().firstSignupBonus : 0;
/** Additional first time bonus */
// Get group members with previous NO_ASSIGNMENT event log items and without direct signups.
// Ignore a NO_ASSIGNMENT from the current assignmentTime — on a re-run it's this run's own
// earlier result, so counting it would make the re-run boost run-1 failures
const groupMembersWithPreviousFailedLotterySignup =
groupMembersWithoutDirectSignups.filter((groupMember) => {
return groupMember.eventLogItems.find(
(eventLogItem) =>
eventLogItem.action === EventLogAction.NO_ASSIGNMENT &&
!isCurrentAssignment(eventLogItem.programItemStartTime),
);
});
// Give additional first time bonus to the whole group if half of the group members have previous failed lottery signups
const averageFailedLotterySignups =
groupMembersWithPreviousFailedLotterySignup.length / attendeeGroup.length;
const additionalFirstTimeBonus =
averageFailedLotterySignups >= 0.5
? config.server().additionalFirstSignupBonus
: 0;
return firstTimeBonus + additionalFirstTimeBonus;
};
|