@tribe-nest/forge 1.13.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/package.json +42 -0
- package/src/client/createForgeClient.ts +54 -0
- package/src/content/ForgeContentProvider.tsx +118 -0
- package/src/content/ForgeEditBridge.tsx +134 -0
- package/src/content/editFlag.ts +23 -0
- package/src/content/index.ts +28 -0
- package/src/content/resolve.ts +67 -0
- package/src/content/types.ts +97 -0
- package/src/content/useField.ts +64 -0
- package/src/contexts/AppAuthContext.tsx +185 -0
- package/src/contexts/AudioPlayerContext.tsx +389 -0
- package/src/contexts/CartContext.tsx +131 -0
- package/src/contexts/PublicAuthContext.tsx +333 -0
- package/src/contexts/useAppAdminGuard.ts +56 -0
- package/src/css.d.ts +5 -0
- package/src/data/collectionParams.ts +57 -0
- package/src/data/queries/useAccount.ts +71 -0
- package/src/data/queries/useAccountSettings.ts +82 -0
- package/src/data/queries/useAnalytics.ts +86 -0
- package/src/data/queries/useAuthActions.ts +28 -0
- package/src/data/queries/useBlog.ts +103 -0
- package/src/data/queries/useBlogComments.ts +96 -0
- package/src/data/queries/useBroadcasts.ts +31 -0
- package/src/data/queries/useCertificates.ts +58 -0
- package/src/data/queries/useChat.ts +267 -0
- package/src/data/queries/useCoachingAvailability.ts +69 -0
- package/src/data/queries/useCoachingProducts.ts +67 -0
- package/src/data/queries/useCohortPage.ts +17 -0
- package/src/data/queries/useCollections.ts +211 -0
- package/src/data/queries/useCommunity.ts +794 -0
- package/src/data/queries/useCoupons.ts +20 -0
- package/src/data/queries/useCourseAccess.ts +50 -0
- package/src/data/queries/useCourses.ts +91 -0
- package/src/data/queries/useCurrencies.ts +33 -0
- package/src/data/queries/useDocuments.ts +208 -0
- package/src/data/queries/useDonations.ts +29 -0
- package/src/data/queries/useEngagement.ts +115 -0
- package/src/data/queries/useEvents.ts +69 -0
- package/src/data/queries/useFinalize.ts +109 -0
- package/src/data/queries/useForms.ts +31 -0
- package/src/data/queries/useInvoice.ts +65 -0
- package/src/data/queries/useLeadMagnet.ts +96 -0
- package/src/data/queries/useMembership.ts +20 -0
- package/src/data/queries/useNotifications.ts +267 -0
- package/src/data/queries/useOffers.ts +56 -0
- package/src/data/queries/useOrders.ts +71 -0
- package/src/data/queries/usePWA.ts +101 -0
- package/src/data/queries/usePageActions.ts +36 -0
- package/src/data/queries/usePaymentFlow.ts +80 -0
- package/src/data/queries/usePaymentLink.ts +47 -0
- package/src/data/queries/usePodcast.ts +85 -0
- package/src/data/queries/usePostCollections.ts +48 -0
- package/src/data/queries/usePosts.ts +94 -0
- package/src/data/queries/useProducts.ts +108 -0
- package/src/data/queries/useReplay.ts +19 -0
- package/src/data/queries/useReviews.ts +122 -0
- package/src/data/queries/useShipping.ts +109 -0
- package/src/data/queries/useSubscriptions.ts +66 -0
- package/src/data/queries/useWebsite.ts +128 -0
- package/src/data/queries/useWebsiteAgent.ts +100 -0
- package/src/index.ts +98 -0
- package/src/provider/ForgeAppProvider.tsx +149 -0
- package/src/provider/ForgeProvider.tsx +91 -0
- package/src/provider/SiteConfigProvider.tsx +27 -0
- package/src/server/_tests/buildPwaHead.spec.ts +182 -0
- package/src/server/_tests/buildWebManifest.spec.ts +313 -0
- package/src/server/_tests/forgeServiceWorkerScript.spec.ts +251 -0
- package/src/server/index.ts +260 -0
- package/src/server/jobs.ts +104 -0
- package/src/server/pwa.ts +332 -0
- package/src/types/index.ts +74 -0
- package/src/types/models.ts +1313 -0
- package/src/ui/analytics/ForgeAnalytics.tsx +208 -0
- package/src/ui/analytics/PageMetaPixel.tsx +92 -0
- package/src/ui/content/Editable.tsx +90 -0
- package/src/ui/format/PriceDisplay.tsx +142 -0
- package/src/ui/format/useFormatCurrency.ts +92 -0
- package/src/ui/headless/agent/useAiAgent.ts +106 -0
- package/src/ui/headless/auth/useLoginFlow.ts +72 -0
- package/src/ui/headless/auth/useSignupForm.ts +85 -0
- package/src/ui/headless/broadcast/useBroadcastWatch.ts +59 -0
- package/src/ui/headless/chat/attachmentKind.ts +27 -0
- package/src/ui/headless/chat/useChatAttachmentUpload.ts +132 -0
- package/src/ui/headless/chat/useChatRoom.ts +223 -0
- package/src/ui/headless/chat/useMessageThread.ts +60 -0
- package/src/ui/headless/checkout/useCheckout.ts +438 -0
- package/src/ui/headless/coaching/useCoachingBooking.ts +223 -0
- package/src/ui/headless/community/index.ts +20 -0
- package/src/ui/headless/community/lexical.ts +131 -0
- package/src/ui/headless/community/replyTree.ts +51 -0
- package/src/ui/headless/community/richLexical.ts +314 -0
- package/src/ui/headless/community/useCommunityAttachmentUpload.ts +137 -0
- package/src/ui/headless/community/useCommunitySpaceFeed.ts +122 -0
- package/src/ui/headless/community/useCommunityThread.ts +95 -0
- package/src/ui/headless/community/useMentionComposer.ts +105 -0
- package/src/ui/headless/community/useRichMentionComposer.ts +193 -0
- package/src/ui/headless/consent/useCookieConsent.ts +81 -0
- package/src/ui/headless/course/useCourseCheckout.ts +99 -0
- package/src/ui/headless/dialog.tsx +14 -0
- package/src/ui/headless/document/index.ts +7 -0
- package/src/ui/headless/document/useContractSignature.ts +68 -0
- package/src/ui/headless/document/useDocumentSigningFlow.ts +92 -0
- package/src/ui/headless/document/useOtpCodeInput.ts +86 -0
- package/src/ui/headless/document/useSignaturePad.ts +180 -0
- package/src/ui/headless/donation/Donation.tsx +115 -0
- package/src/ui/headless/donation/DonationContext.tsx +223 -0
- package/src/ui/headless/donation/fees.ts +15 -0
- package/src/ui/headless/donation/index.ts +10 -0
- package/src/ui/headless/engagement/usePostEngagement.ts +119 -0
- package/src/ui/headless/event/useEventCheckout.ts +141 -0
- package/src/ui/headless/forms/useContactForm.ts +58 -0
- package/src/ui/headless/forms/useEmailListForm.ts +75 -0
- package/src/ui/headless/forms/useSectionedForm.ts +256 -0
- package/src/ui/headless/index.ts +60 -0
- package/src/ui/headless/invoice/useInvoicePayment.ts +48 -0
- package/src/ui/headless/memberHome/index.ts +7 -0
- package/src/ui/headless/memberHome/useMemberHomeNav.ts +82 -0
- package/src/ui/headless/membership/MembershipGate.tsx +39 -0
- package/src/ui/headless/membership/useMembershipCheckout.ts +121 -0
- package/src/ui/headless/offer/Offer.tsx +88 -0
- package/src/ui/headless/offer/OfferContext.tsx +162 -0
- package/src/ui/headless/offer/index.ts +8 -0
- package/src/ui/headless/paymentLink/usePaymentLinkPayment.ts +46 -0
- package/src/ui/headless/podcast/usePodcastPlayer.ts +96 -0
- package/src/ui/headless/posts/index.ts +13 -0
- package/src/ui/headless/posts/upsell.ts +41 -0
- package/src/ui/headless/posts/useMemberPostsFeed.ts +110 -0
- package/src/ui/headless/posts/usePostCollectionDetail.ts +56 -0
- package/src/ui/headless/posts/usePostCollectionsList.ts +90 -0
- package/src/ui/headless/posts/usePostItem.ts +81 -0
- package/src/ui/headless/reviews/index.ts +6 -0
- package/src/ui/headless/reviews/useHelpfulVote.ts +45 -0
- package/src/ui/headless/reviews/useReviewForm.ts +108 -0
- package/src/ui/headless/reviews/useReviewsList.ts +79 -0
- package/src/ui/headless/work/index.ts +25 -0
- package/src/ui/headless/work/useWorkPortal.ts +349 -0
- package/src/ui/index.ts +144 -0
- package/src/ui/payment/ForgePaymentProvider.tsx +45 -0
- package/src/ui/payment/ForgeStripePayment.tsx +171 -0
- package/src/ui/shell/TribeNestApp.tsx +121 -0
- package/src/ui/shell/shellGating.spec.ts +28 -0
- package/src/ui/shell/shellGating.ts +11 -0
- package/src/ui/styled/AccountDashboard.tsx +575 -0
- package/src/ui/styled/AiAgentWidget.tsx +152 -0
- package/src/ui/styled/AudioPlayer.tsx +123 -0
- package/src/ui/styled/BlogCategory.tsx +79 -0
- package/src/ui/styled/BlogComments.tsx +236 -0
- package/src/ui/styled/BlogList.tsx +101 -0
- package/src/ui/styled/BlogPost.tsx +160 -0
- package/src/ui/styled/BlogPostFooter.tsx +33 -0
- package/src/ui/styled/BotProtection.tsx +101 -0
- package/src/ui/styled/Button.tsx +88 -0
- package/src/ui/styled/Cart.tsx +276 -0
- package/src/ui/styled/ChatRoom.tsx +252 -0
- package/src/ui/styled/Checkout.tsx +988 -0
- package/src/ui/styled/CheckoutConfirmation.tsx +452 -0
- package/src/ui/styled/CoachingBooking.tsx +605 -0
- package/src/ui/styled/CoachingConfirmation.tsx +151 -0
- package/src/ui/styled/CoachingDetail.tsx +99 -0
- package/src/ui/styled/CohortPage.tsx +82 -0
- package/src/ui/styled/ConfirmSubscription.tsx +134 -0
- package/src/ui/styled/Confirmation.tsx +171 -0
- package/src/ui/styled/ContactForm.tsx +81 -0
- package/src/ui/styled/CookieConsent.tsx +239 -0
- package/src/ui/styled/CourseAccess.tsx +169 -0
- package/src/ui/styled/CourseCheckout.tsx +425 -0
- package/src/ui/styled/CourseConfirmation.tsx +191 -0
- package/src/ui/styled/CourseDetail.tsx +140 -0
- package/src/ui/styled/CoursesGrid.tsx +85 -0
- package/src/ui/styled/CurrencySwitcher.tsx +51 -0
- package/src/ui/styled/DonationButton.tsx +247 -0
- package/src/ui/styled/DonationPage.tsx +29 -0
- package/src/ui/styled/EmailListForm.tsx +88 -0
- package/src/ui/styled/EventConfirmation.tsx +228 -0
- package/src/ui/styled/EventCountdown.tsx +98 -0
- package/src/ui/styled/EventDetail.tsx +141 -0
- package/src/ui/styled/EventTickets.tsx +548 -0
- package/src/ui/styled/EventsList.tsx +83 -0
- package/src/ui/styled/ForgotPasswordForm.tsx +105 -0
- package/src/ui/styled/FormRenderer.tsx +249 -0
- package/src/ui/styled/InstallBanner.tsx +114 -0
- package/src/ui/styled/InvoiceConfirmation.tsx +50 -0
- package/src/ui/styled/InvoicePayment.tsx +141 -0
- package/src/ui/styled/LeadMagnet.tsx +93 -0
- package/src/ui/styled/Loading.tsx +56 -0
- package/src/ui/styled/LoginForm.tsx +134 -0
- package/src/ui/styled/Markdown.tsx +103 -0
- package/src/ui/styled/MembershipCheckout.tsx +197 -0
- package/src/ui/styled/MembershipTiers.tsx +115 -0
- package/src/ui/styled/OfferButton.tsx +181 -0
- package/src/ui/styled/PageActions.tsx +124 -0
- package/src/ui/styled/PaymentLinkConfirmation.tsx +50 -0
- package/src/ui/styled/PaymentLinkPayment.tsx +85 -0
- package/src/ui/styled/Paywall.tsx +54 -0
- package/src/ui/styled/PlayButton.tsx +48 -0
- package/src/ui/styled/PodcastEpisode.tsx +137 -0
- package/src/ui/styled/PodcastList.tsx +58 -0
- package/src/ui/styled/PodcastShow.tsx +164 -0
- package/src/ui/styled/PostsFeed.tsx +63 -0
- package/src/ui/styled/ProductDetail.tsx +616 -0
- package/src/ui/styled/ProductGrid.tsx +82 -0
- package/src/ui/styled/PushOptIn.tsx +65 -0
- package/src/ui/styled/PwaRegistration.tsx +58 -0
- package/src/ui/styled/ReactionBar.tsx +93 -0
- package/src/ui/styled/ReplayList.tsx +134 -0
- package/src/ui/styled/ResetPasswordForm.tsx +127 -0
- package/src/ui/styled/ReviewForm.tsx +292 -0
- package/src/ui/styled/ReviewsSection.tsx +260 -0
- package/src/ui/styled/SectionedFormRenderer.tsx +146 -0
- package/src/ui/styled/SignupForm.tsx +109 -0
- package/src/ui/styled/UserMenu.tsx +166 -0
- package/src/ui/styled/chat/ChatAttachments.tsx +172 -0
- package/src/ui/styled/chat/ChatComposer.tsx +153 -0
- package/src/ui/styled/chat/ChatThreadPanel.tsx +94 -0
- package/src/ui/styled/chat/MessageBubble.tsx +66 -0
- package/src/ui/styled/chat/NewDmDialog.tsx +78 -0
- package/src/ui/styled/community/CommunityComposer.tsx +358 -0
- package/src/ui/styled/community/CommunityFeed.tsx +483 -0
- package/src/ui/styled/community/CommunityLeaderboard.tsx +109 -0
- package/src/ui/styled/community/CommunityMediaGallery.tsx +116 -0
- package/src/ui/styled/community/CommunityMemberProfile.tsx +285 -0
- package/src/ui/styled/community/CommunityNotifications.tsx +222 -0
- package/src/ui/styled/community/CommunityPostCard.tsx +165 -0
- package/src/ui/styled/community/CommunityPostDetail.tsx +337 -0
- package/src/ui/styled/community/CommunityReactionBar.tsx +107 -0
- package/src/ui/styled/community/CommunityRichText.tsx +157 -0
- package/src/ui/styled/community/CommunitySpaces.tsx +174 -0
- package/src/ui/styled/community/MemberAvatar.tsx +74 -0
- package/src/ui/styled/community/index.ts +23 -0
- package/src/ui/styled/community/util.ts +15 -0
- package/src/ui/styled/members/MemberHomeLayout.tsx +98 -0
- package/src/ui/styled/members/MemberPostCard.tsx +392 -0
- package/src/ui/styled/members/MemberPostsFeed.tsx +219 -0
- package/src/ui/styled/members/PostCollectionDetail.tsx +227 -0
- package/src/ui/styled/members/PostCollectionsGrid.tsx +287 -0
- package/src/ui/styled/members/index.ts +7 -0
- package/src/ui/styled/rich-text.css +150 -0
- package/src/ui/styled/work/WorkInviteAccept.tsx +222 -0
- package/src/ui/styled/work/WorkPortalProjects.tsx +163 -0
- package/src/ui/styled/work/WorkProjectInvoices.tsx +113 -0
- package/src/ui/styled/work/WorkProjectReport.tsx +66 -0
- package/src/ui/styled/work/WorkReportBody.tsx +327 -0
- package/src/ui/styled/work/WorkTaskAttachments.tsx +67 -0
- package/src/ui/styled/work/WorkTaskComments.tsx +151 -0
- package/src/ui/styled/work/WorkTaskDetail.tsx +92 -0
- package/src/ui/styled/work/WorkTokenReport.tsx +49 -0
- package/src/ui/styled/work/index.ts +10 -0
- package/src/ui/theme/ForgeThemeProvider.tsx +121 -0
- package/src/ui/theme/contrast.ts +22 -0
- package/src/utils/analyticsBus.ts +31 -0
- package/src/utils/attribution.ts +68 -0
- package/src/utils/cookieConsent.ts +83 -0
- package/src/utils/landing.ts +153 -0
- package/src/utils/metaPixel.ts +122 -0
- package/src/utils/structuredData.ts +126 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { useForge } from "../../provider/ForgeProvider";
|
|
3
|
+
import type {
|
|
4
|
+
IPublicReviewsPage,
|
|
5
|
+
IReviewRequestContext,
|
|
6
|
+
ISubmittedReview,
|
|
7
|
+
ReviewEntityType,
|
|
8
|
+
ReviewSortOption,
|
|
9
|
+
} from "../../types/models";
|
|
10
|
+
|
|
11
|
+
export interface GetPublicReviewsParams {
|
|
12
|
+
entityType: ReviewEntityType;
|
|
13
|
+
entityId: string;
|
|
14
|
+
page?: number;
|
|
15
|
+
limit?: number;
|
|
16
|
+
sort?: ReviewSortOption;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Published reviews (+ aggregate) for an entity — GET /public/reviews. */
|
|
20
|
+
export function usePublicReviews(params: GetPublicReviewsParams, enabled = true) {
|
|
21
|
+
const { client, profileId } = useForge();
|
|
22
|
+
|
|
23
|
+
return useQuery<IPublicReviewsPage>({
|
|
24
|
+
queryKey: [
|
|
25
|
+
"public-reviews",
|
|
26
|
+
profileId,
|
|
27
|
+
params.entityType,
|
|
28
|
+
params.entityId,
|
|
29
|
+
params.page ?? 1,
|
|
30
|
+
params.limit ?? 10,
|
|
31
|
+
params.sort ?? "recent",
|
|
32
|
+
],
|
|
33
|
+
queryFn: async () => {
|
|
34
|
+
const res = await client.get("/public/reviews", {
|
|
35
|
+
params: {
|
|
36
|
+
profileId,
|
|
37
|
+
entityType: params.entityType,
|
|
38
|
+
entityId: params.entityId,
|
|
39
|
+
page: params.page ?? 1,
|
|
40
|
+
limit: params.limit ?? 10,
|
|
41
|
+
sort: params.sort ?? "recent",
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
return res.data;
|
|
45
|
+
},
|
|
46
|
+
enabled: !!profileId && !!client && !!params.entityId && enabled,
|
|
47
|
+
placeholderData: (prev) => prev,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Review-form context behind an emailed token link — GET /public/reviews/request/:token. */
|
|
52
|
+
export function useReviewRequest(token?: string) {
|
|
53
|
+
const { client } = useForge();
|
|
54
|
+
|
|
55
|
+
return useQuery<IReviewRequestContext>({
|
|
56
|
+
queryKey: ["review-request", token],
|
|
57
|
+
queryFn: async () => {
|
|
58
|
+
const res = await client.get(`/public/reviews/request/${token}`);
|
|
59
|
+
return res.data;
|
|
60
|
+
},
|
|
61
|
+
enabled: !!client && !!token,
|
|
62
|
+
retry: false,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface SubmitReviewInput {
|
|
67
|
+
/** Token from the emailed review request (proves the purchase). */
|
|
68
|
+
token?: string;
|
|
69
|
+
/** Fallback path (no token): entity + email/authed account. */
|
|
70
|
+
profileId?: string;
|
|
71
|
+
entityType?: ReviewEntityType;
|
|
72
|
+
entityId?: string;
|
|
73
|
+
email?: string;
|
|
74
|
+
rating: number;
|
|
75
|
+
title?: string | null;
|
|
76
|
+
body?: string | null;
|
|
77
|
+
reviewerName?: string | null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Submit (or edit within the window) a review — POST /public/reviews. */
|
|
81
|
+
export function useSubmitReview() {
|
|
82
|
+
const { client } = useForge();
|
|
83
|
+
const queryClient = useQueryClient();
|
|
84
|
+
|
|
85
|
+
return useMutation<ISubmittedReview, unknown, SubmitReviewInput>({
|
|
86
|
+
mutationFn: async (input) => {
|
|
87
|
+
const res = await client.post("/public/reviews", input);
|
|
88
|
+
return res.data;
|
|
89
|
+
},
|
|
90
|
+
onSuccess: (review, variables) => {
|
|
91
|
+
queryClient.invalidateQueries({ queryKey: ["public-reviews"] });
|
|
92
|
+
if (variables.token) {
|
|
93
|
+
queryClient.invalidateQueries({ queryKey: ["review-request", variables.token] });
|
|
94
|
+
}
|
|
95
|
+
return review;
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Mark a review helpful (logged-in members) — POST /public/reviews/:id/helpful. */
|
|
101
|
+
export function useAddHelpfulVote() {
|
|
102
|
+
const { client } = useForge();
|
|
103
|
+
|
|
104
|
+
return useMutation<{ helpfulCount: number }, unknown, { reviewId: string }>({
|
|
105
|
+
mutationFn: async ({ reviewId }) => {
|
|
106
|
+
const res = await client.post(`/public/reviews/${reviewId}/helpful`);
|
|
107
|
+
return res.data;
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Withdraw a helpful vote — DELETE /public/reviews/:id/helpful. */
|
|
113
|
+
export function useRemoveHelpfulVote() {
|
|
114
|
+
const { client } = useForge();
|
|
115
|
+
|
|
116
|
+
return useMutation<{ helpfulCount: number }, unknown, { reviewId: string }>({
|
|
117
|
+
mutationFn: async ({ reviewId }) => {
|
|
118
|
+
const res = await client.delete(`/public/reviews/${reviewId}/helpful`);
|
|
119
|
+
return res.data;
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { useForge } from "../../provider/ForgeProvider";
|
|
2
|
+
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
3
|
+
|
|
4
|
+
export type ShippingCountry = {
|
|
5
|
+
name: string;
|
|
6
|
+
code: string;
|
|
7
|
+
region: string;
|
|
8
|
+
states?: { name: string; code: string }[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type ShippingRate = {
|
|
12
|
+
rateId: string;
|
|
13
|
+
carrier: string;
|
|
14
|
+
service: string;
|
|
15
|
+
amount: number;
|
|
16
|
+
currency: string;
|
|
17
|
+
estimatedDays: number | null;
|
|
18
|
+
shipmentId: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A shippable group in the checkout. Physical items are grouped by how they
|
|
23
|
+
* ship: `external` (one combined cost), per-product `flat`, and one `dynamic`
|
|
24
|
+
* carrier-rated shipment (all dynamic items packed into the seller's boxes → one
|
|
25
|
+
* carrier choice). `flat`/`external` are auto-selected (single rate); `dynamic`
|
|
26
|
+
* (`selectable`) is the buyer's carrier choice.
|
|
27
|
+
*/
|
|
28
|
+
export type ShippingGroup = {
|
|
29
|
+
id: string;
|
|
30
|
+
type: "flat" | "dynamic" | "external";
|
|
31
|
+
title: string;
|
|
32
|
+
productIds: string[];
|
|
33
|
+
selectable: boolean;
|
|
34
|
+
rates: ShippingRate[];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Countries the profile ships physical products to. */
|
|
38
|
+
export function useShippingCountries() {
|
|
39
|
+
const { client } = useForge();
|
|
40
|
+
|
|
41
|
+
return useQuery<ShippingCountry[]>({
|
|
42
|
+
queryKey: ["shipping-countries"],
|
|
43
|
+
queryFn: async () => {
|
|
44
|
+
const res = await client.get("/public/products/shipping-countries");
|
|
45
|
+
return res.data;
|
|
46
|
+
},
|
|
47
|
+
enabled: !!client,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type ShippingRateCartItem = {
|
|
52
|
+
productId: string;
|
|
53
|
+
productVariantId: string;
|
|
54
|
+
quantity: number;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** Compute shipping rates for an address + cart. */
|
|
58
|
+
export function useShippingRates() {
|
|
59
|
+
const { client, profileId } = useForge();
|
|
60
|
+
|
|
61
|
+
return useMutation<
|
|
62
|
+
{ groups: ShippingGroup[] },
|
|
63
|
+
unknown,
|
|
64
|
+
{
|
|
65
|
+
shippingAddress: { address1: string; city: string; stateCode: string; countryCode: string; zip: string; phone?: string };
|
|
66
|
+
cartItems: ShippingRateCartItem[];
|
|
67
|
+
}
|
|
68
|
+
>({
|
|
69
|
+
mutationFn: async ({ shippingAddress, cartItems }) => {
|
|
70
|
+
const res = await client.post("/public/orders/shipping-rates", {
|
|
71
|
+
profileId,
|
|
72
|
+
shippingAddress,
|
|
73
|
+
cartItems,
|
|
74
|
+
});
|
|
75
|
+
return res.data;
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type ApplyCouponResult = {
|
|
81
|
+
coupon: { code: string; discountType: string | null; discountValue: number | null } | null;
|
|
82
|
+
discountAmount: number;
|
|
83
|
+
chargedAmount: number;
|
|
84
|
+
chargedCurrency: string;
|
|
85
|
+
paymentSecret?: string;
|
|
86
|
+
paymentId?: string;
|
|
87
|
+
/** Re-quoted sales tax for the re-issued payment intent (display only). */
|
|
88
|
+
taxQuote?: import("../../types/models").PublicTaxQuote;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Apply (or, with no couponCode, clear) a coupon on an order. Re-issues the
|
|
93
|
+
* payment intent, so the result carries the updated paymentSecret/paymentId.
|
|
94
|
+
*/
|
|
95
|
+
export function useApplyCoupon() {
|
|
96
|
+
const { client, profileId } = useForge();
|
|
97
|
+
|
|
98
|
+
return useMutation<ApplyCouponResult, unknown, { orderId: string; couponCode?: string; returnUrl: string }>({
|
|
99
|
+
mutationFn: async ({ orderId, couponCode, returnUrl }) => {
|
|
100
|
+
const res = await client.post("/public/orders/apply-coupon", {
|
|
101
|
+
orderId,
|
|
102
|
+
profileId,
|
|
103
|
+
couponCode,
|
|
104
|
+
returnUrl,
|
|
105
|
+
});
|
|
106
|
+
return res.data;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useForge } from "../../provider/ForgeProvider";
|
|
2
|
+
import { useMutation } from "@tanstack/react-query";
|
|
3
|
+
|
|
4
|
+
export type CreateSubscriptionInput = {
|
|
5
|
+
amount?: number;
|
|
6
|
+
billingCycle: "month" | "year";
|
|
7
|
+
membershipTierId: string;
|
|
8
|
+
returnUrl: string;
|
|
9
|
+
attributionRefId?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Create a paid membership subscription (returns the payment client secret). */
|
|
13
|
+
export function useCreateSubscription() {
|
|
14
|
+
const { client, profileId } = useForge();
|
|
15
|
+
|
|
16
|
+
return useMutation<{ subscriptionId: string; clientSecret: string }, unknown, CreateSubscriptionInput>({
|
|
17
|
+
mutationFn: async (body) => {
|
|
18
|
+
const res = await client.post("/public/payments/subscriptions", { ...body, profileId });
|
|
19
|
+
return res.data;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Activate a free membership tier. */
|
|
25
|
+
export function useCreateFreeSubscription() {
|
|
26
|
+
const { client, profileId } = useForge();
|
|
27
|
+
|
|
28
|
+
return useMutation<unknown, unknown, { membershipTierId: string; attributionRefId?: string }>({
|
|
29
|
+
mutationFn: async (body) => {
|
|
30
|
+
const res = await client.post("/public/payments/subscriptions/free", { ...body, profileId });
|
|
31
|
+
return res.data;
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Cancel the member's active paid subscription. */
|
|
37
|
+
export function useCancelMembership() {
|
|
38
|
+
const { client, profileId } = useForge();
|
|
39
|
+
|
|
40
|
+
return useMutation<unknown, unknown, { membershipId: string }>({
|
|
41
|
+
mutationFn: async ({ membershipId }) => {
|
|
42
|
+
const res = await client.post("/public/payments/subscriptions/cancel", {
|
|
43
|
+
membershipId,
|
|
44
|
+
profileId,
|
|
45
|
+
});
|
|
46
|
+
return res.data;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Reconcile the most recent subscription after a checkout return.
|
|
53
|
+
* Returns the latest subscription status (e.g. "active").
|
|
54
|
+
*/
|
|
55
|
+
export function useConfirmLatestSubscription() {
|
|
56
|
+
const { client, profileId } = useForge();
|
|
57
|
+
|
|
58
|
+
return useMutation<{ status: string }, unknown, void>({
|
|
59
|
+
mutationFn: async () => {
|
|
60
|
+
const res = await client.post("/public/payments/subscriptions/confirm-latest", {
|
|
61
|
+
profileId,
|
|
62
|
+
});
|
|
63
|
+
return res.data;
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { WebPage } from "../../types";
|
|
2
|
+
import { useForge } from "../../provider/ForgeProvider";
|
|
3
|
+
import { useInitialSiteConfig } from "../../provider/SiteConfigProvider";
|
|
4
|
+
import { keepPreviousData, useMutation, useQuery } from "@tanstack/react-query";
|
|
5
|
+
|
|
6
|
+
export interface SiteConfig {
|
|
7
|
+
/** The tenant's settlement currency (e.g. "USD") — the currency API amounts
|
|
8
|
+
* are in and payments are charged in. */
|
|
9
|
+
currency: string;
|
|
10
|
+
/** Sales-tax display mode: true = listing prices already contain tax
|
|
11
|
+
* ("incl. VAT" style, EU/UK), false/absent = tax added at checkout (US).
|
|
12
|
+
* Display-only — checkout totals come from the authoritative taxQuote. */
|
|
13
|
+
pricesIncludeTax?: boolean;
|
|
14
|
+
metaPixelId: string | null;
|
|
15
|
+
stripeAccountId: string | null;
|
|
16
|
+
paystackAccountId: string | null;
|
|
17
|
+
paymentProviderName: string | null;
|
|
18
|
+
paymentProviderPublicKey: string | null;
|
|
19
|
+
/** The single PLATFORM Stripe publishable key. Stripe is Connect, so forge
|
|
20
|
+
* initialises `loadStripe(stripePublishableKey, { stripeAccount: stripeAccountId })`. */
|
|
21
|
+
stripePublishableKey: string | null;
|
|
22
|
+
/** Whether Altcha proof-of-work bot protection is active. Self-hosted, so it
|
|
23
|
+
* works on every tenant subdomain + custom domain with no per-domain config. */
|
|
24
|
+
altchaEnabled?: boolean;
|
|
25
|
+
/** The creator's site display name — the manifest `name` fallback when the
|
|
26
|
+
* PWA identity has no explicit name. */
|
|
27
|
+
siteName?: string | null;
|
|
28
|
+
/** The profile-level PWA identity (icons/name/screenshots) used to build the
|
|
29
|
+
* installable manifest + head tags. `null` when the creator has no pwaConfig
|
|
30
|
+
* (minimal name-only manifest, not installable). Screenshots are optional. */
|
|
31
|
+
pwa?: PwaConfig | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The PWA identity block on `site-config` (mirrors `pwaConfig` on the profile). */
|
|
35
|
+
export interface PwaConfig {
|
|
36
|
+
name: string;
|
|
37
|
+
shortName: string;
|
|
38
|
+
description: string;
|
|
39
|
+
icon96: string;
|
|
40
|
+
icon192: string;
|
|
41
|
+
icon512: string;
|
|
42
|
+
screenshotWide1280X720?: string;
|
|
43
|
+
screenshotNarrow750X1334?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The tenant's mutable runtime config (settlement currency, Meta Pixel id,
|
|
48
|
+
* payment provider). Fetched at runtime — NOT baked into the build — so a
|
|
49
|
+
* creator can change these in settings and the live site reflects them without
|
|
50
|
+
* a rebuild/redeploy.
|
|
51
|
+
*
|
|
52
|
+
* If a `<SiteConfigProvider>` seeded an SSR-fetched value (see `fetchSiteConfig`
|
|
53
|
+
* in `@tribe-nest/forge/server`), it's used as `initialData` so the config is
|
|
54
|
+
* present on the first render — no client-fetch flash, no hydration mismatch.
|
|
55
|
+
* An explicit `initialData` override still wins.
|
|
56
|
+
*/
|
|
57
|
+
export function useSiteConfig(opts?: { initialData?: SiteConfig }) {
|
|
58
|
+
const { client, profileId } = useForge();
|
|
59
|
+
const ssrInitial = useInitialSiteConfig();
|
|
60
|
+
|
|
61
|
+
return useQuery<SiteConfig>({
|
|
62
|
+
queryKey: ["site-config", profileId],
|
|
63
|
+
queryFn: async () => {
|
|
64
|
+
const res = await client.get("/public/websites/site-config", { params: { profileId } });
|
|
65
|
+
return res.data;
|
|
66
|
+
},
|
|
67
|
+
enabled: !!client && !!profileId,
|
|
68
|
+
initialData: opts?.initialData ?? ssrInitial,
|
|
69
|
+
staleTime: 1000 * 60 * 5, // 5 min — settings change rarely; refetch keeps it fresh
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The store's tax display mode from site config: true = prices shown to the
|
|
75
|
+
* buyer already include tax (inclusive/EU display), false = tax is added at
|
|
76
|
+
* checkout (exclusive/US display). Defaults to false until config loads.
|
|
77
|
+
* Feed this into `<PriceDisplay pricesIncludeTax={...}>`.
|
|
78
|
+
*/
|
|
79
|
+
export function usePricesIncludeTax(): boolean {
|
|
80
|
+
const { data } = useSiteConfig();
|
|
81
|
+
return data?.pricesIncludeTax ?? false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Tax-aware price rendering primitive, re-exported here (a file the root barrel
|
|
85
|
+
// already star-exports) so `@tribe-nest/frontend-shared` and app code can import
|
|
86
|
+
// it from "@tribe-nest/forge". Its home is `ui/format/PriceDisplay` — the
|
|
87
|
+
// `forge/ui` barrel should export it from there as well.
|
|
88
|
+
export {
|
|
89
|
+
PriceDisplay,
|
|
90
|
+
priceTaxCaption,
|
|
91
|
+
summarizeTaxQuote,
|
|
92
|
+
type PriceDisplayProps,
|
|
93
|
+
} from "../../ui/format/PriceDisplay";
|
|
94
|
+
|
|
95
|
+
/** Submit the website contact form. */
|
|
96
|
+
export function useSubmitContactForm() {
|
|
97
|
+
const { client, profileId } = useForge();
|
|
98
|
+
|
|
99
|
+
return useMutation<unknown, unknown, { name: string; email: string; message: string; joinEmailList?: boolean }>({
|
|
100
|
+
mutationFn: async (body) => {
|
|
101
|
+
const res = await client.post("/public/websites/contact", { ...body, profileId });
|
|
102
|
+
return res.data;
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The rendered web page for a pathname — either the published site (by
|
|
109
|
+
* subdomain) or a preview (by token). Keeps the previous page during navigation
|
|
110
|
+
* to avoid a white flash.
|
|
111
|
+
*/
|
|
112
|
+
export function useGetWebPage(pathname: string, opts?: { subdomain?: string; previewToken?: string | null }) {
|
|
113
|
+
const { client } = useForge();
|
|
114
|
+
const { subdomain, previewToken } = opts ?? {};
|
|
115
|
+
|
|
116
|
+
return useQuery<WebPage>({
|
|
117
|
+
queryKey: ["web-page", subdomain, pathname, previewToken],
|
|
118
|
+
queryFn: async () => {
|
|
119
|
+
const url = previewToken
|
|
120
|
+
? `/public/websites/preview?token=${previewToken}&pathname=${pathname}`
|
|
121
|
+
: `/public/websites?subdomain=${subdomain}&pathname=${pathname}`;
|
|
122
|
+
const res = await client.get(url);
|
|
123
|
+
return res.data;
|
|
124
|
+
},
|
|
125
|
+
enabled: !!client && (!!previewToken || !!subdomain),
|
|
126
|
+
placeholderData: keepPreviousData,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { useForge } from "../../provider/ForgeProvider";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
|
|
4
|
+
export interface WebsiteAgentConfig {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
displayName?: string;
|
|
7
|
+
greeting?: string | null;
|
|
8
|
+
allowAnonymous?: boolean;
|
|
9
|
+
allowOrderLookup?: boolean;
|
|
10
|
+
allowLeadCapture?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Widget bootstrap config for the profile. When `enabled` is false the widget
|
|
14
|
+
* should render nothing. */
|
|
15
|
+
export function useWebsiteAgentConfig() {
|
|
16
|
+
const { client, profileId } = useForge();
|
|
17
|
+
return useQuery<WebsiteAgentConfig>({
|
|
18
|
+
queryKey: ["website-agent-config", profileId],
|
|
19
|
+
queryFn: async () => {
|
|
20
|
+
const res = await client.get(`/public/agent/config`, { params: { profileId } });
|
|
21
|
+
return res.data;
|
|
22
|
+
},
|
|
23
|
+
enabled: !!profileId && !!client,
|
|
24
|
+
staleTime: 5 * 60 * 1000,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type AgentStreamEvent =
|
|
29
|
+
| { type: "text_delta"; delta: string }
|
|
30
|
+
| { type: "tool_use_start"; name: string }
|
|
31
|
+
| { type: "tool_use_result"; name: string }
|
|
32
|
+
| { type: "turn_complete" }
|
|
33
|
+
| { type: "error"; message: string };
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Streams a chat turn over SSE using fetch (axios can't stream). Calls
|
|
37
|
+
* `onEvent` for each parsed event. Returns when the stream ends.
|
|
38
|
+
*/
|
|
39
|
+
export async function streamAgentMessage(params: {
|
|
40
|
+
apiUrl: string;
|
|
41
|
+
token?: string | null;
|
|
42
|
+
profileId: string;
|
|
43
|
+
visitorId: string;
|
|
44
|
+
conversationId: string;
|
|
45
|
+
message: string;
|
|
46
|
+
onEvent: (ev: AgentStreamEvent) => void;
|
|
47
|
+
signal?: AbortSignal;
|
|
48
|
+
}): Promise<void> {
|
|
49
|
+
const res = await fetch(`${params.apiUrl}/public/agent/conversations/${params.conversationId}/messages`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: {
|
|
52
|
+
"Content-Type": "application/json",
|
|
53
|
+
...(params.token ? { authorization: `Bearer ${params.token}` } : {}),
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({ profileId: params.profileId, visitorId: params.visitorId, message: params.message }),
|
|
56
|
+
signal: params.signal,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (!res.body) throw new Error("No response stream");
|
|
60
|
+
const reader = res.body.getReader();
|
|
61
|
+
const decoder = new TextDecoder();
|
|
62
|
+
let buffer = "";
|
|
63
|
+
|
|
64
|
+
for (;;) {
|
|
65
|
+
const { done, value } = await reader.read();
|
|
66
|
+
if (done) break;
|
|
67
|
+
buffer += decoder.decode(value, { stream: true });
|
|
68
|
+
const frames = buffer.split("\n\n");
|
|
69
|
+
buffer = frames.pop() ?? "";
|
|
70
|
+
for (const frame of frames) {
|
|
71
|
+
const line = frame.split("\n").find((l) => l.startsWith("data:"));
|
|
72
|
+
if (!line) continue;
|
|
73
|
+
const payload = line.slice(5).trim();
|
|
74
|
+
if (!payload) continue;
|
|
75
|
+
try {
|
|
76
|
+
params.onEvent(JSON.parse(payload) as AgentStreamEvent);
|
|
77
|
+
} catch {
|
|
78
|
+
/* ignore heartbeats / malformed frames */
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Creates a visitor conversation, returning its id (or null when disabled). */
|
|
85
|
+
export async function createAgentConversation(params: {
|
|
86
|
+
apiUrl: string;
|
|
87
|
+
token?: string | null;
|
|
88
|
+
profileId: string;
|
|
89
|
+
visitorId: string;
|
|
90
|
+
}): Promise<{ id: string | null; requiresLogin?: boolean }> {
|
|
91
|
+
const res = await fetch(`${params.apiUrl}/public/agent/conversations`, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: {
|
|
94
|
+
"Content-Type": "application/json",
|
|
95
|
+
...(params.token ? { authorization: `Bearer ${params.token}` } : {}),
|
|
96
|
+
},
|
|
97
|
+
body: JSON.stringify({ profileId: params.profileId, visitorId: params.visitorId }),
|
|
98
|
+
});
|
|
99
|
+
return res.json();
|
|
100
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Forge — the headless React SDK for TribeNest creator sites.
|
|
2
|
+
//
|
|
3
|
+
// Phase 1 (the spine): client factory, root provider, core types.
|
|
4
|
+
// Subsequent phases add providers (auth/cart/audio), data hooks, flow hooks,
|
|
5
|
+
// headless blocks, and SEO — see docs/code-websites-initiative.md.
|
|
6
|
+
|
|
7
|
+
export { createForgeClient, getForgeWebSocketUrl } from "./client/createForgeClient";
|
|
8
|
+
export type { ForgeClientOptions } from "./client/createForgeClient";
|
|
9
|
+
|
|
10
|
+
// All-in-one root provider (query + content + auth + cart + audio + site-config
|
|
11
|
+
// + theme). Most sites import just this.
|
|
12
|
+
export { ForgeProvider, type ForgeProviderProps } from "./provider/ForgeAppProvider";
|
|
13
|
+
// Low-level pieces for hand-composing the tree.
|
|
14
|
+
export { ForgeClientProvider, useForge, type ForgeClientProviderProps, type ForgeContextValue } from "./provider/ForgeProvider";
|
|
15
|
+
export { SiteConfigProvider, useInitialSiteConfig } from "./provider/SiteConfigProvider";
|
|
16
|
+
|
|
17
|
+
// All domain types + enums/consts (models) and WebPage.
|
|
18
|
+
export * from "./types";
|
|
19
|
+
|
|
20
|
+
// Providers (Phase 2 — moving from frontend-shared into Forge)
|
|
21
|
+
export { AudioPlayerProvider, useAudioPlayer } from "./contexts/AudioPlayerContext";
|
|
22
|
+
export type { AudioTrack } from "./contexts/AudioPlayerContext";
|
|
23
|
+
export { CartProvider, useCart } from "./contexts/CartContext";
|
|
24
|
+
export type { CartItem } from "./contexts/CartContext";
|
|
25
|
+
export {
|
|
26
|
+
ACCESS_TOKEN_KEY,
|
|
27
|
+
PUBLIC_ACCESS_TOKEN_KEY,
|
|
28
|
+
usePublicAuth,
|
|
29
|
+
PublicAuthProvider,
|
|
30
|
+
PublicAuthContext,
|
|
31
|
+
} from "./contexts/PublicAuthContext";
|
|
32
|
+
export type { AuthActions } from "./contexts/PublicAuthContext";
|
|
33
|
+
// App-user auth (mini-apps) + the /admin guard.
|
|
34
|
+
export {
|
|
35
|
+
useAppAuth,
|
|
36
|
+
AppAuthProvider,
|
|
37
|
+
APP_ACCESS_TOKEN_KEY,
|
|
38
|
+
type AppAuthUser,
|
|
39
|
+
type AppSignupInput,
|
|
40
|
+
type AppSignupResult,
|
|
41
|
+
} from "./contexts/AppAuthContext";
|
|
42
|
+
export { useAppAdminGuard, type AppAdminGuardResult } from "./contexts/useAppAdminGuard";
|
|
43
|
+
|
|
44
|
+
// Data hooks (React Query) — Phase 3
|
|
45
|
+
export * from "./data/queries/useProducts";
|
|
46
|
+
export * from "./data/queries/useMembership";
|
|
47
|
+
export * from "./data/queries/useCourses";
|
|
48
|
+
export * from "./data/queries/useCoachingProducts";
|
|
49
|
+
export * from "./data/queries/usePosts";
|
|
50
|
+
export * from "./data/queries/usePostCollections";
|
|
51
|
+
export * from "./data/queries/useBlog";
|
|
52
|
+
export * from "./data/queries/usePodcast";
|
|
53
|
+
export * from "./data/queries/useCollections";
|
|
54
|
+
export * from "./data/queries/useEvents";
|
|
55
|
+
export * from "./data/queries/useInvoice";
|
|
56
|
+
export * from "./data/queries/usePaymentLink";
|
|
57
|
+
export * from "./data/queries/useLeadMagnet";
|
|
58
|
+
export * from "./data/queries/useBlogComments";
|
|
59
|
+
export * from "./data/queries/usePageActions";
|
|
60
|
+
export * from "./data/queries/useForms";
|
|
61
|
+
export * from "./data/queries/useReplay";
|
|
62
|
+
export * from "./data/queries/useCoachingAvailability";
|
|
63
|
+
export * from "./data/queries/useCohortPage";
|
|
64
|
+
export * from "./data/queries/useCourseAccess";
|
|
65
|
+
export * from "./data/queries/useBroadcasts";
|
|
66
|
+
export * from "./data/queries/useAccount";
|
|
67
|
+
export * from "./data/queries/useFinalize";
|
|
68
|
+
export * from "./data/queries/useSubscriptions";
|
|
69
|
+
export * from "./data/queries/useEngagement";
|
|
70
|
+
export * from "./data/queries/usePaymentFlow";
|
|
71
|
+
export * from "./data/queries/useOrders";
|
|
72
|
+
export * from "./data/queries/useAuthActions";
|
|
73
|
+
export * from "./data/queries/useCoupons";
|
|
74
|
+
export * from "./data/queries/useAccountSettings";
|
|
75
|
+
export * from "./data/queries/useDonations";
|
|
76
|
+
export * from "./data/queries/useOffers";
|
|
77
|
+
export * from "./data/queries/useShipping";
|
|
78
|
+
export * from "./data/queries/useWebsite";
|
|
79
|
+
export * from "./data/queries/useWebsiteAgent";
|
|
80
|
+
export * from "./data/queries/useCurrencies";
|
|
81
|
+
export * from "./data/queries/useChat";
|
|
82
|
+
export * from "./data/queries/useAnalytics";
|
|
83
|
+
export * from "./data/queries/useCommunity";
|
|
84
|
+
export * from "./data/queries/useReviews";
|
|
85
|
+
export * from "./data/queries/useDocuments";
|
|
86
|
+
export * from "./data/queries/useNotifications";
|
|
87
|
+
export * from "./data/queries/usePWA";
|
|
88
|
+
export * from "./data/queries/useCertificates";
|
|
89
|
+
|
|
90
|
+
// Content layer (Phase E) — typed/editable/localizable site content
|
|
91
|
+
export * from "./content";
|
|
92
|
+
|
|
93
|
+
// Utils
|
|
94
|
+
export * from "./utils/attribution";
|
|
95
|
+
export * from "./utils/landing";
|
|
96
|
+
export * from "./utils/metaPixel";
|
|
97
|
+
export * from "./utils/cookieConsent";
|
|
98
|
+
export * from "./utils/structuredData";
|