@odla-ai/chapter 0.17.0 → 0.19.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.
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { CrmClient, Crm } from '@odla-ai/crm';
3
+ import { CrmClient, Crm, CrmRecord } from '@odla-ai/crm';
4
4
 
5
5
  /** What each admin section receives. `client` is a CrmClient bound to the
6
6
  * signed-in admin's bearer token; `navigate` switches sections. */
@@ -70,29 +70,40 @@ interface CollectionSectionOptions {
70
70
  id?: string;
71
71
  /** Nav label. Defaults to the type's plural label from the CRM config. */
72
72
  label?: string;
73
+ /** Show the lifecycle action panel (role change / approve / refund) on an open
74
+ * record — for application-backed people. Default `true` for `type: "person"`,
75
+ * `false` otherwise (a `deal`/`investment` has no approve/refund). */
76
+ lifecycle?: boolean;
77
+ /** Role ladder for the role selector. Default `["provisional","member","admin"]`
78
+ * — pass your `chapter.auth.ladder` if you use a custom ladder. */
79
+ roles?: readonly string[];
73
80
  }
74
81
  /**
75
82
  * Build a CRM collection admin section for ANY declared record type: a
76
83
  * server-driven records table plus a facet-composed detail drawer (fields,
77
- * pipeline stage, tags) over the token-bound CrmClient. This is the generic kit
78
- * call it once per collection a site runs (members, deals, investments), and each
79
- * renders with the same UX. Every action goes through `/api/crm/*`, never a direct
80
- * db write, so the CRM invariants hold.
84
+ * pipeline stage, tags) over the token-bound CrmClient, and for people a
85
+ * lifecycle action panel (role change, approve, refund) wired to the
86
+ * `/api/admin/*` routes. This is the generic kit call it once per collection a
87
+ * site runs (members, deals, investments), and each renders with the same UX.
88
+ * CRM edits go through `/api/crm/*` and lifecycle actions through `/api/admin/*`,
89
+ * never a direct db write, so the invariants hold.
81
90
  */
82
91
  declare function collectionSection(options: CollectionSectionOptions): AdminSection;
83
92
  /**
84
93
  * Build the People/CRM admin section — {@link collectionSection} preset to the
85
- * `person` type. Kept as a convenience; new collections use `collectionSection`.
94
+ * `person` type (so the lifecycle actions are on). New collections use
95
+ * `collectionSection`.
86
96
  */
87
- declare function peopleSection(options: PeopleSectionOptions): AdminSection;
97
+ declare function peopleSection(options: PeopleSectionOptions & {
98
+ roles?: readonly string[];
99
+ }): AdminSection;
88
100
 
89
101
  /** Options for {@link dashboardSection}. */
90
102
  interface DashboardSectionOptions {
91
103
  id?: string;
92
104
  label?: string;
93
105
  }
94
- /** Build the Dashboard admin section over `GET /api/admin/dashboard`. Drop the
95
- * result into `ChapterAdmin`'s `sections`. */
106
+ /** Build the Dashboard admin section over `GET /api/admin/dashboard`. */
96
107
  declare function dashboardSection(options?: DashboardSectionOptions): AdminSection;
97
108
 
98
109
  /** Options for {@link billingSection}. */
@@ -122,6 +133,28 @@ interface MeetingsSectionOptions {
122
133
  * `GET /api/admin/meetings`, with reschedule/cancel actions. */
123
134
  declare function meetingsSection(options?: MeetingsSectionOptions): AdminSection;
124
135
 
136
+ /** Options for {@link availabilitySection}. */
137
+ interface AvailabilitySectionOptions {
138
+ id?: string;
139
+ label?: string;
140
+ }
141
+ /** Build the Availability admin section: the booking-rules editor over
142
+ * `GET/PUT /api/admin/scheduling`, with field-keyed validation surfaced inline. */
143
+ declare function availabilitySection(options?: AvailabilitySectionOptions): AdminSection;
144
+
145
+ /** Props for {@link RecordActions}. */
146
+ interface RecordActionsProps {
147
+ getToken: () => Promise<string | null>;
148
+ record: CrmRecord;
149
+ /** The role ladder offered by the role selector. Default provisional→admin. */
150
+ roles: readonly string[];
151
+ /** Called after any action mutates state, so the caller can refresh. */
152
+ onChanged: () => void;
153
+ }
154
+ /** The role/approve/refund controls for one person record. Renders only the
155
+ * actions the record supports. */
156
+ declare function RecordActions({ getToken, record, roles, onChanged }: RecordActionsProps): react.JSX.Element | null;
157
+
125
158
  /** Fetch a JSON `/api/admin/*` route with the admin bearer token. Throws on a
126
159
  * non-2xx (the body's `error`, else the status). */
127
160
  declare function adminFetch<T = unknown>(getToken: () => Promise<string | null>, path: string, init?: RequestInit): Promise<T>;
@@ -137,4 +170,22 @@ interface AdminResource<T> {
137
170
  * or when `path` changes. */
138
171
  declare function useAdminResource<T = unknown>(getToken: () => Promise<string | null>, path: string): AdminResource<T>;
139
172
 
140
- export { type AdminResource, type AdminSection, type AdminSectionContext, type BillingSectionOptions, ChapterAdmin, type ChapterAdminProps, type CollectionSectionOptions, type DashboardSectionOptions, type EmailSectionOptions, type MeetingsSectionOptions, type PeopleSectionOptions, adminFetch, billingSection, collectionSection, dashboardSection, emailSection, meetingsSection, peopleSection, useAdminResource };
173
+ /** The centered content column every admin section renders into. */
174
+ declare function AdminPage({ children }: {
175
+ children: ReactNode;
176
+ }): react.JSX.Element;
177
+ /** An odla-ui `.panel` card with an optional heading + trailing actions. */
178
+ declare function Panel({ title, actions, children }: {
179
+ title?: ReactNode;
180
+ actions?: ReactNode;
181
+ children: ReactNode;
182
+ }): react.JSX.Element;
183
+ /** A loud banner when the odla-ui theme token layer is missing — the silent-and-
184
+ * total failure S&S flagged. Renders nothing when the theme is present. */
185
+ declare function ThemeWarning(): react.JSX.Element | null;
186
+ /** A centered status line for loading / empty / error states. */
187
+ declare function AdminNote({ children }: {
188
+ children: ReactNode;
189
+ }): react.JSX.Element;
190
+
191
+ export { AdminNote, AdminPage, type AdminResource, type AdminSection, type AdminSectionContext, type AvailabilitySectionOptions, type BillingSectionOptions, ChapterAdmin, type ChapterAdminProps, type CollectionSectionOptions, type DashboardSectionOptions, type EmailSectionOptions, type MeetingsSectionOptions, Panel, type PeopleSectionOptions, RecordActions, type RecordActionsProps, ThemeWarning, adminFetch, availabilitySection, billingSection, collectionSection, dashboardSection, emailSection, meetingsSection, peopleSection, useAdminResource };
@@ -1,6 +1,12 @@
1
1
  import {
2
+ AdminNote,
3
+ AdminPage,
2
4
  ChapterAdmin,
5
+ Panel,
6
+ RecordActions,
7
+ ThemeWarning,
3
8
  adminFetch,
9
+ availabilitySection,
4
10
  billingSection,
5
11
  collectionSection,
6
12
  dashboardSection,
@@ -8,10 +14,16 @@ import {
8
14
  meetingsSection,
9
15
  peopleSection,
10
16
  useAdminResource
11
- } from "../../chunk-HB2HUJCW.js";
17
+ } from "../../chunk-D3QMK3ED.js";
12
18
  export {
19
+ AdminNote,
20
+ AdminPage,
13
21
  ChapterAdmin,
22
+ Panel,
23
+ RecordActions,
24
+ ThemeWarning,
14
25
  adminFetch,
26
+ availabilitySection,
15
27
  billingSection,
16
28
  collectionSection,
17
29
  dashboardSection,
@@ -1,4 +1,4 @@
1
- export { AdminResource, AdminSection, AdminSectionContext, BillingSectionOptions, ChapterAdmin, ChapterAdminProps, CollectionSectionOptions, DashboardSectionOptions, EmailSectionOptions, MeetingsSectionOptions, PeopleSectionOptions, adminFetch, billingSection, collectionSection, dashboardSection, emailSection, meetingsSection, peopleSection, useAdminResource } from './admin/index.js';
1
+ export { AdminNote, AdminPage, AdminResource, AdminSection, AdminSectionContext, AvailabilitySectionOptions, BillingSectionOptions, ChapterAdmin, ChapterAdminProps, CollectionSectionOptions, DashboardSectionOptions, EmailSectionOptions, MeetingsSectionOptions, Panel, PeopleSectionOptions, RecordActions, RecordActionsProps, ThemeWarning, adminFetch, availabilitySection, billingSection, collectionSection, dashboardSection, emailSection, meetingsSection, peopleSection, useAdminResource } from './admin/index.js';
2
2
  export { ApiFn, BrandStyle, BrandStyleProps, JoinConfig, JoinIsland, JoinIslandProps, MembersArea, MembersAreaProps, PaymentStep, PaymentStepProps, RescheduleProps, Rescheduler, Slot, SlotPicker, SlotPickerClasses, SlotPickerProps, dayKey, dayLabel, fmtDate, fmtMoney, fullLabel, groupSlotsByDay, timeLabel, tzShort } from './member/index.js';
3
3
  import 'react';
4
4
  import '@odla-ai/crm';
package/dist/ui/index.js CHANGED
@@ -13,10 +13,16 @@ import {
13
13
  groupSlotsByDay,
14
14
  timeLabel,
15
15
  tzShort
16
- } from "../chunk-ZCZK6QLC.js";
16
+ } from "../chunk-GWY2ZTN7.js";
17
17
  import {
18
+ AdminNote,
19
+ AdminPage,
18
20
  ChapterAdmin,
21
+ Panel,
22
+ RecordActions,
23
+ ThemeWarning,
19
24
  adminFetch,
25
+ availabilitySection,
20
26
  billingSection,
21
27
  collectionSection,
22
28
  dashboardSection,
@@ -24,16 +30,22 @@ import {
24
30
  meetingsSection,
25
31
  peopleSection,
26
32
  useAdminResource
27
- } from "../chunk-HB2HUJCW.js";
33
+ } from "../chunk-D3QMK3ED.js";
28
34
  export {
35
+ AdminNote,
36
+ AdminPage,
29
37
  BrandStyle,
30
38
  ChapterAdmin,
31
39
  JoinIsland,
32
40
  MembersArea,
41
+ Panel,
33
42
  PaymentStep,
43
+ RecordActions,
34
44
  Rescheduler,
35
45
  SlotPicker,
46
+ ThemeWarning,
36
47
  adminFetch,
48
+ availabilitySection,
37
49
  billingSection,
38
50
  collectionSection,
39
51
  dashboardSection,
@@ -124,8 +124,13 @@ declare function PaymentStep(props: PaymentStepProps): react.JSX.Element;
124
124
  /** Brand tokens that theme the site: palette, fonts, wordmark, nav, logos. */
125
125
  interface ChapterBrand {
126
126
  /** Palette overrides written into styles.css :root (e.g. `{ moss: "#2F3E34" }`
127
- * or `--ui-*` token names). */
127
+ * or `--ui-*` token names). Applies in BOTH light and dark unless overridden
128
+ * by {@link paletteDark}. */
128
129
  palette?: Record<string, string>;
130
+ /** Dark-mode palette overrides. Same shape as {@link palette}; emitted under
131
+ * `:root[data-theme="dark"]` and `@media (prefers-color-scheme: dark)`, so a
132
+ * site brands both modes. */
133
+ paletteDark?: Record<string, string>;
129
134
  fonts?: {
130
135
  display?: string;
131
136
  body?: string;
@@ -13,7 +13,7 @@ import {
13
13
  groupSlotsByDay,
14
14
  timeLabel,
15
15
  tzShort
16
- } from "../../chunk-ZCZK6QLC.js";
16
+ } from "../../chunk-GWY2ZTN7.js";
17
17
  export {
18
18
  BrandStyle,
19
19
  JoinIsland,
@@ -35,8 +35,13 @@ type DbRules = Record<string, Rule>;
35
35
  /** Brand tokens that theme the site: palette, fonts, wordmark, nav, logos. */
36
36
  interface ChapterBrand {
37
37
  /** Palette overrides written into styles.css :root (e.g. `{ moss: "#2F3E34" }`
38
- * or `--ui-*` token names). */
38
+ * or `--ui-*` token names). Applies in BOTH light and dark unless overridden
39
+ * by {@link paletteDark}. */
39
40
  palette?: Record<string, string>;
41
+ /** Dark-mode palette overrides. Same shape as {@link palette}; emitted under
42
+ * `:root[data-theme="dark"]` and `@media (prefers-color-scheme: dark)`, so a
43
+ * site brands both modes. */
44
+ paletteDark?: Record<string, string>;
40
45
  fonts?: {
41
46
  display?: string;
42
47
  body?: string;
@@ -35,8 +35,13 @@ type DbRules = Record<string, Rule>;
35
35
  /** Brand tokens that theme the site: palette, fonts, wordmark, nav, logos. */
36
36
  interface ChapterBrand {
37
37
  /** Palette overrides written into styles.css :root (e.g. `{ moss: "#2F3E34" }`
38
- * or `--ui-*` token names). */
38
+ * or `--ui-*` token names). Applies in BOTH light and dark unless overridden
39
+ * by {@link paletteDark}. */
39
40
  palette?: Record<string, string>;
41
+ /** Dark-mode palette overrides. Same shape as {@link palette}; emitted under
42
+ * `:root[data-theme="dark"]` and `@media (prefers-color-scheme: dark)`, so a
43
+ * site brands both modes. */
44
+ paletteDark?: Record<string, string>;
40
45
  fonts?: {
41
46
  display?: string;
42
47
  body?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@odla-ai/chapter",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "A foundation for membership sites: one config (defineChapter) stands up a full member site (join, Stripe membership, Google booking, member area, admin, CRM) or an admin-only hub, on odla-db + Clerk + @odla-ai/crm + calendar + email.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://odla.ai/docs/packages/chapter",