Auth = window.Auth || {};
// Colors
colors = ({
navy: '#2C3E50',
teal: '#16A085',
orange: '#E67E22',
gray: '#7F8C8D'
})
// Check authentication and admin status
currentUser = {
const user = Auth.getCurrentUser();
if (!user) return null;
const isAdmin = Auth.isUserAdmin();
return { ...user, isAdmin };
}
// Load content inventory from gallery indices
contentInventory = {
if (!currentUser || !currentUser.isAdmin) {
return null;
}
try {
// Load all gallery indices
const [gamesIndex, simsIndex, labsIndex, checksIndex, squadIndex] = await Promise.all([
fetch('/assets/data/games-master-index.json').then(r => r.json()).catch(() => ({ galleries: {} })),
fetch('/assets/data/simulations-master-index.json').then(r => r.json()).catch(() => ({ galleries: {} })),
fetch('/assets/data/labs-master-index.json').then(r => r.json()).catch(() => ({ galleries: {} })),
fetch('/assets/data/knowledge-checks-master-index.json').then(r => r.json()).catch(() => ({ galleries: {} })),
fetch('/assets/data/sensor-squad-master-index.json').then(r => r.json()).catch(() => ({ galleries: {} }))
]);
// Aggregate by chapter
const chapterMap = new Map();
// Helper to add content to chapter
const addToChapter = (chapterPath, type) => {
if (!chapterMap.has(chapterPath)) {
chapterMap.set(chapterPath, {
chapter: chapterPath,
games: 0,
simulations: 0,
labs: 0,
knowledgeChecks: 0,
sensorSquad: 0
});
}
const entry = chapterMap.get(chapterPath);
entry[type]++;
};
// Process games
Object.values(gamesIndex.galleries || {}).forEach(gallery => {
(gallery.items || []).forEach(item => {
if (item.chapter_path) {
addToChapter(item.chapter_path, 'games');
}
});
});
// Process simulations
Object.values(simsIndex.galleries || {}).forEach(gallery => {
(gallery.items || []).forEach(item => {
if (item.chapter_path) {
addToChapter(item.chapter_path, 'simulations');
}
});
});
// Process labs
Object.values(labsIndex.galleries || {}).forEach(gallery => {
(gallery.items || []).forEach(item => {
if (item.chapter_path) {
addToChapter(item.chapter_path, 'labs');
}
});
});
// Process knowledge checks
Object.values(checksIndex.galleries || {}).forEach(gallery => {
(gallery.items || []).forEach(item => {
if (item.chapter_path) {
addToChapter(item.chapter_path, 'knowledgeChecks');
}
});
});
// Process Sensor Squad
Object.values(squadIndex.galleries || {}).forEach(gallery => {
(gallery.items || []).forEach(item => {
if (item.chapter_path) {
addToChapter(item.chapter_path, 'sensorSquad');
}
});
});
// Convert to array and sort by chapter name
const inventory = Array.from(chapterMap.values())
.sort((a, b) => a.chapter.localeCompare(b.chapter));
// Calculate totals
const totals = inventory.reduce((acc, item) => ({
games: acc.games + item.games,
simulations: acc.simulations + item.simulations,
labs: acc.labs + item.labs,
knowledgeChecks: acc.knowledgeChecks + item.knowledgeChecks,
sensorSquad: acc.sensorSquad + item.sensorSquad
}), { games: 0, simulations: 0, labs: 0, knowledgeChecks: 0, sensorSquad: 0 });
return {
inventory,
totals,
chaptersWithContent: inventory.length,
chaptersWithGaps: inventory.filter(item =>
item.games === 0 || item.labs === 0 || item.knowledgeChecks === 0
).length
};
} catch (error) {
console.error('Error loading content inventory:', error);
return null;
}
}
// Filter state
viewState = ({ search: '', sortBy: 'chapter', filterType: 'all' })
// Filtered and sorted inventory
filteredInventory = {
if (!contentInventory) return [];
let filtered = contentInventory.inventory;
// Apply search filter
if (viewState.search) {
const searchLower = viewState.search.toLowerCase();
filtered = filtered.filter(item =>
item.chapter.toLowerCase().includes(searchLower)
);
}
// Apply type filter
if (viewState.filterType !== 'all') {
filtered = filtered.filter(item => {
switch (viewState.filterType) {
case 'with-gaps':
return item.games === 0 || item.labs === 0 || item.knowledgeChecks === 0;
case 'complete':
return item.games > 0 && item.labs > 0 && item.knowledgeChecks > 0;
case 'games-only':
return item.games > 0;
case 'labs-only':
return item.labs > 0;
case 'checks-only':
return item.knowledgeChecks > 0;
default:
return true;
}
});
}
// Apply sorting
filtered.sort((a, b) => {
switch (viewState.sortBy) {
case 'chapter':
return a.chapter.localeCompare(b.chapter);
case 'games':
return b.games - a.games;
case 'simulations':
return b.simulations - a.simulations;
case 'labs':
return b.labs - a.labs;
case 'checks':
return b.knowledgeChecks - a.knowledgeChecks;
case 'total':
return (b.games + b.simulations + b.labs + b.knowledgeChecks) -
(a.games + a.simulations + a.labs + a.knowledgeChecks);
default:
return 0;
}
});
return filtered;
}