@tribe-nest/forge 3.52.0 → 3.54.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 +1 -1
- package/src/contexts/AppAuthContext.tsx +3 -2
- package/src/contexts/AudioPlayerContext.tsx +3 -2
- package/src/contexts/CartContext.tsx +3 -2
- package/src/contexts/PublicAuthContext.tsx +3 -2
- package/src/data/queries/useEvents.ts +14 -0
- package/src/data/queries/useMyCourses.ts +42 -0
- package/src/data/queries/useMyTickets.ts +49 -0
- package/src/data/queries/usePaymentFlow.ts +8 -0
- package/src/data/queries/useWebsiteAgent.ts +2 -0
- package/src/i18n/de.json +47 -0
- package/src/i18n/en.json +47 -0
- package/src/i18n/index.ts +3 -2
- package/src/index.ts +23 -0
- package/src/provider/ForgeAppProvider.tsx +8 -1
- package/src/provider/ForgeProvider.tsx +3 -2
- package/src/provider/SiteConfigProvider.tsx +3 -2
- package/src/runtime/RemotePage.tsx +110 -0
- package/src/runtime/hostRuntime.ts +84 -0
- package/src/runtime/pages.spec.ts +41 -0
- package/src/runtime/pages.ts +183 -0
- package/src/runtime/pagesClient.ts +127 -0
- package/src/runtime/registry.spec.ts +45 -0
- package/src/runtime/registry.ts +102 -0
- package/src/server/jobs.ts +4 -1
- package/src/server/platformEvents.generated.ts +92 -0
- package/src/types/models.ts +58 -0
- package/src/ui/headless/agent/_tests/pathExclusion.spec.ts +52 -0
- package/src/ui/headless/agent/_tests/useCurrentPath.spec.tsx +54 -0
- package/src/ui/headless/agent/pathExclusion.ts +53 -0
- package/src/ui/headless/agent/useAiAgent.ts +10 -1
- package/src/ui/headless/agent/useCurrentPath.ts +49 -0
- package/src/ui/headless/event/_tests/ticketApproval.spec.ts +137 -0
- package/src/ui/headless/event/_tests/useEventCheckoutApproval.spec.tsx +250 -0
- package/src/ui/headless/event/ticketApproval.ts +109 -0
- package/src/ui/headless/event/useEventCheckout.ts +74 -4
- package/src/ui/headless/index.ts +11 -0
- package/src/ui/index.ts +18 -0
- package/src/ui/payment/ForgePaymentProvider.tsx +15 -0
- package/src/ui/payment/ForgeStripePayment.tsx +37 -3
- package/src/ui/payment/_tests/stripeConfirmOutcome.spec.ts +61 -0
- package/src/ui/payment/stripeConfirmOutcome.ts +50 -0
- package/src/ui/shell/TribeNestApp.tsx +6 -0
- package/src/ui/styled/AccountDashboard.tsx +181 -14
- package/src/ui/styled/AiAgentWidget.tsx +3 -2
- package/src/ui/styled/DocumentSigningPage.tsx +516 -0
- package/src/ui/styled/EventConfirmation.tsx +106 -9
- package/src/ui/styled/EventTickets.tsx +107 -13
- package/src/ui/styled/ReviewRequestPage.tsx +214 -0
- package/src/ui/styled/forge-utilities.css +310 -0
- package/src/ui/theme/ForgeThemeProvider.tsx +3 -2
- package/src/utils/_tests/ticketOrderOutcome.spec.ts +82 -0
- package/src/utils/ticketOrderOutcome.ts +57 -1
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
|
3
|
+
import { createSharedContext } from "../runtime/registry";
|
|
3
4
|
import { useForge } from "../provider/ForgeProvider";
|
|
4
5
|
import { createForgeClient } from "../client/createForgeClient";
|
|
5
6
|
import {
|
|
@@ -105,7 +106,7 @@ interface AppAuthContextType {
|
|
|
105
106
|
hasPermission: (permission: string) => boolean;
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
const AppAuthContext =
|
|
109
|
+
const AppAuthContext = createSharedContext<AppAuthContextType | null>("appAuth", null);
|
|
109
110
|
|
|
110
111
|
export function AppAuthProvider({ children }: { children: ReactNode }) {
|
|
111
112
|
const { apiUrl, appId, publishableKey } = useForge();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { useContext, useState, useRef, useEffect, useCallback } from "react";
|
|
3
|
+
import { createSharedContext } from "../runtime/registry";
|
|
3
4
|
import type { ReactNode } from "react";
|
|
4
5
|
|
|
5
6
|
export interface AudioTrack {
|
|
@@ -34,7 +35,7 @@ interface AudioPlayerContextType {
|
|
|
34
35
|
queue: AudioTrack[];
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
const AudioPlayerContext =
|
|
38
|
+
const AudioPlayerContext = createSharedContext<AudioPlayerContextType | undefined>("audioPlayer", undefined);
|
|
38
39
|
|
|
39
40
|
export function AudioPlayerProvider({ children }: { children: ReactNode }) {
|
|
40
41
|
const [currentTrack, setCurrentTrack] = useState<AudioTrack | null>(null);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import type { IBookingFee, ProductDeliveryType } from "../types/models";
|
|
3
|
-
import {
|
|
3
|
+
import { useCallback, useContext, useMemo, useState } from "react";
|
|
4
|
+
import { createSharedContext } from "../runtime/registry";
|
|
4
5
|
import type { ReactNode } from "react";
|
|
5
6
|
import { useEffect } from "react";
|
|
6
7
|
|
|
@@ -153,7 +154,7 @@ interface CartContextType {
|
|
|
153
154
|
isReady: boolean;
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
const CartContext =
|
|
157
|
+
const CartContext = createSharedContext<CartContextType | undefined>("cart", undefined);
|
|
157
158
|
|
|
158
159
|
const CART_STORAGE_KEY = "tribenest-cart";
|
|
159
160
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { type ReactNode, useCallback, useContext, useEffect, useReducer, useState } from "react";
|
|
3
|
+
import { createSharedContext } from "../runtime/registry";
|
|
3
4
|
import {
|
|
4
5
|
type ApiError,
|
|
5
6
|
type PublicAuthUser,
|
|
@@ -107,7 +108,7 @@ const AuthReducer = (state: PublicAuthState, action: AuthActions): PublicAuthSta
|
|
|
107
108
|
}
|
|
108
109
|
};
|
|
109
110
|
|
|
110
|
-
const PublicAuthContext =
|
|
111
|
+
const PublicAuthContext = createSharedContext<PublicAuthContextType | null>("publicAuth", null);
|
|
111
112
|
|
|
112
113
|
// ----------------------------------------------------------------------
|
|
113
114
|
|
|
@@ -161,6 +161,20 @@ export type CreateEventOrderResult = {
|
|
|
161
161
|
* exists — and for a profile with inventory holds switched off.
|
|
162
162
|
*/
|
|
163
163
|
holdExpiresAt?: string | null;
|
|
164
|
+
/**
|
|
165
|
+
* This order is a ticket REQUEST (curated access, feature 3): the tiers in it
|
|
166
|
+
* need the organiser's approval, so nothing is sold until they decide.
|
|
167
|
+
*
|
|
168
|
+
* With a price on it the payment step runs as today and the charge is
|
|
169
|
+
* deferred (`settlement: "deferred"` on start-payment). With nothing to pay
|
|
170
|
+
* the order is already `pending_approval` when this returns, `isFreeCheckout`
|
|
171
|
+
* is FALSE (no passes were minted), and there is no payment step: the
|
|
172
|
+
* checkout goes straight to the request-received outcome. See
|
|
173
|
+
* `nextStepAfterTicketOrder`.
|
|
174
|
+
*/
|
|
175
|
+
awaitingApproval?: boolean;
|
|
176
|
+
/** When an undecided request lapses, ISO-8601. `null` on an ordinary sale. */
|
|
177
|
+
requestExpiresAt?: string | null;
|
|
164
178
|
};
|
|
165
179
|
|
|
166
180
|
/** Create an event ticket order (the step before start-payment). */
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
|
|
3
|
+
import { useForge } from "../../provider/ForgeProvider";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The courses this fan can open on this site.
|
|
7
|
+
*
|
|
8
|
+
* `GET /public/courses/mine` resolves a grant by account OR by verified email,
|
|
9
|
+
* so a buyer who never clicked the claim link still sees what they paid for.
|
|
10
|
+
* That matters more here than anywhere: before this, a purchased course was the
|
|
11
|
+
* one thing a fan could buy and then not find, and the creator's only remedy
|
|
12
|
+
* was re-sending a claim link by hand.
|
|
13
|
+
*/
|
|
14
|
+
export type MyCourse = {
|
|
15
|
+
accessId: string;
|
|
16
|
+
courseId: string;
|
|
17
|
+
title: string;
|
|
18
|
+
description: string | null;
|
|
19
|
+
slug: string | null;
|
|
20
|
+
cohortId: string | null;
|
|
21
|
+
currentLessonId: string | null;
|
|
22
|
+
completedAt: string | null;
|
|
23
|
+
/** False when the claim link was never used. The course is theirs either way;
|
|
24
|
+
* the flag exists so the UI can reassure rather than stay silent. */
|
|
25
|
+
claimed: boolean;
|
|
26
|
+
purchasedAt: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function useMyCourses({ accountId, enabled = true }: { accountId?: string; enabled?: boolean } = {}) {
|
|
30
|
+
const { client, profileId } = useForge();
|
|
31
|
+
|
|
32
|
+
return useQuery<MyCourse[]>({
|
|
33
|
+
// `accountId` is in the key so signing out and back in as someone else
|
|
34
|
+
// cannot serve the previous fan's courses from cache.
|
|
35
|
+
queryKey: ["my-courses", accountId, profileId],
|
|
36
|
+
enabled: Boolean(accountId) && enabled,
|
|
37
|
+
queryFn: async () => {
|
|
38
|
+
const res = await client.get("/public/courses/mine", { params: { profileId } });
|
|
39
|
+
return (res.data ?? []) as MyCourse[];
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -108,6 +108,33 @@ export type MyTicketPendingTransfer = {
|
|
|
108
108
|
/** How the caller comes to be looking at an order. */
|
|
109
109
|
export type MyTicketRole = "purchaser" | "holder";
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Where a ticket REQUEST stands (curated access, feature 3), per order.
|
|
113
|
+
*
|
|
114
|
+
* pending lodged; the organiser has until `expiresAt` to decide
|
|
115
|
+
* approved approved; on a priced request the charge is settled or
|
|
116
|
+
* settling, and the passes are on the order
|
|
117
|
+
* declined the organiser said no; `decisionNote` carries their words
|
|
118
|
+
* expired the window lapsed undecided; the hold was released
|
|
119
|
+
* payment_failed approved, but the deferred charge could not be settled
|
|
120
|
+
* (`failureReason`); the seat was released
|
|
121
|
+
*
|
|
122
|
+
* `state: null` means the order was never a request. The whole object is
|
|
123
|
+
* optional because it is newer than the endpoint: an older API build sends no
|
|
124
|
+
* `request` at all, and `myTicketRequestState` reads that as "not a request".
|
|
125
|
+
*/
|
|
126
|
+
export type MyTicketRequestState = "pending" | "approved" | "declined" | "expired" | "payment_failed";
|
|
127
|
+
|
|
128
|
+
export type MyTicketRequest = {
|
|
129
|
+
state: MyTicketRequestState | null;
|
|
130
|
+
requestedAt: string | null;
|
|
131
|
+
/** The "decide by" instant while `pending`. */
|
|
132
|
+
expiresAt: string | null;
|
|
133
|
+
decidedAt: string | null;
|
|
134
|
+
decisionNote: string | null;
|
|
135
|
+
failureReason: string | null;
|
|
136
|
+
};
|
|
137
|
+
|
|
111
138
|
export type MyTicketItem = {
|
|
112
139
|
id: string;
|
|
113
140
|
quantity: number;
|
|
@@ -150,6 +177,8 @@ export type MyTicket = {
|
|
|
150
177
|
* `purchaser` reproduces exactly the previous behaviour.
|
|
151
178
|
*/
|
|
152
179
|
role?: MyTicketRole;
|
|
180
|
+
/** The ticket request behind this order, if it was one. See `MyTicketRequest`. */
|
|
181
|
+
request?: MyTicketRequest | null;
|
|
153
182
|
/**
|
|
154
183
|
* The event's `.ics`, both forms — what lets the portal offer Apple Calendar
|
|
155
184
|
* rather than only the three template providers. Null for a cancelled show.
|
|
@@ -163,6 +192,26 @@ export type MyTicket = {
|
|
|
163
192
|
passes?: MyTicketPass[];
|
|
164
193
|
};
|
|
165
194
|
|
|
195
|
+
/**
|
|
196
|
+
* The request state of an order, or `null` when it was never a request (or
|
|
197
|
+
* the API build predates requests). One place to read it so no surface has to
|
|
198
|
+
* know the object is optional.
|
|
199
|
+
*/
|
|
200
|
+
export function myTicketRequestState(ticket: Pick<MyTicket, "request">): MyTicketRequestState | null {
|
|
201
|
+
return ticket.request?.state ?? null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Does this request still have a live decision ahead of it, or did it end
|
|
206
|
+
* without a sale? Both mean "no passes, nothing to cancel, nothing to hand
|
|
207
|
+
* on", which is what the tickets tab reads to draw the row as a request rather
|
|
208
|
+
* than as a purchase. An `approved` request is a purchase by now.
|
|
209
|
+
*/
|
|
210
|
+
export function isMyTicketRequestOpenOrEnded(ticket: Pick<MyTicket, "request">): boolean {
|
|
211
|
+
const state = myTicketRequestState(ticket);
|
|
212
|
+
return state === "pending" || state === "declined" || state === "expired" || state === "payment_failed";
|
|
213
|
+
}
|
|
214
|
+
|
|
166
215
|
/**
|
|
167
216
|
* Every pass id on an order.
|
|
168
217
|
*
|
|
@@ -152,6 +152,14 @@ export function usePaymentFlow(opts: UsePaymentFlowOptions) {
|
|
|
152
152
|
/** PAYSTACK: the hosted page used only when the modal cannot open. */
|
|
153
153
|
checkoutUrl: result?.checkoutUrl,
|
|
154
154
|
isPaystack,
|
|
155
|
+
/**
|
|
156
|
+
* `"deferred"` when the charge is committed now and settled only if the
|
|
157
|
+
* organiser approves (an event ticket request). Undefined on every
|
|
158
|
+
* ordinary sale and on an older API build, which renders as before.
|
|
159
|
+
*/
|
|
160
|
+
settlement: result?.settlement,
|
|
161
|
+
/** How the provider defers a `settlement: "deferred"` charge. See `PaymentStartResponse`. */
|
|
162
|
+
deferredStrategy: result?.deferredStrategy ?? null,
|
|
155
163
|
/** True once there is a Paystack session a pay button can open. */
|
|
156
164
|
canOpenPaystack: hasPaystackSession(session),
|
|
157
165
|
openPaystackCheckout: openPaystack,
|
|
@@ -8,6 +8,8 @@ export interface WebsiteAgentConfig {
|
|
|
8
8
|
allowAnonymous?: boolean;
|
|
9
9
|
allowOrderLookup?: boolean;
|
|
10
10
|
allowLeadCapture?: boolean;
|
|
11
|
+
/** Paths the widget must not appear on. "/blog/*" covers every child. */
|
|
12
|
+
excludedPaths?: string[];
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
/** Widget bootstrap config for the profile. When `enabled` is false the widget
|
package/src/i18n/de.json
CHANGED
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"forge.account_dashboard.cancelling": "Wird storniert…",
|
|
24
24
|
"forge.account_dashboard.close": "Schließen",
|
|
25
25
|
"forge.account_dashboard.confirm_password": "Neues Passwort bestätigen",
|
|
26
|
+
"forge.account_dashboard.courses_completed": "Abgeschlossen",
|
|
27
|
+
"forge.account_dashboard.courses_continue": "Dort weitermachen, wo du aufgehört hast",
|
|
28
|
+
"forge.account_dashboard.courses_empty": "Noch nichts hier. Gekaufte Kurse erscheinen auf dieser Seite.",
|
|
29
|
+
"forge.account_dashboard.courses_start": "Starten",
|
|
30
|
+
"forge.account_dashboard.courses_title": "Deine Kurse",
|
|
26
31
|
"forge.account_dashboard.current_password": "Aktuelles Passwort",
|
|
27
32
|
"forge.account_dashboard.data_export_description": "Exportiere eine Kopie deiner persönlichen Daten.",
|
|
28
33
|
"forge.account_dashboard.data_section_title": "Deine Daten",
|
|
@@ -63,7 +68,16 @@
|
|
|
63
68
|
"forge.account_dashboard.profile_update_error": "Profil konnte nicht aktualisiert werden.",
|
|
64
69
|
"forge.account_dashboard.profile_update_success": "Profil aktualisiert.",
|
|
65
70
|
"forge.account_dashboard.rentals_title": "Meine Ausleihen",
|
|
71
|
+
"forge.account_dashboard.request_approved": "Anfrage freigegeben",
|
|
72
|
+
"forge.account_dashboard.request_decide_by": "Wir entscheiden bis {date}",
|
|
73
|
+
"forge.account_dashboard.request_declined": "Nicht freigegeben",
|
|
66
74
|
"forge.account_dashboard.request_deletion": "Kontolöschung beantragen",
|
|
75
|
+
"forge.account_dashboard.request_expired": "Anfrage abgelaufen",
|
|
76
|
+
"forge.account_dashboard.request_note": "Unser Hinweis: {note}",
|
|
77
|
+
"forge.account_dashboard.request_nothing_charged": "Es wird nichts berechnet, bis wir deine Anfrage freigeben.",
|
|
78
|
+
"forge.account_dashboard.request_payment_failed": "Freigegeben, Zahlung fehlgeschlagen",
|
|
79
|
+
"forge.account_dashboard.request_pending": "Anfrage offen",
|
|
80
|
+
"forge.account_dashboard.request_seat_released": "Der Platz wurde freigegeben. Das Event hat möglicherweise noch Tickets.",
|
|
67
81
|
"forge.account_dashboard.reschedule": "Verschieben",
|
|
68
82
|
"forge.account_dashboard.reschedule_empty": "In den nächsten zwei Wochen sind keine anderen Zeiten frei.",
|
|
69
83
|
"forge.account_dashboard.reschedule_error": "Wir konnten diese Session nicht verschieben. Bitte wähle eine andere Zeit.",
|
|
@@ -78,6 +92,7 @@
|
|
|
78
92
|
"forge.account_dashboard.sessions_title": "Meine Sessions",
|
|
79
93
|
"forge.account_dashboard.tab_account": "Konto",
|
|
80
94
|
"forge.account_dashboard.tab_bookings": "Buchungen",
|
|
95
|
+
"forge.account_dashboard.tab_courses": "Kurse",
|
|
81
96
|
"forge.account_dashboard.tab_membership": "Mitgliedschaft",
|
|
82
97
|
"forge.account_dashboard.tab_notifications": "Mitteilungen",
|
|
83
98
|
"forge.account_dashboard.tab_orders": "Bestellungen",
|
|
@@ -93,6 +108,7 @@
|
|
|
93
108
|
"forge.account_dashboard.tickets_title": "Meine Tickets",
|
|
94
109
|
"forge.account_dashboard.title": "Mein Konto",
|
|
95
110
|
"forge.account_dashboard.total": "Gesamt",
|
|
111
|
+
"forge.account_dashboard.total_on_approval": "Gesamt bei Freigabe",
|
|
96
112
|
"forge.account_dashboard.update_password": "Passwort ändern",
|
|
97
113
|
"forge.account_dashboard.update_payment_method": "Zahlungsmethode ändern",
|
|
98
114
|
"forge.account_dashboard.update_profile": "Profil aktualisieren",
|
|
@@ -727,10 +743,20 @@
|
|
|
727
743
|
"forge.ended_broadcast.refresh_instruction": "Du kannst diese Seite immer wieder neu laden, bis die Übertragung wieder läuft. Tritt ihr dann bei und du kannst das Event weiter ansehen. Du bekommst außerdem eine E-Mail, sobald die Übertragung wieder läuft.",
|
|
728
744
|
"forge.ended_broadcast.why_body": "Wenn das mitten im Event passiert ist, lag es sehr wahrscheinlich an einer instabilen Internetverbindung beim Host.",
|
|
729
745
|
"forge.ended_broadcast.why_label": "Warum wurde die Übertragung beendet?",
|
|
746
|
+
"forge.event_confirmation.awaiting_nothing_charged": "Es wird nichts berechnet, bis wir deine Anfrage freigeben.",
|
|
747
|
+
"forge.event_confirmation.body_awaiting_no_date": "Wir prüfen deine Anfrage und schicken dir eine E-Mail, sobald wir entschieden haben.",
|
|
748
|
+
"forge.event_confirmation.body_declined": "Wir konnten diese Anfrage nicht freigeben. Es wurde nichts berechnet, und eine Vormerkung auf deiner Karte wurde aufgehoben.",
|
|
749
|
+
"forge.event_confirmation.body_expired": "Wir haben deine Anfrage nicht rechtzeitig bearbeitet, daher ist sie abgelaufen. Es wurde nichts berechnet, und eine Vormerkung auf deiner Karte wurde aufgehoben.",
|
|
730
750
|
"forge.event_confirmation.body_incomplete": "Deine Bestellung ist {status}. Falls dir etwas berechnet wurde, melde dich beim Support.",
|
|
731
751
|
"forge.event_confirmation.body_paid": "Wir haben deine Tickets an {email} geschickt.",
|
|
752
|
+
"forge.event_confirmation.body_request_payment_failed": "Wir haben deine Anfrage freigegeben, aber deine Karte konnte nicht belastet werden. Der Platz wurde freigegeben. Möglicherweise sind noch Plätze verfügbar.",
|
|
753
|
+
"forge.event_confirmation.buy_again": "Erneut kaufen",
|
|
732
754
|
"forge.event_confirmation.explore": "Mehr Events ansehen",
|
|
755
|
+
"forge.event_confirmation.eyebrow_awaiting": "Anfrage eingegangen",
|
|
756
|
+
"forge.event_confirmation.eyebrow_declined": "Nicht freigegeben",
|
|
757
|
+
"forge.event_confirmation.eyebrow_expired": "Anfrage abgelaufen",
|
|
733
758
|
"forge.event_confirmation.eyebrow_paid": "E-Ticket",
|
|
759
|
+
"forge.event_confirmation.eyebrow_request_payment_failed": "Zahlung fehlgeschlagen",
|
|
734
760
|
"forge.event_confirmation.eyebrow_status": "Bestellung {status}",
|
|
735
761
|
"forge.event_confirmation.loading": "Deine Bestellung wird abgeschlossen…",
|
|
736
762
|
"forge.event_confirmation.not_found": "Wir konnten deine Bestellung nicht finden.",
|
|
@@ -740,10 +766,16 @@
|
|
|
740
766
|
"forge.event_confirmation.tax": "MwSt.",
|
|
741
767
|
"forge.event_confirmation.tax_included": "Enthält {amount} MwSt.",
|
|
742
768
|
"forge.event_confirmation.tickets_heading": "Tickets",
|
|
769
|
+
"forge.event_confirmation.title_awaiting": "Deine Anfrage ist eingegangen",
|
|
770
|
+
"forge.event_confirmation.title_declined": "Deine Anfrage wurde nicht freigegeben",
|
|
771
|
+
"forge.event_confirmation.title_expired": "Deine Anfrage ist abgelaufen",
|
|
743
772
|
"forge.event_confirmation.title_incomplete": "Bestellung nicht abgeschlossen",
|
|
744
773
|
"forge.event_confirmation.title_paid": "Du bist dabei! 🎟",
|
|
774
|
+
"forge.event_confirmation.title_request_payment_failed": "Freigegeben, aber die Zahlung ist fehlgeschlagen",
|
|
745
775
|
"forge.event_confirmation.total": "Gesamt",
|
|
776
|
+
"forge.event_confirmation.total_on_approval": "Gesamt bei Freigabe",
|
|
746
777
|
"forge.event_confirmation.total_paid": "Bezahlt gesamt",
|
|
778
|
+
"forge.event_confirmation.view_event": "Event ansehen",
|
|
747
779
|
"forge.event_confirmation.virtual_location": "Online-Event",
|
|
748
780
|
"forge.event_countdown.past": "Dieses Event ist vorbei",
|
|
749
781
|
"forge.event_countdown.unit_days": "Tage",
|
|
@@ -763,11 +795,20 @@
|
|
|
763
795
|
"forge.event_series_detail.status_cancelled": "Abgesagt",
|
|
764
796
|
"forge.event_series_detail.status_sold_out": "Ausverkauft",
|
|
765
797
|
"forge.event_tickets.add_to_cart": "In den Warenkorb",
|
|
798
|
+
"forge.event_tickets.approval_badge": "Freigabe erforderlich",
|
|
799
|
+
"forge.event_tickets.approval_help_body": "Wir entscheiden, wer dieses Ticket bekommt. Deine Karte wird nur vorgemerkt, nicht belastet, und der Platz bleibt für dich reserviert, bis wir entschieden haben. Bei einer Freigabe wird die Karte belastet und deine Tickets werden verschickt. Bei einer Ablehnung oder nach Ablauf der Anfrage wird die Vormerkung aufgehoben und nichts berechnet.",
|
|
800
|
+
"forge.event_tickets.approval_help_label": "Was bedeutet Freigabe erforderlich?",
|
|
801
|
+
"forge.event_tickets.approval_mix_blocked": "Kann nicht zu deiner aktuellen Auswahl hinzugefügt werden",
|
|
802
|
+
"forge.event_tickets.approval_mix_help_body": "Tickets, die unsere Freigabe brauchen, werden separat angefragt. Eine Bestellung ist entweder eine Anfrage oder ein Kauf, nie beides. Entferne die ausgewählten Tickets, um dieses hinzuzufügen.",
|
|
803
|
+
"forge.event_tickets.approval_mix_help_label": "Warum können diese Tickets nicht kombiniert werden?",
|
|
766
804
|
"forge.event_tickets.aria_close": "Schließen",
|
|
767
805
|
"forge.event_tickets.attendee_is_you": "(das bist du)",
|
|
768
806
|
"forge.event_tickets.attendee_name_placeholder": "Vollständiger Name",
|
|
769
807
|
"forge.event_tickets.attendees_description": "Bei diesem Event steht auf jedem Ticket der Name des jeweiligen Gastes, damit die Einlassliste zu den Leuten passt, die wirklich kommen.",
|
|
770
808
|
"forge.event_tickets.attendees_title": "Wer kommt mit?",
|
|
809
|
+
"forge.event_tickets.authorize": "{amount} vormerken",
|
|
810
|
+
"forge.event_tickets.authorize_subtitle": "Deine Anfrage erreicht uns, sobald deine Karte vorgemerkt ist.",
|
|
811
|
+
"forge.event_tickets.authorize_title": "Karte vormerken",
|
|
771
812
|
"forge.event_tickets.back": "Zurück",
|
|
772
813
|
"forge.event_tickets.booking_fee": "Buchungsgebühr",
|
|
773
814
|
"forge.event_tickets.checkout_tickets_only": "Nur Tickets kaufen",
|
|
@@ -776,6 +817,8 @@
|
|
|
776
817
|
"forge.event_tickets.continue": "Weiter",
|
|
777
818
|
"forge.event_tickets.continue_addons": "Weiter zu den Extras",
|
|
778
819
|
"forge.event_tickets.continue_payment": "Weiter zur Zahlung",
|
|
820
|
+
"forge.event_tickets.deferred_charged_on_approval": "Deine Karte wird nur belastet, wenn wir deine Anfrage freigeben.",
|
|
821
|
+
"forge.event_tickets.deferred_hold_on_statement": "Bis dahin erscheint eine vorübergehende Vormerkung auf deiner Abrechnung.",
|
|
779
822
|
"forge.event_tickets.details_title": "Deine Daten",
|
|
780
823
|
"forge.event_tickets.email_mismatch": "Die E-Mail-Adressen stimmen nicht überein",
|
|
781
824
|
"forge.event_tickets.email_placeholder": "E-Mail",
|
|
@@ -818,6 +861,7 @@
|
|
|
818
861
|
"forge.event_tickets.pwyw_range_min": "(mindestens {min})",
|
|
819
862
|
"forge.event_tickets.pwyw_range_min_max": "(mindestens {min}, bis {max})",
|
|
820
863
|
"forge.event_tickets.remove_discount": "Rabatt entfernen",
|
|
864
|
+
"forge.event_tickets.request_tickets": "Tickets anfragen",
|
|
821
865
|
"forge.event_tickets.select_option": "Auswählen…",
|
|
822
866
|
"forge.event_tickets.select_title": "Tickets wählen",
|
|
823
867
|
"forge.event_tickets.subtotal": "Zwischensumme",
|
|
@@ -958,6 +1002,9 @@
|
|
|
958
1002
|
"forge.film_watch.unavailable": "Diese Folge kann gerade nicht abgespielt werden.",
|
|
959
1003
|
"forge.film_watch.up_next": "Als Nächstes: {title}",
|
|
960
1004
|
"forge.film_watch.window_not_started": "Dein Zeitfenster startet jetzt.",
|
|
1005
|
+
"forge.forge_stripe_payment.authorize": "{amount} vormerken",
|
|
1006
|
+
"forge.forge_stripe_payment.deferred_charged_on_approval": "Deine Karte wird nur belastet, wenn wir deine Anfrage freigeben.",
|
|
1007
|
+
"forge.forge_stripe_payment.deferred_hold_on_statement": "Bis dahin erscheint eine vorübergehende Vormerkung auf deiner Abrechnung.",
|
|
961
1008
|
"forge.forgot_password_form.back_to_login": "Zurück zur Anmeldung",
|
|
962
1009
|
"forge.forgot_password_form.email_label": "E-Mail",
|
|
963
1010
|
"forge.forgot_password_form.email_placeholder": "E-Mail",
|
package/src/i18n/en.json
CHANGED
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"forge.account_dashboard.cancelling": "Cancelling…",
|
|
24
24
|
"forge.account_dashboard.close": "Close",
|
|
25
25
|
"forge.account_dashboard.confirm_password": "Confirm new password",
|
|
26
|
+
"forge.account_dashboard.courses_completed": "Completed",
|
|
27
|
+
"forge.account_dashboard.courses_continue": "Continue where you left off",
|
|
28
|
+
"forge.account_dashboard.courses_empty": "Nothing here yet. Courses you buy appear on this page.",
|
|
29
|
+
"forge.account_dashboard.courses_start": "Start",
|
|
30
|
+
"forge.account_dashboard.courses_title": "Your courses",
|
|
26
31
|
"forge.account_dashboard.current_password": "Current password",
|
|
27
32
|
"forge.account_dashboard.data_export_description": "Export a copy of your personal data.",
|
|
28
33
|
"forge.account_dashboard.data_section_title": "Your Data",
|
|
@@ -63,7 +68,16 @@
|
|
|
63
68
|
"forge.account_dashboard.profile_update_error": "Failed to update profile.",
|
|
64
69
|
"forge.account_dashboard.profile_update_success": "Profile updated.",
|
|
65
70
|
"forge.account_dashboard.rentals_title": "My Rentals",
|
|
71
|
+
"forge.account_dashboard.request_approved": "Request approved",
|
|
72
|
+
"forge.account_dashboard.request_decide_by": "We'll decide by {date}",
|
|
73
|
+
"forge.account_dashboard.request_declined": "Not approved",
|
|
66
74
|
"forge.account_dashboard.request_deletion": "Request Account Deletion",
|
|
75
|
+
"forge.account_dashboard.request_expired": "Request expired",
|
|
76
|
+
"forge.account_dashboard.request_note": "Our note: {note}",
|
|
77
|
+
"forge.account_dashboard.request_nothing_charged": "Nothing is charged until we approve your request.",
|
|
78
|
+
"forge.account_dashboard.request_payment_failed": "Approved, payment failed",
|
|
79
|
+
"forge.account_dashboard.request_pending": "Request pending",
|
|
80
|
+
"forge.account_dashboard.request_seat_released": "The seat was released. The event may still have tickets available.",
|
|
67
81
|
"forge.account_dashboard.reschedule": "Reschedule",
|
|
68
82
|
"forge.account_dashboard.reschedule_empty": "No other times are open in the next two weeks.",
|
|
69
83
|
"forge.account_dashboard.reschedule_error": "We could not move this session. Please try another time.",
|
|
@@ -78,6 +92,7 @@
|
|
|
78
92
|
"forge.account_dashboard.sessions_title": "My Sessions",
|
|
79
93
|
"forge.account_dashboard.tab_account": "Account",
|
|
80
94
|
"forge.account_dashboard.tab_bookings": "Bookings",
|
|
95
|
+
"forge.account_dashboard.tab_courses": "Courses",
|
|
81
96
|
"forge.account_dashboard.tab_membership": "Membership",
|
|
82
97
|
"forge.account_dashboard.tab_notifications": "Notifications",
|
|
83
98
|
"forge.account_dashboard.tab_orders": "Orders",
|
|
@@ -93,6 +108,7 @@
|
|
|
93
108
|
"forge.account_dashboard.tickets_title": "My Tickets",
|
|
94
109
|
"forge.account_dashboard.title": "My Account",
|
|
95
110
|
"forge.account_dashboard.total": "Total",
|
|
111
|
+
"forge.account_dashboard.total_on_approval": "Total if approved",
|
|
96
112
|
"forge.account_dashboard.update_password": "Update Password",
|
|
97
113
|
"forge.account_dashboard.update_payment_method": "Update payment method",
|
|
98
114
|
"forge.account_dashboard.update_profile": "Update Profile",
|
|
@@ -727,10 +743,20 @@
|
|
|
727
743
|
"forge.ended_broadcast.refresh_instruction": "You can keep refreshing this page until the broadcast is live again. Join it and you should be able to watch the event again. You will also get an email when the broadcast is live again.",
|
|
728
744
|
"forge.ended_broadcast.why_body": "If this happened in the middle of the event, it was most likely caused by an unstable internet connection at the host's end.",
|
|
729
745
|
"forge.ended_broadcast.why_label": "Why did the broadcast end?",
|
|
746
|
+
"forge.event_confirmation.awaiting_nothing_charged": "Nothing is charged until we approve your request.",
|
|
747
|
+
"forge.event_confirmation.body_awaiting_no_date": "We're reviewing your request and will email you as soon as we've decided.",
|
|
748
|
+
"forge.event_confirmation.body_declined": "We weren't able to approve this request. Nothing has been charged, and any hold on your card has been released.",
|
|
749
|
+
"forge.event_confirmation.body_expired": "We didn't get to your request in time, so it has expired. Nothing has been charged, and any hold on your card has been released.",
|
|
730
750
|
"forge.event_confirmation.body_incomplete": "Your order is {status}. If you were charged, contact support.",
|
|
731
751
|
"forge.event_confirmation.body_paid": "We’ve sent your tickets to {email}.",
|
|
752
|
+
"forge.event_confirmation.body_request_payment_failed": "We approved your request but your card could not be charged, so the seat was released. Seats may still be available.",
|
|
753
|
+
"forge.event_confirmation.buy_again": "Buy again",
|
|
732
754
|
"forge.event_confirmation.explore": "Browse more events",
|
|
755
|
+
"forge.event_confirmation.eyebrow_awaiting": "Request received",
|
|
756
|
+
"forge.event_confirmation.eyebrow_declined": "Not approved",
|
|
757
|
+
"forge.event_confirmation.eyebrow_expired": "Request expired",
|
|
733
758
|
"forge.event_confirmation.eyebrow_paid": "E-Ticket",
|
|
759
|
+
"forge.event_confirmation.eyebrow_request_payment_failed": "Payment failed",
|
|
734
760
|
"forge.event_confirmation.eyebrow_status": "Order {status}",
|
|
735
761
|
"forge.event_confirmation.loading": "Finalizing your order…",
|
|
736
762
|
"forge.event_confirmation.not_found": "We couldn’t find your order.",
|
|
@@ -740,10 +766,16 @@
|
|
|
740
766
|
"forge.event_confirmation.tax": "Tax",
|
|
741
767
|
"forge.event_confirmation.tax_included": "Includes {amount} tax",
|
|
742
768
|
"forge.event_confirmation.tickets_heading": "Tickets",
|
|
769
|
+
"forge.event_confirmation.title_awaiting": "Your request is in",
|
|
770
|
+
"forge.event_confirmation.title_declined": "Your request was not approved",
|
|
771
|
+
"forge.event_confirmation.title_expired": "Your request has expired",
|
|
743
772
|
"forge.event_confirmation.title_incomplete": "Order not completed",
|
|
744
773
|
"forge.event_confirmation.title_paid": "You’re going! 🎟",
|
|
774
|
+
"forge.event_confirmation.title_request_payment_failed": "Approved, but the payment did not go through",
|
|
745
775
|
"forge.event_confirmation.total": "Total",
|
|
776
|
+
"forge.event_confirmation.total_on_approval": "Total if approved",
|
|
746
777
|
"forge.event_confirmation.total_paid": "Total paid",
|
|
778
|
+
"forge.event_confirmation.view_event": "View event",
|
|
747
779
|
"forge.event_confirmation.virtual_location": "Virtual event",
|
|
748
780
|
"forge.event_countdown.past": "This event has passed",
|
|
749
781
|
"forge.event_countdown.unit_days": "Days",
|
|
@@ -763,11 +795,20 @@
|
|
|
763
795
|
"forge.event_series_detail.status_cancelled": "Cancelled",
|
|
764
796
|
"forge.event_series_detail.status_sold_out": "Sold out",
|
|
765
797
|
"forge.event_tickets.add_to_cart": "Add to cart",
|
|
798
|
+
"forge.event_tickets.approval_badge": "Approval required",
|
|
799
|
+
"forge.event_tickets.approval_help_body": "We review who gets this ticket. Your card is held, not charged, and the seat is yours while we decide. If we approve, the card is charged and your tickets are sent. If we decline, or the request expires, the hold is released and nothing is charged.",
|
|
800
|
+
"forge.event_tickets.approval_help_label": "What does approval required mean?",
|
|
801
|
+
"forge.event_tickets.approval_mix_blocked": "Can't be added to your current selection",
|
|
802
|
+
"forge.event_tickets.approval_mix_help_body": "Tickets that need our approval are requested on their own, so one order is either a request or a purchase, never both. Remove the tickets you have selected to add this one.",
|
|
803
|
+
"forge.event_tickets.approval_mix_help_label": "Why can't these tickets be combined?",
|
|
766
804
|
"forge.event_tickets.aria_close": "Close",
|
|
767
805
|
"forge.event_tickets.attendee_is_you": "(that’s you)",
|
|
768
806
|
"forge.event_tickets.attendee_name_placeholder": "Full name",
|
|
769
807
|
"forge.event_tickets.attendees_description": "This event prints each attendee’s name on their own pass, so the door list matches who actually turns up.",
|
|
770
808
|
"forge.event_tickets.attendees_title": "Who is coming?",
|
|
809
|
+
"forge.event_tickets.authorize": "Authorize {amount}",
|
|
810
|
+
"forge.event_tickets.authorize_subtitle": "Your request reaches us once your card is authorized.",
|
|
811
|
+
"forge.event_tickets.authorize_title": "Authorize your card",
|
|
771
812
|
"forge.event_tickets.back": "Back",
|
|
772
813
|
"forge.event_tickets.booking_fee": "Booking fee",
|
|
773
814
|
"forge.event_tickets.checkout_tickets_only": "Checkout tickets only",
|
|
@@ -776,6 +817,8 @@
|
|
|
776
817
|
"forge.event_tickets.continue": "Continue",
|
|
777
818
|
"forge.event_tickets.continue_addons": "Continue to add-ons",
|
|
778
819
|
"forge.event_tickets.continue_payment": "Continue to payment",
|
|
820
|
+
"forge.event_tickets.deferred_charged_on_approval": "Your card is only charged if we approve your request.",
|
|
821
|
+
"forge.event_tickets.deferred_hold_on_statement": "Until then a temporary hold will show on your statement.",
|
|
779
822
|
"forge.event_tickets.details_title": "Your details",
|
|
780
823
|
"forge.event_tickets.email_mismatch": "Email addresses do not match",
|
|
781
824
|
"forge.event_tickets.email_placeholder": "Email",
|
|
@@ -818,6 +861,7 @@
|
|
|
818
861
|
"forge.event_tickets.pwyw_range_min": "(minimum {min})",
|
|
819
862
|
"forge.event_tickets.pwyw_range_min_max": "(minimum {min}, up to {max})",
|
|
820
863
|
"forge.event_tickets.remove_discount": "Remove discount",
|
|
864
|
+
"forge.event_tickets.request_tickets": "Request tickets",
|
|
821
865
|
"forge.event_tickets.select_option": "Select…",
|
|
822
866
|
"forge.event_tickets.select_title": "Select Tickets",
|
|
823
867
|
"forge.event_tickets.subtotal": "Subtotal",
|
|
@@ -958,6 +1002,9 @@
|
|
|
958
1002
|
"forge.film_watch.unavailable": "This episode cannot be played right now.",
|
|
959
1003
|
"forge.film_watch.up_next": "Up next: {title}",
|
|
960
1004
|
"forge.film_watch.window_not_started": "Your window starts now.",
|
|
1005
|
+
"forge.forge_stripe_payment.authorize": "Authorize {amount}",
|
|
1006
|
+
"forge.forge_stripe_payment.deferred_charged_on_approval": "Your card is only charged if we approve your request.",
|
|
1007
|
+
"forge.forge_stripe_payment.deferred_hold_on_statement": "Until then a temporary hold will show on your statement.",
|
|
961
1008
|
"forge.forgot_password_form.back_to_login": "Back to login",
|
|
962
1009
|
"forge.forgot_password_form.email_label": "Email",
|
|
963
1010
|
"forge.forgot_password_form.email_placeholder": "Email",
|
package/src/i18n/index.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
// Key naming is fixed by ./CONVENTION.md. Every key starts with "forge." so a
|
|
7
7
|
// tenant's own copy can never collide with the package's.
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { createElement, useContext, useMemo, type ReactNode } from "react";
|
|
10
|
+
import { createSharedContext } from "../runtime/registry";
|
|
10
11
|
import enMessages from "./en.json";
|
|
11
12
|
import deMessages from "./de.json";
|
|
12
13
|
|
|
@@ -73,7 +74,7 @@ export function getForgeMessages(locale: ForgeLocale): ForgeMessages {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
// `null` means "no provider above me", which is a supported state, not a bug.
|
|
76
|
-
const ForgeI18nContext =
|
|
77
|
+
const ForgeI18nContext = createSharedContext<ForgeLocale | null>("i18n", null);
|
|
77
78
|
|
|
78
79
|
export interface ForgeI18nProviderProps {
|
|
79
80
|
/**
|
package/src/index.ts
CHANGED
|
@@ -71,9 +71,11 @@ export { safeRedirectPath } from "./utils/safeRedirect";
|
|
|
71
71
|
export {
|
|
72
72
|
getTicketOrderOutcome,
|
|
73
73
|
isTicketOrderRefunded,
|
|
74
|
+
ticketRequestFailureKind,
|
|
74
75
|
TICKET_ORDER_REFUNDED_COPY,
|
|
75
76
|
type TicketOrderOutcome,
|
|
76
77
|
type TicketOrderOutcomeInput,
|
|
78
|
+
type TicketRequestFailureKind,
|
|
77
79
|
} from "./utils/ticketOrderOutcome";
|
|
78
80
|
// App-user auth (mini-apps) + the /admin guard.
|
|
79
81
|
export {
|
|
@@ -121,6 +123,7 @@ export * from "./data/queries/useAccount";
|
|
|
121
123
|
export * from "./data/queries/useMyTickets";
|
|
122
124
|
export * from "./data/queries/usePassTransfers";
|
|
123
125
|
export * from "./data/queries/useMyBookings";
|
|
126
|
+
export * from "./data/queries/useMyCourses";
|
|
124
127
|
// The member's own call calendar. Beside `useMyBookings` and `useMyTickets`
|
|
125
128
|
// because it answers the same shape of question: what have I got coming up
|
|
126
129
|
// with this artist, and where do I go for it.
|
|
@@ -179,3 +182,23 @@ export * from "./utils/formatDateTime";
|
|
|
179
182
|
// The ONE membership access predicate + the messaging that is deliberately
|
|
180
183
|
// separate from it. Every surface that gates on a membership imports from here.
|
|
181
184
|
export * from "./utils/membershipAccess";
|
|
185
|
+
|
|
186
|
+
// Hosted internal pages. `/i/*` is published once and rendered through the
|
|
187
|
+
// catch-all route on every site, so a fix reaches every fan without a rebuild.
|
|
188
|
+
// `internalLink` / `internalPath` are how anything links into those pages now:
|
|
189
|
+
// a literal `/i/...` path no longer type-checks, because the per-page route
|
|
190
|
+
// files it referred to are gone. See docs/proposals/hosted-internal-pages-initiative.md.
|
|
191
|
+
export * from "./runtime/pages";
|
|
192
|
+
export * from "./runtime/pagesClient";
|
|
193
|
+
export * from "./runtime/RemotePage";
|
|
194
|
+
// The runtime a site shares with the hosted pages bundle. A site never calls
|
|
195
|
+
// these; the chassis catch-all registers the router and TribeNestApp does the
|
|
196
|
+
// rest. Exported because the bundle reads them from the published package.
|
|
197
|
+
export {
|
|
198
|
+
PAGES_RUNTIME_CONTRACT,
|
|
199
|
+
createSharedContext,
|
|
200
|
+
missingRuntimeKeys,
|
|
201
|
+
readRuntimeValue,
|
|
202
|
+
shareRuntimeValue,
|
|
203
|
+
} from "./runtime/registry";
|
|
204
|
+
export { RUNTIME_KEYS, REQUIRED_RUNTIME_KEYS, registerRouterRuntime, hostQueryClient } from "./runtime/hostRuntime";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState, type ReactNode } from "react";
|
|
2
2
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
3
|
+
import { registerQueryClient } from "../runtime/hostRuntime";
|
|
3
4
|
import { ForgeClientProvider } from "./ForgeProvider";
|
|
4
5
|
import { SiteConfigProvider } from "./SiteConfigProvider";
|
|
5
6
|
import { ForgeContentProvider } from "../content/ForgeContentProvider";
|
|
@@ -127,7 +128,13 @@ export function ForgeProvider({
|
|
|
127
128
|
children,
|
|
128
129
|
}: ForgeProviderProps) {
|
|
129
130
|
// One client per provider instance (per SSR request), unless the host supplies one.
|
|
130
|
-
const [client] = useState(() =>
|
|
131
|
+
const [client] = useState(() => {
|
|
132
|
+
const created = queryClient ?? new QueryClient();
|
|
133
|
+
// So a hosted `/i/*` page shares this cache rather than opening its own.
|
|
134
|
+
// No-ops on the server, where one global would span requests.
|
|
135
|
+
registerQueryClient(created);
|
|
136
|
+
return created;
|
|
137
|
+
});
|
|
131
138
|
|
|
132
139
|
return (
|
|
133
140
|
<ForgeClientProvider
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback, useContext, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { createSharedContext } from "../runtime/registry";
|
|
2
3
|
import type { AxiosInstance } from "axios";
|
|
3
4
|
import { createForgeClient } from "../client/createForgeClient";
|
|
4
5
|
import {
|
|
@@ -38,7 +39,7 @@ export interface ForgeContextValue {
|
|
|
38
39
|
setToken: (token: string | null) => void;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const ForgeContext =
|
|
42
|
+
const ForgeContext = createSharedContext<ForgeContextValue | null>("forgeClient", null);
|
|
42
43
|
|
|
43
44
|
export interface ForgeClientProviderProps {
|
|
44
45
|
apiUrl: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useContext, type ReactNode } from "react";
|
|
2
|
+
import { createSharedContext } from "../runtime/registry";
|
|
2
3
|
import type { SiteConfig } from "../data/queries/useWebsite";
|
|
3
4
|
import { setSiteLocale } from "../client/activeLocale";
|
|
4
5
|
|
|
@@ -9,7 +10,7 @@ import { setSiteLocale } from "../client/activeLocale";
|
|
|
9
10
|
* wasn't fetched on the server, in which case `useSiteConfig` just fetches on
|
|
10
11
|
* the client as before.
|
|
11
12
|
*/
|
|
12
|
-
const SiteConfigContext =
|
|
13
|
+
const SiteConfigContext = createSharedContext<SiteConfig | undefined>("siteConfig", undefined);
|
|
13
14
|
|
|
14
15
|
/** Seed the SSR-fetched site config (see `fetchSiteConfig` in `@tribe-nest/forge/server`). */
|
|
15
16
|
export function SiteConfigProvider({
|