@sudobility/building_blocks 0.0.18 → 0.0.22

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/dist/index.js CHANGED
@@ -505,9 +505,31 @@ const AppFooter = ({
505
505
  LinkComponent = DefaultLinkComponent$1,
506
506
  sticky = true,
507
507
  isNetworkOnline = true,
508
- className
508
+ className,
509
+ onTrack
509
510
  }) => {
510
511
  const year = copyrightYear || getCopyrightYear$1();
512
+ const track = useCallback(
513
+ (label, params) => {
514
+ onTrack == null ? void 0 : onTrack({
515
+ eventType: "link_click",
516
+ componentName: "AppFooter",
517
+ label,
518
+ params
519
+ });
520
+ },
521
+ [onTrack]
522
+ );
523
+ const createTrackedLinkHandler = useCallback(
524
+ (linkLabel, linkHref, originalOnClick) => (e) => {
525
+ track("footer_link_clicked", {
526
+ link_label: linkLabel,
527
+ link_href: linkHref
528
+ });
529
+ originalOnClick == null ? void 0 : originalOnClick(e);
530
+ },
531
+ [track]
532
+ );
511
533
  const companyLink = companyUrl ? /* @__PURE__ */ jsx(
512
534
  LinkComponent,
513
535
  {
@@ -549,7 +571,11 @@ const AppFooter = ({
549
571
  /* @__PURE__ */ jsx(FooterCompactRight, { children: links.map((link, index) => /* @__PURE__ */ jsx(React.Fragment, { children: link.onClick ? /* @__PURE__ */ jsx(
550
572
  "button",
551
573
  {
552
- onClick: link.onClick,
574
+ onClick: createTrackedLinkHandler(
575
+ link.label,
576
+ link.href,
577
+ link.onClick
578
+ ),
553
579
  className: "text-gray-400 hover:text-white transition-colors",
554
580
  children: link.label
555
581
  }
@@ -557,6 +583,7 @@ const AppFooter = ({
557
583
  LinkComponent,
558
584
  {
559
585
  href: link.href,
586
+ onClick: createTrackedLinkHandler(link.label, link.href),
560
587
  className: "text-gray-400 hover:text-white transition-colors",
561
588
  children: link.label
562
589
  }
@@ -610,10 +637,33 @@ const AppFooterForHomePage = ({
610
637
  LinkComponent = DefaultLinkComponent,
611
638
  isNetworkOnline = true,
612
639
  className,
613
- gridColumns
640
+ gridColumns,
641
+ onTrack
614
642
  }) => {
615
643
  const year = copyrightYear || getCopyrightYear();
616
644
  const gridClass = getGridColumnsClass(linkSections.length, gridColumns);
645
+ const track = useCallback(
646
+ (label, params) => {
647
+ onTrack == null ? void 0 : onTrack({
648
+ eventType: "link_click",
649
+ componentName: "AppFooterForHomePage",
650
+ label,
651
+ params
652
+ });
653
+ },
654
+ [onTrack]
655
+ );
656
+ const createTrackedLinkHandler = useCallback(
657
+ (linkLabel, linkHref, sectionTitle, originalOnClick) => (e) => {
658
+ track("footer_link_clicked", {
659
+ link_label: linkLabel,
660
+ link_href: linkHref,
661
+ section_title: sectionTitle
662
+ });
663
+ originalOnClick == null ? void 0 : originalOnClick(e);
664
+ },
665
+ [track]
666
+ );
617
667
  const companyLink = companyUrl ? /* @__PURE__ */ jsx(
618
668
  LinkComponent,
619
669
  {
@@ -627,7 +677,30 @@ const AppFooterForHomePage = ({
627
677
  FooterLinkSection,
628
678
  {
629
679
  title: section.title,
630
- children: section.links.map((link, linkIndex) => /* @__PURE__ */ jsx(FooterLink, { children: link.onClick ? /* @__PURE__ */ jsx("button", { onClick: link.onClick, className: "text-left", children: link.label }) : /* @__PURE__ */ jsx(LinkComponent, { href: link.href, children: link.label }) }, link.href || linkIndex))
680
+ children: section.links.map((link, linkIndex) => /* @__PURE__ */ jsx(FooterLink, { children: link.onClick ? /* @__PURE__ */ jsx(
681
+ "button",
682
+ {
683
+ onClick: createTrackedLinkHandler(
684
+ link.label,
685
+ link.href,
686
+ section.title,
687
+ link.onClick
688
+ ),
689
+ className: "text-left",
690
+ children: link.label
691
+ }
692
+ ) : /* @__PURE__ */ jsx(
693
+ LinkComponent,
694
+ {
695
+ href: link.href,
696
+ onClick: createTrackedLinkHandler(
697
+ link.label,
698
+ link.href,
699
+ section.title
700
+ ),
701
+ children: link.label
702
+ }
703
+ ) }, link.href || linkIndex))
631
704
  },
632
705
  section.title || sectionIndex
633
706
  )) }),
@@ -895,12 +968,38 @@ const GlobalSettingsPage = ({
895
968
  t,
896
969
  appearanceT,
897
970
  className,
898
- showAppearanceInfoBox = true
971
+ showAppearanceInfoBox = true,
972
+ onTrack
899
973
  }) => {
900
974
  const [selectedSection, setSelectedSection] = useState("appearance");
901
975
  const [mobileView, setMobileView] = useState(
902
976
  "navigation"
903
977
  );
978
+ const track = useCallback(
979
+ (label, params) => {
980
+ onTrack == null ? void 0 : onTrack({
981
+ eventType: "settings_change",
982
+ componentName: "GlobalSettingsPage",
983
+ label,
984
+ params
985
+ });
986
+ },
987
+ [onTrack]
988
+ );
989
+ const handleThemeChange = useCallback(
990
+ (newTheme) => {
991
+ track("theme_changed", { theme: newTheme });
992
+ onThemeChange(newTheme);
993
+ },
994
+ [track, onThemeChange]
995
+ );
996
+ const handleFontSizeChange = useCallback(
997
+ (newFontSize) => {
998
+ track("font_size_changed", { font_size: newFontSize });
999
+ onFontSizeChange(newFontSize);
1000
+ },
1001
+ [track, onFontSizeChange]
1002
+ );
904
1003
  const getText = useCallback(
905
1004
  (key) => {
906
1005
  const fallback = defaultTranslations[key];
@@ -920,8 +1019,8 @@ const GlobalSettingsPage = ({
920
1019
  {
921
1020
  theme,
922
1021
  fontSize,
923
- onThemeChange,
924
- onFontSizeChange,
1022
+ onThemeChange: handleThemeChange,
1023
+ onFontSizeChange: handleFontSizeChange,
925
1024
  t: appearanceT,
926
1025
  showInfoBox: showAppearanceInfoBox
927
1026
  }
@@ -934,18 +1033,20 @@ const GlobalSettingsPage = ({
934
1033
  getText,
935
1034
  theme,
936
1035
  fontSize,
937
- onThemeChange,
938
- onFontSizeChange,
1036
+ handleThemeChange,
1037
+ handleFontSizeChange,
939
1038
  appearanceT,
940
1039
  showAppearanceInfoBox
941
1040
  ]
942
1041
  );
943
1042
  const currentSection = allSections.find((s) => s.id === selectedSection) || allSections[0];
944
1043
  const handleSectionSelect = (sectionId) => {
1044
+ track("section_selected", { section_id: sectionId });
945
1045
  setSelectedSection(sectionId);
946
1046
  setMobileView("content");
947
1047
  };
948
1048
  const handleBackToNavigation = () => {
1049
+ track("back_to_navigation");
949
1050
  setMobileView("navigation");
950
1051
  };
951
1052
  const navigationList = /* @__PURE__ */ jsx("div", { className: "space-y-0", children: allSections.map((section) => {
@@ -4180,13 +4281,15 @@ const DEFAULT_PACKAGE_ENTITLEMENT_MAP = {
4180
4281
  function AppSubscriptionsPage({
4181
4282
  subscription,
4182
4283
  rateLimitsConfig,
4284
+ subscriptionUserId,
4183
4285
  labels,
4184
4286
  formatters,
4185
4287
  packageEntitlementMap = DEFAULT_PACKAGE_ENTITLEMENT_MAP,
4186
4288
  onPurchaseSuccess,
4187
4289
  onRestoreSuccess,
4188
4290
  onError,
4189
- onWarning
4291
+ onWarning,
4292
+ onTrack
4190
4293
  }) {
4191
4294
  const {
4192
4295
  products,
@@ -4201,6 +4304,17 @@ function AppSubscriptionsPage({
4201
4304
  const [selectedPlan, setSelectedPlan] = useState(null);
4202
4305
  const [isPurchasing, setIsPurchasing] = useState(false);
4203
4306
  const [isRestoring, setIsRestoring] = useState(false);
4307
+ const track = useCallback(
4308
+ (label, params) => {
4309
+ onTrack == null ? void 0 : onTrack({
4310
+ eventType: "subscription_action",
4311
+ componentName: "AppSubscriptionsPage",
4312
+ label,
4313
+ params
4314
+ });
4315
+ },
4316
+ [onTrack]
4317
+ );
4204
4318
  useEffect(() => {
4205
4319
  if (error) {
4206
4320
  onError == null ? void 0 : onError(labels.errorTitle, error);
@@ -4212,48 +4326,94 @@ function AppSubscriptionsPage({
4212
4326
  const isYearly = product.period.includes("Y") || product.period.includes("year");
4213
4327
  return billingPeriod === "yearly" ? isYearly : !isYearly;
4214
4328
  }).sort((a, b2) => parseFloat(a.price) - parseFloat(b2.price));
4215
- const handlePeriodChange = (period) => {
4216
- setBillingPeriod(period);
4217
- setSelectedPlan(null);
4218
- };
4219
- const handlePurchase = async () => {
4329
+ const handlePeriodChange = useCallback(
4330
+ (period) => {
4331
+ setBillingPeriod(period);
4332
+ setSelectedPlan(null);
4333
+ track("billing_period_changed", { billing_period: period });
4334
+ },
4335
+ [track]
4336
+ );
4337
+ const handlePurchase = useCallback(async () => {
4220
4338
  if (!selectedPlan) return;
4221
4339
  setIsPurchasing(true);
4222
4340
  clearError();
4341
+ track("purchase_initiated", { plan_identifier: selectedPlan });
4223
4342
  try {
4224
- const result = await purchase(selectedPlan);
4343
+ const result = await purchase(selectedPlan, subscriptionUserId);
4225
4344
  if (result) {
4345
+ track("purchase_completed", { plan_identifier: selectedPlan });
4226
4346
  onPurchaseSuccess == null ? void 0 : onPurchaseSuccess();
4227
4347
  setSelectedPlan(null);
4348
+ } else {
4349
+ track("purchase_failed", {
4350
+ plan_identifier: selectedPlan,
4351
+ reason: "purchase_returned_false"
4352
+ });
4228
4353
  }
4229
4354
  } catch (err) {
4230
- onError == null ? void 0 : onError(
4231
- labels.errorTitle,
4232
- err instanceof Error ? err.message : labels.purchaseError
4233
- );
4355
+ const errorMessage = err instanceof Error ? err.message : labels.purchaseError;
4356
+ track("purchase_failed", {
4357
+ plan_identifier: selectedPlan,
4358
+ reason: errorMessage
4359
+ });
4360
+ onError == null ? void 0 : onError(labels.errorTitle, errorMessage);
4234
4361
  } finally {
4235
4362
  setIsPurchasing(false);
4236
4363
  }
4237
- };
4238
- const handleRestore = async () => {
4364
+ }, [
4365
+ selectedPlan,
4366
+ clearError,
4367
+ track,
4368
+ purchase,
4369
+ subscriptionUserId,
4370
+ onPurchaseSuccess,
4371
+ labels.errorTitle,
4372
+ labels.purchaseError,
4373
+ onError
4374
+ ]);
4375
+ const handlePlanSelect = useCallback(
4376
+ (planIdentifier) => {
4377
+ setSelectedPlan(planIdentifier);
4378
+ track("plan_selected", {
4379
+ plan_identifier: planIdentifier ?? "free",
4380
+ is_free_tier: planIdentifier === null
4381
+ });
4382
+ },
4383
+ [track]
4384
+ );
4385
+ const handleRestore = useCallback(async () => {
4239
4386
  setIsRestoring(true);
4240
4387
  clearError();
4388
+ track("restore_initiated");
4241
4389
  try {
4242
- const result = await restore();
4390
+ const result = await restore(subscriptionUserId);
4243
4391
  if (result) {
4392
+ track("restore_completed");
4244
4393
  onRestoreSuccess == null ? void 0 : onRestoreSuccess();
4245
4394
  } else {
4395
+ track("restore_failed", { reason: "no_purchases_found" });
4246
4396
  onWarning == null ? void 0 : onWarning(labels.errorTitle, labels.restoreNoPurchases);
4247
4397
  }
4248
4398
  } catch (err) {
4249
- onError == null ? void 0 : onError(
4250
- labels.errorTitle,
4251
- err instanceof Error ? err.message : labels.restoreError
4252
- );
4399
+ const errorMessage = err instanceof Error ? err.message : labels.restoreError;
4400
+ track("restore_failed", { reason: errorMessage });
4401
+ onError == null ? void 0 : onError(labels.errorTitle, errorMessage);
4253
4402
  } finally {
4254
4403
  setIsRestoring(false);
4255
4404
  }
4256
- };
4405
+ }, [
4406
+ clearError,
4407
+ track,
4408
+ restore,
4409
+ subscriptionUserId,
4410
+ onRestoreSuccess,
4411
+ labels.errorTitle,
4412
+ labels.restoreNoPurchases,
4413
+ labels.restoreError,
4414
+ onWarning,
4415
+ onError
4416
+ ]);
4257
4417
  const formatExpirationDate = useCallback((date) => {
4258
4418
  if (!date) return "";
4259
4419
  return new Intl.DateTimeFormat(void 0, {
@@ -4479,7 +4639,7 @@ function AppSubscriptionsPage({
4479
4639
  periodLabel: labels.periodMonth,
4480
4640
  features: getFreeTierFeatures(),
4481
4641
  isSelected: !(currentSubscription == null ? void 0 : currentSubscription.isActive) && selectedPlan === null,
4482
- onSelect: () => setSelectedPlan(null),
4642
+ onSelect: () => handlePlanSelect(null),
4483
4643
  topBadge: !(currentSubscription == null ? void 0 : currentSubscription.isActive) ? {
4484
4644
  text: labels.currentPlanBadge,
4485
4645
  color: "green"
@@ -4500,7 +4660,7 @@ function AppSubscriptionsPage({
4500
4660
  periodLabel: getPeriodLabel(product.period),
4501
4661
  features: getProductFeatures(product.identifier),
4502
4662
  isSelected: selectedPlan === product.identifier,
4503
- onSelect: () => setSelectedPlan(product.identifier),
4663
+ onSelect: () => handlePlanSelect(product.identifier),
4504
4664
  isBestValue: product.identifier.includes("pro"),
4505
4665
  discountBadge: ((_a = product.period) == null ? void 0 : _a.includes("Y")) ? (() => {
4506
4666
  const savings = getYearlySavingsPercent(
@@ -4533,9 +4693,43 @@ function AppPricingPage({
4533
4693
  onPlanClick,
4534
4694
  onFreePlanClick,
4535
4695
  faqItems,
4536
- className
4696
+ className,
4697
+ onTrack
4537
4698
  }) {
4538
4699
  const [billingPeriod, setBillingPeriod] = useState("monthly");
4700
+ const track = useCallback(
4701
+ (label, params) => {
4702
+ onTrack == null ? void 0 : onTrack({
4703
+ eventType: "subscription_action",
4704
+ componentName: "AppPricingPage",
4705
+ label,
4706
+ params
4707
+ });
4708
+ },
4709
+ [onTrack]
4710
+ );
4711
+ const handleBillingPeriodChange = useCallback(
4712
+ (value) => {
4713
+ const newPeriod = value;
4714
+ setBillingPeriod(newPeriod);
4715
+ track("billing_period_changed", { billing_period: newPeriod });
4716
+ },
4717
+ [track]
4718
+ );
4719
+ const handleFreePlanClick = useCallback(() => {
4720
+ track("free_plan_clicked", { plan: "free" });
4721
+ onFreePlanClick();
4722
+ }, [track, onFreePlanClick]);
4723
+ const handlePlanClick = useCallback(
4724
+ (planIdentifier, actionType) => {
4725
+ track("plan_clicked", {
4726
+ plan_identifier: planIdentifier,
4727
+ action_type: actionType
4728
+ });
4729
+ onPlanClick(planIdentifier);
4730
+ },
4731
+ [track, onPlanClick]
4732
+ );
4539
4733
  const getProductLevel = useCallback(
4540
4734
  (productId) => {
4541
4735
  const entitlement = entitlementMap[productId];
@@ -4619,7 +4813,7 @@ function AppPricingPage({
4619
4813
  {
4620
4814
  options: billingPeriodOptions,
4621
4815
  value: billingPeriod,
4622
- onChange: (value) => setBillingPeriod(value)
4816
+ onChange: handleBillingPeriodChange
4623
4817
  }
4624
4818
  ) }),
4625
4819
  /* @__PURE__ */ jsxs(
@@ -4652,7 +4846,7 @@ function AppPricingPage({
4652
4846
  // Logged in with subscription: no CTA (can't downgrade here)
4653
4847
  !isAuthenticated ? {
4654
4848
  label: labels.ctaTryFree,
4655
- onClick: onFreePlanClick
4849
+ onClick: handleFreePlanClick
4656
4850
  } : void 0
4657
4851
  ),
4658
4852
  hideSelectionIndicator: isAuthenticated
@@ -4666,14 +4860,14 @@ function AppPricingPage({
4666
4860
  if (!isAuthenticated) {
4667
4861
  ctaButton = {
4668
4862
  label: labels.ctaLogIn,
4669
- onClick: () => onPlanClick(product.identifier)
4863
+ onClick: () => handlePlanClick(product.identifier, "login")
4670
4864
  };
4671
4865
  } else if (isCurrent) {
4672
4866
  ctaButton = void 0;
4673
4867
  } else if (canUpgrade) {
4674
4868
  ctaButton = {
4675
4869
  label: labels.ctaUpgrade,
4676
- onClick: () => onPlanClick(product.identifier)
4870
+ onClick: () => handlePlanClick(product.identifier, "upgrade")
4677
4871
  };
4678
4872
  }
4679
4873
  let topBadge;
@@ -4839,129 +5033,20 @@ const AppSitemapPage = ({
4839
5033
  }
4840
5034
  return content;
4841
5035
  };
4842
- const SectionHeading$1 = ({ children }) => /* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100 mt-8 mb-4", children });
4843
- const SubsectionHeading = ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-xl font-semibold text-gray-900 dark:text-gray-100 mt-6 mb-3", children });
4844
- const Paragraph$1 = ({
4845
- children,
4846
- className = ""
4847
- }) => /* @__PURE__ */ jsx("p", { className: `text-gray-600 dark:text-gray-300 mb-6 ${className}`, children });
4848
- const List$1 = ({ items }) => /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside text-gray-600 dark:text-gray-300 mb-6", children: items.map((item, index) => /* @__PURE__ */ jsx("li", { children: item }, index)) });
4849
- const AppPrivacyPolicyPage = ({
4850
- text,
4851
- lastUpdatedDate = (/* @__PURE__ */ new Date()).toLocaleDateString(),
4852
- PageWrapper,
4853
- className
4854
- }) => {
4855
- const content = /* @__PURE__ */ jsxs("div", { className: `max-w-7xl mx-auto px-4 py-12 ${className || ""}`, children: [
4856
- /* @__PURE__ */ jsx("h1", { className: "text-4xl font-bold text-gray-900 dark:text-gray-100 mb-8", children: text.heading }),
4857
- /* @__PURE__ */ jsxs("div", { className: "prose prose-lg max-w-none", children: [
4858
- /* @__PURE__ */ jsxs(Paragraph$1, { className: "mb-6", children: [
4859
- text.lastUpdatedLabel,
4860
- " ",
4861
- lastUpdatedDate
4862
- ] }),
4863
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.introduction.title }),
4864
- /* @__PURE__ */ jsx(Paragraph$1, { children: text.introduction.content }),
4865
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.informationWeCollect.title }),
4866
- /* @__PURE__ */ jsx(SubsectionHeading, { children: text.informationWeCollect.youProvide.title }),
4867
- /* @__PURE__ */ jsx(List$1, { items: text.informationWeCollect.youProvide.items }),
4868
- /* @__PURE__ */ jsx(SubsectionHeading, { children: text.informationWeCollect.automatic.title }),
4869
- /* @__PURE__ */ jsx(List$1, { items: text.informationWeCollect.automatic.items }),
4870
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.howWeUse.title }),
4871
- text.howWeUse.description && /* @__PURE__ */ jsx(Paragraph$1, { className: "mb-4", children: text.howWeUse.description }),
4872
- /* @__PURE__ */ jsx(List$1, { items: text.howWeUse.items }),
4873
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.informationSharing.title }),
4874
- text.informationSharing.description && /* @__PURE__ */ jsx(Paragraph$1, { className: "mb-4", children: text.informationSharing.description }),
4875
- /* @__PURE__ */ jsx(List$1, { items: text.informationSharing.items }),
4876
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.dataSecurity.title }),
4877
- text.dataSecurity.description && /* @__PURE__ */ jsx(Paragraph$1, { className: "mb-4", children: text.dataSecurity.description }),
4878
- /* @__PURE__ */ jsx(List$1, { items: text.dataSecurity.items }),
4879
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.dataRetention.title }),
4880
- /* @__PURE__ */ jsx(Paragraph$1, { children: text.dataRetention.content }),
4881
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.privacyRights.title }),
4882
- text.privacyRights.description && /* @__PURE__ */ jsx(Paragraph$1, { className: "mb-4", children: text.privacyRights.description }),
4883
- /* @__PURE__ */ jsx(List$1, { items: text.privacyRights.items }),
4884
- text.web3Considerations && /* @__PURE__ */ jsxs(Fragment, { children: [
4885
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.web3Considerations.title }),
4886
- text.web3Considerations.description && /* @__PURE__ */ jsx(Paragraph$1, { className: "mb-4", children: text.web3Considerations.description }),
4887
- /* @__PURE__ */ jsx(List$1, { items: text.web3Considerations.items })
4888
- ] }),
4889
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.internationalTransfers.title }),
4890
- /* @__PURE__ */ jsx(Paragraph$1, { children: text.internationalTransfers.content }),
4891
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.childrensPrivacy.title }),
4892
- /* @__PURE__ */ jsx(Paragraph$1, { children: text.childrensPrivacy.content }),
4893
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.cookies.title }),
4894
- /* @__PURE__ */ jsx(Paragraph$1, { children: /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: text.cookies.content } }) }),
4895
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.changes.title }),
4896
- /* @__PURE__ */ jsx(Paragraph$1, { children: text.changes.content }),
4897
- /* @__PURE__ */ jsx(SectionHeading$1, { children: text.contact.title }),
4898
- /* @__PURE__ */ jsx(Paragraph$1, { children: text.contact.description }),
4899
- /* @__PURE__ */ jsx("div", { className: "bg-gray-50 dark:bg-gray-800 p-4 rounded-lg", children: /* @__PURE__ */ jsxs("p", { className: "text-gray-700 dark:text-gray-300", children: [
4900
- text.contact.info.emailLabel,
4901
- " ",
4902
- /* @__PURE__ */ jsx(
4903
- "a",
4904
- {
4905
- href: `mailto:${text.contact.info.email}`,
4906
- className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
4907
- children: text.contact.info.email
4908
- }
4909
- ),
4910
- /* @__PURE__ */ jsx("br", {}),
4911
- text.contact.info.websiteLabel,
4912
- " ",
4913
- /* @__PURE__ */ jsx(
4914
- "a",
4915
- {
4916
- href: text.contact.info.websiteUrl,
4917
- className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
4918
- children: text.contact.info.websiteUrl
4919
- }
4920
- ),
4921
- /* @__PURE__ */ jsx("br", {}),
4922
- text.contact.info.dpoLabel,
4923
- " ",
4924
- /* @__PURE__ */ jsx(
4925
- "a",
4926
- {
4927
- href: `mailto:${text.contact.info.dpoEmail}`,
4928
- className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
4929
- children: text.contact.info.dpoEmail
4930
- }
4931
- )
4932
- ] }) }),
4933
- /* @__PURE__ */ jsxs("div", { className: "mt-8 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg", children: [
4934
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-blue-900 dark:text-blue-200 mb-2", children: text.contact.info.gdprTitle }),
4935
- /* @__PURE__ */ jsxs("p", { className: "text-blue-800 dark:text-blue-300", children: [
4936
- text.contact.info.gdprContent,
4937
- " ",
4938
- /* @__PURE__ */ jsx(
4939
- "a",
4940
- {
4941
- href: `mailto:${text.contact.info.dpoEmail}`,
4942
- className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
4943
- children: text.contact.info.dpoEmail
4944
- }
4945
- )
4946
- ] })
4947
- ] })
4948
- ] })
4949
- ] });
4950
- if (PageWrapper) {
4951
- return /* @__PURE__ */ jsx(PageWrapper, { children: content });
4952
- }
4953
- return content;
4954
- };
4955
5036
  function isSectionWithList(section) {
4956
5037
  return "items" in section && Array.isArray(section.items);
4957
5038
  }
5039
+ function isSectionWithSubsections(section) {
5040
+ return "subsections" in section && Array.isArray(section.subsections);
5041
+ }
4958
5042
  const SectionHeading = ({ children }) => /* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold text-gray-900 dark:text-gray-100 mt-8 mb-4", children });
5043
+ const SubsectionHeading = ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-xl font-semibold text-gray-900 dark:text-gray-100 mt-6 mb-3", children });
4959
5044
  const Paragraph = ({
4960
5045
  children,
4961
5046
  className = ""
4962
5047
  }) => /* @__PURE__ */ jsx("p", { className: `text-gray-600 dark:text-gray-300 mb-6 ${className}`, children });
4963
- const List = ({ items }) => /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside text-gray-600 dark:text-gray-300 mb-6", children: items.map((item, index) => /* @__PURE__ */ jsx("li", { children: item }, index)) });
4964
- const AppTermsOfServicePage = ({
5048
+ const List = ({ items }) => /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside text-gray-600 dark:text-gray-300 mb-6 space-y-1", children: items.map((item, index) => /* @__PURE__ */ jsx("li", { dangerouslySetInnerHTML: { __html: item } }, index)) });
5049
+ const AppTextPage = ({
4965
5050
  text,
4966
5051
  lastUpdatedDate = (/* @__PURE__ */ new Date()).toLocaleDateString(),
4967
5052
  PageWrapper,
@@ -4970,45 +5055,90 @@ const AppTermsOfServicePage = ({
4970
5055
  const content = /* @__PURE__ */ jsxs("div", { className: `max-w-7xl mx-auto px-4 py-12 ${className || ""}`, children: [
4971
5056
  /* @__PURE__ */ jsx("h1", { className: "text-4xl font-bold text-gray-900 dark:text-gray-100 mb-8", children: text.title }),
4972
5057
  /* @__PURE__ */ jsxs("div", { className: "prose prose-lg dark:prose-invert max-w-none", children: [
4973
- /* @__PURE__ */ jsx(Paragraph, { className: "mb-6", children: text.lastUpdated.replace("{{date}}", lastUpdatedDate) }),
5058
+ text.lastUpdated && /* @__PURE__ */ jsx(Paragraph, { className: "mb-6", children: text.lastUpdated.replace("{{date}}", lastUpdatedDate) }),
4974
5059
  text.sections.map((section, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
4975
5060
  /* @__PURE__ */ jsx(SectionHeading, { children: section.title }),
4976
- isSectionWithList(section) ? /* @__PURE__ */ jsxs(Fragment, { children: [
4977
- section.description && /* @__PURE__ */ jsx(Paragraph, { className: "mb-4", children: section.description }),
4978
- /* @__PURE__ */ jsx(List, { items: section.items }),
4979
- section.additionalContent && /* @__PURE__ */ jsx(Paragraph, { children: section.additionalContent })
4980
- ] }) : section.isHtml ? /* @__PURE__ */ jsx(Paragraph, { children: /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: section.content } }) }) : /* @__PURE__ */ jsx(Paragraph, { children: section.content })
5061
+ isSectionWithSubsections(section) ? (
5062
+ // Section with subsections (h3 + lists)
5063
+ /* @__PURE__ */ jsx(Fragment, { children: section.subsections.map((subsection, subIndex) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
5064
+ /* @__PURE__ */ jsx(SubsectionHeading, { children: subsection.title }),
5065
+ /* @__PURE__ */ jsx(List, { items: subsection.items })
5066
+ ] }, subIndex)) })
5067
+ ) : isSectionWithList(section) ? (
5068
+ // Section with list
5069
+ /* @__PURE__ */ jsxs(Fragment, { children: [
5070
+ section.description && /* @__PURE__ */ jsx(Paragraph, { className: "mb-4", children: section.description }),
5071
+ /* @__PURE__ */ jsx(List, { items: section.items }),
5072
+ section.additionalContent && /* @__PURE__ */ jsx(Paragraph, { children: section.additionalContent })
5073
+ ] })
5074
+ ) : section.isHtml ? (
5075
+ // Section with HTML content
5076
+ /* @__PURE__ */ jsx(Paragraph, { children: /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: section.content } }) })
5077
+ ) : (
5078
+ // Section with plain text content
5079
+ /* @__PURE__ */ jsx(Paragraph, { children: section.content })
5080
+ )
4981
5081
  ] }, index)),
4982
- /* @__PURE__ */ jsx(SectionHeading, { children: text.contact.title }),
4983
- text.contact.isHtml ? /* @__PURE__ */ jsx(Paragraph, { children: /* @__PURE__ */ jsx(
4984
- "span",
4985
- {
4986
- dangerouslySetInnerHTML: { __html: text.contact.description }
4987
- }
4988
- ) }) : /* @__PURE__ */ jsx(Paragraph, { children: text.contact.description }),
4989
- /* @__PURE__ */ jsx("div", { className: "bg-gray-50 dark:bg-gray-800 p-4 rounded-lg", children: /* @__PURE__ */ jsxs("p", { className: "text-gray-700 dark:text-gray-300", children: [
4990
- text.contact.info.emailLabel,
4991
- " ",
4992
- /* @__PURE__ */ jsx(
4993
- "a",
4994
- {
4995
- href: `mailto:${text.contact.info.email}`,
4996
- className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
4997
- children: text.contact.info.email
4998
- }
4999
- ),
5000
- /* @__PURE__ */ jsx("br", {}),
5001
- text.contact.info.websiteLabel,
5002
- " ",
5003
- /* @__PURE__ */ jsx(
5004
- "a",
5082
+ text.contact && /* @__PURE__ */ jsxs(Fragment, { children: [
5083
+ /* @__PURE__ */ jsx(SectionHeading, { children: text.contact.title }),
5084
+ text.contact.isHtml ? /* @__PURE__ */ jsx(Paragraph, { children: /* @__PURE__ */ jsx(
5085
+ "span",
5005
5086
  {
5006
- href: text.contact.info.websiteUrl,
5007
- className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
5008
- children: text.contact.info.websiteUrl
5087
+ dangerouslySetInnerHTML: { __html: text.contact.description }
5009
5088
  }
5010
- )
5011
- ] }) })
5089
+ ) }) : /* @__PURE__ */ jsx(Paragraph, { children: text.contact.description }),
5090
+ /* @__PURE__ */ jsx("div", { className: "bg-gray-50 dark:bg-gray-800 p-4 rounded-lg", children: /* @__PURE__ */ jsxs("p", { className: "text-gray-700 dark:text-gray-300", children: [
5091
+ text.contact.info.emailLabel,
5092
+ " ",
5093
+ /* @__PURE__ */ jsx(
5094
+ "a",
5095
+ {
5096
+ href: `mailto:${text.contact.info.email}`,
5097
+ className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
5098
+ children: text.contact.info.email
5099
+ }
5100
+ ),
5101
+ /* @__PURE__ */ jsx("br", {}),
5102
+ text.contact.info.websiteLabel,
5103
+ " ",
5104
+ /* @__PURE__ */ jsx(
5105
+ "a",
5106
+ {
5107
+ href: text.contact.info.websiteUrl,
5108
+ className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
5109
+ children: text.contact.info.websiteUrl
5110
+ }
5111
+ ),
5112
+ text.contact.info.dpoLabel && text.contact.info.dpoEmail && /* @__PURE__ */ jsxs(Fragment, { children: [
5113
+ /* @__PURE__ */ jsx("br", {}),
5114
+ text.contact.info.dpoLabel,
5115
+ " ",
5116
+ /* @__PURE__ */ jsx(
5117
+ "a",
5118
+ {
5119
+ href: `mailto:${text.contact.info.dpoEmail}`,
5120
+ className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
5121
+ children: text.contact.info.dpoEmail
5122
+ }
5123
+ )
5124
+ ] })
5125
+ ] }) }),
5126
+ text.contact.gdprNotice && /* @__PURE__ */ jsxs("div", { className: "mt-8 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg", children: [
5127
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-blue-900 dark:text-blue-200 mb-2", children: text.contact.gdprNotice.title }),
5128
+ /* @__PURE__ */ jsxs("p", { className: "text-blue-800 dark:text-blue-300", children: [
5129
+ text.contact.gdprNotice.content,
5130
+ " ",
5131
+ text.contact.info.dpoEmail && /* @__PURE__ */ jsx(
5132
+ "a",
5133
+ {
5134
+ href: `mailto:${text.contact.info.dpoEmail}`,
5135
+ className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
5136
+ children: text.contact.info.dpoEmail
5137
+ }
5138
+ )
5139
+ ] })
5140
+ ] })
5141
+ ] })
5012
5142
  ] })
5013
5143
  ] });
5014
5144
  if (PageWrapper) {
@@ -5022,10 +5152,9 @@ export {
5022
5152
  AppFooterForHomePage,
5023
5153
  AppPageLayout,
5024
5154
  AppPricingPage,
5025
- AppPrivacyPolicyPage,
5026
5155
  AppSitemapPage,
5027
5156
  AppSubscriptionsPage,
5028
- AppTermsOfServicePage,
5157
+ AppTextPage,
5029
5158
  AppTopBar,
5030
5159
  AppTopBarWithFirebaseAuth,
5031
5160
  AppTopBarWithWallet,