@churchapps/helpers 1.2.6 → 1.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ApiHelper.js +3 -6
- package/dist/ApiHelper.js.map +1 -1
- package/dist/AppearanceHelper.js +1 -5
- package/dist/AppearanceHelper.js.map +1 -1
- package/dist/ArrayHelper.js +3 -7
- package/dist/ArrayHelper.js.map +1 -1
- package/dist/CommonEnvironmentHelper.js +1 -5
- package/dist/CommonEnvironmentHelper.js.map +1 -1
- package/dist/CurrencyHelper.js +1 -5
- package/dist/CurrencyHelper.js.map +1 -1
- package/dist/DateHelper.js +9 -49
- package/dist/DateHelper.js.map +1 -1
- package/dist/DonationHelper.js +1 -5
- package/dist/DonationHelper.js.map +1 -1
- package/dist/ErrorHelper.js +1 -5
- package/dist/ErrorHelper.js.map +1 -1
- package/dist/EventHelper.js +4 -8
- package/dist/EventHelper.js.map +1 -1
- package/dist/FileHelper.js +1 -5
- package/dist/FileHelper.js.map +1 -1
- package/dist/PersonHelper.js +3 -7
- package/dist/PersonHelper.js.map +1 -1
- package/dist/PlanHelper.d.ts +13 -0
- package/dist/PlanHelper.d.ts.map +1 -0
- package/dist/PlanHelper.js +85 -0
- package/dist/PlanHelper.js.map +1 -0
- package/dist/UniqueIdHelper.js +1 -5
- package/dist/UniqueIdHelper.js.map +1 -1
- package/dist/UserHelper.js +7 -11
- package/dist/UserHelper.js.map +1 -1
- package/dist/contentProviders/ContentProvider.d.ts +7 -0
- package/dist/contentProviders/ContentProvider.d.ts.map +1 -0
- package/dist/contentProviders/ContentProvider.js +2 -0
- package/dist/contentProviders/ContentProvider.js.map +1 -0
- package/dist/contentProviders/LessonsContentProvider.d.ts +66 -0
- package/dist/contentProviders/LessonsContentProvider.d.ts.map +1 -0
- package/dist/contentProviders/LessonsContentProvider.js +237 -0
- package/dist/contentProviders/LessonsContentProvider.js.map +1 -0
- package/dist/contentProviders/index.d.ts +3 -0
- package/dist/contentProviders/index.d.ts.map +1 -0
- package/dist/contentProviders/index.js +2 -0
- package/dist/contentProviders/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -44
- package/dist/index.js.map +1 -1
- package/dist/interfaces/Access.js +1 -2
- package/dist/interfaces/Attendance.js +1 -2
- package/dist/interfaces/Content.js +1 -2
- package/dist/interfaces/Doing.d.ts +35 -0
- package/dist/interfaces/Doing.d.ts.map +1 -1
- package/dist/interfaces/Doing.js +1 -2
- package/dist/interfaces/Donation.js +1 -5
- package/dist/interfaces/Donation.js.map +1 -1
- package/dist/interfaces/Error.js +1 -2
- package/dist/interfaces/Lessons.d.ts +4 -0
- package/dist/interfaces/Lessons.d.ts.map +1 -1
- package/dist/interfaces/Lessons.js +1 -2
- package/dist/interfaces/Lessons.js.map +1 -1
- package/dist/interfaces/Membership.js +1 -2
- package/dist/interfaces/Messaging.js +1 -2
- package/dist/interfaces/Permissions.js +1 -5
- package/dist/interfaces/Permissions.js.map +1 -1
- package/dist/interfaces/Reporting.js +1 -2
- package/dist/interfaces/UserContextInterface.js +1 -2
- package/dist/interfaces/index.js +12 -28
- package/dist/interfaces/index.js.map +1 -1
- package/package.json +9 -1
- package/src/PlanHelper.ts +109 -0
- package/src/contentProviders/ContentProvider.ts +15 -0
- package/src/contentProviders/LessonsContentProvider.ts +279 -0
- package/src/contentProviders/index.ts +2 -0
- package/src/index.ts +2 -1
- package/src/interfaces/Doing.ts +39 -0
- package/src/interfaces/Lessons.ts +6 -0
- package/tsconfig.json +2 -2
|
@@ -40,4 +40,8 @@ export interface VenueActionResponseInterface {
|
|
|
40
40
|
venueName?: string;
|
|
41
41
|
sections?: LessonSectionInterface[];
|
|
42
42
|
}
|
|
43
|
+
export interface VenuePlanItemsResponseInterface {
|
|
44
|
+
venueName?: string;
|
|
45
|
+
items?: import("./Doing").PlanItemInterface[];
|
|
46
|
+
}
|
|
43
47
|
//# sourceMappingURL=Lessons.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Lessons.d.ts","sourceRoot":"","sources":["../../src/interfaces/Lessons.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAGD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAGD,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAGD,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACrC"}
|
|
1
|
+
{"version":3,"file":"Lessons.d.ts","sourceRoot":"","sources":["../../src/interfaces/Lessons.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAGD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAGD,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAGD,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAGD,MAAM,WAAW,+BAA+B;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAC/C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Lessons.js","sourceRoot":"","sources":["../../src/interfaces/Lessons.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Lessons.js","sourceRoot":"","sources":["../../src/interfaces/Lessons.ts"],"names":[],"mappings":"AAAA,yDAAyD"}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Permissions = void 0;
|
|
4
|
-
class Permissions {
|
|
1
|
+
export class Permissions {
|
|
5
2
|
static attendanceApi = {
|
|
6
3
|
attendance: {
|
|
7
4
|
view: { api: "AttendanceApi", contentType: "Attendance", action: "View" },
|
|
@@ -90,5 +87,4 @@ class Permissions {
|
|
|
90
87
|
}
|
|
91
88
|
};
|
|
92
89
|
}
|
|
93
|
-
exports.Permissions = Permissions;
|
|
94
90
|
//# sourceMappingURL=Permissions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Permissions.js","sourceRoot":"","sources":["../../src/interfaces/Permissions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Permissions.js","sourceRoot":"","sources":["../../src/interfaces/Permissions.ts"],"names":[],"mappings":"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"}
|
package/dist/interfaces/index.js
CHANGED
|
@@ -1,30 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./Error"), exports);
|
|
18
|
-
__exportStar(require("./UserContextInterface"), exports);
|
|
19
|
-
__exportStar(require("./Permissions"), exports);
|
|
1
|
+
export * from "./Error";
|
|
2
|
+
export * from "./UserContextInterface";
|
|
3
|
+
export * from "./Permissions";
|
|
20
4
|
// API interfaces
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
5
|
+
export * from "./Access";
|
|
6
|
+
export * from "./Attendance";
|
|
7
|
+
export * from "./Content";
|
|
8
|
+
export * from "./Doing";
|
|
9
|
+
export * from "./Donation";
|
|
10
|
+
export * from "./Lessons";
|
|
11
|
+
export * from "./Membership";
|
|
12
|
+
export * from "./Messaging";
|
|
13
|
+
export * from "./Reporting";
|
|
30
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interfaces/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interfaces/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAE9B,iBAAiB;AACjB,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@churchapps/helpers",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"description": "Library of helper functions not specific to any one ChurchApps project or framework.",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
6
8
|
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
7
15
|
"scripts": {
|
|
8
16
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
17
|
"clean": "rimraf dist",
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { PlanInterface, PlanItemInterface, PlanItemContentInterface } from "./interfaces";
|
|
2
|
+
import type { ContentProviderInterface } from "./contentProviders/ContentProvider";
|
|
3
|
+
import { LessonsContentProvider } from "./contentProviders/LessonsContentProvider";
|
|
4
|
+
|
|
5
|
+
export class PlanHelper {
|
|
6
|
+
private static providers: ContentProviderInterface[] = [
|
|
7
|
+
new LessonsContentProvider()
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
// Register additional content providers
|
|
11
|
+
static registerProvider(provider: ContentProviderInterface): void {
|
|
12
|
+
// Avoid duplicates
|
|
13
|
+
if (!this.providers.find(p => p.providerId === provider.providerId)) {
|
|
14
|
+
this.providers.push(provider);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Replace a provider (useful for configuring with different URLs)
|
|
19
|
+
static replaceProvider(provider: ContentProviderInterface): void {
|
|
20
|
+
const index = this.providers.findIndex(p => p.providerId === provider.providerId);
|
|
21
|
+
if (index >= 0) {
|
|
22
|
+
this.providers[index] = provider;
|
|
23
|
+
} else {
|
|
24
|
+
this.providers.push(provider);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Main method: populate planItems with their content
|
|
29
|
+
static async populate(
|
|
30
|
+
plan: PlanInterface,
|
|
31
|
+
planItems: PlanItemInterface[]
|
|
32
|
+
): Promise<PlanItemInterface[]> {
|
|
33
|
+
// Flatten hierarchy to get all items
|
|
34
|
+
const allItems = this.flattenItems(planItems);
|
|
35
|
+
|
|
36
|
+
// Group items by provider
|
|
37
|
+
const itemsByProvider = new Map<ContentProviderInterface, PlanItemInterface[]>();
|
|
38
|
+
|
|
39
|
+
for (const item of allItems) {
|
|
40
|
+
for (const provider of this.providers) {
|
|
41
|
+
if (provider.canHandle(plan, item)) {
|
|
42
|
+
const existing = itemsByProvider.get(provider) || [];
|
|
43
|
+
existing.push(item);
|
|
44
|
+
itemsByProvider.set(provider, existing);
|
|
45
|
+
break; // First matching provider wins
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Fetch content from each provider in parallel
|
|
51
|
+
const fetchPromises: Promise<void>[] = [];
|
|
52
|
+
const contentMap = new Map<string, PlanItemContentInterface>();
|
|
53
|
+
|
|
54
|
+
for (const [provider, items] of itemsByProvider) {
|
|
55
|
+
fetchPromises.push(
|
|
56
|
+
provider.fetchContent(plan, items).then(providerContent => {
|
|
57
|
+
for (const [itemId, content] of providerContent) {
|
|
58
|
+
contentMap.set(itemId, content);
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await Promise.all(fetchPromises);
|
|
65
|
+
|
|
66
|
+
// Attach content to items (mutates in place for efficiency)
|
|
67
|
+
this.attachContent(planItems, contentMap);
|
|
68
|
+
|
|
69
|
+
return planItems;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Flatten nested planItems for processing
|
|
73
|
+
private static flattenItems(items: PlanItemInterface[]): PlanItemInterface[] {
|
|
74
|
+
const result: PlanItemInterface[] = [];
|
|
75
|
+
|
|
76
|
+
const collect = (itemList: PlanItemInterface[]) => {
|
|
77
|
+
for (const item of itemList) {
|
|
78
|
+
result.push(item);
|
|
79
|
+
if (item.children?.length) {
|
|
80
|
+
collect(item.children);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
collect(items);
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Attach content to items recursively
|
|
90
|
+
private static attachContent(
|
|
91
|
+
items: PlanItemInterface[],
|
|
92
|
+
contentMap: Map<string, PlanItemContentInterface>
|
|
93
|
+
): void {
|
|
94
|
+
for (const item of items) {
|
|
95
|
+
const content = contentMap.get(item.id);
|
|
96
|
+
if (content) {
|
|
97
|
+
item.content = content;
|
|
98
|
+
}
|
|
99
|
+
if (item.children?.length) {
|
|
100
|
+
this.attachContent(item.children, contentMap);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Convenience: Get the lessons provider for direct lesson operations
|
|
106
|
+
static getLessonsProvider(): LessonsContentProvider {
|
|
107
|
+
return this.providers.find(p => p.providerId === "lessons") as LessonsContentProvider;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PlanInterface, PlanItemInterface, PlanItemContentInterface } from "../interfaces";
|
|
2
|
+
|
|
3
|
+
export interface ContentProviderInterface {
|
|
4
|
+
// Unique identifier for this provider
|
|
5
|
+
readonly providerId: string;
|
|
6
|
+
|
|
7
|
+
// Check if this provider handles the given plan/planItem
|
|
8
|
+
canHandle(plan: PlanInterface, planItem: PlanItemInterface): boolean;
|
|
9
|
+
|
|
10
|
+
// Fetch content for multiple planItems (batch for efficiency)
|
|
11
|
+
fetchContent(
|
|
12
|
+
plan: PlanInterface,
|
|
13
|
+
planItems: PlanItemInterface[]
|
|
14
|
+
): Promise<Map<string, PlanItemContentInterface>>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { ApiHelper } from "../ApiHelper";
|
|
2
|
+
import type { PlanInterface, PlanItemInterface, PlanItemContentInterface, ExternalVenueRefInterface } from "../interfaces";
|
|
3
|
+
import type { VenuePlanItemsResponseInterface, VenueActionResponseInterface, LessonTreeInterface, LessonActionTreeInterface } from "../interfaces/Lessons";
|
|
4
|
+
import type { ContentProviderInterface } from "./ContentProvider";
|
|
5
|
+
|
|
6
|
+
export class LessonsContentProvider implements ContentProviderInterface {
|
|
7
|
+
readonly providerId = "lessons";
|
|
8
|
+
|
|
9
|
+
private lessonsUrl: string;
|
|
10
|
+
|
|
11
|
+
constructor(lessonsUrl: string = "https://lessons.church") {
|
|
12
|
+
this.lessonsUrl = lessonsUrl;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
canHandle(plan: PlanInterface, planItem: PlanItemInterface): boolean {
|
|
16
|
+
// Handles: action, addOn, lessonSection, and items with relatedId when plan has lesson
|
|
17
|
+
const lessonTypes = ["action", "addOn", "lessonSection"];
|
|
18
|
+
const hasLessonPlan = plan?.contentType === "venue" || plan?.contentType === "externalVenue";
|
|
19
|
+
|
|
20
|
+
if (lessonTypes.includes(planItem.itemType) && planItem.relatedId) return true;
|
|
21
|
+
if (planItem.itemType === "item" && planItem.relatedId && hasLessonPlan) return true;
|
|
22
|
+
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async fetchContent(
|
|
27
|
+
plan: PlanInterface,
|
|
28
|
+
planItems: PlanItemInterface[]
|
|
29
|
+
): Promise<Map<string, PlanItemContentInterface>> {
|
|
30
|
+
const result = new Map<string, PlanItemContentInterface>();
|
|
31
|
+
|
|
32
|
+
// Group by type for efficient batching
|
|
33
|
+
const actions = planItems.filter(p => p.itemType === "action" && p.relatedId);
|
|
34
|
+
const addOns = planItems.filter(p => p.itemType === "addOn" && p.relatedId);
|
|
35
|
+
const sections = planItems.filter(p =>
|
|
36
|
+
(p.itemType === "lessonSection" || p.itemType === "item") && p.relatedId
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const externalRef = this.getExternalRef(plan);
|
|
40
|
+
|
|
41
|
+
// Build embed URLs for each item
|
|
42
|
+
for (const item of actions) {
|
|
43
|
+
result.set(item.id, {
|
|
44
|
+
provider: this.providerId,
|
|
45
|
+
embedUrl: externalRef
|
|
46
|
+
? `${this.lessonsUrl}/embed/external/${externalRef.externalProviderId}/action/${item.relatedId}`
|
|
47
|
+
: `${this.lessonsUrl}/embed/action/${item.relatedId}`
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (const item of addOns) {
|
|
52
|
+
result.set(item.id, {
|
|
53
|
+
provider: this.providerId,
|
|
54
|
+
embedUrl: externalRef
|
|
55
|
+
? `${this.lessonsUrl}/embed/external/${externalRef.externalProviderId}/addon/${item.relatedId}`
|
|
56
|
+
: `${this.lessonsUrl}/embed/addon/${item.relatedId}`
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const item of sections) {
|
|
61
|
+
result.set(item.id, {
|
|
62
|
+
provider: this.providerId,
|
|
63
|
+
embedUrl: externalRef
|
|
64
|
+
? `${this.lessonsUrl}/embed/external/${externalRef.externalProviderId}/section/${item.relatedId}`
|
|
65
|
+
: `${this.lessonsUrl}/embed/section/${item.relatedId}`
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ============================================
|
|
73
|
+
// Plan/Lesson Association Methods
|
|
74
|
+
// ============================================
|
|
75
|
+
|
|
76
|
+
hasAssociatedLesson(plan: PlanInterface): boolean {
|
|
77
|
+
return (plan?.contentType === "venue" || plan?.contentType === "externalVenue") && !!plan?.contentId;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
isExternalVenue(plan: PlanInterface): boolean {
|
|
81
|
+
return plan?.contentType === "externalVenue";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getExternalRef(plan: PlanInterface): ExternalVenueRefInterface | null {
|
|
85
|
+
if (!this.isExternalVenue(plan) || !plan?.contentId) return null;
|
|
86
|
+
try {
|
|
87
|
+
return JSON.parse(plan.contentId);
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getVenueId(plan: PlanInterface): string | null {
|
|
94
|
+
if (!this.hasAssociatedLesson(plan)) return null;
|
|
95
|
+
if (this.isExternalVenue(plan)) {
|
|
96
|
+
return this.getExternalRef(plan)?.venueId || null;
|
|
97
|
+
}
|
|
98
|
+
return plan.contentId || null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ============================================
|
|
102
|
+
// API Fetch Methods
|
|
103
|
+
// ============================================
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Fetch venue plan items - the basic hierarchical structure
|
|
107
|
+
* Returns: headers with children (sections), but sections don't have their actions
|
|
108
|
+
* Use this for preview mode display
|
|
109
|
+
*/
|
|
110
|
+
async fetchVenuePlanItems(plan: PlanInterface): Promise<VenuePlanItemsResponseInterface> {
|
|
111
|
+
if (!this.hasAssociatedLesson(plan)) return { items: [] };
|
|
112
|
+
const externalRef = this.getExternalRef(plan);
|
|
113
|
+
if (externalRef) {
|
|
114
|
+
return await ApiHelper.getAnonymous(
|
|
115
|
+
`/externalProviders/${externalRef.externalProviderId}/venue/${externalRef.venueId}/planItems`,
|
|
116
|
+
"LessonsApi"
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return await ApiHelper.getAnonymous(`/venues/public/planItems/${plan.contentId}`, "LessonsApi");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Fetch venue actions - sections with their full action lists
|
|
124
|
+
* Use this for action selection dialogs and full expansion
|
|
125
|
+
*/
|
|
126
|
+
async fetchVenueActions(plan: PlanInterface): Promise<VenueActionResponseInterface> {
|
|
127
|
+
if (!this.hasAssociatedLesson(plan)) return { sections: [] };
|
|
128
|
+
const externalRef = this.getExternalRef(plan);
|
|
129
|
+
if (externalRef) {
|
|
130
|
+
return await ApiHelper.getAnonymous(
|
|
131
|
+
`/externalProviders/${externalRef.externalProviderId}/venue/${externalRef.venueId}/actions`,
|
|
132
|
+
"LessonsApi"
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return await ApiHelper.getAnonymous(`/venues/public/actions/${plan.contentId}`, "LessonsApi");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Fetch the full lesson tree for browsing (programs -> studies -> lessons -> venues)
|
|
140
|
+
*/
|
|
141
|
+
async fetchLessonTree(): Promise<LessonTreeInterface> {
|
|
142
|
+
return await ApiHelper.getAnonymous("/lessons/public/tree", "LessonsApi");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Fetch the action tree for action selection (includes actions in each venue section)
|
|
147
|
+
*/
|
|
148
|
+
async fetchActionTree(): Promise<LessonActionTreeInterface> {
|
|
149
|
+
return await ApiHelper.getAnonymous("/lessons/public/actionTree", "LessonsApi");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ============================================
|
|
153
|
+
// Display List Methods (for preview/display without full actions)
|
|
154
|
+
// ============================================
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get the display list - hierarchical items suitable for preview
|
|
158
|
+
* Structure: headers -> sections (no actions expanded)
|
|
159
|
+
* This is the lightweight version for showing what a lesson contains
|
|
160
|
+
*/
|
|
161
|
+
async getDisplayList(plan: PlanInterface): Promise<PlanItemInterface[]> {
|
|
162
|
+
const response = await this.fetchVenuePlanItems(plan);
|
|
163
|
+
return response?.items || [];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get display list with sections only (strip actions from children)
|
|
168
|
+
* Use this when importing a lesson as editable plan items
|
|
169
|
+
*/
|
|
170
|
+
async getSectionsOnlyList(plan: PlanInterface): Promise<PlanItemInterface[]> {
|
|
171
|
+
const response = await this.fetchVenuePlanItems(plan);
|
|
172
|
+
if (!response?.items) return [];
|
|
173
|
+
|
|
174
|
+
return response.items.map(item => ({
|
|
175
|
+
...item,
|
|
176
|
+
children: item.children?.map(section => ({
|
|
177
|
+
...section,
|
|
178
|
+
children: undefined // Remove actions from sections
|
|
179
|
+
}))
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ============================================
|
|
184
|
+
// Expanded List Methods (with full actions)
|
|
185
|
+
// ============================================
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get the fully expanded list - items with all actions populated in sections
|
|
189
|
+
* Merges fetchVenuePlanItems with fetchVenueActions to get complete data
|
|
190
|
+
*/
|
|
191
|
+
async getExpandedList(plan: PlanInterface): Promise<PlanItemInterface[]> {
|
|
192
|
+
const [planItemsResponse, actionsResponse] = await Promise.all([
|
|
193
|
+
this.fetchVenuePlanItems(plan),
|
|
194
|
+
this.fetchVenueActions(plan)
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
if (!planItemsResponse?.items) return [];
|
|
198
|
+
|
|
199
|
+
// Create a map of section ID -> actions
|
|
200
|
+
const sectionActionsMap = new Map<string, PlanItemInterface[]>();
|
|
201
|
+
if (actionsResponse?.sections) {
|
|
202
|
+
for (const section of actionsResponse.sections) {
|
|
203
|
+
if (section.id && section.actions) {
|
|
204
|
+
sectionActionsMap.set(section.id, section.actions.map(action => ({
|
|
205
|
+
itemType: "action",
|
|
206
|
+
relatedId: action.id,
|
|
207
|
+
label: action.name,
|
|
208
|
+
description: action.actionType,
|
|
209
|
+
seconds: action.seconds
|
|
210
|
+
})));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Recursively expand sections with their actions
|
|
216
|
+
const expandItem = (item: PlanItemInterface): PlanItemInterface => {
|
|
217
|
+
if (!item.children) return item;
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
...item,
|
|
221
|
+
children: item.children.map(child => {
|
|
222
|
+
// If this is a section (has relatedId), try to get its actions
|
|
223
|
+
if (child.relatedId && sectionActionsMap.has(child.relatedId)) {
|
|
224
|
+
return {
|
|
225
|
+
...child,
|
|
226
|
+
children: sectionActionsMap.get(child.relatedId)
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// Otherwise recursively process
|
|
230
|
+
return expandItem(child);
|
|
231
|
+
})
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
return planItemsResponse.items.map(expandItem);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ============================================
|
|
239
|
+
// Embed URL Helpers
|
|
240
|
+
// ============================================
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get embed URL for an action
|
|
244
|
+
*/
|
|
245
|
+
getActionEmbedUrl(actionId: string, externalProviderId?: string): string {
|
|
246
|
+
if (externalProviderId) {
|
|
247
|
+
return `${this.lessonsUrl}/embed/external/${externalProviderId}/action/${actionId}`;
|
|
248
|
+
}
|
|
249
|
+
return `${this.lessonsUrl}/embed/action/${actionId}`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get embed URL for an add-on
|
|
254
|
+
*/
|
|
255
|
+
getAddOnEmbedUrl(addOnId: string, externalProviderId?: string): string {
|
|
256
|
+
if (externalProviderId) {
|
|
257
|
+
return `${this.lessonsUrl}/embed/external/${externalProviderId}/addon/${addOnId}`;
|
|
258
|
+
}
|
|
259
|
+
return `${this.lessonsUrl}/embed/addon/${addOnId}`;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Get embed URL for a section
|
|
264
|
+
*/
|
|
265
|
+
getSectionEmbedUrl(sectionId: string, externalProviderId?: string): string {
|
|
266
|
+
if (externalProviderId) {
|
|
267
|
+
return `${this.lessonsUrl}/embed/external/${externalProviderId}/section/${sectionId}`;
|
|
268
|
+
}
|
|
269
|
+
return `${this.lessonsUrl}/embed/section/${sectionId}`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get the external provider ID from a plan (if external)
|
|
274
|
+
*/
|
|
275
|
+
getExternalProviderId(plan: PlanInterface): string | null {
|
|
276
|
+
const externalRef = this.getExternalRef(plan);
|
|
277
|
+
return externalRef?.externalProviderId || null;
|
|
278
|
+
}
|
|
279
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,4 +12,5 @@ export { FileHelper } from "./FileHelper";
|
|
|
12
12
|
export { PersonHelper } from "./PersonHelper";
|
|
13
13
|
export { UserHelper } from "./UserHelper";
|
|
14
14
|
export { UniqueIdHelper } from "./UniqueIdHelper";
|
|
15
|
-
|
|
15
|
+
export { PlanHelper } from "./PlanHelper";
|
|
16
|
+
export * from "./contentProviders";
|
package/src/interfaces/Doing.ts
CHANGED
|
@@ -93,3 +93,42 @@ export interface BlockoutDateInterface {
|
|
|
93
93
|
startDate?: Date;
|
|
94
94
|
endDate?: Date;
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
export interface ExternalVenueRefInterface {
|
|
98
|
+
externalProviderId: string;
|
|
99
|
+
programId: string;
|
|
100
|
+
studyId: string;
|
|
101
|
+
lessonId: string;
|
|
102
|
+
venueId: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface ContentFileInterface {
|
|
106
|
+
id?: string;
|
|
107
|
+
name?: string;
|
|
108
|
+
url?: string;
|
|
109
|
+
fileType?: string; // "image", "video", "audio", "document"
|
|
110
|
+
seconds?: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface PlanItemContentInterface {
|
|
114
|
+
provider: string; // "lessons", "songs", "media", "church"
|
|
115
|
+
embedUrl?: string; // URL for iframe embed
|
|
116
|
+
html?: string; // Raw HTML content
|
|
117
|
+
files?: ContentFileInterface[];
|
|
118
|
+
metadata?: Record<string, any>; // Provider-specific data
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface PlanItemInterface {
|
|
122
|
+
id?: string;
|
|
123
|
+
planId?: string;
|
|
124
|
+
parentId?: string;
|
|
125
|
+
sort?: number;
|
|
126
|
+
itemType?: string; // "header", "song", "action", "addOn", "lessonSection", "item"
|
|
127
|
+
relatedId?: string;
|
|
128
|
+
label?: string;
|
|
129
|
+
description?: string;
|
|
130
|
+
seconds?: number;
|
|
131
|
+
link?: string;
|
|
132
|
+
children?: PlanItemInterface[];
|
|
133
|
+
content?: PlanItemContentInterface; // Populated by PlanHelper
|
|
134
|
+
}
|
|
@@ -53,3 +53,9 @@ export interface VenueActionResponseInterface {
|
|
|
53
53
|
venueName?: string;
|
|
54
54
|
sections?: LessonSectionInterface[];
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
// Response from /venues/public/planItems/{id}
|
|
58
|
+
export interface VenuePlanItemsResponseInterface {
|
|
59
|
+
venueName?: string;
|
|
60
|
+
items?: import("./Doing").PlanItemInterface[];
|
|
61
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"allowSyntheticDefaultImports": true,
|
|
17
17
|
"strict": false,
|
|
18
18
|
"forceConsistentCasingInFileNames": true,
|
|
19
|
-
"module": "
|
|
20
|
-
"moduleResolution": "
|
|
19
|
+
"module": "ESNext",
|
|
20
|
+
"moduleResolution": "bundler",
|
|
21
21
|
"resolveJsonModule": true,
|
|
22
22
|
"isolatedModules": true,
|
|
23
23
|
"jsx": "react-jsx",
|