@capxul/sdk-react 2.3.2 → 2.4.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 +13 -0
- package/dist/{controllers-VwUPB619.mjs → controllers-DLBe4-OP.mjs} +14 -2
- package/dist/index.d.mts +245 -10
- package/dist/index.mjs +675 -14
- package/dist/testing/index.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -35,6 +35,19 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
35
35
|
- Rich-data hooks such as `useCapxulProfile`, `useCapxulOrgs`, members, roles,
|
|
36
36
|
treasury, and money hooks remain TanStack Query projections. Personal
|
|
37
37
|
holdings and activity reads start only after the Account is claimed.
|
|
38
|
+
- `CapxulActivity` is the compound activity component. One root owns fetching,
|
|
39
|
+
paging, filtering, searching, the summary numbers, row meaning, memo saving
|
|
40
|
+
and CSV building, and draws nothing. The `.Summary`, `.Filters`, `.Search`,
|
|
41
|
+
`.Rows`, `.LoadMore`, `.Detail` and `.Export` region parts each hand the
|
|
42
|
+
screen one finished slice, so the same component serves a ten-row dashboard
|
|
43
|
+
card and a full transactions page. Paging is infinite scroll through a
|
|
44
|
+
sentinel ref; `.Export` pages at the backend maximum and stops at 5,000 rows
|
|
45
|
+
rather than draining a ledger. Detail state and reads stay scoped to the root
|
|
46
|
+
actor.
|
|
47
|
+
- `capxulKeys` is the public query-key catalog. An application invalidates SDK
|
|
48
|
+
lanes with it instead of keeping a parallel key namespace.
|
|
49
|
+
- `useCapxulHoldings` takes an optional `actor`, and its cache entry is keyed by
|
|
50
|
+
that actor.
|
|
38
51
|
- `CapxulSendMoney` is the compound send component. One root owns the send
|
|
39
52
|
behaviour and draws nothing. The `.Asset`, `.Amount`, `.Recipient`, and
|
|
40
53
|
`.Actions` region parts each hand the screen one finished slice. The engine
|
|
@@ -104,12 +104,24 @@ const capxulKeys = {
|
|
|
104
104
|
includeHidden ? "all" : "visible"
|
|
105
105
|
],
|
|
106
106
|
activity: ["capxul", "activity"],
|
|
107
|
-
activityDetail: (reference) => [
|
|
107
|
+
activityDetail: (reference, actor = void 0) => [
|
|
108
108
|
"capxul",
|
|
109
109
|
"activity",
|
|
110
|
+
actor ?? "self",
|
|
110
111
|
reference ?? "pending"
|
|
111
112
|
],
|
|
112
|
-
|
|
113
|
+
activitySummary: (actor, window) => [
|
|
114
|
+
"capxul",
|
|
115
|
+
"activity",
|
|
116
|
+
"summary",
|
|
117
|
+
actor ?? "self",
|
|
118
|
+
window ?? "all"
|
|
119
|
+
],
|
|
120
|
+
holdings: (actor) => [
|
|
121
|
+
"capxul",
|
|
122
|
+
"holdings",
|
|
123
|
+
actor ?? "self"
|
|
124
|
+
],
|
|
113
125
|
payments: ["capxul", "payments"],
|
|
114
126
|
payment: (paymentId) => [
|
|
115
127
|
"capxul",
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { A as useCapxulAuth, C as CreateOrganizationSubmission, D as ProfileDetails, E as OrganizationDetails, M as useCapxulIdentity, N as useCapxulSend, O as SendResult, P as useCapxulTransitions, S as CapxulSend, T as InvocationOptions, _ as ReadyDestination, a as AuthenticationSlots, b as Slot, c as ControllerAction, d as OnboardingControllerProps, f as OrgFailure, g as ProfileSlotProps, h as PendingAuthState, i as AuthenticatedState, j as useCapxulDestination, k as entered, l as FaultedState, m as OtpPendingState, n as AccountProgress, o as CapxulAuthenticationController, p as OrgProgress, r as ActionResult, s as CapxulOnboardingController, t as AccountFailure, u as NavigationAction, v as RetryAction, w as Destination, x as CapxulAuth, y as SignedOutState } from "./controllers-BT4YzBr9.mjs";
|
|
2
|
-
import { ReactNode } from "react";
|
|
2
|
+
import { ReactNode, RefCallback } from "react";
|
|
3
3
|
import { QueryClient, UseMutationResult, UseQueryResult } from "@tanstack/react-query";
|
|
4
|
-
import { Account, AccountRequirement, ActivityAnnotationInput, ActivityDetail, ActivityListParams, ActivityPage, ActivityReference, AddressBookEntry, CapxulClient, CapxulError, CapxulSigner, CreateOrgInput, CurrentHoldings, HostObservability, IdentityDestination, InviteMemberInput, MemberView, Money, MoneyParseErrorReason,
|
|
4
|
+
import { Account, AccountRequirement, ActivityAnnotation, ActivityAnnotationInput, ActivityDetail, ActivityKind, ActivityListParams, ActivityPage, ActivityPhase, ActivityRange, ActivityReference, ActorReference, AddressBookEntry, CapxulClient, CapxulError, CapxulSigner, CreateOrgInput, CurrentHoldings, HostObservability, IdentityDestination, InviteMemberInput, MemberView, Money, MoneyParseErrorReason, OrgId, OrgView, OrganizationPaymentBatchInput, OrganizationPaymentInput, PartyId, Payment, PaymentDirection, PaymentDocumentRef, PaymentDocumentRender, PaymentStatus, PaymentTiming, PaymentType, PaymentsPayInput, Permission, PermissionReadResult, Profile, RoleView, isClaimed, isRestoring } from "@capxul/sdk";
|
|
5
5
|
|
|
6
6
|
//#region src/provider.d.ts
|
|
7
7
|
type CapxulProviderSharedProps = {
|
|
@@ -315,11 +315,15 @@ declare function useCapxulPermission(orgId: OrgId, permissionId: string | undefi
|
|
|
315
315
|
//#endregion
|
|
316
316
|
//#region src/hooks/use-capxul-activity.d.ts
|
|
317
317
|
declare function useCapxulActivity(params?: ActivityListParams): UseQueryResult<ActivityPage, CapxulError>;
|
|
318
|
-
declare function useCapxulActivityDetail(reference: ActivityReference | undefined): UseQueryResult<ActivityDetail | null, CapxulError>;
|
|
319
|
-
declare function useCapxulAnnotateMovement(): UseMutationResult<
|
|
318
|
+
declare function useCapxulActivityDetail(reference: ActivityReference | undefined, actor?: ActorReference): UseQueryResult<ActivityDetail | null, CapxulError>;
|
|
319
|
+
declare function useCapxulAnnotateMovement(): UseMutationResult<ActivityAnnotation, CapxulError, ActivityAnnotationInput>;
|
|
320
320
|
//#endregion
|
|
321
321
|
//#region src/hooks/use-capxul-holdings.d.ts
|
|
322
|
-
|
|
322
|
+
interface UseCapxulHoldingsParams {
|
|
323
|
+
/** Omitted = the signed-in person. SDK core already accepts one. */
|
|
324
|
+
readonly actor?: ActorReference;
|
|
325
|
+
}
|
|
326
|
+
declare function useCapxulHoldings(params?: UseCapxulHoldingsParams): UseQueryResult<CurrentHoldings, CapxulError>;
|
|
323
327
|
//#endregion
|
|
324
328
|
//#region src/hooks/use-capxul-orgs.d.ts
|
|
325
329
|
/**
|
|
@@ -600,13 +604,13 @@ interface CapxulContactsProps {
|
|
|
600
604
|
readonly onFailed: (error: CapxulError) => void;
|
|
601
605
|
readonly children: ReactNode;
|
|
602
606
|
}
|
|
603
|
-
declare function Root$
|
|
607
|
+
declare function Root$4({
|
|
604
608
|
actor,
|
|
605
609
|
onAdded,
|
|
606
610
|
onFailed,
|
|
607
611
|
children
|
|
608
612
|
}: CapxulContactsProps): import("react/jsx-runtime").JSX.Element;
|
|
609
|
-
declare function Summary({
|
|
613
|
+
declare function Summary$1({
|
|
610
614
|
children
|
|
611
615
|
}: {
|
|
612
616
|
readonly children: (slice: ContactsSummarySlice) => ReactNode;
|
|
@@ -624,12 +628,216 @@ declare function Add({
|
|
|
624
628
|
readonly children: (slice: ContactsAddSlice) => ReactNode;
|
|
625
629
|
}): import("react/jsx-runtime").JSX.Element;
|
|
626
630
|
/** The compound shape the app's own design system already uses (`StatusTabs`). */
|
|
627
|
-
declare const CapxulContacts: typeof Root$
|
|
628
|
-
Summary: typeof Summary;
|
|
631
|
+
declare const CapxulContacts: typeof Root$4 & {
|
|
632
|
+
Summary: typeof Summary$1;
|
|
629
633
|
List: typeof List;
|
|
630
634
|
Add: typeof Add;
|
|
631
635
|
};
|
|
632
636
|
//#endregion
|
|
637
|
+
//#region src/headless/activity/types.d.ts
|
|
638
|
+
/** The settled transfer a row was built from. The app builds the explorer URL. */
|
|
639
|
+
interface ActivityReceipt {
|
|
640
|
+
readonly chainId: number;
|
|
641
|
+
readonly transactionHash: string;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* One finished row. A DISCRIMINATED UNION on `kind`, because a Movement has no
|
|
645
|
+
* payment status: one flat shape carrying `status` for both kinds cannot
|
|
646
|
+
* compile. The two branches match the two branches every app mapper already
|
|
647
|
+
* writes.
|
|
648
|
+
*/
|
|
649
|
+
type ActivityRow = {
|
|
650
|
+
readonly kind: "payment";
|
|
651
|
+
readonly reference: ActivityReference;
|
|
652
|
+
readonly direction: PaymentDirection;
|
|
653
|
+
readonly counterpartyLabel: string;
|
|
654
|
+
readonly amountDisplay: string;
|
|
655
|
+
readonly signedAmountDisplay: string;
|
|
656
|
+
readonly createdAt: number;
|
|
657
|
+
readonly ledgerKind: "Payment" | "Payout" | "Deposit";
|
|
658
|
+
readonly paymentType: PaymentType;
|
|
659
|
+
readonly status: PaymentStatus;
|
|
660
|
+
readonly phase: ActivityPhase;
|
|
661
|
+
readonly receipt: ActivityReceipt | null;
|
|
662
|
+
} | {
|
|
663
|
+
readonly kind: "movement";
|
|
664
|
+
readonly reference: ActivityReference;
|
|
665
|
+
readonly direction: PaymentDirection;
|
|
666
|
+
readonly counterpartyLabel: string;
|
|
667
|
+
readonly amountDisplay: string;
|
|
668
|
+
readonly signedAmountDisplay: string;
|
|
669
|
+
readonly createdAt: number;
|
|
670
|
+
readonly classification: "movement_only_outflow";
|
|
671
|
+
readonly phase: ActivityPhase;
|
|
672
|
+
readonly receipt: ActivityReceipt;
|
|
673
|
+
};
|
|
674
|
+
/**
|
|
675
|
+
* `"last30days"` is the last 30 whole UTC days including today. Quantizing to
|
|
676
|
+
* the UTC day keeps the cache key stable for a whole day instead of changing
|
|
677
|
+
* on every render.
|
|
678
|
+
*/
|
|
679
|
+
type SummaryWindow = "all" | "last30days" | ActivityRange;
|
|
680
|
+
/**
|
|
681
|
+
* Finished money strings for ONE currency bucket, so no consumer indexes an
|
|
682
|
+
* array of per-currency totals. All four strings are `null` and `count` is `0`
|
|
683
|
+
* when the window holds no activity — we say there is nothing, the app says it
|
|
684
|
+
* in its own words.
|
|
685
|
+
*/
|
|
686
|
+
interface ActivitySummarySlice {
|
|
687
|
+
readonly currency: string | null;
|
|
688
|
+
readonly moneyIn: string | null;
|
|
689
|
+
readonly moneyOut: string | null;
|
|
690
|
+
readonly net: string | null;
|
|
691
|
+
readonly pending: string | null;
|
|
692
|
+
/** A count is not money, so it is not formatted. */
|
|
693
|
+
readonly count: number;
|
|
694
|
+
readonly isLoading: boolean;
|
|
695
|
+
readonly error: CapxulError | null;
|
|
696
|
+
}
|
|
697
|
+
interface ActivityFilterValues {
|
|
698
|
+
readonly kind?: ActivityKind;
|
|
699
|
+
readonly direction?: PaymentDirection;
|
|
700
|
+
readonly status?: readonly PaymentStatus[];
|
|
701
|
+
}
|
|
702
|
+
interface ActivityFiltersSlice {
|
|
703
|
+
readonly values: ActivityFilterValues;
|
|
704
|
+
readonly set: {
|
|
705
|
+
readonly kind: (value?: ActivityKind) => void;
|
|
706
|
+
readonly direction: (value?: PaymentDirection) => void; /** REPLACES the array; it does not toggle one value. */
|
|
707
|
+
readonly status: (value: readonly PaymentStatus[]) => void;
|
|
708
|
+
readonly clear: () => void;
|
|
709
|
+
};
|
|
710
|
+
/** CODES, never labels. There is no `{value, label}` pair in this seam. */
|
|
711
|
+
readonly options: {
|
|
712
|
+
readonly kind: readonly ActivityKind[];
|
|
713
|
+
readonly direction: readonly PaymentDirection[];
|
|
714
|
+
readonly status: readonly PaymentStatus[];
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
interface ActivitySearchSlice {
|
|
718
|
+
readonly value: string;
|
|
719
|
+
readonly change: (text: string) => void;
|
|
720
|
+
}
|
|
721
|
+
interface ActivityRowsSlice {
|
|
722
|
+
/** Already filtered and already searched. */
|
|
723
|
+
readonly rows: readonly ActivityRow[];
|
|
724
|
+
readonly isLoading: boolean;
|
|
725
|
+
readonly error: CapxulError | null;
|
|
726
|
+
readonly retry: () => void;
|
|
727
|
+
/** Server read time of the newest page, so the app can say which read is older. */
|
|
728
|
+
readonly observedAt: number | null;
|
|
729
|
+
}
|
|
730
|
+
interface ActivityLoadMoreSlice {
|
|
731
|
+
readonly hasMore: boolean;
|
|
732
|
+
readonly loadMore: () => void;
|
|
733
|
+
readonly isLoadingMore: boolean;
|
|
734
|
+
/**
|
|
735
|
+
* Attach to whatever the screen renders at the bottom of the list. Where
|
|
736
|
+
* `IntersectionObserver` is undefined — server rendering, and the jsdom test
|
|
737
|
+
* environment — attaching is a no-op and `loadMore()` stays callable.
|
|
738
|
+
*
|
|
739
|
+
* A CALLBACK ref, not the wider `Ref<HTMLElement>`: `RefObject` is invariant,
|
|
740
|
+
* so `Ref<HTMLElement>` refuses to attach to a `<div>`, which is exactly what
|
|
741
|
+
* a screen renders at the bottom of its list.
|
|
742
|
+
*/
|
|
743
|
+
readonly sentinelRef: RefCallback<HTMLElement>;
|
|
744
|
+
}
|
|
745
|
+
interface ActivityDetailSlice {
|
|
746
|
+
/** ONE finished document, never the array, so no consumer writes `documents[0]`. */
|
|
747
|
+
readonly receiptDocument: PaymentDocumentRef | null;
|
|
748
|
+
readonly openReceiptDocument: () => Promise<PaymentDocumentRender>;
|
|
749
|
+
readonly isOpeningDocument: boolean;
|
|
750
|
+
readonly memo: string;
|
|
751
|
+
readonly setMemo: (text: string) => void;
|
|
752
|
+
readonly saveMemo: () => void;
|
|
753
|
+
readonly isSavingMemo: boolean;
|
|
754
|
+
readonly isLoading: boolean;
|
|
755
|
+
readonly error: CapxulError | null;
|
|
756
|
+
}
|
|
757
|
+
interface CsvExport {
|
|
758
|
+
readonly text: string;
|
|
759
|
+
readonly rowCount: number;
|
|
760
|
+
/** The 5,000-row ceiling was reached and rows were left unread. */
|
|
761
|
+
readonly truncated: boolean;
|
|
762
|
+
}
|
|
763
|
+
interface ActivityExportSlice {
|
|
764
|
+
readonly toCsv: () => Promise<CsvExport>;
|
|
765
|
+
readonly isExporting: boolean;
|
|
766
|
+
}
|
|
767
|
+
//#endregion
|
|
768
|
+
//#region src/headless/activity/activity.d.ts
|
|
769
|
+
interface CapxulActivityProps {
|
|
770
|
+
/** Omitted = the signed-in person. */
|
|
771
|
+
readonly actor?: ActorReference;
|
|
772
|
+
/**
|
|
773
|
+
* 1..100, default 25. The root CLAMPS an out-of-range value into that band
|
|
774
|
+
* and warns once in development; it never throws, because a bad prop must not
|
|
775
|
+
* blank a screen. The band is the backend's own.
|
|
776
|
+
*/
|
|
777
|
+
readonly pageSize?: number;
|
|
778
|
+
readonly children: ReactNode;
|
|
779
|
+
}
|
|
780
|
+
declare function Root$3({
|
|
781
|
+
actor,
|
|
782
|
+
pageSize,
|
|
783
|
+
children
|
|
784
|
+
}: CapxulActivityProps): import("react/jsx-runtime").JSX.Element;
|
|
785
|
+
/**
|
|
786
|
+
* The one part that holds a query rather than reading the engine's: it takes a
|
|
787
|
+
* `window` prop, and two placements can ask for different windows, so a single
|
|
788
|
+
* pre-fetched result cannot serve both. It still holds no logic and draws
|
|
789
|
+
* nothing.
|
|
790
|
+
*/
|
|
791
|
+
declare function Summary({
|
|
792
|
+
window,
|
|
793
|
+
children
|
|
794
|
+
}: {
|
|
795
|
+
readonly window?: SummaryWindow;
|
|
796
|
+
readonly children: (slice: ActivitySummarySlice) => ReactNode;
|
|
797
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
798
|
+
declare function Filters({
|
|
799
|
+
children
|
|
800
|
+
}: {
|
|
801
|
+
readonly children: (slice: ActivityFiltersSlice) => ReactNode;
|
|
802
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
803
|
+
declare function Search({
|
|
804
|
+
children
|
|
805
|
+
}: {
|
|
806
|
+
readonly children: (slice: ActivitySearchSlice) => ReactNode;
|
|
807
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
808
|
+
declare function Rows({
|
|
809
|
+
children
|
|
810
|
+
}: {
|
|
811
|
+
readonly children: (slice: ActivityRowsSlice) => ReactNode;
|
|
812
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
813
|
+
declare function LoadMore({
|
|
814
|
+
children
|
|
815
|
+
}: {
|
|
816
|
+
readonly children: (slice: ActivityLoadMoreSlice) => ReactNode;
|
|
817
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
818
|
+
declare function Detail({
|
|
819
|
+
reference,
|
|
820
|
+
children
|
|
821
|
+
}: {
|
|
822
|
+
readonly reference?: ActivityReference;
|
|
823
|
+
readonly children: (slice: ActivityDetailSlice) => ReactNode;
|
|
824
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
825
|
+
declare function Export({
|
|
826
|
+
children
|
|
827
|
+
}: {
|
|
828
|
+
readonly children: (slice: ActivityExportSlice) => ReactNode;
|
|
829
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
830
|
+
/** The compound shape the app's own design system already uses (`StatusTabs`). */
|
|
831
|
+
declare const CapxulActivity: typeof Root$3 & {
|
|
832
|
+
Summary: typeof Summary;
|
|
833
|
+
Filters: typeof Filters;
|
|
834
|
+
Search: typeof Search;
|
|
835
|
+
Rows: typeof Rows;
|
|
836
|
+
LoadMore: typeof LoadMore;
|
|
837
|
+
Detail: typeof Detail;
|
|
838
|
+
Export: typeof Export;
|
|
839
|
+
};
|
|
840
|
+
//#endregion
|
|
633
841
|
//#region src/headless/send-money/use-recipient-resolution.d.ts
|
|
634
842
|
type SendMoneyRecipientMethod = "username" | "email-address";
|
|
635
843
|
type SendMoneyRecipientStatus = "empty" | "checking" | "found" | "not-found" | "failed";
|
|
@@ -834,4 +1042,31 @@ declare const CapxulDashboardAccess: typeof Root & {
|
|
|
834
1042
|
Granted: typeof Granted;
|
|
835
1043
|
};
|
|
836
1044
|
//#endregion
|
|
837
|
-
|
|
1045
|
+
//#region src/internal/reactivity-keys.d.ts
|
|
1046
|
+
declare const capxulKeys: {
|
|
1047
|
+
root: readonly ["capxul"];
|
|
1048
|
+
profile: readonly ["capxul", "profile"];
|
|
1049
|
+
usernameAvailability: (username: string) => readonly ["capxul", "profile", "username-availability", string];
|
|
1050
|
+
account: readonly ["capxul", "account"];
|
|
1051
|
+
provisioning: readonly ["capxul", "provisioning"];
|
|
1052
|
+
binding: readonly ["capxul", "binding"];
|
|
1053
|
+
accountBalance: readonly ["capxul", "accountBalance"];
|
|
1054
|
+
orgs: readonly ["capxul", "orgs"];
|
|
1055
|
+
org: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId];
|
|
1056
|
+
orgMembers: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "members"];
|
|
1057
|
+
orgRoles: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "roles"];
|
|
1058
|
+
orgTreasury: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "treasury"];
|
|
1059
|
+
orgPermissions: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "permissions"];
|
|
1060
|
+
orgMe: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "me"];
|
|
1061
|
+
orgLifecycle: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "lifecycle"];
|
|
1062
|
+
contacts: (scope: string) => readonly ["capxul", "contacts", string];
|
|
1063
|
+
contactsList: (scope: string, includeHidden: boolean) => readonly ["capxul", "contacts", string, "all" | "visible"];
|
|
1064
|
+
activity: readonly ["capxul", "activity"];
|
|
1065
|
+
activityDetail: (reference: ActivityReference | undefined, actor?: ActorReference | undefined) => readonly ["capxul", "activity", "self" | ActorReference, "pending" | ActivityReference];
|
|
1066
|
+
activitySummary: (actor?: ActorReference, window?: ActivityRange) => readonly ["capxul", "activity", "summary", "self" | ActorReference, "all" | ActivityRange];
|
|
1067
|
+
holdings: (actor?: ActorReference) => readonly ["capxul", "holdings", "self" | ActorReference];
|
|
1068
|
+
payments: readonly ["capxul", "payments"];
|
|
1069
|
+
payment: (paymentId: string | undefined) => readonly ["capxul", "payments", string];
|
|
1070
|
+
};
|
|
1071
|
+
//#endregion
|
|
1072
|
+
export { type AccountFailure, type AccountProgress, type ActionResult, type ActivityDetailSlice, type ActivityExportSlice, type ActivityFilterValues, type ActivityFiltersSlice, type ActivityLoadMoreSlice, type ActivityReceipt, type ActivityRow, type ActivityRowsSlice, type ActivitySearchSlice, type ActivitySummarySlice, type AuthenticatedState, type AuthenticationSlots, type CanReason, CapxulActivity, type CapxulActivityProps, type CapxulAuth, CapxulAuthenticationController, type CapxulBootstrapState, type CapxulBootstrapStatus, CapxulContacts, type CapxulContactsProps, CapxulDashboardAccess, type CapxulDashboardAccessProps, CapxulOnboardingController, CapxulOrgMember, type CapxulOrgMemberProps, CapxulProvider, type CapxulProviderProps, type CapxulSend, CapxulSendMoney, type CapxulSendMoneyBlockedReason, type CapxulSendMoneyProps, type Contact, type ContactRelationship, type ContactRow, type ContactsActor, type ContactsAddBlockedReason, type ContactsAddError, type ContactsAddSlice, type ContactsListOptions, type ContactsListSlice, type ContactsRefusal, type ContactsSummarySlice, type ControllerAction, type CreateOrganizationSubmission, type CsvExport, type DashboardAccessErrorSlice, type DashboardAccessPhase, type DashboardAccessRedirectSlice, type DashboardScope, type Destination, type FaultedState, type ImageUploadInput, type ImageUploadTarget, type InvocationOptions, type NavigationAction, type OnboardingControllerProps, type OnboardingIntent, type OnboardingJourney, type OnboardingJourneyPosition, type OnboardingOrigin, type OnboardingStep, type OrgFailure, type OrgMemberAction, type OrgMemberCanSlice, type OrgMemberStanding, type OrgMemberStandingSlice, type OrgProgress, type OrganizationDetails, type OrganizationDraft, type OtpPendingState, type PayoutDraftChain, type PayoutDraftEntry, type PendingAuthState, type ProfileDetails, type ProfileDraft, type ProfileSlotProps, type ReadyDestination, type RetryAction, type SendActor, type SendMoneyActionsSlice, type SendMoneyAmountSlice, type SendMoneyAssetError, type SendMoneyAssetOption, type SendMoneyAssetSlice, type SendMoneyRecipientMethod, type SendMoneyRecipientSlice, type SendMoneyRecipientStatus, type SendResult, type SentPayment, type SignedOutState, type Slot, type SummaryWindow, type UseCapxulAccountBalanceOptions, type UseCapxulAccountBalanceReturn, type UseCapxulAccountFundReturn, type UseCapxulCreateCommitmentReturn, type UseCapxulCreateOrgReturn, type UseCapxulImageUploadReturn, type UseCapxulInviteMemberReturn, type UseCapxulOrgMembersOptions, type UseCapxulOrgMembersReturn, type UseCapxulOrgRolesOptions, type UseCapxulOrgRolesReturn, type UseCapxulOrgTreasuryOptions, type UseCapxulOrgTreasuryReturn, type UseCapxulOrgsReturn, type UseCapxulPayReturn, type UseCapxulPaymentReturn, type UseCapxulPaymentsReturn, type UseCapxulProfileReturn, type UseCapxulRedirectPaymentReturn, type UseCapxulUsernameAvailabilityReturn, type UsernameAvailability, acknowledgeOnboardingDestination, activeOnboardingRecovery, capxulKeys, clearOnboardingJourney, currentOnboardingJourneyId, entered, invalidateOnboardingJourneyObservation, isClaimed, isRestoring, loadOnboardingJourney, onboardingJourneyPosition, saveOnboardingJourney, startOnboardingJourney, useCapxul, useCapxulAccountBalance, useCapxulAccountFund, useCapxulActivity, useCapxulActivityDetail, useCapxulAnnotateMovement, useCapxulAuth, useCapxulCancelPayment, useCapxulClaimPayment, useCapxulClientOrNull, useCapxulCreateCommitment, useCapxulCreateOrg, useCapxulDestination, useCapxulHoldings, useCapxulIdentity, useCapxulImageUpload, useCapxulInviteMember, useCapxulOrgMembers, useCapxulOrgRoles, useCapxulOrgTreasury, useCapxulOrganizationPay, useCapxulOrganizationPayBatch, useCapxulOrgs, useCapxulPay, useCapxulPayment, useCapxulPayments, useCapxulPermission, useCapxulPermissionAssign, useCapxulPermissionChange, useCapxulPermissionCreate, useCapxulPermissionReplace, useCapxulPermissionRevoke, useCapxulPermissions, useCapxulProfile, useCapxulRedirectPayment, useCapxulSend, useCapxulTransitions, useCapxulUsernameAvailability };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { a as useCapxulAuth, c as useCapxulIdentityOrNull, d as capxulKeys, f as useCapxulClientOrNull, i as entered, l as useCapxulSend, n as CapxulOnboardingController, o as useCapxulDestination, p as useCapxul, r as CapxulProvider, s as useCapxulIdentity, t as CapxulAuthenticationController, u as useCapxulTransitions } from "./controllers-
|
|
2
|
+
import { a as useCapxulAuth, c as useCapxulIdentityOrNull, d as capxulKeys, f as useCapxulClientOrNull, i as entered, l as useCapxulSend, n as CapxulOnboardingController, o as useCapxulDestination, p as useCapxul, r as CapxulProvider, s as useCapxulIdentity, t as CapxulAuthenticationController, u as useCapxulTransitions } from "./controllers-DLBe4-OP.mjs";
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
-
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
5
|
-
import { CapxulError, Errors, fingerprintPaymentIntent, formatMoney, isClaimed, isClaimed as isClaimed$1, isMoneyParseError, isRestoring, isRestoring as isRestoring$1, parseMoney, resolveIdentityDestination } from "@capxul/sdk";
|
|
4
|
+
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
5
|
+
import { CapxulError, Errors, PAYMENT_DIRECTIONS, PAYMENT_STATUSES, fingerprintPaymentIntent, formatMoney, isCapxulError, isClaimed, isClaimed as isClaimed$1, isMoneyParseError, isRestoring, isRestoring as isRestoring$1, parseMoney, paymentPhase, resolveIdentityDestination } from "@capxul/sdk";
|
|
6
6
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
7
7
|
//#region src/internal/require-bootstrapped-client.ts
|
|
8
8
|
/**
|
|
@@ -429,14 +429,14 @@ function useCapxulActivity(params) {
|
|
|
429
429
|
enabled: client !== null && identity !== null && isClaimed$1(identity)
|
|
430
430
|
});
|
|
431
431
|
}
|
|
432
|
-
function useCapxulActivityDetail(reference) {
|
|
432
|
+
function useCapxulActivityDetail(reference, actor) {
|
|
433
433
|
const client = useCapxulClientOrNull();
|
|
434
434
|
const identity = useCapxulIdentityOrNull();
|
|
435
435
|
return useQuery({
|
|
436
|
-
queryKey: capxulKeys.activityDetail(reference),
|
|
436
|
+
queryKey: capxulKeys.activityDetail(reference, actor),
|
|
437
437
|
queryFn: async () => {
|
|
438
438
|
if (reference === void 0) throw Errors.invalidInput("reference", "required for activity.get");
|
|
439
|
-
return unwrapCapxulResult(await requireBootstrappedClient(client, "activity.get").activity.get(reference));
|
|
439
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, "activity.get").activity.get(reference, actor === void 0 ? void 0 : { actor }));
|
|
440
440
|
},
|
|
441
441
|
enabled: client !== null && reference !== void 0 && identity !== null && isClaimed$1(identity)
|
|
442
442
|
});
|
|
@@ -453,13 +453,14 @@ function useCapxulAnnotateMovement() {
|
|
|
453
453
|
}
|
|
454
454
|
//#endregion
|
|
455
455
|
//#region src/hooks/use-capxul-holdings.ts
|
|
456
|
-
function useCapxulHoldings() {
|
|
456
|
+
function useCapxulHoldings(params) {
|
|
457
457
|
const client = useCapxulClientOrNull();
|
|
458
458
|
const identity = useCapxulIdentityOrNull();
|
|
459
|
+
const actor = params?.actor;
|
|
459
460
|
return useQuery({
|
|
460
|
-
queryKey: capxulKeys.holdings,
|
|
461
|
+
queryKey: capxulKeys.holdings(actor),
|
|
461
462
|
queryFn: async () => {
|
|
462
|
-
return unwrapCapxulResult(await requireBootstrappedClient(client, "holdings.current").holdings.current());
|
|
463
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, "holdings.current").holdings.current(actor === void 0 ? void 0 : { actor }));
|
|
463
464
|
},
|
|
464
465
|
enabled: client !== null && identity !== null && isClaimed$1(identity)
|
|
465
466
|
});
|
|
@@ -1013,7 +1014,7 @@ function useContactsContext() {
|
|
|
1013
1014
|
if (engine === null) throw new Error("CapxulContacts parts must be used inside <CapxulContacts>");
|
|
1014
1015
|
return engine;
|
|
1015
1016
|
}
|
|
1016
|
-
function Root$
|
|
1017
|
+
function Root$4({ actor, onAdded, onFailed, children }) {
|
|
1017
1018
|
const engine = useContacts({
|
|
1018
1019
|
actor,
|
|
1019
1020
|
onAdded,
|
|
@@ -1024,7 +1025,7 @@ function Root$3({ actor, onAdded, onFailed, children }) {
|
|
|
1024
1025
|
children
|
|
1025
1026
|
});
|
|
1026
1027
|
}
|
|
1027
|
-
function Summary({ children }) {
|
|
1028
|
+
function Summary$1({ children }) {
|
|
1028
1029
|
return /* @__PURE__ */ jsx(Fragment, { children: children(useContactsSummary(useContactsContext())) });
|
|
1029
1030
|
}
|
|
1030
1031
|
function List({ limit, show, children }) {
|
|
@@ -1037,12 +1038,672 @@ function Add({ children }) {
|
|
|
1037
1038
|
return /* @__PURE__ */ jsx(Fragment, { children: children(useContactsContext().add) });
|
|
1038
1039
|
}
|
|
1039
1040
|
/** The compound shape the app's own design system already uses (`StatusTabs`). */
|
|
1040
|
-
const CapxulContacts = Object.assign(Root$
|
|
1041
|
-
Summary,
|
|
1041
|
+
const CapxulContacts = Object.assign(Root$4, {
|
|
1042
|
+
Summary: Summary$1,
|
|
1042
1043
|
List,
|
|
1043
1044
|
Add
|
|
1044
1045
|
});
|
|
1045
1046
|
//#endregion
|
|
1047
|
+
//#region src/internal/as-capxul-error.ts
|
|
1048
|
+
/**
|
|
1049
|
+
* TanStack types a query error as `Error`. Every query in this package throws
|
|
1050
|
+
* through `unwrapCapxulResult` or `requireBootstrappedClient`, so the value IS a
|
|
1051
|
+
* `CapxulError`. Anything else is a defect inside this package: it is WRAPPED
|
|
1052
|
+
* with the `UNKNOWN` code and its cause, never swallowed, because a slice hands
|
|
1053
|
+
* the app an error VALUE carrying a code and the app writes the sentence
|
|
1054
|
+
* (ADR-0023).
|
|
1055
|
+
*/
|
|
1056
|
+
function asCapxulError(error) {
|
|
1057
|
+
if (error === null) return null;
|
|
1058
|
+
return isCapxulError(error) ? error : Errors.unknown(error);
|
|
1059
|
+
}
|
|
1060
|
+
//#endregion
|
|
1061
|
+
//#region src/headless/activity/enabled.ts
|
|
1062
|
+
/**
|
|
1063
|
+
* The one gate every read under `CapxulActivity` shares — the engine, each
|
|
1064
|
+
* `.Summary` lane, and each `.Detail` lane. One function, because a gate that
|
|
1065
|
+
* differs between the list and the detail lets a screen load rows it can never
|
|
1066
|
+
* open.
|
|
1067
|
+
*
|
|
1068
|
+
* Every backend activity read resolves the authenticated Account before it
|
|
1069
|
+
* resolves either a personal or Organization actor. Wait for that Account so a
|
|
1070
|
+
* new session cannot issue requests the backend must refuse.
|
|
1071
|
+
*/
|
|
1072
|
+
function useActivityEnabled() {
|
|
1073
|
+
const client = useCapxulClientOrNull();
|
|
1074
|
+
const identity = useCapxulIdentityOrNull();
|
|
1075
|
+
return client !== null && identity !== null && isClaimed$1(identity);
|
|
1076
|
+
}
|
|
1077
|
+
//#endregion
|
|
1078
|
+
//#region src/headless/activity/detail.ts
|
|
1079
|
+
/**
|
|
1080
|
+
* ONE finished document, never the array, so no consumer writes `documents[0]`:
|
|
1081
|
+
* the payslip, else the receipt, else nothing. Those two kinds are the ones the
|
|
1082
|
+
* Download receipt button is for. A Movement detail carries no documents.
|
|
1083
|
+
*/
|
|
1084
|
+
function pickReceiptDocument(detail) {
|
|
1085
|
+
if (detail === null || detail.kind !== "payment") return null;
|
|
1086
|
+
const documents = detail.payment.documents;
|
|
1087
|
+
return documents.find((document) => document.kind === "payslip") ?? documents.find((document) => document.kind === "receipt") ?? null;
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* The root actor and the whole reference are included. A payment reference can
|
|
1091
|
+
* carry its own actor, and a Movement reference relies on the root actor. A key
|
|
1092
|
+
* of kind and id alone would show one actor's draft memo on the other actor's
|
|
1093
|
+
* row, and save it there.
|
|
1094
|
+
*
|
|
1095
|
+
* The parts go into an ARRAY, and the array is what gets serialized. A joined
|
|
1096
|
+
* string collides: an organization whose id is the sentinel `self`, or any id
|
|
1097
|
+
* that carries the separator, produces another reference's key. Serializing the
|
|
1098
|
+
* reference OBJECT collides the other way, because property order is not part of
|
|
1099
|
+
* a reference's meaning and a literal written `{ id, kind }` must not read as a
|
|
1100
|
+
* different row. The array is ordered here, by this function, so neither the
|
|
1101
|
+
* caller's property order nor the content of an id can move a part.
|
|
1102
|
+
*/
|
|
1103
|
+
function actorKey(actor) {
|
|
1104
|
+
if (actor === void 0) return null;
|
|
1105
|
+
return actor.kind === "organization" ? [actor.kind, actor.organizationId] : [actor.kind];
|
|
1106
|
+
}
|
|
1107
|
+
function activityDetailKey(actor, reference) {
|
|
1108
|
+
if (reference === void 0) return JSON.stringify([actorKey(actor), null]);
|
|
1109
|
+
const referenceActor = reference.kind === "payment" ? reference.actor : void 0;
|
|
1110
|
+
return JSON.stringify([actorKey(actor), [
|
|
1111
|
+
reference.kind,
|
|
1112
|
+
reference.id,
|
|
1113
|
+
actorKey(referenceActor)
|
|
1114
|
+
]]);
|
|
1115
|
+
}
|
|
1116
|
+
function useActivityDetail(reference, actor) {
|
|
1117
|
+
const client = useCapxulClientOrNull();
|
|
1118
|
+
const enabled = useActivityEnabled() && reference !== void 0;
|
|
1119
|
+
const detail = useQuery({
|
|
1120
|
+
queryKey: capxulKeys.activityDetail(reference, actor),
|
|
1121
|
+
queryFn: async () => {
|
|
1122
|
+
if (reference === void 0) throw Errors.invalidInput("reference", "required for activity.get");
|
|
1123
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, "activity.get").activity.get(reference, actor === void 0 ? void 0 : { actor }));
|
|
1124
|
+
},
|
|
1125
|
+
enabled
|
|
1126
|
+
});
|
|
1127
|
+
const receiptDocument = pickReceiptDocument(detail.data ?? null);
|
|
1128
|
+
const [isOpeningDocument, setIsOpeningDocument] = useState(false);
|
|
1129
|
+
const openReceiptDocument = useCallback(async () => {
|
|
1130
|
+
if (reference === void 0 || receiptDocument === null) throw Errors.invalidInput("receiptDocument", "no renderable document on this row");
|
|
1131
|
+
setIsOpeningDocument(true);
|
|
1132
|
+
try {
|
|
1133
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, "paymentDocuments.render").paymentDocuments.render(receiptDocument.documentHash));
|
|
1134
|
+
} finally {
|
|
1135
|
+
setIsOpeningDocument(false);
|
|
1136
|
+
}
|
|
1137
|
+
}, [
|
|
1138
|
+
client,
|
|
1139
|
+
receiptDocument,
|
|
1140
|
+
reference
|
|
1141
|
+
]);
|
|
1142
|
+
const [typed, setTyped] = useState(null);
|
|
1143
|
+
const annotate = useCapxulAnnotateMovement();
|
|
1144
|
+
const saveMemo = useCallback(() => {
|
|
1145
|
+
if (reference === void 0 || typed === null) return;
|
|
1146
|
+
annotate.mutate({
|
|
1147
|
+
...actor === void 0 ? {} : { actor },
|
|
1148
|
+
reference,
|
|
1149
|
+
memo: typed
|
|
1150
|
+
});
|
|
1151
|
+
}, [
|
|
1152
|
+
actor,
|
|
1153
|
+
annotate,
|
|
1154
|
+
reference,
|
|
1155
|
+
typed
|
|
1156
|
+
]);
|
|
1157
|
+
return {
|
|
1158
|
+
receiptDocument,
|
|
1159
|
+
openReceiptDocument,
|
|
1160
|
+
isOpeningDocument,
|
|
1161
|
+
memo: typed ?? detail.data?.annotation?.memo ?? "",
|
|
1162
|
+
setMemo: setTyped,
|
|
1163
|
+
saveMemo,
|
|
1164
|
+
isSavingMemo: annotate.isPending,
|
|
1165
|
+
isLoading: enabled && detail.isLoading,
|
|
1166
|
+
error: asCapxulError(detail.error) ?? annotate.error ?? null
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
//#endregion
|
|
1170
|
+
//#region src/headless/activity/summary.ts
|
|
1171
|
+
const DAY_MS = 864e5;
|
|
1172
|
+
/**
|
|
1173
|
+
* `"last30days"` is the last 30 whole UTC days including today. Quantizing to
|
|
1174
|
+
* the UTC day keeps the cache key stable for a whole day instead of changing on
|
|
1175
|
+
* every render.
|
|
1176
|
+
*/
|
|
1177
|
+
function resolveWindow(window, now) {
|
|
1178
|
+
if (window === "all") return void 0;
|
|
1179
|
+
if (window === "last30days") return { from: Math.floor(now / DAY_MS) * DAY_MS - 29 * DAY_MS };
|
|
1180
|
+
return window;
|
|
1181
|
+
}
|
|
1182
|
+
/** An integer raw-unit string lifted into a major-unit decimal string. */
|
|
1183
|
+
function majorUnits(raw, decimals) {
|
|
1184
|
+
const negative = raw.startsWith("-");
|
|
1185
|
+
const digits = negative ? raw.slice(1) : raw;
|
|
1186
|
+
const sign = negative ? "-" : "";
|
|
1187
|
+
if (decimals === 0) return `${sign}${digits}`;
|
|
1188
|
+
const padded = digits.padStart(decimals + 1, "0");
|
|
1189
|
+
const cut = padded.length - decimals;
|
|
1190
|
+
return `${sign}${padded.slice(0, cut)}.${padded.slice(cut)}`;
|
|
1191
|
+
}
|
|
1192
|
+
function absoluteNet(total) {
|
|
1193
|
+
const net = BigInt(total.net);
|
|
1194
|
+
return net < 0n ? -net : net;
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Buckets carry different `decimals`, so their raw integers are not comparable.
|
|
1198
|
+
* Both are scaled to the wider precision before the magnitudes are ordered.
|
|
1199
|
+
*/
|
|
1200
|
+
function compareNet(left, right) {
|
|
1201
|
+
const width = Math.max(left.decimals, right.decimals);
|
|
1202
|
+
const scaledLeft = absoluteNet(left) * 10n ** BigInt(width - left.decimals);
|
|
1203
|
+
const scaledRight = absoluteNet(right) * 10n ** BigInt(width - right.decimals);
|
|
1204
|
+
if (scaledLeft === scaledRight) return 0;
|
|
1205
|
+
return scaledLeft < scaledRight ? -1 : 1;
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Which currency `.Summary` shows: the bucket matching the primary holding's
|
|
1209
|
+
* currency, else the bucket with the largest absolute `net`, breaking a tie on
|
|
1210
|
+
* currency code ascending so the choice is stable across reloads.
|
|
1211
|
+
*
|
|
1212
|
+
* The primary holding is matched on `available.currency` — the consumer
|
|
1213
|
+
* `CurrencyCode` — and NOT on `Holding.symbol`, which is the raw token ticker
|
|
1214
|
+
* ("USDX") and can never equal a bucket's currency ("USD"). See the contract
|
|
1215
|
+
* correction on #1449.
|
|
1216
|
+
*/
|
|
1217
|
+
function pickBucket(totals, primaryCurrency) {
|
|
1218
|
+
if (primaryCurrency !== null) {
|
|
1219
|
+
const matched = totals.find((total) => total.currency === primaryCurrency);
|
|
1220
|
+
if (matched !== void 0) return matched;
|
|
1221
|
+
}
|
|
1222
|
+
let best = null;
|
|
1223
|
+
for (const total of totals) {
|
|
1224
|
+
if (best === null) {
|
|
1225
|
+
best = total;
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
const order = compareNet(total, best);
|
|
1229
|
+
if (order > 0 || order === 0 && total.currency < best.currency) best = total;
|
|
1230
|
+
}
|
|
1231
|
+
return best;
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* The current UTC day number, which advances ON ITS OWN at UTC midnight.
|
|
1235
|
+
*
|
|
1236
|
+
* The day is NOT held in state. It is read at every render, so it can never be
|
|
1237
|
+
* stale — not after a mount that sat through midnight, and not when a part
|
|
1238
|
+
* mounted on a fixed window is later switched to a rolling one. State holds
|
|
1239
|
+
* only `tick`, whose single job is to force the render that a screen sitting
|
|
1240
|
+
* idle would otherwise never do: React recomputes nothing on its own, so an
|
|
1241
|
+
* untouched summary would hold yesterday's boundary indefinitely.
|
|
1242
|
+
*
|
|
1243
|
+
* The effect depends on `tick`, not on the day, so the timer re-arms whatever
|
|
1244
|
+
* the clock says when it fires. A wake a millisecond early re-arms for the
|
|
1245
|
+
* boundary still ahead instead of silently ending the rollover, and a wake
|
|
1246
|
+
* hours late — a throttled tab, a sleeping machine — lands on the true day
|
|
1247
|
+
* rather than drifting one day per sleep.
|
|
1248
|
+
*
|
|
1249
|
+
* `active` is false for the windows that do not roll, so a fixed window arms no
|
|
1250
|
+
* timer at all.
|
|
1251
|
+
*/
|
|
1252
|
+
function useUtcDay(active) {
|
|
1253
|
+
const [tick, setTick] = useState(0);
|
|
1254
|
+
useEffect(() => {
|
|
1255
|
+
if (!active) return;
|
|
1256
|
+
const timer = setTimeout(() => {
|
|
1257
|
+
setTick((value) => value + 1);
|
|
1258
|
+
}, DAY_MS - Date.now() % DAY_MS + 1);
|
|
1259
|
+
return () => {
|
|
1260
|
+
clearTimeout(timer);
|
|
1261
|
+
};
|
|
1262
|
+
}, [active, tick]);
|
|
1263
|
+
return Math.floor(Date.now() / DAY_MS);
|
|
1264
|
+
}
|
|
1265
|
+
function useActivitySummary(actor, window) {
|
|
1266
|
+
const client = useCapxulClientOrNull();
|
|
1267
|
+
const enabled = useActivityEnabled();
|
|
1268
|
+
const range = resolveWindow(window, useUtcDay(window === "last30days") * DAY_MS);
|
|
1269
|
+
const summary = useQuery({
|
|
1270
|
+
queryKey: capxulKeys.activitySummary(actor, range),
|
|
1271
|
+
queryFn: async () => {
|
|
1272
|
+
const params = {};
|
|
1273
|
+
if (actor !== void 0) params.actor = actor;
|
|
1274
|
+
if (range !== void 0) params.window = range;
|
|
1275
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, "activity.summary").activity.summary(params));
|
|
1276
|
+
},
|
|
1277
|
+
enabled
|
|
1278
|
+
});
|
|
1279
|
+
const primary = useQuery({
|
|
1280
|
+
queryKey: [...capxulKeys.holdings(actor), "primary"],
|
|
1281
|
+
queryFn: async () => {
|
|
1282
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, "holdings.primary").holdings.primary(actor === void 0 ? void 0 : { actor }));
|
|
1283
|
+
},
|
|
1284
|
+
enabled
|
|
1285
|
+
});
|
|
1286
|
+
const totals = summary.data?.totals;
|
|
1287
|
+
const primaryCurrency = primary.data?.available.currency ?? null;
|
|
1288
|
+
const isLoading = summary.isLoading || primary.isLoading;
|
|
1289
|
+
const bucket = useMemo(() => totals === void 0 || isLoading ? null : pickBucket(totals, primaryCurrency), [
|
|
1290
|
+
isLoading,
|
|
1291
|
+
primaryCurrency,
|
|
1292
|
+
totals
|
|
1293
|
+
]);
|
|
1294
|
+
if (bucket === null) return {
|
|
1295
|
+
currency: null,
|
|
1296
|
+
moneyIn: null,
|
|
1297
|
+
moneyOut: null,
|
|
1298
|
+
net: null,
|
|
1299
|
+
pending: null,
|
|
1300
|
+
count: summary.data?.count ?? 0,
|
|
1301
|
+
isLoading,
|
|
1302
|
+
error: asCapxulError(summary.error)
|
|
1303
|
+
};
|
|
1304
|
+
const display = (raw) => formatMoney({
|
|
1305
|
+
currency: bucket.currency,
|
|
1306
|
+
value: majorUnits(raw, bucket.decimals),
|
|
1307
|
+
decimals: bucket.decimals
|
|
1308
|
+
});
|
|
1309
|
+
return {
|
|
1310
|
+
currency: bucket.currency,
|
|
1311
|
+
moneyIn: display(bucket.in),
|
|
1312
|
+
moneyOut: display(bucket.out),
|
|
1313
|
+
net: display(bucket.net),
|
|
1314
|
+
pending: display(bucket.pendingIn),
|
|
1315
|
+
count: summary.data?.count ?? 0,
|
|
1316
|
+
isLoading,
|
|
1317
|
+
error: asCapxulError(summary.error)
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
//#endregion
|
|
1321
|
+
//#region src/headless/activity/rows.ts
|
|
1322
|
+
/**
|
|
1323
|
+
* A Movement's phase is DERIVED, not asserted: `movementItems` returns `null`
|
|
1324
|
+
* for any Movement whose `canonicalState` is not `"finalized"`
|
|
1325
|
+
* (`activityList.ts:120`), so a Movement that reaches a page is finished and
|
|
1326
|
+
* carries no verdict of its own.
|
|
1327
|
+
*/
|
|
1328
|
+
const MOVEMENT_PHASE = Object.freeze({
|
|
1329
|
+
terminal: true,
|
|
1330
|
+
outcome: "neutral",
|
|
1331
|
+
needsAction: false
|
|
1332
|
+
});
|
|
1333
|
+
/** The sign grammar of the app's `formatDirectionalAmount` — unsigned for `self`. */
|
|
1334
|
+
const SIGN = Object.freeze({
|
|
1335
|
+
in: "+",
|
|
1336
|
+
out: "-",
|
|
1337
|
+
self: ""
|
|
1338
|
+
});
|
|
1339
|
+
function toActivityRow(item, actor) {
|
|
1340
|
+
const amountDisplay = formatMoney(item.amount);
|
|
1341
|
+
const signedAmountDisplay = `${SIGN[item.direction]}${amountDisplay}`;
|
|
1342
|
+
if (item.kind === "movement") return {
|
|
1343
|
+
kind: "movement",
|
|
1344
|
+
reference: {
|
|
1345
|
+
kind: "movement",
|
|
1346
|
+
id: item.id
|
|
1347
|
+
},
|
|
1348
|
+
direction: item.direction,
|
|
1349
|
+
counterpartyLabel: item.counterpartyLabel,
|
|
1350
|
+
amountDisplay,
|
|
1351
|
+
signedAmountDisplay,
|
|
1352
|
+
createdAt: item.createdAt,
|
|
1353
|
+
classification: item.classification,
|
|
1354
|
+
phase: MOVEMENT_PHASE,
|
|
1355
|
+
receipt: item.receipt
|
|
1356
|
+
};
|
|
1357
|
+
return {
|
|
1358
|
+
kind: "payment",
|
|
1359
|
+
reference: actor === void 0 ? {
|
|
1360
|
+
kind: "payment",
|
|
1361
|
+
id: item.id
|
|
1362
|
+
} : {
|
|
1363
|
+
kind: "payment",
|
|
1364
|
+
id: item.id,
|
|
1365
|
+
actor
|
|
1366
|
+
},
|
|
1367
|
+
direction: item.direction,
|
|
1368
|
+
counterpartyLabel: item.counterpartyLabel,
|
|
1369
|
+
amountDisplay,
|
|
1370
|
+
signedAmountDisplay,
|
|
1371
|
+
createdAt: item.createdAt,
|
|
1372
|
+
ledgerKind: item.ledgerKind,
|
|
1373
|
+
paymentType: item.paymentType,
|
|
1374
|
+
status: item.status,
|
|
1375
|
+
phase: paymentPhase(item.status),
|
|
1376
|
+
receipt: item.receipt
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* The exact field set `.Search` matches, case-insensitively, joined with a
|
|
1381
|
+
* space. Two of today's searchable strings drop out on purpose: `account` is
|
|
1382
|
+
* the currency-to-name guess this item deletes, and `statusLabel` is app copy —
|
|
1383
|
+
* the Status dropdown, wired up in the same change, is the affordance for
|
|
1384
|
+
* filtering by status and it uses the app's own words.
|
|
1385
|
+
*/
|
|
1386
|
+
function searchableText(row) {
|
|
1387
|
+
return (row.kind === "payment" ? [
|
|
1388
|
+
row.counterpartyLabel,
|
|
1389
|
+
row.amountDisplay,
|
|
1390
|
+
row.status,
|
|
1391
|
+
row.paymentType,
|
|
1392
|
+
row.ledgerKind
|
|
1393
|
+
] : [
|
|
1394
|
+
row.counterpartyLabel,
|
|
1395
|
+
row.amountDisplay,
|
|
1396
|
+
row.classification
|
|
1397
|
+
]).join(" ").toLowerCase();
|
|
1398
|
+
}
|
|
1399
|
+
function matchesSearch(row, query) {
|
|
1400
|
+
const needle = query.trim().toLowerCase();
|
|
1401
|
+
return needle === "" || searchableText(row).includes(needle);
|
|
1402
|
+
}
|
|
1403
|
+
//#endregion
|
|
1404
|
+
//#region src/headless/activity/csv.ts
|
|
1405
|
+
/** In this order. A header row is always written, even with no rows. */
|
|
1406
|
+
const COLUMNS = [
|
|
1407
|
+
"Date",
|
|
1408
|
+
"Kind",
|
|
1409
|
+
"Type",
|
|
1410
|
+
"Counterparty",
|
|
1411
|
+
"Direction",
|
|
1412
|
+
"Amount",
|
|
1413
|
+
"Currency",
|
|
1414
|
+
"Status",
|
|
1415
|
+
"Reference",
|
|
1416
|
+
"Transaction hash"
|
|
1417
|
+
];
|
|
1418
|
+
const FORMULA_LEAD = /^[=+\-@\t\r\n]/;
|
|
1419
|
+
const PLAIN_NUMBER = /^-?\d+(\.\d+)?$/;
|
|
1420
|
+
/**
|
|
1421
|
+
* RFC 4180: every field is quoted, and an embedded quote is doubled. A field
|
|
1422
|
+
* that would open a formula is first prefixed with an apostrophe, which the
|
|
1423
|
+
* spreadsheet consumes and renders as text.
|
|
1424
|
+
*/
|
|
1425
|
+
function escape(field) {
|
|
1426
|
+
return `"${(FORMULA_LEAD.test(field) && !PLAIN_NUMBER.test(field) ? `'${field}` : field).replaceAll("\"", "\"\"")}"`;
|
|
1427
|
+
}
|
|
1428
|
+
function record(fields) {
|
|
1429
|
+
return fields.map(escape).join(",");
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* `Amount` is the major-unit decimal value, not the display string, because a
|
|
1433
|
+
* CSV is data and the sheet has its own `Currency` column to pair it with. The
|
|
1434
|
+
* sign lives in `Direction`, which is the code the row carries.
|
|
1435
|
+
*/
|
|
1436
|
+
function buildCsv(items, actor, search) {
|
|
1437
|
+
const records = [record(COLUMNS)];
|
|
1438
|
+
for (const item of items) {
|
|
1439
|
+
const row = toActivityRow(item, actor);
|
|
1440
|
+
if (!matchesSearch(row, search)) continue;
|
|
1441
|
+
records.push(record([
|
|
1442
|
+
new Date(row.createdAt).toISOString(),
|
|
1443
|
+
row.kind,
|
|
1444
|
+
row.kind === "payment" ? row.paymentType : row.classification,
|
|
1445
|
+
row.counterpartyLabel,
|
|
1446
|
+
row.direction,
|
|
1447
|
+
item.amount.value,
|
|
1448
|
+
item.amount.currency,
|
|
1449
|
+
row.kind === "payment" ? row.status : "",
|
|
1450
|
+
row.reference.id,
|
|
1451
|
+
row.receipt?.transactionHash ?? ""
|
|
1452
|
+
]));
|
|
1453
|
+
}
|
|
1454
|
+
return {
|
|
1455
|
+
text: records.join("\r\n"),
|
|
1456
|
+
rowCount: records.length - 1
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
//#endregion
|
|
1460
|
+
//#region src/headless/activity/use-activity.ts
|
|
1461
|
+
/** The band is the backend's own — it hard-rejects a limit outside it. */
|
|
1462
|
+
const MIN_PAGE_SIZE = 1;
|
|
1463
|
+
const MAX_PAGE_SIZE = 100;
|
|
1464
|
+
const DEFAULT_PAGE_SIZE = 25;
|
|
1465
|
+
/**
|
|
1466
|
+
* The export ceiling is HARD: 50 pages of 100 is at most 5,000 rows. An
|
|
1467
|
+
* unbounded `do…while (cursor)` drain is the exact defect this item deletes
|
|
1468
|
+
* from the app; re-creating it inside the SDK would move the bug, not fix it.
|
|
1469
|
+
*/
|
|
1470
|
+
const EXPORT_PAGE_SIZE = MAX_PAGE_SIZE;
|
|
1471
|
+
const EXPORT_PAGE_CEILING = 50;
|
|
1472
|
+
const KIND_OPTIONS = Object.freeze(["payment", "movement"]);
|
|
1473
|
+
/** Clamps into 1..100. A non-number, or a fraction, lands on the default band. */
|
|
1474
|
+
function clampPageSize(pageSize) {
|
|
1475
|
+
if (pageSize === void 0 || !Number.isFinite(pageSize)) return DEFAULT_PAGE_SIZE;
|
|
1476
|
+
return Math.min(MAX_PAGE_SIZE, Math.max(MIN_PAGE_SIZE, Math.trunc(pageSize)));
|
|
1477
|
+
}
|
|
1478
|
+
function useActivity(input) {
|
|
1479
|
+
const { actor, pageSize } = input;
|
|
1480
|
+
const client = useCapxulClientOrNull();
|
|
1481
|
+
const enabled = useActivityEnabled();
|
|
1482
|
+
const limit = clampPageSize(pageSize);
|
|
1483
|
+
const warned = useRef(false);
|
|
1484
|
+
useEffect(() => {
|
|
1485
|
+
if (warned.current || pageSize === void 0 || pageSize === limit) return;
|
|
1486
|
+
warned.current = true;
|
|
1487
|
+
if (process.env.NODE_ENV !== "production") console.warn(`CapxulActivity: pageSize ${String(pageSize)} is outside 1..100 and was clamped to ${String(limit)}.`);
|
|
1488
|
+
}, [limit, pageSize]);
|
|
1489
|
+
const [kind, setKind] = useState(void 0);
|
|
1490
|
+
const [direction, setDirection] = useState(void 0);
|
|
1491
|
+
const [status, setStatus] = useState([]);
|
|
1492
|
+
const [searchText, setSearchText] = useState("");
|
|
1493
|
+
const values = useMemo(() => ({
|
|
1494
|
+
...kind === void 0 ? {} : { kind },
|
|
1495
|
+
...direction === void 0 ? {} : { direction },
|
|
1496
|
+
...status.length === 0 ? {} : { status }
|
|
1497
|
+
}), [
|
|
1498
|
+
direction,
|
|
1499
|
+
kind,
|
|
1500
|
+
status
|
|
1501
|
+
]);
|
|
1502
|
+
const filter = useMemo(() => Object.keys(values).length === 0 ? void 0 : values, [values]);
|
|
1503
|
+
const listParams = useCallback((cursor, pageLimit) => {
|
|
1504
|
+
const params = { limit: pageLimit };
|
|
1505
|
+
if (actor !== void 0) params.actor = actor;
|
|
1506
|
+
if (cursor !== void 0) params.cursor = cursor;
|
|
1507
|
+
if (filter !== void 0) params.filter = filter;
|
|
1508
|
+
return params;
|
|
1509
|
+
}, [actor, filter]);
|
|
1510
|
+
const query = useInfiniteQuery({
|
|
1511
|
+
queryKey: [
|
|
1512
|
+
...capxulKeys.activity,
|
|
1513
|
+
"list",
|
|
1514
|
+
actor ?? "self",
|
|
1515
|
+
limit,
|
|
1516
|
+
filter ?? "none"
|
|
1517
|
+
],
|
|
1518
|
+
queryFn: async ({ pageParam }) => {
|
|
1519
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, "activity.list").activity.list(listParams(pageParam, limit)));
|
|
1520
|
+
},
|
|
1521
|
+
initialPageParam: void 0,
|
|
1522
|
+
getNextPageParam: (last) => last.cursor ?? void 0,
|
|
1523
|
+
enabled
|
|
1524
|
+
});
|
|
1525
|
+
const pages = query.data?.pages;
|
|
1526
|
+
const rows = useMemo(() => {
|
|
1527
|
+
return (pages?.flatMap((page) => page.items) ?? []).map((item) => toActivityRow(item, actor)).filter((row) => matchesSearch(row, searchText));
|
|
1528
|
+
}, [
|
|
1529
|
+
actor,
|
|
1530
|
+
pages,
|
|
1531
|
+
searchText
|
|
1532
|
+
]);
|
|
1533
|
+
const { fetchNextPage, hasNextPage, isFetchingNextPage, refetch } = query;
|
|
1534
|
+
const pagingRef = useRef({
|
|
1535
|
+
fetchNextPage,
|
|
1536
|
+
hasNextPage,
|
|
1537
|
+
isFetchingNextPage
|
|
1538
|
+
});
|
|
1539
|
+
useEffect(() => {
|
|
1540
|
+
pagingRef.current = {
|
|
1541
|
+
fetchNextPage,
|
|
1542
|
+
hasNextPage,
|
|
1543
|
+
isFetchingNextPage
|
|
1544
|
+
};
|
|
1545
|
+
});
|
|
1546
|
+
const loadMore = useCallback(() => {
|
|
1547
|
+
const paging = pagingRef.current;
|
|
1548
|
+
if (!paging.hasNextPage || paging.isFetchingNextPage) return;
|
|
1549
|
+
paging.fetchNextPage();
|
|
1550
|
+
}, []);
|
|
1551
|
+
const observerRef = useRef(null);
|
|
1552
|
+
const sentinelRef = useCallback((node) => {
|
|
1553
|
+
observerRef.current?.disconnect();
|
|
1554
|
+
observerRef.current = null;
|
|
1555
|
+
if (node === null || typeof IntersectionObserver === "undefined") return;
|
|
1556
|
+
const observer = new IntersectionObserver((entries) => {
|
|
1557
|
+
if (entries.some((entry) => entry.isIntersecting)) loadMore();
|
|
1558
|
+
}, {
|
|
1559
|
+
root: null,
|
|
1560
|
+
rootMargin: "200px",
|
|
1561
|
+
threshold: 0
|
|
1562
|
+
});
|
|
1563
|
+
observer.observe(node);
|
|
1564
|
+
observerRef.current = observer;
|
|
1565
|
+
}, [loadMore]);
|
|
1566
|
+
const [isExporting, setIsExporting] = useState(false);
|
|
1567
|
+
const toCsv = useCallback(async () => {
|
|
1568
|
+
setIsExporting(true);
|
|
1569
|
+
try {
|
|
1570
|
+
const bootstrapped = requireBootstrappedClient(client, "activity.list");
|
|
1571
|
+
const items = [];
|
|
1572
|
+
let cursor;
|
|
1573
|
+
for (let page = 0; page < EXPORT_PAGE_CEILING; page += 1) {
|
|
1574
|
+
const result = unwrapCapxulResult(await bootstrapped.activity.list(listParams(cursor, EXPORT_PAGE_SIZE)));
|
|
1575
|
+
items.push(...result.items);
|
|
1576
|
+
cursor = result.cursor ?? void 0;
|
|
1577
|
+
if (cursor === void 0) break;
|
|
1578
|
+
}
|
|
1579
|
+
return {
|
|
1580
|
+
...buildCsv(items, actor, searchText),
|
|
1581
|
+
truncated: cursor !== void 0
|
|
1582
|
+
};
|
|
1583
|
+
} finally {
|
|
1584
|
+
setIsExporting(false);
|
|
1585
|
+
}
|
|
1586
|
+
}, [
|
|
1587
|
+
actor,
|
|
1588
|
+
client,
|
|
1589
|
+
listParams,
|
|
1590
|
+
searchText
|
|
1591
|
+
]);
|
|
1592
|
+
const clear = useCallback(() => {
|
|
1593
|
+
setKind(void 0);
|
|
1594
|
+
setDirection(void 0);
|
|
1595
|
+
setStatus([]);
|
|
1596
|
+
}, []);
|
|
1597
|
+
const retry = useCallback(() => {
|
|
1598
|
+
refetch();
|
|
1599
|
+
}, [refetch]);
|
|
1600
|
+
return {
|
|
1601
|
+
actor,
|
|
1602
|
+
filters: {
|
|
1603
|
+
values,
|
|
1604
|
+
set: {
|
|
1605
|
+
kind: setKind,
|
|
1606
|
+
direction: setDirection,
|
|
1607
|
+
status: setStatus,
|
|
1608
|
+
clear
|
|
1609
|
+
},
|
|
1610
|
+
options: {
|
|
1611
|
+
kind: KIND_OPTIONS,
|
|
1612
|
+
direction: PAYMENT_DIRECTIONS,
|
|
1613
|
+
status: PAYMENT_STATUSES
|
|
1614
|
+
}
|
|
1615
|
+
},
|
|
1616
|
+
search: {
|
|
1617
|
+
value: searchText,
|
|
1618
|
+
change: setSearchText
|
|
1619
|
+
},
|
|
1620
|
+
rows: {
|
|
1621
|
+
rows,
|
|
1622
|
+
isLoading: query.isLoading,
|
|
1623
|
+
error: asCapxulError(query.error),
|
|
1624
|
+
retry,
|
|
1625
|
+
observedAt: pages === void 0 ? null : pages[pages.length - 1]?.observedAt ?? null
|
|
1626
|
+
},
|
|
1627
|
+
loadMore: {
|
|
1628
|
+
hasMore: hasNextPage,
|
|
1629
|
+
loadMore,
|
|
1630
|
+
isLoadingMore: isFetchingNextPage,
|
|
1631
|
+
sentinelRef
|
|
1632
|
+
},
|
|
1633
|
+
csv: {
|
|
1634
|
+
toCsv,
|
|
1635
|
+
isExporting
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
//#endregion
|
|
1640
|
+
//#region src/headless/activity/activity.tsx
|
|
1641
|
+
const ActivityContext = createContext(null);
|
|
1642
|
+
function useActivityContext() {
|
|
1643
|
+
const engine = useContext(ActivityContext);
|
|
1644
|
+
if (engine === null) throw new Error("CapxulActivity parts must be used inside <CapxulActivity>");
|
|
1645
|
+
return engine;
|
|
1646
|
+
}
|
|
1647
|
+
function Root$3({ actor, pageSize, children }) {
|
|
1648
|
+
const engine = useActivity({
|
|
1649
|
+
...actor === void 0 ? {} : { actor },
|
|
1650
|
+
...pageSize === void 0 ? {} : { pageSize }
|
|
1651
|
+
});
|
|
1652
|
+
return /* @__PURE__ */ jsx(ActivityContext.Provider, {
|
|
1653
|
+
value: engine,
|
|
1654
|
+
children
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
/**
|
|
1658
|
+
* The one part that holds a query rather than reading the engine's: it takes a
|
|
1659
|
+
* `window` prop, and two placements can ask for different windows, so a single
|
|
1660
|
+
* pre-fetched result cannot serve both. It still holds no logic and draws
|
|
1661
|
+
* nothing.
|
|
1662
|
+
*/
|
|
1663
|
+
function Summary({ window = "all", children }) {
|
|
1664
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children(useActivitySummary(useActivityContext().actor, window)) });
|
|
1665
|
+
}
|
|
1666
|
+
function Filters({ children }) {
|
|
1667
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children(useActivityContext().filters) });
|
|
1668
|
+
}
|
|
1669
|
+
function Search({ children }) {
|
|
1670
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children(useActivityContext().search) });
|
|
1671
|
+
}
|
|
1672
|
+
function Rows({ children }) {
|
|
1673
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children(useActivityContext().rows) });
|
|
1674
|
+
}
|
|
1675
|
+
function LoadMore({ children }) {
|
|
1676
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children(useActivityContext().loadMore) });
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* The second part that holds a query: it takes a `reference` prop and the root
|
|
1680
|
+
* has no idea which row was clicked. With no `reference` it issues no request.
|
|
1681
|
+
*/
|
|
1682
|
+
function DetailInstance({ actor, reference, children }) {
|
|
1683
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children(useActivityDetail(reference, actor)) });
|
|
1684
|
+
}
|
|
1685
|
+
function Detail({ reference, children }) {
|
|
1686
|
+
const { actor } = useActivityContext();
|
|
1687
|
+
return /* @__PURE__ */ jsx(DetailInstance, {
|
|
1688
|
+
actor,
|
|
1689
|
+
reference,
|
|
1690
|
+
children
|
|
1691
|
+
}, activityDetailKey(actor, reference));
|
|
1692
|
+
}
|
|
1693
|
+
function Export({ children }) {
|
|
1694
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children(useActivityContext().csv) });
|
|
1695
|
+
}
|
|
1696
|
+
/** The compound shape the app's own design system already uses (`StatusTabs`). */
|
|
1697
|
+
const CapxulActivity = Object.assign(Root$3, {
|
|
1698
|
+
Summary,
|
|
1699
|
+
Filters,
|
|
1700
|
+
Search,
|
|
1701
|
+
Rows,
|
|
1702
|
+
LoadMore,
|
|
1703
|
+
Detail,
|
|
1704
|
+
Export
|
|
1705
|
+
});
|
|
1706
|
+
//#endregion
|
|
1046
1707
|
//#region src/headless/send-money/signer-status.ts
|
|
1047
1708
|
const NO_SUBSCRIPTION = () => () => {};
|
|
1048
1709
|
function useSignerStatus(client) {
|
|
@@ -1556,4 +2217,4 @@ const CapxulDashboardAccess = Object.assign(Root, {
|
|
|
1556
2217
|
Granted
|
|
1557
2218
|
});
|
|
1558
2219
|
//#endregion
|
|
1559
|
-
export { CapxulAuthenticationController, CapxulContacts, CapxulDashboardAccess, CapxulOnboardingController, CapxulOrgMember, CapxulProvider, CapxulSendMoney, acknowledgeOnboardingDestination, activeOnboardingRecovery, clearOnboardingJourney, currentOnboardingJourneyId, entered, invalidateOnboardingJourneyObservation, isClaimed, isRestoring, loadOnboardingJourney, onboardingJourneyPosition, saveOnboardingJourney, startOnboardingJourney, useCapxul, useCapxulAccountBalance, useCapxulAccountFund, useCapxulActivity, useCapxulActivityDetail, useCapxulAnnotateMovement, useCapxulAuth, useCapxulCancelPayment, useCapxulClaimPayment, useCapxulClientOrNull, useCapxulCreateCommitment, useCapxulCreateOrg, useCapxulDestination, useCapxulHoldings, useCapxulIdentity, useCapxulImageUpload, useCapxulInviteMember, useCapxulOrgMembers, useCapxulOrgRoles, useCapxulOrgTreasury, useCapxulOrganizationPay, useCapxulOrganizationPayBatch, useCapxulOrgs, useCapxulPay, useCapxulPayment, useCapxulPayments, useCapxulPermission, useCapxulPermissionAssign, useCapxulPermissionChange, useCapxulPermissionCreate, useCapxulPermissionReplace, useCapxulPermissionRevoke, useCapxulPermissions, useCapxulProfile, useCapxulRedirectPayment, useCapxulSend, useCapxulTransitions, useCapxulUsernameAvailability };
|
|
2220
|
+
export { CapxulActivity, CapxulAuthenticationController, CapxulContacts, CapxulDashboardAccess, CapxulOnboardingController, CapxulOrgMember, CapxulProvider, CapxulSendMoney, acknowledgeOnboardingDestination, activeOnboardingRecovery, capxulKeys, clearOnboardingJourney, currentOnboardingJourneyId, entered, invalidateOnboardingJourneyObservation, isClaimed, isRestoring, loadOnboardingJourney, onboardingJourneyPosition, saveOnboardingJourney, startOnboardingJourney, useCapxul, useCapxulAccountBalance, useCapxulAccountFund, useCapxulActivity, useCapxulActivityDetail, useCapxulAnnotateMovement, useCapxulAuth, useCapxulCancelPayment, useCapxulClaimPayment, useCapxulClientOrNull, useCapxulCreateCommitment, useCapxulCreateOrg, useCapxulDestination, useCapxulHoldings, useCapxulIdentity, useCapxulImageUpload, useCapxulInviteMember, useCapxulOrgMembers, useCapxulOrgRoles, useCapxulOrgTreasury, useCapxulOrganizationPay, useCapxulOrganizationPayBatch, useCapxulOrgs, useCapxulPay, useCapxulPayment, useCapxulPayments, useCapxulPermission, useCapxulPermissionAssign, useCapxulPermissionChange, useCapxulPermissionCreate, useCapxulPermissionReplace, useCapxulPermissionRevoke, useCapxulPermissions, useCapxulProfile, useCapxulRedirectPayment, useCapxulSend, useCapxulTransitions, useCapxulUsernameAvailability };
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as CapxulOnboardingController, r as CapxulProvider, t as CapxulAuthenticationController } from "../controllers-
|
|
1
|
+
import { n as CapxulOnboardingController, r as CapxulProvider, t as CapxulAuthenticationController } from "../controllers-DLBe4-OP.mjs";
|
|
2
2
|
import "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import { createCapxulTestClient } from "@capxul/sdk/testing";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capxul/sdk-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/Xelmar-tech/infrastructure.git",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"access": "public"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@capxul/sdk": "2.
|
|
29
|
+
"@capxul/sdk": "2.4.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@tanstack/react-query": "^5.66.9",
|