@sudobility/building_blocks 0.0.21 → 0.0.23
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/README.md +149 -7
- package/dist/components/footer/app-footer-for-home-page.d.ts +3 -1
- package/dist/components/footer/app-footer.d.ts +3 -1
- package/dist/components/settings/global-settings-page.d.ts +3 -0
- package/dist/components/subscription/AppPricingPage.d.ts +4 -1
- package/dist/components/subscription/AppSubscriptionsPage.d.ts +8 -3
- package/dist/index.js +229 -35
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +114 -0
- package/package.json +6 -6
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:
|
|
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(
|
|
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
|
-
|
|
938
|
-
|
|
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 = (
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
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
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
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: () =>
|
|
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: () =>
|
|
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:
|
|
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:
|
|
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: () =>
|
|
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: () =>
|
|
4870
|
+
onClick: () => handlePlanClick(product.identifier, "upgrade")
|
|
4677
4871
|
};
|
|
4678
4872
|
}
|
|
4679
4873
|
let topBadge;
|