@axcode/axcloud-sdk 0.1.6 → 0.1.7-dev.3a3be6d

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 CHANGED
@@ -87,10 +87,10 @@ 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:
90
+ Pages and news can be stored once in AxCloud with translations and requested per language:
91
91
 
92
92
  ```tsx
93
- import { useContentItem } from '@axcode/axcloud-sdk'
93
+ import { useContentItem, useNews } from '@axcode/axcloud-sdk'
94
94
 
95
95
  function AboutPage({ locale }: { locale: 'sv' | 'en' }) {
96
96
  const { data: page } = useContentItem('pages', 'about-us', {
@@ -100,6 +100,12 @@ function AboutPage({ locale }: { locale: 'sv' | 'en' }) {
100
100
 
101
101
  return <h1>{page?.title}</h1>
102
102
  }
103
+
104
+ function NewsList({ locale }: { locale: 'sv' | 'en' }) {
105
+ const { data: news } = useNews({ lang: locale })
106
+
107
+ return news.map(item => <article key={item.id}>{item.title}</article>)
108
+ }
103
109
  ```
104
110
 
105
111
  ### 3. Add authentication
@@ -215,7 +221,35 @@ function HeroImage() {
215
221
 
216
222
  > **Note:** Media URLs are signed S3 URLs that expire after 1 hour. The SDK automatically refreshes them before expiry (staleTime: 30 min).
217
223
 
218
- ### 6. Gate features by module
224
+ ### 6. Fetch public documents
225
+
226
+ ```tsx
227
+ import { useDocuments, useDocumentDownload } from '@axcode/axcloud-sdk'
228
+
229
+ function PublicDocuments() {
230
+ const { documents, isLoading } = useDocuments({ tags: ['handbook'], limit: 20 })
231
+
232
+ if (isLoading) return <Skeleton />
233
+ return (
234
+ <ul>
235
+ {documents.map(doc => (
236
+ <li key={doc.document_id}>
237
+ <DocumentLink documentId={doc.document_id} title={doc.title} />
238
+ </li>
239
+ ))}
240
+ </ul>
241
+ )
242
+ }
243
+
244
+ function DocumentLink({ documentId, title }: { documentId: string; title: string }) {
245
+ const { documentUrl } = useDocumentDownload(documentId)
246
+ return documentUrl ? <a href={documentUrl}>{title}</a> : <span>{title}</span>
247
+ }
248
+ ```
249
+
250
+ Only documents with `status: "published"` and `audience: "public"` are exposed through SDK document hooks.
251
+
252
+ ### 7. Gate features by module
219
253
 
220
254
  ```tsx
221
255
  import { ModuleGate, useOrg } from '@axcode/axcloud-sdk'
@@ -261,6 +295,8 @@ function Dashboard() {
261
295
  | `useMedia(mediaId)` | Fetch specific media file URL |
262
296
  | `useAvatar(userId)` | Fetch user avatar URL |
263
297
  | `useMediaList(type)` | List media files |
298
+ | `useDocuments(options?)` | List published public documents |
299
+ | `useDocumentDownload(documentId)` | Fetch a signed document download URL |
264
300
 
265
301
  ### Content Query Options
266
302
 
package/dist/index.d.mts CHANGED
@@ -366,6 +366,204 @@ interface MediaListResponse {
366
366
  bucket: string;
367
367
  prefix: string;
368
368
  }
369
+ type DocumentStatus = 'draft' | 'published' | 'archived';
370
+ type DocumentAudience = 'public' | 'members' | 'section' | 'internal';
371
+ type DocumentSourceProvider = 'upload' | 'sharepoint';
372
+ /**
373
+ * Public document metadata exposed through the AxCloud SDK.
374
+ */
375
+ interface DocumentItem {
376
+ document_id: string;
377
+ org_id: string;
378
+ title: string;
379
+ description?: string;
380
+ filename: string;
381
+ mime_type: string;
382
+ size: number;
383
+ status: DocumentStatus;
384
+ audience: DocumentAudience;
385
+ tags: string[];
386
+ source_provider: DocumentSourceProvider;
387
+ created_at: string;
388
+ updated_at: string;
389
+ published_at?: string;
390
+ }
391
+ interface DocumentListResponse {
392
+ items: DocumentItem[];
393
+ count: number;
394
+ }
395
+ interface SignedDocumentUrl {
396
+ documentId: string;
397
+ url: string;
398
+ expiresIn: number;
399
+ filename: string;
400
+ mimeType: string;
401
+ }
402
+ interface DocumentQueryOptions {
403
+ search?: string;
404
+ tags?: string[];
405
+ limit?: number;
406
+ }
407
+
408
+ interface BarnsportMunicipality {
409
+ id: string;
410
+ slug: string;
411
+ name: string;
412
+ county?: string;
413
+ geo?: {
414
+ lat: number;
415
+ lng: number;
416
+ bounds?: [number, number, number, number];
417
+ };
418
+ }
419
+ interface BarnsportSport {
420
+ id: string;
421
+ slug: string;
422
+ name: string;
423
+ icon?: string;
424
+ color?: string;
425
+ }
426
+ interface BarnsportActivitySchedule {
427
+ weekday?: number;
428
+ starts_at?: string;
429
+ ends_at?: string;
430
+ label?: string;
431
+ season?: string;
432
+ }
433
+ interface BarnsportActivityLocation {
434
+ name?: string;
435
+ address?: string;
436
+ lat?: number;
437
+ lng?: number;
438
+ }
439
+ interface BarnsportRegistrationMethod {
440
+ type: 'url' | 'email' | 'phone' | 'form' | 'external';
441
+ label?: string;
442
+ value: string;
443
+ instructions?: string;
444
+ preferred?: boolean;
445
+ }
446
+ interface BarnsportActivityListItem {
447
+ id: string;
448
+ slug: string;
449
+ title: string;
450
+ summary?: string;
451
+ sport: {
452
+ id: string;
453
+ slug: string;
454
+ name?: string;
455
+ icon?: string;
456
+ };
457
+ municipality: {
458
+ id: string;
459
+ slug: string;
460
+ name?: string;
461
+ };
462
+ club: {
463
+ id: string;
464
+ slug: string;
465
+ name?: string;
466
+ };
467
+ birthYears?: number[];
468
+ minBirthYear?: number;
469
+ maxBirthYear?: number;
470
+ ageLabel?: string;
471
+ schedule: BarnsportActivitySchedule[];
472
+ location?: BarnsportActivityLocation;
473
+ registrationSummary?: string;
474
+ updatedAt: string;
475
+ }
476
+ interface BarnsportActivity {
477
+ activity_id: string;
478
+ org_id: string;
479
+ slug: string;
480
+ title: string;
481
+ summary?: string;
482
+ description?: string;
483
+ sport_id: string;
484
+ sport_slug: string;
485
+ sport_name?: string;
486
+ sport_icon?: string;
487
+ municipality_id: string;
488
+ municipality_slug: string;
489
+ municipality_name?: string;
490
+ club_id: string;
491
+ club_slug: string;
492
+ club_name?: string;
493
+ club_website_url?: string;
494
+ birth_years?: number[];
495
+ min_birth_year?: number;
496
+ max_birth_year?: number;
497
+ age_label?: string;
498
+ schedule: BarnsportActivitySchedule[];
499
+ location?: BarnsportActivityLocation;
500
+ registration: {
501
+ methods: BarnsportRegistrationMethod[];
502
+ deadline?: string;
503
+ price_label?: string;
504
+ };
505
+ seo?: {
506
+ title?: string;
507
+ description?: string;
508
+ image_media_id?: string;
509
+ };
510
+ published_at?: string;
511
+ updated_at: string;
512
+ }
513
+ interface BarnsportActivitiesFilter {
514
+ municipality?: string;
515
+ sport?: string;
516
+ birthYear?: number;
517
+ q?: string;
518
+ search?: string;
519
+ sort?: 'updated' | 'name' | 'relevance';
520
+ cursor?: string;
521
+ limit?: number;
522
+ }
523
+ interface BarnsportListResponse<T> {
524
+ items: T[];
525
+ count: number;
526
+ nextCursor?: string | null;
527
+ }
528
+ interface BarnsportActivityResponse {
529
+ activity: BarnsportActivity;
530
+ }
531
+ interface BarnsportSitemapUrl {
532
+ loc: string;
533
+ lastmod?: string;
534
+ changefreq?: string;
535
+ priority?: number;
536
+ }
537
+ interface BarnsportSitemapResponse {
538
+ baseUrl: string;
539
+ updatedAt: string;
540
+ urls: BarnsportSitemapUrl[];
541
+ }
542
+ interface BarnsportInterestSubmissionRequest {
543
+ activitySlug: string;
544
+ guardianName: string;
545
+ guardianEmail: string;
546
+ guardianPhone?: string;
547
+ childName?: string;
548
+ childBirthYear?: number;
549
+ message?: string;
550
+ consent: {
551
+ contact: boolean;
552
+ privacyVersion: string;
553
+ };
554
+ honeypot?: string;
555
+ source?: {
556
+ site?: string;
557
+ pageUrl?: string;
558
+ utm?: Record<string, string>;
559
+ };
560
+ }
561
+ interface BarnsportInterestSubmissionResponse {
562
+ success: boolean;
563
+ submissionId?: string;
564
+ duplicate?: boolean;
565
+ message: string;
566
+ }
369
567
 
370
568
  type ContentSlotValue = string | number | boolean | null | undefined | string[] | Record<string, unknown> | unknown[];
371
569
  type ContentSlotMap = Record<string, ContentSlotValue>;
@@ -553,6 +751,128 @@ declare function createFormHelper(config: {
553
751
  submit: (formType: "waitlist" | "contact" | "membership", email: string, data?: Record<string, unknown>) => Promise<FormSubmissionResponse>;
554
752
  };
555
753
 
754
+ /**
755
+ * AxCloud Voting Module
756
+ *
757
+ * Functions for embedding voting/elections on a customer site (e.g. spf.se).
758
+ *
759
+ * Two channels:
760
+ * - PUBLIC (code): no login — the personal one-time code is the credential.
761
+ * Use {@link checkVotingCode}, {@link castVoteWithCode}, {@link getVotingReceipt}.
762
+ * - AUTHED (Auth0): a logged-in member votes with their access token.
763
+ * Use {@link getBallot}, {@link checkEligibility}, {@link castVote}.
764
+ *
765
+ * `votingApiUrl` is the Voting API base, e.g. 'https://api.axcloud.app/voting'.
766
+ */
767
+ interface BallotSeat {
768
+ seat_id: string;
769
+ label_sv: string;
770
+ label_en?: string;
771
+ term?: string;
772
+ count: number;
773
+ order?: number;
774
+ }
775
+ interface BallotCandidate {
776
+ candidate_id: string;
777
+ name: string;
778
+ bio_sv?: string;
779
+ bio_en?: string;
780
+ presentation_media_id?: string;
781
+ photo_media_id?: string;
782
+ }
783
+ interface BallotOption {
784
+ option_id: string;
785
+ text: string;
786
+ description?: string;
787
+ }
788
+ interface Ballot {
789
+ poll_id: string;
790
+ poll_type: 'single_choice' | 'multiple_choice' | 'ranking' | 'election';
791
+ title: string;
792
+ title_en?: string;
793
+ description?: string;
794
+ description_en?: string;
795
+ seats?: BallotSeat[];
796
+ max_selections?: number;
797
+ min_selections?: number;
798
+ ends_at?: string;
799
+ options?: BallotOption[];
800
+ candidates?: BallotCandidate[];
801
+ }
802
+ interface CodeEligibility {
803
+ eligible: boolean;
804
+ has_voted: boolean;
805
+ reason?: string;
806
+ ballot?: Ballot;
807
+ }
808
+ interface VoteReceipt {
809
+ has_voted: boolean;
810
+ voted_at?: string;
811
+ selected_option_ids?: string[];
812
+ selection?: string[];
813
+ }
814
+ interface CastVoteResult {
815
+ success: boolean;
816
+ voted_at?: string;
817
+ message?: string;
818
+ }
819
+ /**
820
+ * Validate a personal code and, if valid, return the ballot to render.
821
+ */
822
+ declare function checkVotingCode(votingApiUrl: string, params: {
823
+ orgId: string;
824
+ pollId: string;
825
+ code: string;
826
+ }): Promise<CodeEligibility>;
827
+ /**
828
+ * Cast a vote using a personal code.
829
+ */
830
+ declare function castVoteWithCode(votingApiUrl: string, params: {
831
+ orgId: string;
832
+ pollId: string;
833
+ code: string;
834
+ selectedOptions: string[];
835
+ rankings?: Record<string, number>;
836
+ }): Promise<CastVoteResult>;
837
+ /**
838
+ * After voting, re-check a code to retrieve the voter's own selection.
839
+ */
840
+ declare function getVotingReceipt(votingApiUrl: string, params: {
841
+ orgId: string;
842
+ pollId: string;
843
+ code: string;
844
+ }): Promise<VoteReceipt>;
845
+ /**
846
+ * Load a ballot (poll + candidates) for a logged-in member.
847
+ */
848
+ declare function getBallot(votingApiUrl: string, params: {
849
+ orgId: string;
850
+ pollId: string;
851
+ accessToken: string;
852
+ }): Promise<Ballot>;
853
+ /**
854
+ * Check whether the logged-in member is eligible to vote / has already voted.
855
+ */
856
+ declare function checkEligibility(votingApiUrl: string, params: {
857
+ orgId: string;
858
+ pollId: string;
859
+ accessToken: string;
860
+ }): Promise<{
861
+ eligible: boolean;
862
+ has_voted: boolean;
863
+ reason?: string;
864
+ }>;
865
+ /**
866
+ * Cast a vote as a logged-in member.
867
+ */
868
+ declare function castVote(votingApiUrl: string, params: {
869
+ orgId: string;
870
+ pollId: string;
871
+ accessToken: string;
872
+ selectedOptions: string[];
873
+ rankings?: Record<string, number>;
874
+ }): Promise<CastVoteResult>;
875
+
556
876
  interface AxCloudProviderProps {
557
877
  children: React.ReactNode;
558
878
  orgId: string;
@@ -1132,6 +1452,25 @@ declare function useUpdateFormSubmission(): _tanstack_react_query.UseMutationRes
1132
1452
  notes?: string;
1133
1453
  }, unknown>;
1134
1454
 
1455
+ type CodeBallotStage = 'enter_code' | 'ballot' | 'submitted' | 'already_voted';
1456
+ interface UseCodeBallotOptions {
1457
+ pollId: string;
1458
+ /** Override the Voting API base URL. Defaults to `${config.apiUrl}/voting`. */
1459
+ votingApiUrl?: string;
1460
+ }
1461
+ declare function useCodeBallot({ pollId, votingApiUrl }: UseCodeBallotOptions): {
1462
+ stage: CodeBallotStage;
1463
+ code: string;
1464
+ ballot: Ballot | null;
1465
+ receipt: VoteReceipt | null;
1466
+ reason: string | undefined;
1467
+ loading: boolean;
1468
+ error: string | null;
1469
+ validateCode: (inputCode: string) => Promise<CodeEligibility | null>;
1470
+ submitVote: (selectedOptions: string[], rankings?: Record<string, number>) => Promise<boolean>;
1471
+ reset: () => void;
1472
+ };
1473
+
1135
1474
  /**
1136
1475
  * useLinkedAccounts Hook
1137
1476
  *
@@ -1344,6 +1683,77 @@ declare function useMedia(mediaId: string): {
1344
1683
  refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<SignedMediaUrl, Error>>;
1345
1684
  };
1346
1685
 
1686
+ /**
1687
+ * List documents that have been explicitly published for public SDK access.
1688
+ *
1689
+ * Documents with members/internal/section audience stay inside AxCloud.
1690
+ */
1691
+ declare function useDocuments(options?: DocumentQueryOptions): {
1692
+ documents: DocumentItem[];
1693
+ items: DocumentItem[];
1694
+ count: number;
1695
+ isLoading: boolean;
1696
+ isError: boolean;
1697
+ error: Error | null;
1698
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<DocumentListResponse, Error>>;
1699
+ };
1700
+ /**
1701
+ * Fetch a short-lived signed download URL for a public document.
1702
+ */
1703
+ declare function useDocumentDownload(documentId: string | undefined): {
1704
+ url: string | null;
1705
+ documentUrl: string | null;
1706
+ filename: string | null;
1707
+ mimeType: string | null;
1708
+ expiresIn: number | null;
1709
+ isLoading: boolean;
1710
+ isError: boolean;
1711
+ error: Error | null;
1712
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<SignedDocumentUrl, Error>>;
1713
+ };
1714
+
1715
+ declare function useBarnsportMunicipalities(): {
1716
+ municipalities: BarnsportMunicipality[];
1717
+ count: number;
1718
+ isLoading: boolean;
1719
+ isError: boolean;
1720
+ error: Error | null;
1721
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<BarnsportListResponse<BarnsportMunicipality>, Error>>;
1722
+ };
1723
+ declare function useBarnsportSports(): {
1724
+ sports: BarnsportSport[];
1725
+ count: number;
1726
+ isLoading: boolean;
1727
+ isError: boolean;
1728
+ error: Error | null;
1729
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<BarnsportListResponse<BarnsportSport>, Error>>;
1730
+ };
1731
+ declare function useBarnsportActivities(filters?: BarnsportActivitiesFilter): {
1732
+ activities: BarnsportActivityListItem[];
1733
+ count: number;
1734
+ nextCursor: string | null;
1735
+ isLoading: boolean;
1736
+ isError: boolean;
1737
+ error: Error | null;
1738
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<BarnsportListResponse<BarnsportActivityListItem>, Error>>;
1739
+ };
1740
+ declare function useBarnsportActivity(slug: string | undefined): {
1741
+ activity: BarnsportActivity | null;
1742
+ isLoading: boolean;
1743
+ isError: boolean;
1744
+ error: Error | null;
1745
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<BarnsportActivityResponse, Error>>;
1746
+ };
1747
+ declare function useBarnsportSitemap(baseUrl?: string): {
1748
+ sitemap: BarnsportSitemapResponse | null;
1749
+ urls: BarnsportSitemapUrl[];
1750
+ isLoading: boolean;
1751
+ isError: boolean;
1752
+ error: Error | null;
1753
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<BarnsportSitemapResponse, Error>>;
1754
+ };
1755
+ declare function useSubmitBarnsportInterest(): _tanstack_react_query.UseMutationResult<BarnsportInterestSubmissionResponse, Error, BarnsportInterestSubmissionRequest, unknown>;
1756
+
1347
1757
  interface LoginButtonProps {
1348
1758
  /**
1349
1759
  * Button text when not authenticated
@@ -1569,4 +1979,4 @@ interface LinkedAccountsListProps {
1569
1979
  */
1570
1980
  declare function LinkedAccountsList({ providers, showConnectButtons, className, onUnlink, onLinkInitiated, renderIdentity, renderAvailableProvider, }: LinkedAccountsListProps): react_jsx_runtime.JSX.Element;
1571
1981
 
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 };
1982
+ export { type AvailableProvider, AxCloudClient, type AxCloudConfig, AxCloudError, type AxCloudErrorCode, type AxCloudModule, AxCloudProvider, type Ballot, type BallotCandidate, type BallotOption, type BallotSeat, type BarnsportActivitiesFilter, type BarnsportActivity, type BarnsportActivityListItem, type BarnsportActivityLocation, type BarnsportActivityResponse, type BarnsportActivitySchedule, type BarnsportInterestSubmissionRequest, type BarnsportInterestSubmissionResponse, type BarnsportListResponse, type BarnsportMunicipality, type BarnsportRegistrationMethod, type BarnsportSitemapResponse, type BarnsportSitemapUrl, type BarnsportSport, type BaseRole, type CastVoteResult, type CodeEligibility, type ContentItem, type ContentQueryOptions, type ContentSlotImage, type ContentSlotMap, type ContentSlotReader, type ContentSlotValue, type CustomRole, type DocumentAudience, type DocumentItem, type DocumentListResponse, type DocumentQueryOptions, type DocumentSourceProvider, type DocumentStatus, 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 SignedDocumentUrl, type SignedMediaUrl, type SystemRole, type UseLinkedAccountsReturn, type User, type UserRole, type VoteReceipt, castVote, castVoteWithCode, checkEligibility, checkVotingCode, createClient, createContentSlotReader, createFormHelper, getBallot, getClient, getContentSlotMap, getVotingReceipt, isAxCloudError, submitForm, useAuth, useAvatar, useAxCloudContext, useBarnsportActivities, useBarnsportActivity, useBarnsportMunicipalities, useBarnsportSitemap, useBarnsportSports, useBranding, useCodeBallot, useContent, useContentItem, useDocumentDownload, useDocuments, useFormStats, useForms, useLinkedAccounts, useLogo, useMedia, useMediaList, useModuleAccess, useMySection, useNews, useOrg, usePageContent, useSections, useSubmitBarnsportInterest, useUpdateFormSubmission, useUser, userHasAllPermissions, userHasAnyPermission, userHasPermission };