@axcode/axcloud-sdk 0.1.4 → 0.1.6
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/LICENSE.md +9 -0
- package/README.md +19 -1
- package/dist/index.d.mts +98 -8
- package/dist/index.d.ts +98 -8
- package/dist/index.js +109 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +107 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# AxCloud SDK License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Axcode AB. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This package is proprietary software owned by Axcode AB.
|
|
6
|
+
|
|
7
|
+
Use, copying, modification, distribution, or sublicensing of this package is only permitted under a separate written agreement with Axcode AB.
|
|
8
|
+
|
|
9
|
+
No open source license is granted.
|
package/README.md
CHANGED
|
@@ -87,6 +87,21 @@ function NewsPage() {
|
|
|
87
87
|
|
|
88
88
|
> **Content visibility:** When the user is authenticated, `useNews`, `useContent('pages')`, and `useContent('events')` automatically fetch **public + internal + members-only** content based on the user's organization membership. For anonymous users, only public content is returned.
|
|
89
89
|
|
|
90
|
+
Pages can be stored once in AxCloud with translations and requested per language:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { useContentItem } from '@axcode/axcloud-sdk'
|
|
94
|
+
|
|
95
|
+
function AboutPage({ locale }: { locale: 'sv' | 'en' }) {
|
|
96
|
+
const { data: page } = useContentItem('pages', 'about-us', {
|
|
97
|
+
lang: locale,
|
|
98
|
+
publicOnly: true,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
return <h1>{page?.title}</h1>
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
90
105
|
### 3. Add authentication
|
|
91
106
|
|
|
92
107
|
```tsx
|
|
@@ -254,11 +269,14 @@ interface ContentQueryOptions {
|
|
|
254
269
|
page?: number // Page number (default: 1)
|
|
255
270
|
pageSize?: number // Items per page (default: 20)
|
|
256
271
|
status?: 'draft' | 'published' | 'archived'
|
|
257
|
-
visibility?: '
|
|
272
|
+
visibility?: 'draft' | 'published' | 'archived'
|
|
273
|
+
audience?: 'public' | 'internal' | 'members' | 'section'
|
|
258
274
|
sectionId?: string // Filter by specific section
|
|
259
275
|
search?: string // Search in title/content
|
|
260
276
|
sortBy?: string // Sort field (default: 'createdAt')
|
|
261
277
|
sortOrder?: 'asc' | 'desc'
|
|
278
|
+
lang?: string // Return translated title/slug/blocks when available
|
|
279
|
+
publicOnly?: boolean // Force public endpoint even when authenticated
|
|
262
280
|
}
|
|
263
281
|
```
|
|
264
282
|
|
package/dist/index.d.mts
CHANGED
|
@@ -197,21 +197,72 @@ interface Membership {
|
|
|
197
197
|
expiresAt?: string;
|
|
198
198
|
metadata?: Record<string, unknown>;
|
|
199
199
|
}
|
|
200
|
+
interface ContentBlock {
|
|
201
|
+
id: string;
|
|
202
|
+
type: string;
|
|
203
|
+
content?: string;
|
|
204
|
+
url?: string;
|
|
205
|
+
alt?: string;
|
|
206
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
207
|
+
items?: unknown[];
|
|
208
|
+
language?: string;
|
|
209
|
+
caption?: string;
|
|
210
|
+
attributes?: Record<string, unknown>;
|
|
211
|
+
ordered?: boolean;
|
|
212
|
+
author?: string;
|
|
213
|
+
}
|
|
214
|
+
interface ContentTranslation {
|
|
215
|
+
title: string;
|
|
216
|
+
slug: string;
|
|
217
|
+
description?: string;
|
|
218
|
+
blocks: ContentBlock[];
|
|
219
|
+
/** Structured website/template fields for this language. */
|
|
220
|
+
fields?: Record<string, unknown>;
|
|
221
|
+
metaTitle?: string;
|
|
222
|
+
metaDescription?: string;
|
|
223
|
+
keywords?: string[];
|
|
224
|
+
}
|
|
225
|
+
type ContentPublicationState = 'draft' | 'published' | 'archived';
|
|
226
|
+
type ContentAudience = 'public' | 'internal' | 'members' | 'section';
|
|
200
227
|
interface ContentItem {
|
|
201
228
|
id: string;
|
|
202
229
|
organizationId: string;
|
|
203
230
|
type: string;
|
|
204
231
|
title: string;
|
|
205
232
|
slug: string;
|
|
206
|
-
content
|
|
233
|
+
/** Legacy string content. New AxCloud content uses `blocks`. */
|
|
234
|
+
content?: string;
|
|
235
|
+
description?: string;
|
|
236
|
+
blocks?: ContentBlock[];
|
|
237
|
+
/** Template identifier used by websites, e.g. "home" or "landing". */
|
|
238
|
+
template?: string;
|
|
239
|
+
/** Structured website/template fields. Frontends own layout and read these values by key. */
|
|
240
|
+
fields?: Record<string, unknown>;
|
|
207
241
|
excerpt?: string;
|
|
208
242
|
author?: {
|
|
209
243
|
id: string;
|
|
210
244
|
name: string;
|
|
211
245
|
};
|
|
212
|
-
status
|
|
213
|
-
visibility
|
|
246
|
+
status?: ContentPublicationState;
|
|
247
|
+
visibility?: ContentPublicationState;
|
|
248
|
+
audience?: ContentAudience;
|
|
214
249
|
sectionId?: string;
|
|
250
|
+
tags?: string[];
|
|
251
|
+
lang?: string;
|
|
252
|
+
featuredImage?: string;
|
|
253
|
+
metaTitle?: string;
|
|
254
|
+
metaDescription?: string;
|
|
255
|
+
keywords?: string[];
|
|
256
|
+
translations?: Record<string, ContentTranslation>;
|
|
257
|
+
currentLanguage?: string;
|
|
258
|
+
availableLanguages?: string[];
|
|
259
|
+
seo?: {
|
|
260
|
+
canonical: string;
|
|
261
|
+
hreflang: Array<{
|
|
262
|
+
lang: string;
|
|
263
|
+
href: string;
|
|
264
|
+
}>;
|
|
265
|
+
};
|
|
215
266
|
publishedAt?: string;
|
|
216
267
|
createdAt: string;
|
|
217
268
|
updatedAt: string;
|
|
@@ -253,12 +304,15 @@ interface AxCloudConfig {
|
|
|
253
304
|
interface ContentQueryOptions {
|
|
254
305
|
page?: number;
|
|
255
306
|
pageSize?: number;
|
|
256
|
-
status?:
|
|
257
|
-
visibility?:
|
|
307
|
+
status?: ContentPublicationState;
|
|
308
|
+
visibility?: ContentPublicationState;
|
|
309
|
+
audience?: ContentAudience;
|
|
258
310
|
sectionId?: string;
|
|
259
311
|
search?: string;
|
|
260
312
|
sortBy?: string;
|
|
261
313
|
sortOrder?: 'asc' | 'desc';
|
|
314
|
+
/** Return the requested translation when content has language variants. */
|
|
315
|
+
lang?: string;
|
|
262
316
|
/** Force public endpoint even when authenticated (for public pages) */
|
|
263
317
|
publicOnly?: boolean;
|
|
264
318
|
}
|
|
@@ -313,6 +367,24 @@ interface MediaListResponse {
|
|
|
313
367
|
prefix: string;
|
|
314
368
|
}
|
|
315
369
|
|
|
370
|
+
type ContentSlotValue = string | number | boolean | null | undefined | string[] | Record<string, unknown> | unknown[];
|
|
371
|
+
type ContentSlotMap = Record<string, ContentSlotValue>;
|
|
372
|
+
interface ContentSlotImage {
|
|
373
|
+
url: string;
|
|
374
|
+
alt?: string;
|
|
375
|
+
caption?: string;
|
|
376
|
+
}
|
|
377
|
+
interface ContentSlotReader {
|
|
378
|
+
fields: ContentSlotMap;
|
|
379
|
+
value<T = ContentSlotValue>(key: string, fallback?: T): ContentSlotValue | T;
|
|
380
|
+
text(key: string, fallback?: string): string;
|
|
381
|
+
html(key: string, fallback?: string): string;
|
|
382
|
+
list(key: string, fallback?: string[]): string[];
|
|
383
|
+
image(key: string, fallback?: ContentSlotImage): ContentSlotImage | undefined;
|
|
384
|
+
}
|
|
385
|
+
declare function getContentSlotMap(content?: Pick<ContentItem, 'fields' | 'blocks'> | null): ContentSlotMap;
|
|
386
|
+
declare function createContentSlotReader(content?: Pick<ContentItem, 'fields' | 'blocks'> | null): ContentSlotReader;
|
|
387
|
+
|
|
316
388
|
/**
|
|
317
389
|
* AxCloud Forms Module
|
|
318
390
|
*
|
|
@@ -685,7 +757,7 @@ interface PublicOrganization {
|
|
|
685
757
|
*
|
|
686
758
|
* Automatically uses the appropriate endpoint:
|
|
687
759
|
* - With API key (public): `/content/public/{orgId}/org`
|
|
688
|
-
* - With JWT auth: `/
|
|
760
|
+
* - With JWT auth: `/orgs/api/organizations/{orgId}`
|
|
689
761
|
*
|
|
690
762
|
* @example
|
|
691
763
|
* ```tsx
|
|
@@ -817,6 +889,8 @@ declare function useContent<T extends ContentItem = ContentItem>(contentType: st
|
|
|
817
889
|
interface ContentItemOptions {
|
|
818
890
|
/** Force public endpoint even when authenticated */
|
|
819
891
|
publicOnly?: boolean;
|
|
892
|
+
/** Return the requested translation when content has language variants. */
|
|
893
|
+
lang?: string;
|
|
820
894
|
}
|
|
821
895
|
/**
|
|
822
896
|
* useContentItem - Fetch a single content item by ID or slug
|
|
@@ -833,7 +907,7 @@ interface ContentItemOptions {
|
|
|
833
907
|
* @example
|
|
834
908
|
* ```tsx
|
|
835
909
|
* // Fetch a page by slug
|
|
836
|
-
* const { data: page } = useContentItem('pages', 'about-us')
|
|
910
|
+
* const { data: page } = useContentItem('pages', 'about-us', { lang: 'sv' })
|
|
837
911
|
*
|
|
838
912
|
* // Force public endpoint
|
|
839
913
|
* const { data: page } = useContentItem('pages', 'about-us', { publicOnly: true })
|
|
@@ -846,6 +920,22 @@ declare function useContentItem<T extends ContentItem = ContentItem>(contentType
|
|
|
846
920
|
error: Error | null;
|
|
847
921
|
refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<_tanstack_react_query.NoInfer<T>, Error>>;
|
|
848
922
|
};
|
|
923
|
+
interface PageContentState<T extends ContentItem = ContentItem> extends ContentSlotReader {
|
|
924
|
+
page: T | null;
|
|
925
|
+
data: T | null;
|
|
926
|
+
isLoading: boolean;
|
|
927
|
+
isError: boolean;
|
|
928
|
+
error: Error | null;
|
|
929
|
+
refetch: () => unknown;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* usePageContent - Fetch a website page and expose structured template fields.
|
|
933
|
+
*
|
|
934
|
+
* Use `page.content`/`page.blocks` for article-like rich text pages. Use
|
|
935
|
+
* `text('hero.title')`, `list('benefits.items')`, etc. for designed website templates
|
|
936
|
+
* where the frontend owns layout and AxCloud owns content.
|
|
937
|
+
*/
|
|
938
|
+
declare function usePageContent<T extends ContentItem = ContentItem>(slug: string, options?: ContentItemOptions): PageContentState<T>;
|
|
849
939
|
|
|
850
940
|
interface SectionWithMembers extends Section {
|
|
851
941
|
members?: User[];
|
|
@@ -1479,4 +1569,4 @@ interface LinkedAccountsListProps {
|
|
|
1479
1569
|
*/
|
|
1480
1570
|
declare function LinkedAccountsList({ providers, showConnectButtons, className, onUnlink, onLinkInitiated, renderIdentity, renderAvailableProvider, }: LinkedAccountsListProps): react_jsx_runtime.JSX.Element;
|
|
1481
1571
|
|
|
1482
|
-
export { type AvailableProvider, AxCloudClient, type AxCloudConfig, AxCloudError, type AxCloudErrorCode, type AxCloudModule, AxCloudProvider, type BaseRole, type ContentItem, type ContentQueryOptions, type CustomRole, type FormStatsResponse, type FormSubmission, type FormSubmissionRecord, type FormSubmissionResponse, type FormSubmissionsResponse, LinkedAccountsList, type LinkedAccountsListProps, type LinkedIdentity, LoginButton, LogoutButton, type MediaItem, type MediaListResponse, type Membership, ModuleGate, type NewsItem, type Organization, type OrganizationBranding, type OrganizationSettings, type Page, type PaginatedResponse, ProtectedRoute, type Section, type SectionPermissions, type SignedMediaUrl, type SystemRole, type UseLinkedAccountsReturn, type User, type UserRole, createClient, createFormHelper, getClient, isAxCloudError, submitForm, useAuth, useAvatar, useAxCloudContext, useBranding, useContent, useContentItem, useFormStats, useForms, useLinkedAccounts, useLogo, useMedia, useMediaList, useModuleAccess, useMySection, useNews, useOrg, useSections, useUpdateFormSubmission, useUser, userHasAllPermissions, userHasAnyPermission, userHasPermission };
|
|
1572
|
+
export { type AvailableProvider, AxCloudClient, type AxCloudConfig, AxCloudError, type AxCloudErrorCode, type AxCloudModule, AxCloudProvider, type BaseRole, type ContentItem, type ContentQueryOptions, type ContentSlotImage, type ContentSlotMap, type ContentSlotReader, type ContentSlotValue, type CustomRole, type FormStatsResponse, type FormSubmission, type FormSubmissionRecord, type FormSubmissionResponse, type FormSubmissionsResponse, LinkedAccountsList, type LinkedAccountsListProps, type LinkedIdentity, LoginButton, LogoutButton, type MediaItem, type MediaListResponse, type Membership, ModuleGate, type NewsItem, type Organization, type OrganizationBranding, type OrganizationSettings, type Page, type PageContentState, type PaginatedResponse, ProtectedRoute, type Section, type SectionPermissions, type SignedMediaUrl, type SystemRole, type UseLinkedAccountsReturn, type User, type UserRole, createClient, createContentSlotReader, createFormHelper, getClient, getContentSlotMap, isAxCloudError, submitForm, useAuth, useAvatar, useAxCloudContext, useBranding, useContent, useContentItem, useFormStats, useForms, useLinkedAccounts, useLogo, useMedia, useMediaList, useModuleAccess, useMySection, useNews, useOrg, usePageContent, useSections, useUpdateFormSubmission, useUser, userHasAllPermissions, userHasAnyPermission, userHasPermission };
|
package/dist/index.d.ts
CHANGED
|
@@ -197,21 +197,72 @@ interface Membership {
|
|
|
197
197
|
expiresAt?: string;
|
|
198
198
|
metadata?: Record<string, unknown>;
|
|
199
199
|
}
|
|
200
|
+
interface ContentBlock {
|
|
201
|
+
id: string;
|
|
202
|
+
type: string;
|
|
203
|
+
content?: string;
|
|
204
|
+
url?: string;
|
|
205
|
+
alt?: string;
|
|
206
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
207
|
+
items?: unknown[];
|
|
208
|
+
language?: string;
|
|
209
|
+
caption?: string;
|
|
210
|
+
attributes?: Record<string, unknown>;
|
|
211
|
+
ordered?: boolean;
|
|
212
|
+
author?: string;
|
|
213
|
+
}
|
|
214
|
+
interface ContentTranslation {
|
|
215
|
+
title: string;
|
|
216
|
+
slug: string;
|
|
217
|
+
description?: string;
|
|
218
|
+
blocks: ContentBlock[];
|
|
219
|
+
/** Structured website/template fields for this language. */
|
|
220
|
+
fields?: Record<string, unknown>;
|
|
221
|
+
metaTitle?: string;
|
|
222
|
+
metaDescription?: string;
|
|
223
|
+
keywords?: string[];
|
|
224
|
+
}
|
|
225
|
+
type ContentPublicationState = 'draft' | 'published' | 'archived';
|
|
226
|
+
type ContentAudience = 'public' | 'internal' | 'members' | 'section';
|
|
200
227
|
interface ContentItem {
|
|
201
228
|
id: string;
|
|
202
229
|
organizationId: string;
|
|
203
230
|
type: string;
|
|
204
231
|
title: string;
|
|
205
232
|
slug: string;
|
|
206
|
-
content
|
|
233
|
+
/** Legacy string content. New AxCloud content uses `blocks`. */
|
|
234
|
+
content?: string;
|
|
235
|
+
description?: string;
|
|
236
|
+
blocks?: ContentBlock[];
|
|
237
|
+
/** Template identifier used by websites, e.g. "home" or "landing". */
|
|
238
|
+
template?: string;
|
|
239
|
+
/** Structured website/template fields. Frontends own layout and read these values by key. */
|
|
240
|
+
fields?: Record<string, unknown>;
|
|
207
241
|
excerpt?: string;
|
|
208
242
|
author?: {
|
|
209
243
|
id: string;
|
|
210
244
|
name: string;
|
|
211
245
|
};
|
|
212
|
-
status
|
|
213
|
-
visibility
|
|
246
|
+
status?: ContentPublicationState;
|
|
247
|
+
visibility?: ContentPublicationState;
|
|
248
|
+
audience?: ContentAudience;
|
|
214
249
|
sectionId?: string;
|
|
250
|
+
tags?: string[];
|
|
251
|
+
lang?: string;
|
|
252
|
+
featuredImage?: string;
|
|
253
|
+
metaTitle?: string;
|
|
254
|
+
metaDescription?: string;
|
|
255
|
+
keywords?: string[];
|
|
256
|
+
translations?: Record<string, ContentTranslation>;
|
|
257
|
+
currentLanguage?: string;
|
|
258
|
+
availableLanguages?: string[];
|
|
259
|
+
seo?: {
|
|
260
|
+
canonical: string;
|
|
261
|
+
hreflang: Array<{
|
|
262
|
+
lang: string;
|
|
263
|
+
href: string;
|
|
264
|
+
}>;
|
|
265
|
+
};
|
|
215
266
|
publishedAt?: string;
|
|
216
267
|
createdAt: string;
|
|
217
268
|
updatedAt: string;
|
|
@@ -253,12 +304,15 @@ interface AxCloudConfig {
|
|
|
253
304
|
interface ContentQueryOptions {
|
|
254
305
|
page?: number;
|
|
255
306
|
pageSize?: number;
|
|
256
|
-
status?:
|
|
257
|
-
visibility?:
|
|
307
|
+
status?: ContentPublicationState;
|
|
308
|
+
visibility?: ContentPublicationState;
|
|
309
|
+
audience?: ContentAudience;
|
|
258
310
|
sectionId?: string;
|
|
259
311
|
search?: string;
|
|
260
312
|
sortBy?: string;
|
|
261
313
|
sortOrder?: 'asc' | 'desc';
|
|
314
|
+
/** Return the requested translation when content has language variants. */
|
|
315
|
+
lang?: string;
|
|
262
316
|
/** Force public endpoint even when authenticated (for public pages) */
|
|
263
317
|
publicOnly?: boolean;
|
|
264
318
|
}
|
|
@@ -313,6 +367,24 @@ interface MediaListResponse {
|
|
|
313
367
|
prefix: string;
|
|
314
368
|
}
|
|
315
369
|
|
|
370
|
+
type ContentSlotValue = string | number | boolean | null | undefined | string[] | Record<string, unknown> | unknown[];
|
|
371
|
+
type ContentSlotMap = Record<string, ContentSlotValue>;
|
|
372
|
+
interface ContentSlotImage {
|
|
373
|
+
url: string;
|
|
374
|
+
alt?: string;
|
|
375
|
+
caption?: string;
|
|
376
|
+
}
|
|
377
|
+
interface ContentSlotReader {
|
|
378
|
+
fields: ContentSlotMap;
|
|
379
|
+
value<T = ContentSlotValue>(key: string, fallback?: T): ContentSlotValue | T;
|
|
380
|
+
text(key: string, fallback?: string): string;
|
|
381
|
+
html(key: string, fallback?: string): string;
|
|
382
|
+
list(key: string, fallback?: string[]): string[];
|
|
383
|
+
image(key: string, fallback?: ContentSlotImage): ContentSlotImage | undefined;
|
|
384
|
+
}
|
|
385
|
+
declare function getContentSlotMap(content?: Pick<ContentItem, 'fields' | 'blocks'> | null): ContentSlotMap;
|
|
386
|
+
declare function createContentSlotReader(content?: Pick<ContentItem, 'fields' | 'blocks'> | null): ContentSlotReader;
|
|
387
|
+
|
|
316
388
|
/**
|
|
317
389
|
* AxCloud Forms Module
|
|
318
390
|
*
|
|
@@ -685,7 +757,7 @@ interface PublicOrganization {
|
|
|
685
757
|
*
|
|
686
758
|
* Automatically uses the appropriate endpoint:
|
|
687
759
|
* - With API key (public): `/content/public/{orgId}/org`
|
|
688
|
-
* - With JWT auth: `/
|
|
760
|
+
* - With JWT auth: `/orgs/api/organizations/{orgId}`
|
|
689
761
|
*
|
|
690
762
|
* @example
|
|
691
763
|
* ```tsx
|
|
@@ -817,6 +889,8 @@ declare function useContent<T extends ContentItem = ContentItem>(contentType: st
|
|
|
817
889
|
interface ContentItemOptions {
|
|
818
890
|
/** Force public endpoint even when authenticated */
|
|
819
891
|
publicOnly?: boolean;
|
|
892
|
+
/** Return the requested translation when content has language variants. */
|
|
893
|
+
lang?: string;
|
|
820
894
|
}
|
|
821
895
|
/**
|
|
822
896
|
* useContentItem - Fetch a single content item by ID or slug
|
|
@@ -833,7 +907,7 @@ interface ContentItemOptions {
|
|
|
833
907
|
* @example
|
|
834
908
|
* ```tsx
|
|
835
909
|
* // Fetch a page by slug
|
|
836
|
-
* const { data: page } = useContentItem('pages', 'about-us')
|
|
910
|
+
* const { data: page } = useContentItem('pages', 'about-us', { lang: 'sv' })
|
|
837
911
|
*
|
|
838
912
|
* // Force public endpoint
|
|
839
913
|
* const { data: page } = useContentItem('pages', 'about-us', { publicOnly: true })
|
|
@@ -846,6 +920,22 @@ declare function useContentItem<T extends ContentItem = ContentItem>(contentType
|
|
|
846
920
|
error: Error | null;
|
|
847
921
|
refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<_tanstack_react_query.NoInfer<T>, Error>>;
|
|
848
922
|
};
|
|
923
|
+
interface PageContentState<T extends ContentItem = ContentItem> extends ContentSlotReader {
|
|
924
|
+
page: T | null;
|
|
925
|
+
data: T | null;
|
|
926
|
+
isLoading: boolean;
|
|
927
|
+
isError: boolean;
|
|
928
|
+
error: Error | null;
|
|
929
|
+
refetch: () => unknown;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* usePageContent - Fetch a website page and expose structured template fields.
|
|
933
|
+
*
|
|
934
|
+
* Use `page.content`/`page.blocks` for article-like rich text pages. Use
|
|
935
|
+
* `text('hero.title')`, `list('benefits.items')`, etc. for designed website templates
|
|
936
|
+
* where the frontend owns layout and AxCloud owns content.
|
|
937
|
+
*/
|
|
938
|
+
declare function usePageContent<T extends ContentItem = ContentItem>(slug: string, options?: ContentItemOptions): PageContentState<T>;
|
|
849
939
|
|
|
850
940
|
interface SectionWithMembers extends Section {
|
|
851
941
|
members?: User[];
|
|
@@ -1479,4 +1569,4 @@ interface LinkedAccountsListProps {
|
|
|
1479
1569
|
*/
|
|
1480
1570
|
declare function LinkedAccountsList({ providers, showConnectButtons, className, onUnlink, onLinkInitiated, renderIdentity, renderAvailableProvider, }: LinkedAccountsListProps): react_jsx_runtime.JSX.Element;
|
|
1481
1571
|
|
|
1482
|
-
export { type AvailableProvider, AxCloudClient, type AxCloudConfig, AxCloudError, type AxCloudErrorCode, type AxCloudModule, AxCloudProvider, type BaseRole, type ContentItem, type ContentQueryOptions, type CustomRole, type FormStatsResponse, type FormSubmission, type FormSubmissionRecord, type FormSubmissionResponse, type FormSubmissionsResponse, LinkedAccountsList, type LinkedAccountsListProps, type LinkedIdentity, LoginButton, LogoutButton, type MediaItem, type MediaListResponse, type Membership, ModuleGate, type NewsItem, type Organization, type OrganizationBranding, type OrganizationSettings, type Page, type PaginatedResponse, ProtectedRoute, type Section, type SectionPermissions, type SignedMediaUrl, type SystemRole, type UseLinkedAccountsReturn, type User, type UserRole, createClient, createFormHelper, getClient, isAxCloudError, submitForm, useAuth, useAvatar, useAxCloudContext, useBranding, useContent, useContentItem, useFormStats, useForms, useLinkedAccounts, useLogo, useMedia, useMediaList, useModuleAccess, useMySection, useNews, useOrg, useSections, useUpdateFormSubmission, useUser, userHasAllPermissions, userHasAnyPermission, userHasPermission };
|
|
1572
|
+
export { type AvailableProvider, AxCloudClient, type AxCloudConfig, AxCloudError, type AxCloudErrorCode, type AxCloudModule, AxCloudProvider, type BaseRole, type ContentItem, type ContentQueryOptions, type ContentSlotImage, type ContentSlotMap, type ContentSlotReader, type ContentSlotValue, type CustomRole, type FormStatsResponse, type FormSubmission, type FormSubmissionRecord, type FormSubmissionResponse, type FormSubmissionsResponse, LinkedAccountsList, type LinkedAccountsListProps, type LinkedIdentity, LoginButton, LogoutButton, type MediaItem, type MediaListResponse, type Membership, ModuleGate, type NewsItem, type Organization, type OrganizationBranding, type OrganizationSettings, type Page, type PageContentState, type PaginatedResponse, ProtectedRoute, type Section, type SectionPermissions, type SignedMediaUrl, type SystemRole, type UseLinkedAccountsReturn, type User, type UserRole, createClient, createContentSlotReader, createFormHelper, getClient, getContentSlotMap, isAxCloudError, submitForm, useAuth, useAvatar, useAxCloudContext, useBranding, useContent, useContentItem, useFormStats, useForms, useLinkedAccounts, useLogo, useMedia, useMediaList, useModuleAccess, useMySection, useNews, useOrg, usePageContent, useSections, useUpdateFormSubmission, useUser, userHasAllPermissions, userHasAnyPermission, userHasPermission };
|
package/dist/index.js
CHANGED
|
@@ -238,6 +238,88 @@ function getClient(key) {
|
|
|
238
238
|
throw new Error("AxCloud client not found. Make sure AxCloudProvider is mounted and use useAxCloudContext() to get the client.");
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
// src/core/contentSlots.ts
|
|
242
|
+
var SLOT_ATTRIBUTE_KEYS = ["slot", "field", "key", "name"];
|
|
243
|
+
function getContentSlotMap(content) {
|
|
244
|
+
const fields = isRecord(content?.fields) ? { ...content?.fields } : {};
|
|
245
|
+
for (const block of content?.blocks || []) {
|
|
246
|
+
const slot = getBlockSlot(block);
|
|
247
|
+
if (!slot) continue;
|
|
248
|
+
fields[slot] = blockToSlotValue(block);
|
|
249
|
+
}
|
|
250
|
+
return fields;
|
|
251
|
+
}
|
|
252
|
+
function createContentSlotReader(content) {
|
|
253
|
+
const fields = getContentSlotMap(content);
|
|
254
|
+
const value = (key, fallback) => {
|
|
255
|
+
return key in fields ? fields[key] : fallback;
|
|
256
|
+
};
|
|
257
|
+
return {
|
|
258
|
+
fields,
|
|
259
|
+
value,
|
|
260
|
+
text: (key, fallback = "") => stringifySlotValue(value(key, fallback)),
|
|
261
|
+
html: (key, fallback = "") => stringifySlotValue(value(key, fallback)),
|
|
262
|
+
list: (key, fallback = []) => slotValueToList(value(key, fallback)),
|
|
263
|
+
image: (key, fallback) => slotValueToImage(value(key, fallback))
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function getBlockSlot(block) {
|
|
267
|
+
const attributes = block.attributes || {};
|
|
268
|
+
for (const key of SLOT_ATTRIBUTE_KEYS) {
|
|
269
|
+
const value = attributes[key];
|
|
270
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
271
|
+
}
|
|
272
|
+
return void 0;
|
|
273
|
+
}
|
|
274
|
+
function blockToSlotValue(block) {
|
|
275
|
+
if (block.attributes && "value" in block.attributes) {
|
|
276
|
+
return block.attributes.value;
|
|
277
|
+
}
|
|
278
|
+
if (block.type === "list") {
|
|
279
|
+
return Array.isArray(block.items) ? block.items : [];
|
|
280
|
+
}
|
|
281
|
+
if (block.type === "image" && block.url) {
|
|
282
|
+
return {
|
|
283
|
+
url: block.url,
|
|
284
|
+
alt: block.alt,
|
|
285
|
+
caption: block.caption
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
return block.content ?? "";
|
|
289
|
+
}
|
|
290
|
+
function stringifySlotValue(value) {
|
|
291
|
+
if (value === void 0 || value === null) return "";
|
|
292
|
+
if (typeof value === "string") return value;
|
|
293
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
294
|
+
if (Array.isArray(value)) return value.map((item) => stringifySlotValue(item)).filter(Boolean).join("\n");
|
|
295
|
+
return "";
|
|
296
|
+
}
|
|
297
|
+
function slotValueToList(value) {
|
|
298
|
+
if (Array.isArray(value)) {
|
|
299
|
+
return value.map((item) => stringifySlotValue(item)).filter(Boolean);
|
|
300
|
+
}
|
|
301
|
+
if (typeof value === "string") {
|
|
302
|
+
return value.split(/\r?\n/).map((item) => item.trim()).filter(Boolean);
|
|
303
|
+
}
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
function slotValueToImage(value) {
|
|
307
|
+
if (isRecord(value) && typeof value.url === "string") {
|
|
308
|
+
return {
|
|
309
|
+
url: value.url,
|
|
310
|
+
alt: typeof value.alt === "string" ? value.alt : void 0,
|
|
311
|
+
caption: typeof value.caption === "string" ? value.caption : void 0
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
if (typeof value === "string" && value) {
|
|
315
|
+
return { url: value };
|
|
316
|
+
}
|
|
317
|
+
return void 0;
|
|
318
|
+
}
|
|
319
|
+
function isRecord(value) {
|
|
320
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
321
|
+
}
|
|
322
|
+
|
|
241
323
|
// src/core/types.ts
|
|
242
324
|
function userHasPermission(user, permission) {
|
|
243
325
|
if (user.permissions && user.permissions.length > 0) {
|
|
@@ -706,6 +788,7 @@ function useNews(options = {}) {
|
|
|
706
788
|
};
|
|
707
789
|
}
|
|
708
790
|
var MEMBER_ENDPOINT_TYPES = ["news", "pages", "events"];
|
|
791
|
+
var PAGE_CONTENT_TYPES = ["page", "pages"];
|
|
709
792
|
function useContent(contentType, options = {}) {
|
|
710
793
|
const { client, orgId, isPublicMode } = useAxCloudContext();
|
|
711
794
|
const {
|
|
@@ -717,7 +800,8 @@ function useContent(contentType, options = {}) {
|
|
|
717
800
|
sectionId,
|
|
718
801
|
search,
|
|
719
802
|
sortBy = "createdAt",
|
|
720
|
-
sortOrder = "desc"
|
|
803
|
+
sortOrder = "desc",
|
|
804
|
+
lang
|
|
721
805
|
} = options;
|
|
722
806
|
const query = reactQuery.useQuery({
|
|
723
807
|
queryKey: [
|
|
@@ -734,7 +818,8 @@ function useContent(contentType, options = {}) {
|
|
|
734
818
|
sectionId,
|
|
735
819
|
search,
|
|
736
820
|
sortBy,
|
|
737
|
-
sortOrder
|
|
821
|
+
sortOrder,
|
|
822
|
+
lang
|
|
738
823
|
],
|
|
739
824
|
queryFn: async () => {
|
|
740
825
|
const useMemberEndpoint = !isPublicMode && !publicOnly && MEMBER_ENDPOINT_TYPES.includes(contentType);
|
|
@@ -747,7 +832,8 @@ function useContent(contentType, options = {}) {
|
|
|
747
832
|
sectionId,
|
|
748
833
|
search,
|
|
749
834
|
sortBy,
|
|
750
|
-
sortOrder
|
|
835
|
+
sortOrder,
|
|
836
|
+
lang
|
|
751
837
|
});
|
|
752
838
|
},
|
|
753
839
|
staleTime: 1e3 * 60 * 5
|
|
@@ -765,13 +851,15 @@ function useContent(contentType, options = {}) {
|
|
|
765
851
|
}
|
|
766
852
|
function useContentItem(contentType, idOrSlug, options = {}) {
|
|
767
853
|
const { client, orgId, isPublicMode } = useAxCloudContext();
|
|
768
|
-
const { publicOnly = false } = options;
|
|
769
|
-
const useMemberEndpoint = !isPublicMode && !publicOnly && MEMBER_ENDPOINT_TYPES.includes(contentType);
|
|
854
|
+
const { publicOnly = false, lang } = options;
|
|
855
|
+
const useMemberEndpoint = !isPublicMode && !publicOnly && (MEMBER_ENDPOINT_TYPES.includes(contentType) || PAGE_CONTENT_TYPES.includes(contentType));
|
|
770
856
|
const query = reactQuery.useQuery({
|
|
771
|
-
queryKey: ["axcloud", "content", orgId, contentType, idOrSlug, useMemberEndpoint],
|
|
857
|
+
queryKey: ["axcloud", "content", orgId, contentType, idOrSlug, useMemberEndpoint, lang],
|
|
772
858
|
queryFn: async () => {
|
|
773
859
|
const basePath = useMemberEndpoint ? "members" : "public";
|
|
774
|
-
|
|
860
|
+
const encodedIdOrSlug = encodeURIComponent(idOrSlug);
|
|
861
|
+
const endpoint = PAGE_CONTENT_TYPES.includes(contentType) ? `/content/${basePath}/${orgId}/page/${encodedIdOrSlug}` : `/content/${basePath}/${orgId}/${contentType}/${encodedIdOrSlug}`;
|
|
862
|
+
return lang ? client.get(endpoint, { lang }) : client.get(endpoint);
|
|
775
863
|
},
|
|
776
864
|
enabled: !!idOrSlug,
|
|
777
865
|
staleTime: 1e3 * 60 * 5
|
|
@@ -785,6 +873,15 @@ function useContentItem(contentType, idOrSlug, options = {}) {
|
|
|
785
873
|
refetch: query.refetch
|
|
786
874
|
};
|
|
787
875
|
}
|
|
876
|
+
function usePageContent(slug, options = {}) {
|
|
877
|
+
const state = useContentItem("pages", slug, options);
|
|
878
|
+
const reader = react.useMemo(() => createContentSlotReader(state.data), [state.data]);
|
|
879
|
+
return {
|
|
880
|
+
...state,
|
|
881
|
+
page: state.data,
|
|
882
|
+
...reader
|
|
883
|
+
};
|
|
884
|
+
}
|
|
788
885
|
function useMySection(options = {}) {
|
|
789
886
|
const { includeMembers = true } = options;
|
|
790
887
|
const { isAuthenticated } = auth0React.useAuth0();
|
|
@@ -800,7 +897,7 @@ function useMySection(options = {}) {
|
|
|
800
897
|
`/orgs/api/organizations/${orgId}/sections/${sectionId}`,
|
|
801
898
|
{ includeMembers: includeMembers ? "true" : void 0 }
|
|
802
899
|
);
|
|
803
|
-
return "success" in response && response.data ? response.data : response;
|
|
900
|
+
return "success" in response && response.success === true && response.data ? response.data : response;
|
|
804
901
|
},
|
|
805
902
|
enabled: isAuthenticated && !isUserLoading && !!sectionId,
|
|
806
903
|
staleTime: 1e3 * 60 * 5
|
|
@@ -827,7 +924,7 @@ function useSections() {
|
|
|
827
924
|
queryKey: ["axcloud", "sections", orgId, stage],
|
|
828
925
|
queryFn: async () => {
|
|
829
926
|
const response = await client.get(`/orgs/api/organizations/${orgId}/sections`);
|
|
830
|
-
return "success" in response && response.data ? response.data : response;
|
|
927
|
+
return "success" in response && response.success === true && response.data ? response.data : response;
|
|
831
928
|
},
|
|
832
929
|
staleTime: 1e3 * 60 * 10
|
|
833
930
|
// 10 minutes
|
|
@@ -1313,8 +1410,10 @@ exports.LogoutButton = LogoutButton;
|
|
|
1313
1410
|
exports.ModuleGate = ModuleGate;
|
|
1314
1411
|
exports.ProtectedRoute = ProtectedRoute;
|
|
1315
1412
|
exports.createClient = createClient;
|
|
1413
|
+
exports.createContentSlotReader = createContentSlotReader;
|
|
1316
1414
|
exports.createFormHelper = createFormHelper;
|
|
1317
1415
|
exports.getClient = getClient;
|
|
1416
|
+
exports.getContentSlotMap = getContentSlotMap;
|
|
1318
1417
|
exports.isAxCloudError = isAxCloudError;
|
|
1319
1418
|
exports.submitForm = submitForm;
|
|
1320
1419
|
exports.useAuth = useAuth;
|
|
@@ -1333,6 +1432,7 @@ exports.useModuleAccess = useModuleAccess;
|
|
|
1333
1432
|
exports.useMySection = useMySection;
|
|
1334
1433
|
exports.useNews = useNews;
|
|
1335
1434
|
exports.useOrg = useOrg;
|
|
1435
|
+
exports.usePageContent = usePageContent;
|
|
1336
1436
|
exports.useSections = useSections;
|
|
1337
1437
|
exports.useUpdateFormSubmission = useUpdateFormSubmission;
|
|
1338
1438
|
exports.useUser = useUser;
|