@tribe-nest/forge 3.54.0 → 3.58.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 +4 -2
- package/src/_tests/workspaceAliases.ts +1 -0
- package/src/contexts/CartContext.tsx +88 -5
- package/src/data/queries/useCallBreakouts.ts +112 -0
- package/src/data/queries/useCheckouts.ts +15 -2
- package/src/data/queries/useCoachingProducts.ts +15 -1
- package/src/data/queries/useCourses.ts +15 -1
- package/src/data/queries/useEvents.ts +80 -1
- package/src/data/queries/useMembership.ts +176 -4
- package/src/data/queries/useMyBookings.ts +16 -0
- package/src/data/queries/useNotifications.ts +1 -1
- package/src/data/queries/useProducts.ts +15 -1
- package/src/data/queries/useSubscriptions.ts +21 -1
- package/src/i18n/de.json +153 -0
- package/src/i18n/en.json +153 -0
- package/src/index.ts +1 -0
- package/src/server/_tests/buildPwaHead.spec.ts +1 -1
- package/src/server/_tests/buildWebManifest.spec.ts +1 -1
- package/src/server/_tests/forgeServiceWorkerScript.spec.ts +1 -1
- package/src/server/index.ts +75 -1
- package/src/server/platformEvents.generated.ts +60 -0
- package/src/server/pwa.ts +1 -1
- package/src/types/models.ts +137 -0
- package/src/ui/analytics/ForgeAnalytics.tsx +55 -1
- package/src/ui/analytics/_tests/ForgeAnalytics.engagement.spec.tsx +78 -0
- package/src/ui/headless/checkout/_tests/bundleCoupon.spec.ts +3 -1
- package/src/ui/headless/checkout/_tests/cartResume.spec.ts +3 -10
- package/src/ui/headless/checkout/_tests/seatConflict.spec.ts +187 -0
- package/src/ui/headless/checkout/_tests/useCartResume.spec.tsx +3 -11
- package/src/ui/headless/checkout/_tests/useCheckoutSeats.spec.tsx +313 -0
- package/src/ui/headless/checkout/seatConflict.ts +117 -0
- package/src/ui/headless/checkout/useCheckout.ts +178 -55
- package/src/ui/headless/event/_tests/seatingFixture.ts +111 -0
- package/src/ui/headless/event/_tests/useEventCheckoutSeats.spec.tsx +443 -0
- package/src/ui/headless/event/_tests/useEventSeating.spec.tsx +154 -0
- package/src/ui/headless/event/useEventCheckout.ts +362 -22
- package/src/ui/headless/event/useEventSeating.ts +233 -0
- package/src/ui/headless/forms/_tests/usePhoneInput.spec.ts +187 -0
- package/src/ui/headless/forms/useEmailListForm.ts +37 -6
- package/src/ui/headless/forms/usePhoneInput.ts +294 -0
- package/src/ui/headless/forms/useSectionedForm.ts +2 -2
- package/src/ui/headless/index.ts +48 -1
- package/src/ui/headless/membership/_tests/membershipApplication.spec.ts +85 -0
- package/src/ui/headless/membership/_tests/membershipCheckoutRefetch.spec.tsx +2 -0
- package/src/ui/headless/membership/_tests/membershipTrial.spec.ts +61 -0
- package/src/ui/headless/membership/_tests/useMembershipCheckoutApplication.spec.tsx +253 -0
- package/src/ui/headless/membership/_tests/useMembershipCheckoutQuestionnaire.spec.tsx +241 -0
- package/src/ui/headless/membership/_tests/useMembershipCheckoutTrial.spec.tsx +165 -0
- package/src/ui/headless/membership/membershipApplication.ts +109 -0
- package/src/ui/headless/membership/membershipQuestionnaire.ts +44 -0
- package/src/ui/headless/membership/membershipTrial.ts +53 -0
- package/src/ui/headless/membership/useMembershipCheckout.ts +227 -8
- package/src/ui/index.ts +16 -0
- package/src/ui/media/CallStage.tsx +107 -10
- package/src/ui/media/_tests/CallBreakoutsPanel.spec.tsx +271 -0
- package/src/ui/media/_tests/CallStageBreakouts.spec.tsx +212 -0
- package/src/ui/media/_tests/callState.spec.ts +103 -1
- package/src/ui/media/callBreakouts.ts +57 -0
- package/src/ui/media/callState.ts +83 -23
- package/src/ui/media/index.ts +11 -0
- package/src/ui/media/panels/CallBreakoutsPanel.tsx +395 -0
- package/src/ui/media/panels/CallSidePanel.tsx +37 -4
- package/src/ui/media/stage/CallCenterNotice.tsx +5 -3
- package/src/ui/media/stage/CallControlsBar.tsx +46 -0
- package/src/ui/media/stage/CallTopBar.tsx +1 -1
- package/src/ui/payment/ForgePaymentProvider.tsx +14 -0
- package/src/ui/payment/ForgeStripePayment.tsx +78 -7
- package/src/ui/payment/_tests/ForgeStripePaymentTrial.spec.tsx +101 -0
- package/src/ui/payment/_tests/stripeIntentKind.spec.ts +43 -0
- package/src/ui/payment/stripeIntentKind.ts +32 -0
- package/src/ui/shell/TribeNestApp.tsx +1 -1
- package/src/ui/styled/AccountDashboard.tsx +165 -2
- package/src/ui/styled/BundleConfirmation.tsx +47 -2
- package/src/ui/styled/Cart.tsx +211 -135
- package/src/ui/styled/Checkout.tsx +163 -32
- package/src/ui/styled/EmailListForm.tsx +7 -9
- package/src/ui/styled/EventTickets.tsx +143 -4
- package/src/ui/styled/LoginForm.tsx +5 -3
- package/src/ui/styled/MembershipCheckout.tsx +596 -256
- package/src/ui/styled/MembershipTierCallout.tsx +17 -3
- package/src/ui/styled/MembershipTiers.tsx +148 -6
- package/src/ui/styled/PhoneInput.tsx +127 -0
- package/src/ui/styled/ProductGrid.tsx +14 -2
- package/src/ui/styled/SignupForm.tsx +4 -2
- package/src/ui/styled/_tests/AccountDashboardBookingCall.spec.tsx +36 -0
- package/src/ui/styled/_tests/AccountDashboardTrial.spec.tsx +105 -0
- package/src/ui/styled/_tests/CartSeats.spec.tsx +109 -0
- package/src/ui/styled/_tests/CheckoutSeatsConflict.spec.tsx +194 -0
- package/src/ui/styled/_tests/EventSeatPicker.spec.tsx +199 -0
- package/src/ui/styled/_tests/MembershipCheckout.spec.tsx +106 -0
- package/src/ui/styled/_tests/membershipTiersCuratedAccess.spec.tsx +139 -0
- package/src/ui/styled/_tests/membershipTiersTrial.spec.tsx +97 -0
- package/src/ui/styled/forge-utilities.css +67 -0
- package/src/ui/styled/seating/EventSeatPicker.tsx +190 -0
- package/src/ui/styled/seating/SeatLegend.tsx +73 -0
- package/src/ui/styled/seating/SeatMapCanvas.tsx +647 -0
- package/src/ui/styled/seating/paint.ts +79 -0
- package/src/ui/styled/seating/useSeatMapViewport.ts +248 -0
- package/src/ui/styled/seating/viewport.ts +86 -0
- package/src/utils/_tests/engagementTracker.spec.ts +111 -0
- package/src/utils/engagementTracker.ts +73 -0
- package/src/utils/landing.ts +1 -1
package/src/i18n/en.json
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
+
"forge.account_dashboard.application_complete": "Complete your membership",
|
|
3
|
+
"forge.account_dashboard.application_complete_by": "Complete by {date}",
|
|
4
|
+
"forge.account_dashboard.application_status_approved": "Approved, finishing up",
|
|
5
|
+
"forge.account_dashboard.application_status_card_pending": "Card not confirmed yet",
|
|
6
|
+
"forge.account_dashboard.application_status_declined": "Not approved",
|
|
7
|
+
"forge.account_dashboard.application_status_expired": "Expired",
|
|
8
|
+
"forge.account_dashboard.application_status_joined": "Joined",
|
|
9
|
+
"forge.account_dashboard.application_status_payment_failed": "Approved: complete your membership",
|
|
10
|
+
"forge.account_dashboard.application_status_pending": "Application pending",
|
|
11
|
+
"forge.account_dashboard.application_status_withdrawn": "Withdrawn",
|
|
12
|
+
"forge.account_dashboard.application_submitted_on": "Applied on {date}",
|
|
13
|
+
"forge.account_dashboard.application_withdraw": "Withdraw",
|
|
14
|
+
"forge.account_dashboard.application_withdraw_error": "We couldn't withdraw your application. Please try again.",
|
|
15
|
+
"forge.account_dashboard.application_withdrawing": "Withdrawing…",
|
|
16
|
+
"forge.account_dashboard.applications_title": "Your applications",
|
|
2
17
|
"forge.account_dashboard.billing_portal_error": "We couldn't open the billing page. Please contact us.",
|
|
3
18
|
"forge.account_dashboard.billing_portal_opening": "Opening…",
|
|
4
19
|
"forge.account_dashboard.booking_cancel_error": "We could not cancel this session. Please try again.",
|
|
@@ -16,6 +31,7 @@
|
|
|
16
31
|
"forge.account_dashboard.cancel_confirm_paid": "It will not renew, and you keep your benefits until the end of the period you have paid for.",
|
|
17
32
|
"forge.account_dashboard.cancel_confirm_paid_until": "It will not renew, and you keep your benefits until {date}.",
|
|
18
33
|
"forge.account_dashboard.cancel_confirm_title": "Cancel your membership?",
|
|
34
|
+
"forge.account_dashboard.cancel_confirm_trial": "Your free trial will not turn into a paid membership. You keep your benefits until {date}, and nothing is charged.",
|
|
19
35
|
"forge.account_dashboard.cancel_deletion": "Cancel Deletion",
|
|
20
36
|
"forge.account_dashboard.cancel_session": "Cancel session",
|
|
21
37
|
"forge.account_dashboard.cancel_ticket": "Cancel ticket",
|
|
@@ -29,6 +45,8 @@
|
|
|
29
45
|
"forge.account_dashboard.courses_start": "Start",
|
|
30
46
|
"forge.account_dashboard.courses_title": "Your courses",
|
|
31
47
|
"forge.account_dashboard.current_password": "Current password",
|
|
48
|
+
"forge.account_dashboard.cycle_month": "month",
|
|
49
|
+
"forge.account_dashboard.cycle_year": "year",
|
|
32
50
|
"forge.account_dashboard.data_export_description": "Export a copy of your personal data.",
|
|
33
51
|
"forge.account_dashboard.data_section_title": "Your Data",
|
|
34
52
|
"forge.account_dashboard.delete_section_title": "Delete Account",
|
|
@@ -50,6 +68,9 @@
|
|
|
50
68
|
"forge.account_dashboard.membership_price": "{amount} / {cycle}",
|
|
51
69
|
"forge.account_dashboard.membership_renews_on": "Renews on {date}",
|
|
52
70
|
"forge.account_dashboard.membership_title": "Current Membership",
|
|
71
|
+
"forge.account_dashboard.membership_trial_cancelled": "Cancelled. Nothing will be charged.",
|
|
72
|
+
"forge.account_dashboard.membership_trial_then": "Then {amount} per {cycle} from {date}.",
|
|
73
|
+
"forge.account_dashboard.membership_trial_until": "Free trial until {date}",
|
|
53
74
|
"forge.account_dashboard.new_password": "New password",
|
|
54
75
|
"forge.account_dashboard.notifications_title": "Notification Types",
|
|
55
76
|
"forge.account_dashboard.notify_chat_description": "Get notified when new chat messages arrive",
|
|
@@ -208,6 +229,7 @@
|
|
|
208
229
|
"forge.bundle_confirmation.partial_body": "Your payment went through and part of your order is confirmed. We're still finishing the rest. It will arrive by email shortly, with nothing more to pay.",
|
|
209
230
|
"forge.bundle_confirmation.partial_title": "Payment received",
|
|
210
231
|
"forge.bundle_confirmation.return_to_checkout": "Return to checkout",
|
|
232
|
+
"forge.bundle_confirmation.seats_title": "Your seats",
|
|
211
233
|
"forge.bundle_confirmation.summary_both": "Paid in one go. Your tickets are on their way by email, and your order is confirmed.",
|
|
212
234
|
"forge.bundle_confirmation.summary_order": "Paid in one go. Your order is confirmed.",
|
|
213
235
|
"forge.bundle_confirmation.summary_paid": "Paid in one go.",
|
|
@@ -215,6 +237,40 @@
|
|
|
215
237
|
"forge.bundle_confirmation.tickets_emailed": "Tickets emailed to you",
|
|
216
238
|
"forge.bundle_confirmation.title": "You're all set",
|
|
217
239
|
"forge.bundle_confirmation.view_orders": "View your orders",
|
|
240
|
+
"forge.call_stage.breakouts.assign_auto": "Automatically",
|
|
241
|
+
"forge.call_stage.breakouts.assign_label": "Assign people",
|
|
242
|
+
"forge.call_stage.breakouts.assign_manual": "I will assign them",
|
|
243
|
+
"forge.call_stage.breakouts.assigned_not_arrived": "(on the way)",
|
|
244
|
+
"forge.call_stage.breakouts.button": "Rooms",
|
|
245
|
+
"forge.call_stage.breakouts.close_all": "Close all rooms",
|
|
246
|
+
"forge.call_stage.breakouts.close_cancel": "Keep them open",
|
|
247
|
+
"forge.call_stage.breakouts.close_confirm": "Close rooms",
|
|
248
|
+
"forge.call_stage.breakouts.close_confirm_body": "Everyone comes back to the main room and the rooms are closed.",
|
|
249
|
+
"forge.call_stage.breakouts.count_label": "Number of rooms",
|
|
250
|
+
"forge.call_stage.breakouts.create": "Create rooms",
|
|
251
|
+
"forge.call_stage.breakouts.create_title": "Breakout rooms",
|
|
252
|
+
"forge.call_stage.breakouts.current_marker": "You are here",
|
|
253
|
+
"forge.call_stage.breakouts.empty_room": "Nobody here yet",
|
|
254
|
+
"forge.call_stage.breakouts.error": "That did not work. Try again.",
|
|
255
|
+
"forge.call_stage.breakouts.help_attendee": "The host has split this call into smaller rooms. You are moved automatically, your camera and microphone stay as they are, and you come back to the main room when the host closes the rooms or when you press Return to main room.",
|
|
256
|
+
"forge.call_stage.breakouts.help_attendee_label": "What are breakout rooms?",
|
|
257
|
+
"forge.call_stage.breakouts.help_create": "Each room is a separate call under this one. With automatic assignment everyone here is spread evenly across the rooms and moved straight away; with manual assignment nobody moves until you pick a room for them. You can join any room yourself, and everyone comes back when you close the rooms.",
|
|
258
|
+
"forge.call_stage.breakouts.help_create_label": "What happens when I create rooms?",
|
|
259
|
+
"forge.call_stage.breakouts.help_join": "Join moves you into that room; the other rooms carry on without you. Picking a room beside somebody's name moves them, and a recording you start follows the room you are in.",
|
|
260
|
+
"forge.call_stage.breakouts.help_join_label": "How do I move between rooms?",
|
|
261
|
+
"forge.call_stage.breakouts.join": "Join",
|
|
262
|
+
"forge.call_stage.breakouts.loading": "Loading rooms…",
|
|
263
|
+
"forge.call_stage.breakouts.main_room": "Main room",
|
|
264
|
+
"forge.call_stage.breakouts.move_to_label": "Move {name} to a room",
|
|
265
|
+
"forge.call_stage.breakouts.participant_count": "{count} in this room",
|
|
266
|
+
"forge.call_stage.breakouts.return_to_main": "Return to main",
|
|
267
|
+
"forge.call_stage.breakouts.return_to_main_room": "Return to main room",
|
|
268
|
+
"forge.call_stage.breakouts.status_moving": "Moving you to {room}",
|
|
269
|
+
"forge.call_stage.breakouts.status_moving_detail": "Your camera and microphone stay as they are.",
|
|
270
|
+
"forge.call_stage.breakouts.status_returning": "Returning you to the main room",
|
|
271
|
+
"forge.call_stage.breakouts.tab": "Rooms",
|
|
272
|
+
"forge.call_stage.breakouts.you_are_in": "You are in {room}",
|
|
273
|
+
"forge.call_stage.breakouts.you_are_in_main": "You are in the main room",
|
|
218
274
|
"forge.call_stage.camera_start": "Start camera",
|
|
219
275
|
"forge.call_stage.camera_stop": "Stop camera",
|
|
220
276
|
"forge.call_stage.chat": "Chat",
|
|
@@ -332,6 +388,7 @@
|
|
|
332
388
|
"forge.cart.aria_remove_item": "Remove item",
|
|
333
389
|
"forge.cart.aria_remove_tickets": "Remove tickets",
|
|
334
390
|
"forge.cart.attached_to_tickets": "Added with your tickets",
|
|
391
|
+
"forge.cart.change_seats": "Change seats",
|
|
335
392
|
"forge.cart.checkout": "Checkout",
|
|
336
393
|
"forge.cart.empty_title": "Your cart is empty.",
|
|
337
394
|
"forge.cart.gift_for": "Gift for {recipient_name} ({recipient_email})",
|
|
@@ -415,6 +472,10 @@
|
|
|
415
472
|
"forge.checkout.rate_days": "({days} days)",
|
|
416
473
|
"forge.checkout.rate_estimated_day": "Estimated {days} day",
|
|
417
474
|
"forge.checkout.rate_estimated_days": "Estimated {days} days",
|
|
475
|
+
"forge.checkout.seats_conflict_action": "Choose other seats",
|
|
476
|
+
"forge.checkout.seats_conflict_body": "{seats} for {event_title} went to another buyer. Choose other seats to continue; the rest of your cart is unchanged.",
|
|
477
|
+
"forge.checkout.seats_conflict_title": "Some of your seats were just taken",
|
|
478
|
+
"forge.checkout.seats_label": "Seats: {seats}",
|
|
418
479
|
"forge.checkout.shipping": "Shipping",
|
|
419
480
|
"forge.checkout.shipping_address_title": "Shipping Address",
|
|
420
481
|
"forge.checkout.shipping_options_title": "Shipping Options",
|
|
@@ -788,6 +849,17 @@
|
|
|
788
849
|
"forge.event_detail.not_found": "Event not found.",
|
|
789
850
|
"forge.event_detail.presale_only": "Tickets for this event are presale only.",
|
|
790
851
|
"forge.event_detail.price_from_label": "From",
|
|
852
|
+
"forge.event_seat_picker.dismiss": "Dismiss",
|
|
853
|
+
"forge.event_seat_picker.empty": "There are no seats to choose from yet.",
|
|
854
|
+
"forge.event_seat_picker.help_body": "Tap a seat to choose it and tap it again to let it go. Pinch or scroll to zoom, drag to move around the map. Grey seats are not available. Best available picks the lowest seats together for you.",
|
|
855
|
+
"forge.event_seat_picker.help_label": "How do I choose seats?",
|
|
856
|
+
"forge.event_seat_picker.loading": "Loading the seat map",
|
|
857
|
+
"forge.event_seat_picker.max_reached": "You have the most seats allowed on {tier}.",
|
|
858
|
+
"forge.event_seat_picker.mix_blocked": "That seat can't be added to your current selection.",
|
|
859
|
+
"forge.event_seat_picker.seat_unavailable": "That seat is not available.",
|
|
860
|
+
"forge.event_seat_picker.seats_taken_body": "{seats} went to another buyer. Choose again from the seats still shown as available.",
|
|
861
|
+
"forge.event_seat_picker.seats_taken_title": "Some of your seats were just taken",
|
|
862
|
+
"forge.event_seat_picker.title": "Choose your seats",
|
|
791
863
|
"forge.event_series_detail.date_count": "{count} dates",
|
|
792
864
|
"forge.event_series_detail.date_count_range": "{count} dates · {first_date} to {last_date}",
|
|
793
865
|
"forge.event_series_detail.location_online": "Online",
|
|
@@ -862,6 +934,11 @@
|
|
|
862
934
|
"forge.event_tickets.pwyw_range_min_max": "(minimum {min}, up to {max})",
|
|
863
935
|
"forge.event_tickets.remove_discount": "Remove discount",
|
|
864
936
|
"forge.event_tickets.request_tickets": "Request tickets",
|
|
937
|
+
"forge.event_tickets.seat_best_available": "Best available",
|
|
938
|
+
"forge.event_tickets.seat_remove_aria": "Remove {seat}",
|
|
939
|
+
"forge.event_tickets.seats_left_one": "{count} seat left",
|
|
940
|
+
"forge.event_tickets.seats_left_other": "{count} seats left",
|
|
941
|
+
"forge.event_tickets.seats_title": "Your seats",
|
|
865
942
|
"forge.event_tickets.select_option": "Select…",
|
|
866
943
|
"forge.event_tickets.select_title": "Select Tickets",
|
|
867
944
|
"forge.event_tickets.subtotal": "Subtotal",
|
|
@@ -1003,8 +1080,16 @@
|
|
|
1003
1080
|
"forge.film_watch.up_next": "Up next: {title}",
|
|
1004
1081
|
"forge.film_watch.window_not_started": "Your window starts now.",
|
|
1005
1082
|
"forge.forge_stripe_payment.authorize": "Authorize {amount}",
|
|
1083
|
+
"forge.forge_stripe_payment.cycle_month": "month",
|
|
1084
|
+
"forge.forge_stripe_payment.cycle_year": "year",
|
|
1006
1085
|
"forge.forge_stripe_payment.deferred_charged_on_approval": "Your card is only charged if we approve your request.",
|
|
1007
1086
|
"forge.forge_stripe_payment.deferred_hold_on_statement": "Until then a temporary hold will show on your statement.",
|
|
1087
|
+
"forge.forge_stripe_payment.setup_charged_on_approval": "Nothing is charged now. We will only charge this card if we approve your application, and then at the amount shown ({amount}).",
|
|
1088
|
+
"forge.forge_stripe_payment.setup_failed": "We couldn't save your card. Please try again.",
|
|
1089
|
+
"forge.forge_stripe_payment.setup_incomplete": "Your card was not saved. Please try again.",
|
|
1090
|
+
"forge.forge_stripe_payment.start_free_trial": "Start free trial",
|
|
1091
|
+
"forge.forge_stripe_payment.submit_application": "Submit application",
|
|
1092
|
+
"forge.forge_stripe_payment.trial_consent": "Nothing is charged today. {amount} per {cycle} from {date}. Cancel before then and you will not be charged.",
|
|
1008
1093
|
"forge.forgot_password_form.back_to_login": "Back to login",
|
|
1009
1094
|
"forge.forgot_password_form.email_label": "Email",
|
|
1010
1095
|
"forge.forgot_password_form.email_placeholder": "Email",
|
|
@@ -1082,8 +1167,27 @@
|
|
|
1082
1167
|
"forge.login_form.verify_submit": "Verify & Sign In",
|
|
1083
1168
|
"forge.login_form.verify_title": "Verify your email",
|
|
1084
1169
|
"forge.login_form.verifying": "Verifying…",
|
|
1170
|
+
"forge.membership_checkout.accept_invite": "Accept invite",
|
|
1085
1171
|
"forge.membership_checkout.amount_below_minimum": "Enter {minimum} or more.",
|
|
1086
1172
|
"forge.membership_checkout.amount_not_positive": "Enter an amount greater than zero.",
|
|
1173
|
+
"forge.membership_checkout.answer_required": "Please answer: {question}",
|
|
1174
|
+
"forge.membership_checkout.application_approved_body": "Your application to {tier_name} was approved. Your membership is being set up.",
|
|
1175
|
+
"forge.membership_checkout.application_approved_title": "You're approved",
|
|
1176
|
+
"forge.membership_checkout.application_card_title": "Your card",
|
|
1177
|
+
"forge.membership_checkout.application_closed_body": "Your application to {tier_name} is closed. Nothing was charged.",
|
|
1178
|
+
"forge.membership_checkout.application_closed_title": "Application closed",
|
|
1179
|
+
"forge.membership_checkout.application_declined_body": "Your application to {tier_name} was not approved. Nothing was charged.",
|
|
1180
|
+
"forge.membership_checkout.application_declined_title": "Application not approved",
|
|
1181
|
+
"forge.membership_checkout.application_received_body": "Thanks for applying to {tier_name}. We'll email you once we've reviewed your application.",
|
|
1182
|
+
"forge.membership_checkout.application_received_paid_body": "Thanks for applying to {tier_name}. Nothing has been charged. If we approve your application, {amount} {cycle} will be charged to your card and your membership starts then.",
|
|
1183
|
+
"forge.membership_checkout.application_received_title": "Application received",
|
|
1184
|
+
"forge.membership_checkout.application_state_approved": "You're approved. We're finishing setting up your membership.",
|
|
1185
|
+
"forge.membership_checkout.application_state_complete": "You're approved, but we couldn't charge your card. Complete your membership below.",
|
|
1186
|
+
"forge.membership_checkout.application_state_declined": "Your application was not approved.",
|
|
1187
|
+
"forge.membership_checkout.application_state_pending": "Your application is pending.",
|
|
1188
|
+
"forge.membership_checkout.application_tier_full_body": "The last place was taken while your card was being saved, so your application was closed. Nothing was charged.",
|
|
1189
|
+
"forge.membership_checkout.application_tier_full_title": "{tier_name} is full",
|
|
1190
|
+
"forge.membership_checkout.apply": "Apply to join",
|
|
1087
1191
|
"forge.membership_checkout.back": "Back",
|
|
1088
1192
|
"forge.membership_checkout.billing_cycle_label": "Billing cycle",
|
|
1089
1193
|
"forge.membership_checkout.billing_monthly": "Monthly",
|
|
@@ -1093,10 +1197,18 @@
|
|
|
1093
1197
|
"forge.membership_checkout.billing_yearly_price": "Yearly ({amount})",
|
|
1094
1198
|
"forge.membership_checkout.billing_yearly_pwyw": "Pay what you want from {amount}/yr",
|
|
1095
1199
|
"forge.membership_checkout.choose_title": "Choose your membership",
|
|
1200
|
+
"forge.membership_checkout.complete_membership": "Complete your membership",
|
|
1096
1201
|
"forge.membership_checkout.confirm_change": "Confirm change",
|
|
1097
1202
|
"forge.membership_checkout.current_plan": "Current plan",
|
|
1098
1203
|
"forge.membership_checkout.empty_title": "No memberships available",
|
|
1204
|
+
"forge.membership_checkout.field_required": "This field is required",
|
|
1099
1205
|
"forge.membership_checkout.free": "Free",
|
|
1206
|
+
"forge.membership_checkout.go_to_account": "Go to your account",
|
|
1207
|
+
"forge.membership_checkout.invite_dead_body": "It may have expired, been used already, or been replaced by a newer invite. Ask us for a new one.",
|
|
1208
|
+
"forge.membership_checkout.invite_dead_title": "This invite is no longer valid",
|
|
1209
|
+
"forge.membership_checkout.invite_email_mismatch": "You're signed in as {signed_in_email}. Sign in with {email} to accept this invite.",
|
|
1210
|
+
"forge.membership_checkout.invite_for_email": "This invite is for {email}.",
|
|
1211
|
+
"forge.membership_checkout.invite_title": "You're invited to join {tier_name}",
|
|
1100
1212
|
"forge.membership_checkout.more_benefits": "+{count} more",
|
|
1101
1213
|
"forge.membership_checkout.no_tier_body": "Select a membership tier to continue.",
|
|
1102
1214
|
"forge.membership_checkout.on_this_plan": "You are on this plan",
|
|
@@ -1108,15 +1220,28 @@
|
|
|
1108
1220
|
"forge.membership_checkout.pwyw_charged_as": "You will be charged {amount}.",
|
|
1109
1221
|
"forge.membership_checkout.pwyw_label": "How much would you like to pay?",
|
|
1110
1222
|
"forge.membership_checkout.pwyw_min": "(minimum {amount})",
|
|
1223
|
+
"forge.membership_checkout.questions_title": "A few questions",
|
|
1224
|
+
"forge.membership_checkout.select_placeholder": "Select…",
|
|
1111
1225
|
"forge.membership_checkout.select_tier": "Select this tier",
|
|
1226
|
+
"forge.membership_checkout.start_free_trial": "Start free trial",
|
|
1112
1227
|
"forge.membership_checkout.submit": "Subscribe",
|
|
1113
1228
|
"forge.membership_checkout.submitting": "Processing…",
|
|
1114
1229
|
"forge.membership_checkout.title": "Join {tier_name}",
|
|
1115
1230
|
"forge.membership_checkout.total": "Total",
|
|
1231
|
+
"forge.membership_checkout.trial_card_title": "Start your free trial",
|
|
1232
|
+
"forge.membership_checkout.trial_line": "{days}-day free trial. Your first charge is on {date}.",
|
|
1116
1233
|
"forge.membership_checkout.view_memberships": "View memberships",
|
|
1117
1234
|
"forge.membership_tier_callout.benefits_label": "Benefits:",
|
|
1235
|
+
"forge.membership_tier_callout.invite_for_email": "This invite is for {email}. Sign in or create an account with that address.",
|
|
1118
1236
|
"forge.membership_tier_callout.join_title": "Join {tier_name}",
|
|
1119
1237
|
"forge.membership_tier_callout.more_benefits": "+{count} more benefits",
|
|
1238
|
+
"forge.membership_tiers.accept_invite": "Accept invite",
|
|
1239
|
+
"forge.membership_tiers.application_approved": "Approved, finishing up",
|
|
1240
|
+
"forge.membership_tiers.application_declined": "Not approved",
|
|
1241
|
+
"forge.membership_tiers.application_payment_failed": "Approved: complete your membership",
|
|
1242
|
+
"forge.membership_tiers.application_pending": "Application pending",
|
|
1243
|
+
"forge.membership_tiers.apply": "Apply to join",
|
|
1244
|
+
"forge.membership_tiers.complete_membership": "Complete your membership",
|
|
1120
1245
|
"forge.membership_tiers.empty_title": "No membership tiers available.",
|
|
1121
1246
|
"forge.membership_tiers.heading": "Membership",
|
|
1122
1247
|
"forge.membership_tiers.price_free": "Free",
|
|
@@ -1125,6 +1250,11 @@
|
|
|
1125
1250
|
"forge.membership_tiers.price_pwyw_yearly": "Pay what you want from {amount}/yr",
|
|
1126
1251
|
"forge.membership_tiers.price_yearly": "{amount}/yr",
|
|
1127
1252
|
"forge.membership_tiers.select": "Select",
|
|
1253
|
+
"forge.membership_tiers.start_free_trial": "Start free trial",
|
|
1254
|
+
"forge.membership_tiers.trial_badge": "{days}-day free trial",
|
|
1255
|
+
"forge.membership_tiers.withdraw": "Withdraw application",
|
|
1256
|
+
"forge.membership_tiers.withdraw_error": "We couldn't withdraw your application. Please try again.",
|
|
1257
|
+
"forge.membership_tiers.withdrawing": "Withdrawing…",
|
|
1128
1258
|
"forge.offer_button.buy_now": "Buy now",
|
|
1129
1259
|
"forge.offer_button.confirm_email": "Confirm email",
|
|
1130
1260
|
"forge.offer_button.continue_to_payment": "Continue to payment",
|
|
@@ -1154,6 +1284,14 @@
|
|
|
1154
1284
|
"forge.payment_link_payment.preparing_payment": "Preparing payment…",
|
|
1155
1285
|
"forge.payment_link_payment.tax_added": "+ {tax_amount} tax",
|
|
1156
1286
|
"forge.payment_link_payment.title": "Payment request",
|
|
1287
|
+
"forge.phone_input.country_label": "Country",
|
|
1288
|
+
"forge.phone_input.country_placeholder": "Select country",
|
|
1289
|
+
"forge.phone_input.error_invalid": "That does not look like a valid number for the country selected",
|
|
1290
|
+
"forge.phone_input.error_no_country": "Please select your country first",
|
|
1291
|
+
"forge.phone_input.error_required": "Please enter a phone number",
|
|
1292
|
+
"forge.phone_input.hint_no_country_code": "You can leave out the country code. The flag sets it for you.",
|
|
1293
|
+
"forge.phone_input.placeholder_fallback": "Phone number",
|
|
1294
|
+
"forge.phone_input.warning_landline": "This looks like a landline, so it may not receive text messages.",
|
|
1157
1295
|
"forge.podcast_episode.next": "Next →",
|
|
1158
1296
|
"forge.podcast_episode.not_found": "Episode not found.",
|
|
1159
1297
|
"forge.podcast_episode.pause": "Pause",
|
|
@@ -1284,6 +1422,21 @@
|
|
|
1284
1422
|
"forge.review_form.title_label": "Title",
|
|
1285
1423
|
"forge.review_form.title_placeholder": "Sum it up in a few words",
|
|
1286
1424
|
"forge.review_form.update_submit": "Update review",
|
|
1425
|
+
"forge.seat_legend.aria_label": "Map key",
|
|
1426
|
+
"forge.seat_legend.left_one": "{count} left",
|
|
1427
|
+
"forge.seat_legend.left_other": "{count} left",
|
|
1428
|
+
"forge.seat_legend.selected": "Selected",
|
|
1429
|
+
"forge.seat_legend.sold_out": "Sold out",
|
|
1430
|
+
"forge.seat_legend.unavailable": "Unavailable",
|
|
1431
|
+
"forge.seat_map_canvas.accessible": "accessible seat",
|
|
1432
|
+
"forge.seat_map_canvas.aria_label": "Seat map",
|
|
1433
|
+
"forge.seat_map_canvas.fit": "Fit the whole map",
|
|
1434
|
+
"forge.seat_map_canvas.general_admission": "General admission",
|
|
1435
|
+
"forge.seat_map_canvas.status_available": "available",
|
|
1436
|
+
"forge.seat_map_canvas.status_selected": "selected",
|
|
1437
|
+
"forge.seat_map_canvas.status_unavailable": "unavailable",
|
|
1438
|
+
"forge.seat_map_canvas.zoom_in": "Zoom in",
|
|
1439
|
+
"forge.seat_map_canvas.zoom_out": "Zoom out",
|
|
1287
1440
|
"forge.signup_form.accept_terms": "I accept the Terms and Privacy Policy",
|
|
1288
1441
|
"forge.signup_form.code_label": "Verification code",
|
|
1289
1442
|
"forge.signup_form.code_sent": "We emailed a 6-digit code to {email}. Enter it to finish creating your account.",
|
package/src/index.ts
CHANGED
|
@@ -148,6 +148,7 @@ export * from "./data/queries/useWebsiteAgent";
|
|
|
148
148
|
export * from "./data/queries/useCurrencies";
|
|
149
149
|
export * from "./data/queries/useChat";
|
|
150
150
|
export * from "./data/queries/useCallChat";
|
|
151
|
+
export * from "./data/queries/useCallBreakouts";
|
|
151
152
|
export * from "./data/queries/useAnalytics";
|
|
152
153
|
export * from "./data/queries/useCommunity";
|
|
153
154
|
export * from "./data/queries/useReviews";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// - null/undefined siteConfig degradation (never throws)
|
|
12
12
|
// - the known client bug this fixes: apple-touch-icon is always emitted when an icon exists
|
|
13
13
|
//
|
|
14
|
-
// Source: packages/forge/src/server/pwa.ts. Spec: docs/pwa-custom-code-initiative.md.
|
|
14
|
+
// Source: packages/forge/src/server/pwa.ts. Spec: docs/archive/shipped/pwa-custom-code-initiative.md.
|
|
15
15
|
|
|
16
16
|
import { describe, it, expect } from "vitest";
|
|
17
17
|
import { buildPwaHead } from "../pwa";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// - overrides (shortcuts) merge + precedence
|
|
12
12
|
// - determinism / idempotence (same input → identical output twice)
|
|
13
13
|
//
|
|
14
|
-
// Source: packages/forge/src/server/pwa.ts. Spec: docs/pwa-custom-code-initiative.md.
|
|
14
|
+
// Source: packages/forge/src/server/pwa.ts. Spec: docs/archive/shipped/pwa-custom-code-initiative.md.
|
|
15
15
|
|
|
16
16
|
import { describe, it, expect } from "vitest";
|
|
17
17
|
import { buildWebManifest, type BuildWebManifestOptions } from "../pwa";
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// ({ title, body, type, url, profileId, channelId, spaceId, icon }) matches the
|
|
14
14
|
// client SW, plus offline-fallback + asset-cache + skipWaiting/clients.claim.
|
|
15
15
|
//
|
|
16
|
-
// Source: packages/forge/src/server/pwa.ts. Spec: docs/pwa-custom-code-initiative.md.
|
|
16
|
+
// Source: packages/forge/src/server/pwa.ts. Spec: docs/archive/shipped/pwa-custom-code-initiative.md.
|
|
17
17
|
|
|
18
18
|
import { describe, it, expect, vi } from "vitest";
|
|
19
19
|
import { forgeServiceWorkerScript, FORGE_PWA_VERSION } from "../pwa";
|
package/src/server/index.ts
CHANGED
|
@@ -46,6 +46,7 @@ import type {
|
|
|
46
46
|
CollectionQueryParams,
|
|
47
47
|
CollectionQuery,
|
|
48
48
|
CollectionSearchResult,
|
|
49
|
+
PaginatedData,
|
|
49
50
|
} from "../types/models";
|
|
50
51
|
import { collectionParamsToQuery, splitCollectionQuery } from "../data/collectionParams";
|
|
51
52
|
// SEO context for structured data. Pure functions over plain data, so this is
|
|
@@ -274,6 +275,18 @@ export async function fetchSiteBootstrap(opts: {
|
|
|
274
275
|
}
|
|
275
276
|
|
|
276
277
|
/** Fetch a single event by id or slug for SSR. */
|
|
278
|
+
/**
|
|
279
|
+
* Every published event, for SSR of the events list.
|
|
280
|
+
*
|
|
281
|
+
* The list page had no server fetch at all: it rendered a spinner into the
|
|
282
|
+
* document and filled itself in from the browser, so a crawler saw an empty
|
|
283
|
+
* page and a fan saw a flash of nothing. It is the same endpoint the client
|
|
284
|
+
* hook reads, so the markup and the first client render agree.
|
|
285
|
+
*/
|
|
286
|
+
export async function fetchEventsServer(opts: { apiUrl: string; profileId?: string }): Promise<IEvent[]> {
|
|
287
|
+
return (await getJson<IEvent[]>(opts.apiUrl, `/public/events`, { profileId: opts.profileId })) ?? [];
|
|
288
|
+
}
|
|
289
|
+
|
|
277
290
|
export function fetchEventServer(opts: {
|
|
278
291
|
apiUrl: string;
|
|
279
292
|
profileId?: string;
|
|
@@ -351,6 +364,67 @@ export function buildMusicLinkHead(
|
|
|
351
364
|
}
|
|
352
365
|
|
|
353
366
|
/** Fetch a single product by id or slug for SSR. */
|
|
367
|
+
/**
|
|
368
|
+
* The catalogue pages, server-rendered.
|
|
369
|
+
*
|
|
370
|
+
* Each of these list pages used to render a spinner into the document and
|
|
371
|
+
* fill itself in from the browser, so a crawler indexed an empty page and a
|
|
372
|
+
* fan saw nothing until the fetch landed. They are the pages search engines
|
|
373
|
+
* actually index, which makes an empty server render the expensive kind.
|
|
374
|
+
*
|
|
375
|
+
* Each mirrors its client hook exactly, same endpoint and same page size, so
|
|
376
|
+
* the markup and the first client render agree and nothing is fetched twice.
|
|
377
|
+
* An empty page is a real answer here (a creator who sells no courses), so a
|
|
378
|
+
* failed fetch resolves to an empty page rather than throwing.
|
|
379
|
+
*/
|
|
380
|
+
const emptyPage = <T,>(): PaginatedData<T> => ({
|
|
381
|
+
data: [],
|
|
382
|
+
total: 0,
|
|
383
|
+
hasNextPage: false,
|
|
384
|
+
page: 1,
|
|
385
|
+
nextPage: null,
|
|
386
|
+
pageSize: 10,
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
export async function fetchProductsServer(opts: {
|
|
390
|
+
apiUrl: string;
|
|
391
|
+
profileId?: string;
|
|
392
|
+
}): Promise<PaginatedData<IPublicProduct>> {
|
|
393
|
+
return (
|
|
394
|
+
(await getJson<PaginatedData<IPublicProduct>>(opts.apiUrl, `/public/products`, {
|
|
395
|
+
profileId: opts.profileId,
|
|
396
|
+
page: "1",
|
|
397
|
+
limit: "10",
|
|
398
|
+
})) ?? emptyPage<IPublicProduct>()
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export async function fetchCoursesServer(opts: {
|
|
403
|
+
apiUrl: string;
|
|
404
|
+
profileId?: string;
|
|
405
|
+
}): Promise<PaginatedData<PublicCourse>> {
|
|
406
|
+
return (
|
|
407
|
+
(await getJson<PaginatedData<PublicCourse>>(opts.apiUrl, `/public/courses`, {
|
|
408
|
+
profileId: opts.profileId,
|
|
409
|
+
page: "1",
|
|
410
|
+
limit: "10",
|
|
411
|
+
})) ?? emptyPage<PublicCourse>()
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export async function fetchCoachingProductsServer(opts: {
|
|
416
|
+
apiUrl: string;
|
|
417
|
+
profileId?: string;
|
|
418
|
+
}): Promise<PaginatedData<CoachingProduct>> {
|
|
419
|
+
return (
|
|
420
|
+
(await getJson<PaginatedData<CoachingProduct>>(opts.apiUrl, `/public/coaching/products`, {
|
|
421
|
+
profileId: opts.profileId,
|
|
422
|
+
page: "1",
|
|
423
|
+
limit: "10",
|
|
424
|
+
})) ?? emptyPage<CoachingProduct>()
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
354
428
|
export function fetchProductServer(opts: {
|
|
355
429
|
apiUrl: string;
|
|
356
430
|
profileId?: string;
|
|
@@ -567,7 +641,7 @@ export function toPlainText(html?: string, max = 200): string | undefined {
|
|
|
567
641
|
return text.length > max ? `${text.slice(0, max - 1).trimEnd()}…` : text;
|
|
568
642
|
}
|
|
569
643
|
|
|
570
|
-
// Platform access + events (docs/app-platform-access-initiative.md). SERVER ONLY —
|
|
644
|
+
// Platform access + events (docs/archive/shipped/app-platform-access-initiative.md). SERVER ONLY —
|
|
571
645
|
// the client carries the app's platform credential.
|
|
572
646
|
export {
|
|
573
647
|
createPlatformClient,
|
|
@@ -308,6 +308,63 @@ export type PlatformEventMap = {
|
|
|
308
308
|
unitPrice: number | null;
|
|
309
309
|
}>;
|
|
310
310
|
};
|
|
311
|
+
/**
|
|
312
|
+
* Membership application approved: An application was approved. `status` is `joined`, or `payment_failed` when the saved card was declined.
|
|
313
|
+
*
|
|
314
|
+
* Requires the `membership.application_approved` grant.
|
|
315
|
+
*/
|
|
316
|
+
"membership_application.approved": {
|
|
317
|
+
applicationId: string;
|
|
318
|
+
membershipTierId: string | null;
|
|
319
|
+
status: string | null;
|
|
320
|
+
billingCycle: string | null;
|
|
321
|
+
amount: number | null;
|
|
322
|
+
currency: string | null;
|
|
323
|
+
membershipId: string | null;
|
|
324
|
+
applicant: {
|
|
325
|
+
contactId: string | null;
|
|
326
|
+
email: string | null;
|
|
327
|
+
name: string | null;
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
/**
|
|
331
|
+
* Membership application declined: An application to join a membership tier was declined.
|
|
332
|
+
*
|
|
333
|
+
* Requires the `membership.application_declined` grant.
|
|
334
|
+
*/
|
|
335
|
+
"membership_application.declined": {
|
|
336
|
+
applicationId: string;
|
|
337
|
+
membershipTierId: string | null;
|
|
338
|
+
status: string | null;
|
|
339
|
+
billingCycle: string | null;
|
|
340
|
+
amount: number | null;
|
|
341
|
+
currency: string | null;
|
|
342
|
+
membershipId: string | null;
|
|
343
|
+
applicant: {
|
|
344
|
+
contactId: string | null;
|
|
345
|
+
email: string | null;
|
|
346
|
+
name: string | null;
|
|
347
|
+
};
|
|
348
|
+
};
|
|
349
|
+
/**
|
|
350
|
+
* Membership application submitted: Someone applied to join a membership tier that needs approval. Nothing is charged until approved.
|
|
351
|
+
*
|
|
352
|
+
* Requires the `membership.application_submitted` grant.
|
|
353
|
+
*/
|
|
354
|
+
"membership_application.submitted": {
|
|
355
|
+
applicationId: string;
|
|
356
|
+
membershipTierId: string | null;
|
|
357
|
+
status: string | null;
|
|
358
|
+
billingCycle: string | null;
|
|
359
|
+
amount: number | null;
|
|
360
|
+
currency: string | null;
|
|
361
|
+
membershipId: string | null;
|
|
362
|
+
applicant: {
|
|
363
|
+
contactId: string | null;
|
|
364
|
+
email: string | null;
|
|
365
|
+
name: string | null;
|
|
366
|
+
};
|
|
367
|
+
};
|
|
311
368
|
/**
|
|
312
369
|
* Membership tier archived: A membership tier was archived and can no longer be joined.
|
|
313
370
|
*
|
|
@@ -495,6 +552,9 @@ export const PLATFORM_EVENT_PERMISSIONS: Record<PlatformEventName, string> = {
|
|
|
495
552
|
"event_ticket_request.declined": "events.read",
|
|
496
553
|
"event_ticket_request.expired": "events.read",
|
|
497
554
|
"event_ticket_request.submitted": "events.read",
|
|
555
|
+
"membership_application.approved": "membership.application_approved",
|
|
556
|
+
"membership_application.declined": "membership.application_declined",
|
|
557
|
+
"membership_application.submitted": "membership.application_submitted",
|
|
498
558
|
"membership_tier.archived": "membership.tier_archived",
|
|
499
559
|
"membership_tier.created": "membership.tier_created",
|
|
500
560
|
"message.received": "contacts.read",
|
package/src/server/pwa.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// only three thin route shells (`/manifest.webmanifest`, `/sw.js`, `/offline`)
|
|
9
9
|
// that call these functions.
|
|
10
10
|
//
|
|
11
|
-
// See docs/pwa-custom-code-initiative.md (locked decisions).
|
|
11
|
+
// See docs/archive/shipped/pwa-custom-code-initiative.md (locked decisions).
|
|
12
12
|
|
|
13
13
|
import type { ContentDocument } from "../content/types";
|
|
14
14
|
import type { SiteConfig } from "../data/queries/useWebsite";
|