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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | 357x 357x 357x 357x 357x 758x 758x 2x 758x 46x 758x 735x 23x 23x 357x 765x 742x 23x 54x 71x 2x 69x 29x 40x 9x 31x 2x 29x 1x 28x 357x 3278x 3278x 3367x 152x 3215x 3278x | import {
AgeGroup,
Language,
ProgramItem,
Tag,
} from "shared/types/models/programItem";
import { isPreConventionWeekProgramItem } from "shared/utils/isPreConventionWeekProgramItem";
import {
getUpcomingProgramItems,
isMainEventProgramVisible,
} from "client/utils/getUpcomingProgramItems";
import { getTimeNow } from "client/utils/getTimeNow";
export enum StartingTimeOption {
UPCOMING = "upcoming",
ALL = "all",
REVOLVING_DOOR = "revolvingDoor",
}
export const getVisibleProgramItems = (
programItems: readonly ProgramItem[],
selectedView: StartingTimeOption,
selectedTags: readonly string[],
hideFull: boolean,
fullProgramItemIds: ReadonlySet<string>,
): readonly ProgramItem[] => {
const tagFilteredProgramItems = getTagFilteredProgramItems(
programItems,
selectedTags,
);
const fullnessFiltered = hideFull
? tagFilteredProgramItems.filter(
(item) => !fullProgramItemIds.has(item.programItemId),
)
: tagFilteredProgramItems;
// Before the main event program is visible, only show pre-convention week program.
// After it is visible, pre-convention week program is in the past so it drops out of
// the upcoming list on its own
const phaseFilteredProgramItems = isMainEventProgramVisible(getTimeNow())
? fullnessFiltered
: fullnessFiltered.filter((programItem) =>
isPreConventionWeekProgramItem(programItem),
);
if (selectedView === StartingTimeOption.UPCOMING) {
return getUpcomingProgramItems(phaseFilteredProgramItems);
} else Iif (selectedView === StartingTimeOption.REVOLVING_DOOR) {
return getUpcomingProgramItems(phaseFilteredProgramItems).filter(
(programItem) => programItem.revolvingDoor,
);
}
return phaseFilteredProgramItems;
};
export const getTagFilteredProgramItems = (
programItems: readonly ProgramItem[],
selectedTags: readonly string[],
): readonly ProgramItem[] => {
if (selectedTags.length === 0) {
return programItems;
}
// Show items matching all of the selected tags (AND)
return programItems.filter((programItem) =>
selectedTags.every((selectedTag) => {
if (programItem.programType.includes(selectedTag)) {
return true;
}
if (programItem.tags.includes(selectedTag as Tag)) {
return true;
}
if (programItem.ageGroups.includes(selectedTag as AgeGroup)) {
return true;
}
if (programItem.languages.includes(selectedTag as Language)) {
return true;
}
if (
programItem.languages.includes(Language.LANGUAGE_FREE) &&
Object.values(Language).includes(selectedTag as Language)
) {
return true;
}
return false;
}),
);
};
// The header of the group currently at (or scrolled past) the top of the visible
// range — pinned to the top while its group scrolls. `stickyHeaderIndexes` is
// ascending, so the last one at or before `rangeStartIndex` is the active header
export const getActiveStickyHeaderIndex = (
stickyHeaderIndexes: readonly number[],
rangeStartIndex: number,
): number => {
let activeIndex = 0;
for (const headerIndex of stickyHeaderIndexes) {
if (headerIndex > rangeStartIndex) {
break;
}
activeIndex = headerIndex;
}
return activeIndex;
};
|