@tribe-nest/forge 3.50.0 → 3.52.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.
Files changed (32) hide show
  1. package/package.json +2 -2
  2. package/src/data/queries/useCohortEnrolment.ts +87 -0
  3. package/src/i18n/de.json +45 -0
  4. package/src/i18n/en.json +45 -0
  5. package/src/index.ts +1 -0
  6. package/src/types/models.ts +20 -0
  7. package/src/ui/headless/cohort/useCohortCheckout.ts +180 -0
  8. package/src/ui/index.ts +7 -0
  9. package/src/ui/styled/BlogPost.tsx +1 -1
  10. package/src/ui/styled/ChatRoom.tsx +2 -2
  11. package/src/ui/styled/Checkout.tsx +125 -125
  12. package/src/ui/styled/CoachingBooking.tsx +1 -1
  13. package/src/ui/styled/CoachingDetail.tsx +4 -4
  14. package/src/ui/styled/CohortCheckout.tsx +450 -0
  15. package/src/ui/styled/CohortConfirmation.tsx +259 -0
  16. package/src/ui/styled/CohortPage.tsx +16 -0
  17. package/src/ui/styled/CourseDetail.tsx +4 -4
  18. package/src/ui/styled/EventDetail.tsx +4 -4
  19. package/src/ui/styled/PaystackPayButton.tsx +1 -1
  20. package/src/ui/styled/PodcastEpisode.tsx +1 -1
  21. package/src/ui/styled/ProductDetail.tsx +4 -4
  22. package/src/ui/styled/_tests/CohortCheckout.spec.tsx +232 -0
  23. package/src/ui/styled/_tests/packagedCssIsCurrent.spec.ts +43 -0
  24. package/src/ui/styled/_tests/utilityPrefix.spec.ts +156 -0
  25. package/src/ui/styled/broadcast/BroadcastMoqStage.tsx +1 -1
  26. package/src/ui/styled/chat/ChatThreadPanel.tsx +1 -1
  27. package/src/ui/styled/forge-utilities.css +463 -731
  28. package/src/ui/styled/members/MemberCallsCalendar.tsx +2 -2
  29. package/src/ui/styled/members/MemberHomeLayout.tsx +4 -4
  30. package/src/ui/styled/members/MemberPostsFeed.tsx +1 -1
  31. package/src/ui/styled/members/PostCollectionsGrid.tsx +1 -1
  32. package/src/ui/styled/musicLinkStyles.tsx +4 -4
@@ -139,7 +139,7 @@ export function Checkout({
139
139
  type={type}
140
140
  onClick={onClick}
141
141
  disabled={disabled}
142
- className={fullWidth ? "w-full" : ""}
142
+ className={fullWidth ? "fg:w-full" : ""}
143
143
  style={{
144
144
  padding: "12px 18px",
145
145
  backgroundColor: theme.colors.primary,
@@ -159,7 +159,7 @@ export function Checkout({
159
159
  <button
160
160
  type="button"
161
161
  onClick={onClick}
162
- className={fullWidth ? "w-full" : ""}
162
+ className={fullWidth ? "fg:w-full" : ""}
163
163
  style={{
164
164
  padding: "12px 18px",
165
165
  backgroundColor: "transparent",
@@ -185,14 +185,14 @@ export function Checkout({
185
185
  if (c.cartItems.length === 0 && c.ticketItems.length === 0) {
186
186
  return (
187
187
  <div
188
- className={["w-full max-w-4xl mx-auto p-6", className].filter(Boolean).join(" ")}
188
+ className={["fg:w-full fg:max-w-4xl fg:mx-auto fg:p-6", className].filter(Boolean).join(" ")}
189
189
  style={{ backgroundColor: theme.colors.background, color: theme.colors.text, fontFamily: theme.fontFamily, ...style }}
190
190
  >
191
- <div className="text-center py-12">
192
- <h1 className="text-2xl font-bold mb-4" style={{ color: theme.colors.text }}>
191
+ <div className="fg:text-center fg:py-12">
192
+ <h1 className="fg:text-2xl fg:font-bold fg:mb-4" style={{ color: theme.colors.text }}>
193
193
  {tr("forge.checkout.empty_title")}
194
194
  </h1>
195
- <p className="mb-6" style={{ color: `${theme.colors.text}${alpha(0.7)}` }}>
195
+ <p className="fg:mb-6" style={{ color: `${theme.colors.text}${alpha(0.7)}` }}>
196
196
  {tr("forge.checkout.empty_body")}
197
197
  </p>
198
198
  <PrimaryButton text={tr("forge.checkout.continue_shopping")} onClick={() => go(storePath)} />
@@ -217,23 +217,23 @@ export function Checkout({
217
217
 
218
218
  return (
219
219
  <div
220
- className={["w-full max-w-6xl mx-auto p-6", className].filter(Boolean).join(" ")}
220
+ className={["fg:w-full fg:max-w-6xl fg:mx-auto fg:p-6", className].filter(Boolean).join(" ")}
221
221
  style={{ backgroundColor: theme.colors.background, color: theme.colors.text, fontFamily: theme.fontFamily, ...style }}
222
222
  >
223
223
  {/* Progress Indicator */}
224
- <div className="mb-8">
225
- <div className="flex items-center justify-center space-x-4">
224
+ <div className="fg:mb-8">
225
+ <div className="fg:flex fg:items-center fg:justify-center fg:space-x-4">
226
226
  {stages.map((stage, idx) => {
227
227
  const reached = currentIdx >= stageIdx(stage.key);
228
228
  return (
229
229
  <React.Fragment key={stage.key}>
230
- {idx > 0 && <div className="w-4 h-0.5" style={{ backgroundColor: `${theme.colors.text}${alpha(0.3)}` }} />}
230
+ {idx > 0 && <div className="fg:w-4 fg:h-0.5" style={{ backgroundColor: `${theme.colors.text}${alpha(0.3)}` }} />}
231
231
  <div
232
- className="flex items-center"
232
+ className="fg:flex fg:items-center"
233
233
  style={{ color: reached ? theme.colors.primary : `${theme.colors.text}${alpha(0.4)}` }}
234
234
  >
235
235
  <div
236
- className="w-8 h-8 rounded-full flex items-center justify-center border-2"
236
+ className="fg:w-8 fg:h-8 fg:rounded-full fg:flex fg:items-center fg:justify-center fg:border-2"
237
237
  style={{
238
238
  borderColor: reached ? theme.colors.primary : `${theme.colors.text}${alpha(0.3)}`,
239
239
  backgroundColor: reached ? theme.colors.primary : "transparent",
@@ -243,7 +243,7 @@ export function Checkout({
243
243
  >
244
244
  <stage.icon size={16} />
245
245
  </div>
246
- <span className="ml-2">{stage.label}</span>
246
+ <span className="fg:ml-2">{stage.label}</span>
247
247
  </div>
248
248
  </React.Fragment>
249
249
  );
@@ -251,12 +251,12 @@ export function Checkout({
251
251
  </div>
252
252
  </div>
253
253
 
254
- <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
254
+ <div className="fg:grid fg:grid-cols-1 fg:lg:grid-cols-3 fg:gap-8">
255
255
  {/* Main Content */}
256
- <div className="lg:col-span-2">
256
+ <div className="fg:lg:col-span-2">
257
257
  {c.pageError && (
258
258
  <div
259
- className="mb-4 p-3 text-sm"
259
+ className="fg:mb-4 fg:p-3 fg:text-sm"
260
260
  style={{ color: "#ef4444", border: "1px solid #ef444440", borderRadius: `${theme.cornerRadius}px` }}
261
261
  >
262
262
  {c.pageError}
@@ -266,31 +266,31 @@ export function Checkout({
266
266
  {/* Stage: User Details */}
267
267
  {c.currentStage === "userDetails" && !c.user && (
268
268
  <div
269
- className="rounded-lg shadow-md p-6"
269
+ className="fg:rounded-lg fg:shadow-md fg:p-6"
270
270
  style={{
271
271
  backgroundColor: theme.colors.background,
272
272
  border: `1px solid ${theme.colors.primary}${alpha(0.2)}`,
273
273
  borderRadius: `${theme.cornerRadius}px`,
274
274
  }}
275
275
  >
276
- <div className="pb-6" style={{ borderTop: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
277
- <h3 className="text-lg font-semibold mb-4" style={{ color: theme.colors.text }}>
276
+ <div className="fg:pb-6" style={{ borderTop: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
277
+ <h3 className="fg:text-lg fg:font-semibold fg:mb-4" style={{ color: theme.colors.text }}>
278
278
  {tr("forge.checkout.have_account")}
279
279
  </h3>
280
280
  <PrimaryButton text={tr("forge.checkout.login")} onClick={handleLogin} fullWidth />
281
281
  </div>
282
- <h2 className="text-2xl font-bold mb-6" style={{ color: theme.colors.text }}>
282
+ <h2 className="fg:text-2xl fg:font-bold fg:mb-6" style={{ color: theme.colors.text }}>
283
283
  {tr("forge.checkout.or")}
284
284
  </h2>
285
285
 
286
- <div className="mb-6">
287
- <h3 className="text-lg font-semibold mb-4" style={{ color: theme.colors.text }}>
286
+ <div className="fg:mb-6">
287
+ <h3 className="fg:text-lg fg:font-semibold fg:mb-4" style={{ color: theme.colors.text }}>
288
288
  {tr("forge.checkout.guest_title")}
289
289
  </h3>
290
- <form onSubmit={guestForm.handleSubmit(c.submitGuest)} className="space-y-4">
291
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
290
+ <form onSubmit={guestForm.handleSubmit(c.submitGuest)} className="fg:space-y-4">
291
+ <div className="fg:grid fg:grid-cols-1 fg:md:grid-cols-2 fg:gap-4">
292
292
  <div>
293
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
293
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
294
294
  {tr("forge.checkout.first_name")}
295
295
  </label>
296
296
  <Controller
@@ -306,11 +306,11 @@ export function Checkout({
306
306
  )}
307
307
  />
308
308
  {guestForm.formState.errors.firstName && (
309
- <p className="text-sm text-red-500 mt-1">{guestForm.formState.errors.firstName.message}</p>
309
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{guestForm.formState.errors.firstName.message}</p>
310
310
  )}
311
311
  </div>
312
312
  <div>
313
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
313
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
314
314
  {tr("forge.checkout.last_name")}
315
315
  </label>
316
316
  <Controller
@@ -326,12 +326,12 @@ export function Checkout({
326
326
  )}
327
327
  />
328
328
  {guestForm.formState.errors.lastName && (
329
- <p className="text-sm text-red-500 mt-1">{guestForm.formState.errors.lastName.message}</p>
329
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{guestForm.formState.errors.lastName.message}</p>
330
330
  )}
331
331
  </div>
332
332
  </div>
333
333
  <div>
334
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
334
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
335
335
  {tr("forge.checkout.email")}
336
336
  </label>
337
337
  <Controller
@@ -354,19 +354,19 @@ export function Checkout({
354
354
  )}
355
355
  />
356
356
  {guestForm.formState.errors.email && (
357
- <p className="text-sm text-red-500 mt-1">{guestForm.formState.errors.email.message}</p>
357
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{guestForm.formState.errors.email.message}</p>
358
358
  )}
359
359
  </div>
360
- <div className="flex items-start gap-2">
360
+ <div className="fg:flex fg:items-start fg:gap-2">
361
361
  <input
362
362
  type="checkbox"
363
363
  id="joinEmailList"
364
364
  checked={c.joinEmailList}
365
365
  onChange={(e) => c.setJoinEmailList(e.target.checked)}
366
- className="mt-1 h-4 w-4 rounded"
366
+ className="fg:mt-1 fg:h-4 fg:w-4 fg:rounded"
367
367
  style={{ accentColor: theme.colors.primary }}
368
368
  />
369
- <label htmlFor="joinEmailList" className="text-sm" style={{ color: theme.colors.text }}>
369
+ <label htmlFor="joinEmailList" className="fg:text-sm" style={{ color: theme.colors.text }}>
370
370
  {tr("forge.checkout.join_email_list")}
371
371
  </label>
372
372
  </div>
@@ -379,19 +379,19 @@ export function Checkout({
379
379
  {/* Stage: Shipping Address */}
380
380
  {c.currentStage === "shippingAddress" && c.hasPhysicalProduct && (
381
381
  <div
382
- className="rounded-lg shadow-md p-6"
382
+ className="fg:rounded-lg fg:shadow-md fg:p-6"
383
383
  style={{
384
384
  backgroundColor: theme.colors.background,
385
385
  border: `1px solid ${theme.colors.primary}${alpha(0.2)}`,
386
386
  borderRadius: `${theme.cornerRadius}px`,
387
387
  }}
388
388
  >
389
- <h2 className="text-2xl font-bold mb-6" style={{ color: theme.colors.text }}>
389
+ <h2 className="fg:text-2xl fg:font-bold fg:mb-6" style={{ color: theme.colors.text }}>
390
390
  {tr("forge.checkout.shipping_address_title")}
391
391
  </h2>
392
- <form onSubmit={shippingForm.handleSubmit(c.submitAddress)} className="space-y-4">
392
+ <form onSubmit={shippingForm.handleSubmit(c.submitAddress)} className="fg:space-y-4">
393
393
  <div>
394
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
394
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
395
395
  {tr("forge.checkout.address1_label")}
396
396
  </label>
397
397
  <Controller
@@ -403,13 +403,13 @@ export function Checkout({
403
403
  )}
404
404
  />
405
405
  {shippingForm.formState.errors.address1 && (
406
- <p className="text-sm text-red-500 mt-1">{shippingForm.formState.errors.address1.message}</p>
406
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{shippingForm.formState.errors.address1.message}</p>
407
407
  )}
408
408
  </div>
409
409
 
410
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
410
+ <div className="fg:grid fg:grid-cols-1 fg:md:grid-cols-2 fg:gap-4">
411
411
  <div>
412
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
412
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
413
413
  {tr("forge.checkout.city_label")}
414
414
  </label>
415
415
  <Controller
@@ -421,12 +421,12 @@ export function Checkout({
421
421
  )}
422
422
  />
423
423
  {shippingForm.formState.errors.city && (
424
- <p className="text-sm text-red-500 mt-1">{shippingForm.formState.errors.city.message}</p>
424
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{shippingForm.formState.errors.city.message}</p>
425
425
  )}
426
426
  </div>
427
427
 
428
428
  <div>
429
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
429
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
430
430
  {tr("forge.checkout.zip_label")}
431
431
  </label>
432
432
  <Controller
@@ -438,14 +438,14 @@ export function Checkout({
438
438
  )}
439
439
  />
440
440
  {shippingForm.formState.errors.zip && (
441
- <p className="text-sm text-red-500 mt-1">{shippingForm.formState.errors.zip.message}</p>
441
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{shippingForm.formState.errors.zip.message}</p>
442
442
  )}
443
443
  </div>
444
444
  </div>
445
445
 
446
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
446
+ <div className="fg:grid fg:grid-cols-1 fg:md:grid-cols-2 fg:gap-4">
447
447
  <div>
448
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
448
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
449
449
  {tr("forge.checkout.country_label")}
450
450
  </label>
451
451
  <Controller
@@ -464,13 +464,13 @@ export function Checkout({
464
464
  )}
465
465
  />
466
466
  {shippingForm.formState.errors.countryCode && (
467
- <p className="text-sm text-red-500 mt-1">{shippingForm.formState.errors.countryCode.message}</p>
467
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{shippingForm.formState.errors.countryCode.message}</p>
468
468
  )}
469
469
  </div>
470
470
 
471
471
  {selectedCountry?.states && selectedCountry.states.length > 0 && (
472
472
  <div>
473
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
473
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
474
474
  {tr("forge.checkout.state_label")}
475
475
  </label>
476
476
  <Controller
@@ -489,14 +489,14 @@ export function Checkout({
489
489
  )}
490
490
  />
491
491
  {shippingForm.formState.errors.stateCode && (
492
- <p className="text-sm text-red-500 mt-1">{shippingForm.formState.errors.stateCode.message}</p>
492
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{shippingForm.formState.errors.stateCode.message}</p>
493
493
  )}
494
494
  </div>
495
495
  )}
496
496
  </div>
497
497
 
498
498
  <div>
499
- <label className="block text-sm font-medium mb-2" style={{ color: theme.colors.text }}>
499
+ <label className="fg:block fg:text-sm fg:font-medium fg:mb-2" style={{ color: theme.colors.text }}>
500
500
  {tr("forge.checkout.phone_label")}
501
501
  </label>
502
502
  <Controller
@@ -508,11 +508,11 @@ export function Checkout({
508
508
  )}
509
509
  />
510
510
  {shippingForm.formState.errors.phone && (
511
- <p className="text-sm text-red-500 mt-1">{shippingForm.formState.errors.phone.message}</p>
511
+ <p className="fg:text-sm fg:text-red-500 fg:mt-1">{shippingForm.formState.errors.phone.message}</p>
512
512
  )}
513
513
  </div>
514
514
 
515
- <div className="flex gap-4 pt-4">
515
+ <div className="fg:flex fg:gap-4 fg:pt-4">
516
516
  {!c.user && (
517
517
  <SecondaryButton
518
518
  text={tr("forge.checkout.back")}
@@ -537,14 +537,14 @@ export function Checkout({
537
537
  {/* Stage: Shipping Rates */}
538
538
  {c.currentStage === "shippingRates" && c.hasPhysicalProduct && c.shippingData && (
539
539
  <div
540
- className="rounded-lg shadow-md p-6"
540
+ className="fg:rounded-lg fg:shadow-md fg:p-6"
541
541
  style={{
542
542
  backgroundColor: theme.colors.background,
543
543
  border: `1px solid ${theme.colors.primary}${alpha(0.2)}`,
544
544
  borderRadius: `${theme.cornerRadius}px`,
545
545
  }}
546
546
  >
547
- <h2 className="text-2xl font-bold mb-6" style={{ color: theme.colors.text }}>
547
+ <h2 className="fg:text-2xl fg:font-bold fg:mb-6" style={{ color: theme.colors.text }}>
548
548
  {tr("forge.checkout.shipping_options_title")}
549
549
  </h2>
550
550
 
@@ -555,7 +555,7 @@ export function Checkout({
555
555
  formatCurrency={formatCurrency}
556
556
  />
557
557
 
558
- <div className="flex gap-4 pt-6">
558
+ <div className="fg:flex fg:gap-4 fg:pt-6">
559
559
  <SecondaryButton
560
560
  text={tr("forge.checkout.back")}
561
561
  onClick={() => c.setCurrentStage("shippingAddress")}
@@ -587,17 +587,17 @@ export function Checkout({
587
587
  {/* Stage: Payment — Free */}
588
588
  {c.currentStage === "payment" && !c.isPaidCheckout && (
589
589
  <div
590
- className="rounded-lg shadow-md p-6"
590
+ className="fg:rounded-lg fg:shadow-md fg:p-6"
591
591
  style={{
592
592
  backgroundColor: theme.colors.background,
593
593
  border: `1px solid ${theme.colors.primary}${alpha(0.2)}`,
594
594
  borderRadius: `${theme.cornerRadius}px`,
595
595
  }}
596
596
  >
597
- <h2 className="text-2xl font-bold mb-6" style={{ color: theme.colors.text }}>
597
+ <h2 className="fg:text-2xl fg:font-bold fg:mb-6" style={{ color: theme.colors.text }}>
598
598
  {tr("forge.checkout.payment_title")}
599
599
  </h2>
600
- <p className="text-sm mb-8" style={{ color: `${theme.colors.text}${alpha(0.7)}` }}>
600
+ <p className="fg:text-sm fg:mb-8" style={{ color: `${theme.colors.text}${alpha(0.7)}` }}>
601
601
  {tr("forge.checkout.free_checkout_body")}
602
602
  </p>
603
603
  <PrimaryButton
@@ -611,40 +611,40 @@ export function Checkout({
611
611
  </div>
612
612
 
613
613
  {/* Order Summary */}
614
- <div className="lg:col-span-1">
614
+ <div className="fg:lg:col-span-1">
615
615
  <div
616
- className="rounded-lg shadow-md p-6 sticky top-6"
616
+ className="fg:rounded-lg fg:shadow-md fg:p-6 fg:sticky fg:top-6"
617
617
  style={{
618
618
  backgroundColor: theme.colors.background,
619
619
  border: `1px solid ${theme.colors.primary}${alpha(0.2)}`,
620
620
  borderRadius: `${theme.cornerRadius}px`,
621
621
  }}
622
622
  >
623
- <h3 className="text-xl font-bold mb-4" style={{ color: theme.colors.text }}>
623
+ <h3 className="fg:text-xl fg:font-bold fg:mb-4" style={{ color: theme.colors.text }}>
624
624
  {tr("forge.checkout.summary_title")}
625
625
  </h3>
626
626
 
627
627
  {/* Customer */}
628
- <div className="mb-4 pb-4" style={{ borderBottom: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
629
- <h4 className="font-semibold mb-2" style={{ color: theme.colors.text }}>
628
+ <div className="fg:mb-4 fg:pb-4" style={{ borderBottom: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
629
+ <h4 className="fg:font-semibold fg:mb-2" style={{ color: theme.colors.text }}>
630
630
  {tr("forge.checkout.summary_customer")}
631
631
  </h4>
632
632
  {c.user ? (
633
- <div className="text-sm">
633
+ <div className="fg:text-sm">
634
634
  <p style={{ color: theme.colors.text }}>
635
635
  {c.user?.firstName} {c.user?.lastName}
636
636
  </p>
637
637
  <p style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>{c.user?.email}</p>
638
638
  </div>
639
639
  ) : c.guestUserData ? (
640
- <div className="text-sm">
640
+ <div className="fg:text-sm">
641
641
  <p style={{ color: theme.colors.text }}>
642
642
  {c.guestUserData.firstName} {c.guestUserData.lastName}
643
643
  </p>
644
644
  <p style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>{c.guestUserData.email}</p>
645
645
  </div>
646
646
  ) : (
647
- <p className="text-sm" style={{ color: `${theme.colors.text}${alpha(0.5)}` }}>
647
+ <p className="fg:text-sm" style={{ color: `${theme.colors.text}${alpha(0.5)}` }}>
648
648
  {tr("forge.checkout.guest_checkout")}
649
649
  </p>
650
650
  )}
@@ -652,11 +652,11 @@ export function Checkout({
652
652
 
653
653
  {/* Shipping Info */}
654
654
  {c.hasPhysicalProduct && c.shippingData && (
655
- <div className="mb-4 pb-4" style={{ borderBottom: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
656
- <h4 className="font-semibold mb-2" style={{ color: theme.colors.text }}>
655
+ <div className="fg:mb-4 fg:pb-4" style={{ borderBottom: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
656
+ <h4 className="fg:font-semibold fg:mb-2" style={{ color: theme.colors.text }}>
657
657
  {tr("forge.checkout.summary_shipping_address")}
658
658
  </h4>
659
- <div className="text-sm">
659
+ <div className="fg:text-sm">
660
660
  <p style={{ color: theme.colors.text }}>{c.shippingData.address1}</p>
661
661
  <p style={{ color: theme.colors.text }}>
662
662
  {c.shippingData.city}, {c.shippingData.stateCode} {c.shippingData.zip}
@@ -669,11 +669,11 @@ export function Checkout({
669
669
  )}
670
670
 
671
671
  {/* Cart Items */}
672
- <div className="mb-4 pb-4" style={{ borderBottom: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
673
- <h4 className="font-semibold mb-2" style={{ color: theme.colors.text }}>
672
+ <div className="fg:mb-4 fg:pb-4" style={{ borderBottom: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
673
+ <h4 className="fg:font-semibold fg:mb-2" style={{ color: theme.colors.text }}>
674
674
  {tr("forge.checkout.summary_items")}
675
675
  </h4>
676
- <div className="space-y-2">
676
+ <div className="fg:space-y-2">
677
677
  {/* Ticket lines first: they are what the bundle is FOR, and the
678
678
  subtotal already includes them, so a summary without them
679
679
  reads as a wrong total. */}
@@ -683,19 +683,19 @@ export function Checkout({
683
683
  .map(([ticketId, qty]) => {
684
684
  const meta = t.ticketMeta[ticketId];
685
685
  return (
686
- <div key={`${t.eventId}-${ticketId}`} className="flex justify-between text-sm" data-testid="summary-ticket-line">
687
- <div className="flex-1">
688
- <p className="font-medium" style={{ color: theme.colors.text }}>
686
+ <div key={`${t.eventId}-${ticketId}`} className="fg:flex fg:justify-between fg:text-sm" data-testid="summary-ticket-line">
687
+ <div className="fg:flex-1">
688
+ <p className="fg:font-medium" style={{ color: theme.colors.text }}>
689
689
  {meta?.title ?? tr("forge.checkout.ticket_fallback")}
690
690
  </p>
691
- <p className="text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
691
+ <p className="fg:text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
692
692
  {t.eventTitle}
693
693
  </p>
694
- <p className="text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
694
+ <p className="fg:text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
695
695
  {tr("forge.checkout.qty", { count: qty })}
696
696
  </p>
697
697
  </div>
698
- <p className="font-medium" style={{ color: theme.colors.text }}>
698
+ <p className="fg:font-medium" style={{ color: theme.colors.text }}>
699
699
  {formatCurrency((meta?.price ?? 0) * qty)}
700
700
  </p>
701
701
  </div>
@@ -705,10 +705,10 @@ export function Checkout({
705
705
  {c.cartItems.map((item) => (
706
706
  <div
707
707
  key={`${item.productId}-${item.productVariantId}-${item.isGift}-${item.recipientEmail}`}
708
- className="flex justify-between text-sm"
708
+ className="fg:flex fg:justify-between fg:text-sm"
709
709
  >
710
- <div className="flex-1">
711
- <p className="font-medium" style={{ color: theme.colors.text }}>
710
+ <div className="fg:flex-1">
711
+ <p className="fg:font-medium" style={{ color: theme.colors.text }}>
712
712
  {item.title}
713
713
  </p>
714
714
  {/* Which version. This page never showed it at all, so a
@@ -716,15 +716,15 @@ export function Checkout({
716
716
  reached payment as two identical rows. */}
717
717
  <CartLineOptions item={item} accent={theme.colors.primary} size="small" />
718
718
  {item.isGift && (
719
- <p className="text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
719
+ <p className="fg:text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
720
720
  {tr("forge.checkout.gift_for", { recipient_name: item.recipientName ?? "" })}
721
721
  </p>
722
722
  )}
723
- <p className="text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
723
+ <p className="fg:text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
724
724
  {tr("forge.checkout.qty", { count: item.quantity })}
725
725
  </p>
726
726
  </div>
727
- <p className="font-medium" style={{ color: theme.colors.text }}>
727
+ <p className="fg:font-medium" style={{ color: theme.colors.text }}>
728
728
  {formatCurrency(item.price * item.quantity)}
729
729
  </p>
730
730
  </div>
@@ -740,11 +740,11 @@ export function Checkout({
740
740
  that creates it, and one typed afterwards goes through
741
741
  `/public/checkouts/apply-coupon`. Neither freezes the field. */}
742
742
  {((c.currentStage === "payment" && c.orderId) || c.isBundle) && (
743
- <div className="mb-4 pb-4" style={{ borderBottom: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
743
+ <div className="fg:mb-4 fg:pb-4" style={{ borderBottom: `1px solid ${theme.colors.primary}${alpha(0.2)}` }}>
744
744
  {!c.showCouponInput && !c.appliedCoupon && c.isCouponEditable && (
745
745
  <button
746
746
  type="button"
747
- className="text-sm underline"
747
+ className="fg:text-sm fg:underline"
748
748
  style={{ color: theme.colors.primary }}
749
749
  onClick={() => c.setShowCouponInput(true)}
750
750
  >
@@ -752,9 +752,9 @@ export function Checkout({
752
752
  </button>
753
753
  )}
754
754
  {c.showCouponInput && !c.appliedCoupon && c.isCouponEditable && (
755
- <div className="flex gap-2 items-end">
756
- <div className="flex-1">
757
- <p className="text-sm mb-1" style={{ color: theme.colors.text }}>
755
+ <div className="fg:flex fg:gap-2 fg:items-end">
756
+ <div className="fg:flex-1">
757
+ <p className="fg:text-sm fg:mb-1" style={{ color: theme.colors.text }}>
758
758
  {tr("forge.checkout.coupon_label")}
759
759
  </p>
760
760
  <input
@@ -775,24 +775,24 @@ export function Checkout({
775
775
  {/* Only while the bundle does not exist yet: from then on the
776
776
  code is priced live, so promising "at payment" would be wrong. */}
777
777
  {c.isBundle && !c.checkoutId && c.showCouponInput && !c.appliedCoupon && c.isCouponEditable && (
778
- <p className="text-xs mt-1" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
778
+ <p className="fg:text-xs fg:mt-1" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
779
779
  {tr("forge.checkout.coupon_deferred_note")}
780
780
  </p>
781
781
  )}
782
- {c.couponError && <p className="text-sm text-red-500 mt-1">{c.couponError}</p>}
782
+ {c.couponError && <p className="fg:text-sm fg:text-red-500 fg:mt-1">{c.couponError}</p>}
783
783
  {c.appliedCoupon && (
784
784
  <div
785
- className="p-3 rounded-lg flex justify-between items-center"
785
+ className="fg:p-3 fg:rounded-lg fg:flex fg:justify-between fg:items-center"
786
786
  style={{ backgroundColor: `${theme.colors.primary}${alpha(0.1)}` }}
787
787
  >
788
788
  <div>
789
- <p className="text-sm font-semibold" style={{ color: theme.colors.primary }}>
789
+ <p className="fg:text-sm fg:font-semibold" style={{ color: theme.colors.primary }}>
790
790
  {tr("forge.checkout.coupon_applied", { code: c.appliedCoupon.code })}
791
791
  </p>
792
792
  {/* A bundle reports the cash that came off and the code it
793
793
  came off under, but not the rate — so say the cash,
794
794
  never a made-up "0% off". */}
795
- <p className="text-xs" style={{ color: theme.colors.text }}>
795
+ <p className="fg:text-xs" style={{ color: theme.colors.text }}>
796
796
  {c.appliedCoupon.discountType === "percentage"
797
797
  ? // `String(...)` keeps a null rate rendering exactly as the old template
798
798
  // literal did, rather than quietly turning it into a made-up "0".
@@ -811,7 +811,7 @@ export function Checkout({
811
811
  {c.isCouponEditable && (
812
812
  <button
813
813
  type="button"
814
- className="text-sm underline"
814
+ className="fg:text-sm fg:underline"
815
815
  style={{ color: theme.colors.text }}
816
816
  onClick={c.removeCoupon}
817
817
  disabled={c.isApplyingCoupon}
@@ -825,19 +825,19 @@ export function Checkout({
825
825
  )}
826
826
 
827
827
  {/* Totals */}
828
- <div className="space-y-2">
829
- <div className="flex justify-between">
828
+ <div className="fg:space-y-2">
829
+ <div className="fg:flex fg:justify-between">
830
830
  <span style={{ color: theme.colors.text }}>{tr("forge.checkout.subtotal")}</span>
831
831
  <span style={{ color: theme.colors.text }}>{formatCurrency(c.subTotal)}</span>
832
832
  </div>
833
833
  {c.discountAmount > 0 && (
834
- <div className="flex justify-between">
834
+ <div className="fg:flex fg:justify-between">
835
835
  <span style={{ color: theme.colors.text }}>{tr("forge.checkout.discount")}</span>
836
836
  <span style={{ color: theme.colors.primary }}>-{formatCurrency(c.discountAmount)}</span>
837
837
  </div>
838
838
  )}
839
839
  {c.shippingCost > 0 && (
840
- <div className="flex justify-between">
840
+ <div className="fg:flex fg:justify-between">
841
841
  <span style={{ color: theme.colors.text }}>{tr("forge.checkout.shipping")}</span>
842
842
  <span style={{ color: theme.colors.text }}>{formatCurrency(c.shippingCost)}</span>
843
843
  </div>
@@ -846,7 +846,7 @@ export function Checkout({
846
846
  charged either way; omitting the line here left a total that
847
847
  jumped past the subtotal with no explanation. */}
848
848
  {c.bookingFeeCost > 0 && (
849
- <div className="flex justify-between" data-testid="summary-booking-fee">
849
+ <div className="fg:flex fg:justify-between" data-testid="summary-booking-fee">
850
850
  <span style={{ color: theme.colors.text }}>{tr("forge.checkout.booking_fee")}</span>
851
851
  <span style={{ color: theme.colors.text }}>{formatCurrency(c.bookingFeeCost)}</span>
852
852
  </div>
@@ -854,13 +854,13 @@ export function Checkout({
854
854
  {/* Exclusive mode: the authoritative tax line, once the checkout
855
855
  quote is known (added on top of the total). */}
856
856
  {taxSummary?.mode === "exclusive" && (
857
- <div className="flex justify-between">
857
+ <div className="fg:flex fg:justify-between">
858
858
  <span style={{ color: theme.colors.text }}>{tr("forge.checkout.tax")}</span>
859
859
  <span style={{ color: theme.colors.text }}>{taxSummary.formattedTax}</span>
860
860
  </div>
861
861
  )}
862
862
  <div
863
- className="flex justify-between font-bold text-lg pt-2"
863
+ className="fg:flex fg:justify-between fg:font-bold fg:text-lg fg:pt-2"
864
864
  style={{ borderTop: `1px solid ${theme.colors.primary}${alpha(0.2)}`, color: theme.colors.primary }}
865
865
  >
866
866
  <span>{tr("forge.checkout.total")}</span>
@@ -873,13 +873,13 @@ export function Checkout({
873
873
  {/* Inclusive mode: the total already contains tax — break out the
874
874
  contained amount once known, else a generic muted caption. */}
875
875
  {taxSummary?.mode === "inclusive" ? (
876
- <p className="text-xs text-right" style={{ color: `${theme.colors.text}${alpha(0.6)}`, margin: 0 }}>
876
+ <p className="fg:text-xs fg:text-right" style={{ color: `${theme.colors.text}${alpha(0.6)}`, margin: 0 }}>
877
877
  {taxSummary.label}
878
878
  </p>
879
879
  ) : (
880
880
  !taxSummary &&
881
881
  pricesIncludeTax && (
882
- <p className="text-xs text-right" style={{ color: `${theme.colors.text}${alpha(0.6)}`, margin: 0 }}>
882
+ <p className="fg:text-xs fg:text-right" style={{ color: `${theme.colors.text}${alpha(0.6)}`, margin: 0 }}>
883
883
  {tr("forge.checkout.incl_tax")}
884
884
  </p>
885
885
  )
@@ -928,7 +928,7 @@ function PaymentSection({
928
928
  <button
929
929
  type="button"
930
930
  onClick={onBack}
931
- className="px-4 py-3 font-semibold"
931
+ className="fg:px-4 fg:py-3 fg:font-semibold"
932
932
  style={{
933
933
  border: `1px solid ${theme.colors.primary}`,
934
934
  color: theme.colors.primary,
@@ -943,17 +943,17 @@ function PaymentSection({
943
943
  if (!isPaystack && !renderPay) {
944
944
  return (
945
945
  <div
946
- className="rounded-lg shadow-md p-6"
946
+ className="fg:rounded-lg fg:shadow-md fg:p-6"
947
947
  style={{
948
948
  backgroundColor: theme.colors.background,
949
949
  border: `1px solid ${theme.colors.primary}${alpha(0.2)}`,
950
950
  borderRadius: `${theme.cornerRadius}px`,
951
951
  }}
952
952
  >
953
- <h2 className="text-2xl font-bold mb-2" style={{ color: theme.colors.text }}>
953
+ <h2 className="fg:text-2xl fg:font-bold fg:mb-2" style={{ color: theme.colors.text }}>
954
954
  {tr("forge.checkout.payment_heading")}
955
955
  </h2>
956
- <p className="text-lg mb-4" style={{ color: theme.colors.text }}>
956
+ <p className="fg:text-lg fg:mb-4" style={{ color: theme.colors.text }}>
957
957
  {tr("forge.checkout.payment_not_configured")}
958
958
  </p>
959
959
  {backButton}
@@ -963,19 +963,19 @@ function PaymentSection({
963
963
 
964
964
  return (
965
965
  <div
966
- className="rounded-lg shadow-md p-6"
966
+ className="fg:rounded-lg fg:shadow-md fg:p-6"
967
967
  style={{
968
968
  backgroundColor: theme.colors.background,
969
969
  border: `1px solid ${theme.colors.primary}${alpha(0.2)}`,
970
970
  borderRadius: `${theme.cornerRadius}px`,
971
971
  }}
972
972
  >
973
- <h2 className="text-2xl font-bold mb-6" style={{ color: theme.colors.text }}>
973
+ <h2 className="fg:text-2xl fg:font-bold fg:mb-6" style={{ color: theme.colors.text }}>
974
974
  {tr("forge.checkout.payment_title")}
975
975
  </h2>
976
976
 
977
977
  {startError && (
978
- <p className="text-sm mb-4" style={{ color: "#ef4444" }}>
978
+ <p className="fg:text-sm fg:mb-4" style={{ color: "#ef4444" }}>
979
979
  {startError}
980
980
  </p>
981
981
  )}
@@ -1021,7 +1021,7 @@ function PaymentSection({
1021
1021
  </div>
1022
1022
  )}
1023
1023
 
1024
- {backButton && <div className="mt-4">{backButton}</div>}
1024
+ {backButton && <div className="fg:mt-4">{backButton}</div>}
1025
1025
  </div>
1026
1026
  );
1027
1027
  }
@@ -1048,42 +1048,42 @@ function ShippingRateSelector({
1048
1048
  if (groups.length === 0) return null;
1049
1049
 
1050
1050
  return (
1051
- <div className="space-y-6">
1051
+ <div className="fg:space-y-6">
1052
1052
  {groups.map((group) => (
1053
1053
  <div
1054
1054
  key={group.id}
1055
- className="p-4 rounded-lg"
1055
+ className="fg:p-4 fg:rounded-lg"
1056
1056
  style={{ border: `1px solid ${theme.colors.primary}${alpha(0.15)}`, borderRadius: `${theme.cornerRadius}px` }}
1057
1057
  >
1058
- <p className="font-medium mb-3" style={{ color: theme.colors.text }}>
1058
+ <p className="fg:font-medium fg:mb-3" style={{ color: theme.colors.text }}>
1059
1059
  {group.title}
1060
1060
  </p>
1061
1061
 
1062
1062
  {!group.selectable && group.rates.length > 0 ? (
1063
1063
  // Flat / external — a single, auto-selected rate.
1064
1064
  <div
1065
- className="flex items-center justify-between p-3 rounded-md"
1065
+ className="fg:flex fg:items-center fg:justify-between fg:p-3 fg:rounded-md"
1066
1066
  style={{ backgroundColor: `${theme.colors.primary}${alpha(0.05)}`, borderRadius: `${theme.cornerRadius}px` }}
1067
1067
  >
1068
1068
  <div>
1069
- <span className="text-sm font-medium" style={{ color: theme.colors.text }}>
1069
+ <span className="fg:text-sm fg:font-medium" style={{ color: theme.colors.text }}>
1070
1070
  {group.rates[0].carrier} · {group.rates[0].service}
1071
1071
  </span>
1072
1072
  {group.rates[0].estimatedDays != null && (
1073
- <span className="text-xs ml-2" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
1073
+ <span className="fg:text-xs fg:ml-2" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
1074
1074
  {tr("forge.checkout.rate_days", { days: group.rates[0].estimatedDays })}
1075
1075
  </span>
1076
1076
  )}
1077
1077
  </div>
1078
- <span className="text-sm font-semibold" style={{ color: theme.colors.primary }}>
1078
+ <span className="fg:text-sm fg:font-semibold" style={{ color: theme.colors.primary }}>
1079
1079
  {formatCurrency(group.rates[0].amount, group.rates[0].currency)}
1080
1080
  </span>
1081
1081
  </div>
1082
1082
  ) : (
1083
1083
  // Dynamic — buyer picks a carrier option.
1084
- <div className="space-y-2">
1084
+ <div className="fg:space-y-2">
1085
1085
  {group.rates.length === 0 && (
1086
- <p className="text-sm" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
1086
+ <p className="fg:text-sm" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
1087
1087
  {tr("forge.checkout.no_shipping_options")}
1088
1088
  </p>
1089
1089
  )}
@@ -1092,14 +1092,14 @@ function ShippingRateSelector({
1092
1092
  return (
1093
1093
  <label
1094
1094
  key={rate.rateId}
1095
- className="flex items-center justify-between p-3 rounded-md cursor-pointer transition-colors"
1095
+ className="fg:flex fg:items-center fg:justify-between fg:p-3 fg:rounded-md fg:cursor-pointer fg:transition-colors"
1096
1096
  style={{
1097
1097
  backgroundColor: isSelected ? `${theme.colors.primary}${alpha(0.1)}` : "transparent",
1098
1098
  border: `1px solid ${isSelected ? theme.colors.primary : `${theme.colors.primary}${alpha(0.2)}`}`,
1099
1099
  borderRadius: `${theme.cornerRadius}px`,
1100
1100
  }}
1101
1101
  >
1102
- <div className="flex items-center gap-3">
1102
+ <div className="fg:flex fg:items-center fg:gap-3">
1103
1103
  <input
1104
1104
  type="radio"
1105
1105
  name={`shipping-rate-${group.id}`}
@@ -1108,11 +1108,11 @@ function ShippingRateSelector({
1108
1108
  style={{ accentColor: theme.colors.primary }}
1109
1109
  />
1110
1110
  <div>
1111
- <span className="text-sm font-medium" style={{ color: theme.colors.text }}>
1111
+ <span className="fg:text-sm fg:font-medium" style={{ color: theme.colors.text }}>
1112
1112
  {rate.carrier} - {rate.service}
1113
1113
  </span>
1114
1114
  {rate.estimatedDays && (
1115
- <p className="text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
1115
+ <p className="fg:text-xs" style={{ color: `${theme.colors.text}${alpha(0.6)}` }}>
1116
1116
  {rate.estimatedDays === 1
1117
1117
  ? tr("forge.checkout.rate_estimated_day", { days: rate.estimatedDays })
1118
1118
  : tr("forge.checkout.rate_estimated_days", { days: rate.estimatedDays })}
@@ -1120,7 +1120,7 @@ function ShippingRateSelector({
1120
1120
  )}
1121
1121
  </div>
1122
1122
  </div>
1123
- <span className="text-sm font-semibold" style={{ color: theme.colors.primary }}>
1123
+ <span className="fg:text-sm fg:font-semibold" style={{ color: theme.colors.primary }}>
1124
1124
  {formatCurrency(rate.amount, rate.currency)}
1125
1125
  </span>
1126
1126
  </label>