@fayz-ai/plugin-courses 0.2.4 → 0.8.0
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/README.md +1 -1
- package/dist/dashboardWidgets.d.ts +8 -1
- package/dist/dashboardWidgets.d.ts.map +1 -1
- package/dist/index.cjs +36 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -27
- package/dist/index.js.map +1 -1
- package/package.json +9 -6
- package/src/dashboardWidgets.tsx +18 -5
- package/src/index.ts +47 -20
package/package.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fayz-ai/plugin-courses",
|
|
3
|
-
"
|
|
3
|
+
"fayz": {
|
|
4
|
+
"status": "preview"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.8.0",
|
|
4
7
|
"description": "[experimental] Fayz SDK — courses admin management plugin",
|
|
5
8
|
"type": "module",
|
|
6
9
|
"main": "./dist/index.cjs",
|
|
@@ -23,12 +26,12 @@
|
|
|
23
26
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
24
27
|
},
|
|
25
28
|
"dependencies": {
|
|
26
|
-
"@tanstack/react-table": "^8.20.0",
|
|
27
29
|
"lucide-react": "^0.400.0",
|
|
28
|
-
"@
|
|
29
|
-
"@fayz-ai/
|
|
30
|
-
"@fayz-ai/
|
|
31
|
-
"@fayz-ai/courses": "^0.
|
|
30
|
+
"@tanstack/react-table": "^8.20.0",
|
|
31
|
+
"@fayz-ai/core": "^0.8.0",
|
|
32
|
+
"@fayz-ai/ui": "^0.8.0",
|
|
33
|
+
"@fayz-ai/courses": "^0.8.0",
|
|
34
|
+
"@fayz-ai/saas": "^0.8.0"
|
|
32
35
|
},
|
|
33
36
|
"devDependencies": {
|
|
34
37
|
"@types/react": "^18.3.0",
|
package/src/dashboardWidgets.tsx
CHANGED
|
@@ -41,11 +41,24 @@ function FeesKpi() {
|
|
|
41
41
|
return <KpiCard label={t('courses.kpi.fees') || 'Platform fees'} icon="Percent" loading={!s} value={s ? formatMoney(s.platformFeeTotal, s.currency) : undefined} />
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
/** Commerce KPIs are contributed only for the modules the host opted into —
|
|
45
|
+
* a host embedding courses as a lightweight members feature must not get
|
|
46
|
+
* revenue/MRR cards broadcast onto its home dashboard (FAY-1247 rule). */
|
|
47
|
+
export function createCoursesDashboardWidgets(
|
|
48
|
+
modules: { sales?: boolean; subscriptions?: boolean; financial?: boolean } = {},
|
|
49
|
+
): DashboardWidgetDef[] {
|
|
45
50
|
return [
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
...(modules.sales
|
|
52
|
+
? [
|
|
53
|
+
defineKpiWidget({ id: 'courses.kpi.revenue', title: 'courses.kpi.revenue', domain: 'courses', defaultOrder: 0, component: RevenueKpi }),
|
|
54
|
+
defineKpiWidget({ id: 'courses.kpi.sales', title: 'courses.kpi.sales', domain: 'courses', defaultOrder: 1, component: SalesKpi }),
|
|
55
|
+
]
|
|
56
|
+
: []),
|
|
57
|
+
...(modules.subscriptions
|
|
58
|
+
? [defineKpiWidget({ id: 'courses.kpi.mrr', title: 'courses.kpi.mrr', domain: 'courses', defaultOrder: 2, component: MrrKpi })]
|
|
59
|
+
: []),
|
|
60
|
+
...(modules.financial
|
|
61
|
+
? [defineKpiWidget({ id: 'courses.kpi.fees', title: 'courses.kpi.fees', domain: 'courses', defaultOrder: 3, component: FeesKpi })]
|
|
62
|
+
: []),
|
|
50
63
|
]
|
|
51
64
|
}
|
package/src/index.ts
CHANGED
|
@@ -35,6 +35,20 @@ export interface CoursesPluginOptions {
|
|
|
35
35
|
navLabel?: string
|
|
36
36
|
scope?: PluginScope
|
|
37
37
|
verticalId?: VerticalId
|
|
38
|
+
/**
|
|
39
|
+
* Commerce-vertical modules — ALL OFF by default (the one architectural
|
|
40
|
+
* rule: shared-surface contributions are opt-in, never broadcast — FAY-1247).
|
|
41
|
+
* course-admin (the vertical owner) enables everything via its PluginRef
|
|
42
|
+
* config; a host embedding courses as a lightweight members feature (e.g.
|
|
43
|
+
* agency-os's "Memberships") gets only the base nav entry + editor.
|
|
44
|
+
*/
|
|
45
|
+
modules?: {
|
|
46
|
+
membersArea?: boolean
|
|
47
|
+
sales?: boolean
|
|
48
|
+
subscriptions?: boolean
|
|
49
|
+
financial?: boolean
|
|
50
|
+
reports?: boolean
|
|
51
|
+
}
|
|
38
52
|
}
|
|
39
53
|
|
|
40
54
|
const asComp = (c: unknown) => c as React.ComponentType<unknown>
|
|
@@ -56,6 +70,30 @@ export function createCoursesPlugin(options?: CoursesPluginOptions): PluginManif
|
|
|
56
70
|
|
|
57
71
|
const base = options?.navPosition ?? 1
|
|
58
72
|
const section = options?.navSection ?? 'main'
|
|
73
|
+
const modules = options?.modules ?? {}
|
|
74
|
+
|
|
75
|
+
// Opt-in nav/routes per module. Position offsets stay stable relative to the
|
|
76
|
+
// enabled set so hosts control exactly where the block sits.
|
|
77
|
+
const navigation = [
|
|
78
|
+
{ section, position: base, label: options?.navLabel ?? 'Courses', route: '/courses', icon: 'BookOpen', permission: read('courses') },
|
|
79
|
+
...(modules.membersArea ? [{ section, position: base + 1, label: 'Members area', route: '/courses/members', icon: 'GraduationCap', permission: read('courses') }] : []),
|
|
80
|
+
...(modules.sales ? [{ section, position: base + 2, label: 'Sales', route: '/courses/sales', icon: 'TrendingUp', permission: read('courses.sales') }] : []),
|
|
81
|
+
...(modules.subscriptions ? [{ section, position: base + 3, label: 'Subscriptions', route: '/courses/subscriptions', icon: 'Repeat', permission: read('courses.sales') }] : []),
|
|
82
|
+
...(modules.financial ? [{ section, position: base + 4, label: 'Financial', route: '/courses/financial', icon: 'CreditCard', permission: read('courses.finance') }] : []),
|
|
83
|
+
...(modules.reports ? [{ section, position: base + 5, label: 'Reports', route: '/courses/reports', icon: 'BarChart3', permission: read('courses.sales') }] : []),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
const routes = [
|
|
87
|
+
// Static segments outscore the `:id` param in the saas router, so these
|
|
88
|
+
// resolve before the editor route (AdminShell sorts by routeScore).
|
|
89
|
+
{ path: '/courses', component: asComp(CoursesListPage), permission: read('courses') },
|
|
90
|
+
...(modules.membersArea ? [{ path: '/courses/members', component: asComp(MembersAreaPage), permission: read('courses') }] : []),
|
|
91
|
+
...(modules.sales ? [{ path: '/courses/sales', component: asComp(SalesPage), permission: read('courses.sales') }] : []),
|
|
92
|
+
...(modules.subscriptions ? [{ path: '/courses/subscriptions', component: asComp(SubscriptionsPage), permission: read('courses.sales') }] : []),
|
|
93
|
+
...(modules.financial ? [{ path: '/courses/financial', component: asComp(FinancialPage), permission: read('courses.finance') }] : []),
|
|
94
|
+
...(modules.reports ? [{ path: '/courses/reports', component: asComp(ReportsPage), permission: read('courses.sales') }] : []),
|
|
95
|
+
{ path: '/courses/:id', component: asComp(CourseEditorPage) },
|
|
96
|
+
]
|
|
59
97
|
|
|
60
98
|
return {
|
|
61
99
|
id: 'courses',
|
|
@@ -64,6 +102,10 @@ export function createCoursesPlugin(options?: CoursesPluginOptions): PluginManif
|
|
|
64
102
|
version: '1.0.0',
|
|
65
103
|
scope: options?.scope ?? 'vertical',
|
|
66
104
|
verticalId: options?.verticalId,
|
|
105
|
+
// LMS is its own business model with opt-in commerce modules
|
|
106
|
+
// (members/sales/subscriptions — see modules.* below) — targets the
|
|
107
|
+
// saas/admin Panel world rather than the ecommerce storefront.
|
|
108
|
+
scaffolds: ['saas'],
|
|
67
109
|
defaultEnabled: true,
|
|
68
110
|
dependencies: [],
|
|
69
111
|
declaredFeatures: [
|
|
@@ -71,27 +113,12 @@ export function createCoursesPlugin(options?: CoursesPluginOptions): PluginManif
|
|
|
71
113
|
{ id: 'courses.sales', label: 'Sales', group: 'Courses' },
|
|
72
114
|
{ id: 'courses.finance', label: 'Financial', group: 'Courses' },
|
|
73
115
|
],
|
|
74
|
-
navigation
|
|
75
|
-
|
|
76
|
-
{ section, position: base + 1, label: 'Members area', route: '/courses/members', icon: 'GraduationCap', permission: read('courses') },
|
|
77
|
-
{ section, position: base + 2, label: 'Sales', route: '/courses/sales', icon: 'TrendingUp', permission: read('courses.sales') },
|
|
78
|
-
{ section, position: base + 3, label: 'Subscriptions', route: '/courses/subscriptions', icon: 'Repeat', permission: read('courses.sales') },
|
|
79
|
-
{ section, position: base + 4, label: 'Financial', route: '/courses/financial', icon: 'CreditCard', permission: read('courses.finance') },
|
|
80
|
-
{ section, position: base + 5, label: 'Reports', route: '/courses/reports', icon: 'BarChart3', permission: read('courses.sales') },
|
|
81
|
-
],
|
|
82
|
-
routes: [
|
|
83
|
-
// Static segments outscore the `:id` param in the saas router, so these
|
|
84
|
-
// resolve before the editor route (AdminShell sorts by routeScore).
|
|
85
|
-
{ path: '/courses', component: asComp(CoursesListPage), permission: read('courses') },
|
|
86
|
-
{ path: '/courses/members', component: asComp(MembersAreaPage), permission: read('courses') },
|
|
87
|
-
{ path: '/courses/sales', component: asComp(SalesPage), permission: read('courses.sales') },
|
|
88
|
-
{ path: '/courses/subscriptions', component: asComp(SubscriptionsPage), permission: read('courses.sales') },
|
|
89
|
-
{ path: '/courses/financial', component: asComp(FinancialPage), permission: read('courses.finance') },
|
|
90
|
-
{ path: '/courses/reports', component: asComp(ReportsPage), permission: read('courses.sales') },
|
|
91
|
-
{ path: '/courses/:id', component: asComp(CourseEditorPage) },
|
|
92
|
-
],
|
|
116
|
+
navigation,
|
|
117
|
+
routes,
|
|
93
118
|
widgets: [],
|
|
94
|
-
|
|
119
|
+
// Commerce KPIs on the shared 'home' surface follow the same opt-in rule:
|
|
120
|
+
// no module enabled → no widgets broadcast into a host's dashboard.
|
|
121
|
+
dashboardWidgets: createCoursesDashboardWidgets(modules),
|
|
95
122
|
connectors: [createStripeConnector()],
|
|
96
123
|
settings: [
|
|
97
124
|
{ id: 'courses', label: 'Courses', icon: 'BookOpen', component: asComp(CoursesSettingsTab), order: 20, permission: read('courses') },
|