@churchapps/helpers
Version:
Library of helper functions not specific to any one ChurchApps project or framework.
108 lines • 4 kB
JavaScript
import { LessonsContentProvider } from "./contentProviders/LessonsContentProvider.js";
export class PlanHelper {
static providers = [new LessonsContentProvider()];
// Register additional content providers
static registerProvider(provider) {
// Avoid duplicates
if (!this.providers.find(p => p.providerId === provider.providerId)) {
this.providers.push(provider);
}
}
// Replace a provider (useful for configuring with different URLs)
static replaceProvider(provider) {
const index = this.providers.findIndex(p => p.providerId === provider.providerId);
if (index >= 0) {
this.providers[index] = provider;
}
else {
this.providers.push(provider);
}
}
// Main method: populate planItems with their content
static async populate(plan, planItems) {
// Flatten hierarchy to get all items
const allItems = this.flattenItems(planItems);
// Group items by provider
const itemsByProvider = new Map();
for (const item of allItems) {
for (const provider of this.providers) {
if (provider.canHandle(plan, item)) {
const existing = itemsByProvider.get(provider) || [];
existing.push(item);
itemsByProvider.set(provider, existing);
break; // First matching provider wins
}
}
}
// Fetch content from each provider in parallel
const fetchPromises = [];
const contentMap = new Map();
for (const [provider, items] of itemsByProvider) {
fetchPromises.push(provider.fetchContent(plan, items).then(providerContent => {
for (const [itemId, content] of providerContent) {
contentMap.set(itemId, content);
}
}));
}
await Promise.all(fetchPromises);
// Attach content to items (mutates in place for efficiency)
this.attachContent(planItems, contentMap);
return planItems;
}
// Flatten nested planItems for processing
static flattenItems(items) {
const result = [];
const collect = (itemList) => {
for (const item of itemList) {
result.push(item);
if (item.children?.length) {
collect(item.children);
}
}
};
collect(items);
return result;
}
// Attach content to items recursively
static attachContent(items, contentMap) {
for (const item of items) {
const content = contentMap.get(item.id);
if (content) {
item.content = content;
}
if (item.children?.length) {
this.attachContent(item.children, contentMap);
}
}
}
// Convenience: Get the lessons provider for direct lesson operations
static getLessonsProvider() {
return this.providers.find(p => p.providerId === "lessons");
}
// ============================================
// Time Formatting Utilities
// ============================================
/**
* Format seconds as MM:SS string
* @param seconds - Number of seconds to format
* @returns Formatted time string (e.g., "3:45")
*/
static formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return mins + ":" + (secs < 10 ? "0" : "") + secs;
}
/**
* Calculate total duration of a section's children
* @param section - PlanItem with children
* @returns Total seconds from all children
*/
static getSectionDuration(section) {
let totalSeconds = 0;
section.children?.forEach((child) => {
totalSeconds += child.seconds || 0;
});
return totalSeconds;
}
}
//# sourceMappingURL=PlanHelper.js.map