@monetizekit/react 0.2.0 → 0.4.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/dist/index.cjs CHANGED
@@ -359,13 +359,14 @@ var INTERVAL_SUFFIX = {
359
359
  annually: "/yr",
360
360
  one_time: ""
361
361
  };
362
- function describePlanPrice(plan, locale) {
362
+ function describePlanPrice(plan, locale, billingCycle = "monthly") {
363
363
  const pricing = plan.pricing ?? [];
364
364
  const contactSales = (plan.tags ?? []).includes("contact_sales") || pricing.length === 0;
365
365
  if (contactSales) {
366
366
  return { headline: null, contactSales: true };
367
367
  }
368
- const base = pricing.find((t) => t.type === "flat");
368
+ const flats = pricing.filter((t) => t.type === "flat");
369
+ const base = flats.find((t) => t.interval === billingCycle) ?? flats.find((t) => t.interval === "monthly") ?? flats[0];
369
370
  const hasUsage = pricing.some((t) => t.type === "usage");
370
371
  const currency = base?.currency ?? pricing[0]?.currency ?? "USD";
371
372
  const interval = base?.interval ?? pricing[0]?.interval ?? "monthly";
@@ -377,6 +378,14 @@ function describePlanPrice(plan, locale) {
377
378
  contactSales: false
378
379
  };
379
380
  }
381
+ function annualSavingsPercent(plan) {
382
+ const flats = (plan.pricing ?? []).filter((t) => t.type === "flat");
383
+ const monthly = flats.find((t) => t.interval === "monthly");
384
+ const annual = flats.find((t) => t.interval === "annually");
385
+ if (!monthly || !annual || monthly.amount <= 0) return null;
386
+ const pct = Math.round((1 - annual.amount / (monthly.amount * 12)) * 100);
387
+ return pct > 0 ? pct : null;
388
+ }
380
389
  function describeUsageTerm(term, locale) {
381
390
  const parts = [];
382
391
  if (term.includedUnits && term.includedUnits > 0) {
@@ -409,7 +418,7 @@ var SAMPLE_PLANS = [
409
418
  id: "sample_pro",
410
419
  name: "Growth",
411
420
  description: "Product-led monetization at scale",
412
- pricing: [{ type: "flat", amount: 49900, currency: "USD", interval: "monthly" }],
421
+ pricing: [{ type: "flat", amount: 499, currency: "USD", interval: "monthly" }],
413
422
  entitlements: [
414
423
  { featureKey: "max_customers", featureDisplayName: "Tracked customers", type: "limit", value: 1e4 },
415
424
  { featureKey: "stripe", featureDisplayName: "Stripe integration", type: "boolean", value: true },
@@ -422,7 +431,7 @@ var SAMPLE_PLANS = [
422
431
  name: "Scale",
423
432
  description: "Volume-based capacity pricing",
424
433
  pricing: [
425
- { type: "flat", amount: 99900, currency: "USD", interval: "monthly" },
434
+ { type: "flat", amount: 999, currency: "USD", interval: "monthly" },
426
435
  {
427
436
  type: "usage",
428
437
  amount: 0,
@@ -460,7 +469,21 @@ var SAMPLE_USAGE = {
460
469
  seats: { meterId: "seats", current: 8, limit: 10 },
461
470
  storage_gb: { meterId: "storage_gb", current: 3, limit: 10 }
462
471
  };
463
- var SAMPLE_CREDITS = { balance: 12e4, currency: "USD" };
472
+ var SAMPLE_CREDITS = { balance: 1200, currency: "USD" };
473
+ var SAMPLE_TEAM = {
474
+ members: [
475
+ { name: "Jordan Lee", email: "jordan@acme.test", role: "owner" },
476
+ { name: "Sam Rivera", email: "sam@acme.test", role: "admin" },
477
+ { name: "Taylor Kim", email: "taylor@acme.test", role: "member" }
478
+ ],
479
+ seats: 3,
480
+ maxSeats: 10
481
+ };
482
+ var SAMPLE_INVOICES = [
483
+ { id: "in_1003", date: "2026-03-01T00:00:00Z", amount: 499, currency: "USD", status: "paid" },
484
+ { id: "in_1002", date: "2026-02-01T00:00:00Z", amount: 499, currency: "USD", status: "paid" },
485
+ { id: "in_1001", date: "2026-01-01T00:00:00Z", amount: 499, currency: "USD", status: "paid" }
486
+ ];
464
487
  var SAMPLE_PORTAL = {
465
488
  planName: "Growth",
466
489
  meterIds: ["api_calls", "seats"]
@@ -484,6 +507,78 @@ function SampleNotice({ children }) {
484
507
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: children ?? SAMPLE_NOTICE_TEXT })
485
508
  ] });
486
509
  }
510
+ var trackStyle = {
511
+ display: "inline-flex",
512
+ alignSelf: "center",
513
+ gap: "0.125rem",
514
+ padding: "0.25rem",
515
+ borderRadius: "var(--mk-radius)",
516
+ background: "color-mix(in srgb, var(--mk-fg) 6%, transparent)",
517
+ fontFamily: "var(--mk-font)"
518
+ };
519
+ function optionStyle(active) {
520
+ return {
521
+ border: "none",
522
+ cursor: "pointer",
523
+ borderRadius: "var(--mk-radius)",
524
+ padding: "0.375rem 0.875rem",
525
+ fontSize: "0.8125rem",
526
+ fontWeight: 600,
527
+ display: "inline-flex",
528
+ alignItems: "center",
529
+ gap: "0.375rem",
530
+ background: active ? "var(--mk-card)" : "transparent",
531
+ color: active ? "var(--mk-card-fg)" : "var(--mk-muted)",
532
+ boxShadow: active ? "var(--mk-shadow)" : "none"
533
+ };
534
+ }
535
+ function BillingCycleToggle({
536
+ value,
537
+ onChange,
538
+ savingsPercent = 0,
539
+ monthlyLabel = "Monthly",
540
+ annuallyLabel = "Yearly"
541
+ }) {
542
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: trackStyle, role: "group", "aria-label": "Billing cycle", "data-mk-component": "billing-toggle", children: [
543
+ /* @__PURE__ */ jsxRuntime.jsx(
544
+ "button",
545
+ {
546
+ type: "button",
547
+ style: optionStyle(value === "monthly"),
548
+ "aria-pressed": value === "monthly",
549
+ onClick: () => onChange("monthly"),
550
+ children: monthlyLabel
551
+ }
552
+ ),
553
+ /* @__PURE__ */ jsxRuntime.jsxs(
554
+ "button",
555
+ {
556
+ type: "button",
557
+ style: optionStyle(value === "annually"),
558
+ "aria-pressed": value === "annually",
559
+ onClick: () => onChange("annually"),
560
+ children: [
561
+ annuallyLabel,
562
+ savingsPercent > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
563
+ "span",
564
+ {
565
+ style: {
566
+ fontSize: "0.6875rem",
567
+ fontWeight: 700,
568
+ color: "var(--mk-success)"
569
+ },
570
+ children: [
571
+ "Save ",
572
+ savingsPercent,
573
+ "%"
574
+ ]
575
+ }
576
+ ) : null
577
+ ]
578
+ }
579
+ )
580
+ ] });
581
+ }
487
582
  var wrapperStyle = {
488
583
  display: "grid",
489
584
  gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))",
@@ -503,6 +598,8 @@ var cardBase = {
503
598
  function PricingTable({
504
599
  plans: plansProp,
505
600
  highlightPlan,
601
+ billingCycle,
602
+ showBillingToggle = false,
506
603
  locale,
507
604
  onSelectPlan,
508
605
  onContactSales,
@@ -512,6 +609,10 @@ function PricingTable({
512
609
  const { client, tokens } = useMonetizeKit();
513
610
  const [plans, setPlans] = react.useState(plansProp ?? null);
514
611
  const [error, setError] = react.useState(null);
612
+ const [cycle, setCycle] = react.useState(billingCycle ?? "monthly");
613
+ react.useEffect(() => {
614
+ if (billingCycle) setCycle(billingCycle);
615
+ }, [billingCycle]);
515
616
  react.useEffect(() => {
516
617
  if (plansProp) {
517
618
  setPlans(plansProp);
@@ -546,8 +647,19 @@ function PricingTable({
546
647
  "data-mk-sample": isSample ? "true" : void 0,
547
648
  children: [
548
649
  isSample ? /* @__PURE__ */ jsxRuntime.jsx(SampleNotice, { children: disclaimer }) : null,
650
+ showBillingToggle ? /* @__PURE__ */ jsxRuntime.jsx(
651
+ BillingCycleToggle,
652
+ {
653
+ value: cycle,
654
+ onChange: setCycle,
655
+ savingsPercent: Math.max(
656
+ 0,
657
+ ...effectivePlans.map((p) => annualSavingsPercent(p) ?? 0)
658
+ )
659
+ }
660
+ ) : null,
549
661
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: wrapperStyle, children: effectivePlans.map((plan) => {
550
- const price = describePlanPrice(plan, locale);
662
+ const price = describePlanPrice(plan, locale, cycle);
551
663
  const highlighted = highlightPlan != null && plan.name.toLowerCase() === highlightPlan.toLowerCase();
552
664
  return /* @__PURE__ */ jsxRuntime.jsxs(
553
665
  "div",
@@ -612,6 +724,169 @@ function PricingTable({
612
724
  }
613
725
  );
614
726
  }
727
+ var UNLIMITED_THRESHOLD = 9999;
728
+ function entitlementCell(ent, locale) {
729
+ if (!ent) return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--mk-muted)" }, children: "\u2014" });
730
+ switch (ent.type) {
731
+ case "boolean":
732
+ return ent.value ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-label": "Included", style: { color: "var(--mk-success)", fontWeight: 700 }, children: "\u2713" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-label": "Not included", style: { color: "var(--mk-muted)" }, children: "\u2014" });
733
+ case "limit": {
734
+ const n = Number(ent.value);
735
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: n >= UNLIMITED_THRESHOLD ? "Unlimited" : formatUnits(n, locale) });
736
+ }
737
+ default:
738
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: String(ent.value) });
739
+ }
740
+ }
741
+ function deriveGroups(plans) {
742
+ const seen = /* @__PURE__ */ new Map();
743
+ for (const plan of plans) {
744
+ for (const ent of plan.entitlements ?? []) {
745
+ if (!seen.has(ent.featureKey)) seen.set(ent.featureKey, ent.featureDisplayName);
746
+ }
747
+ }
748
+ return [
749
+ {
750
+ title: "Features",
751
+ features: Array.from(seen, ([key, label]) => ({ key, label }))
752
+ }
753
+ ];
754
+ }
755
+ var cellStyle = {
756
+ padding: "0.75rem 1rem",
757
+ textAlign: "center",
758
+ fontSize: "0.875rem",
759
+ borderTop: "1px solid var(--mk-border)"
760
+ };
761
+ function PricingComparison({
762
+ plans: plansProp,
763
+ groups,
764
+ highlightPlan,
765
+ billingCycle = "monthly",
766
+ locale,
767
+ sampleWhenEmpty = true,
768
+ disclaimer
769
+ }) {
770
+ const { client, tokens } = useMonetizeKit();
771
+ const [plans, setPlans] = react.useState(plansProp ?? null);
772
+ const [error, setError] = react.useState(null);
773
+ react.useEffect(() => {
774
+ if (plansProp) {
775
+ setPlans(plansProp);
776
+ return;
777
+ }
778
+ let active = true;
779
+ client.listPlans().then((res) => {
780
+ if (active) setPlans(res.data ?? []);
781
+ }).catch((e) => {
782
+ if (active) setError(e instanceof Error ? e : new Error(String(e)));
783
+ });
784
+ return () => {
785
+ active = false;
786
+ };
787
+ }, [client, plansProp]);
788
+ if (error) {
789
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", style: { color: "var(--mk-muted)" }, children: "Unable to load plan comparison." });
790
+ }
791
+ if (!plans) {
792
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-busy": "true", style: { color: "var(--mk-muted)" }, children: "Loading comparison\u2026" });
793
+ }
794
+ const isSample = plans.length === 0 && sampleWhenEmpty;
795
+ const effectivePlans = isSample ? SAMPLE_PLANS : plans;
796
+ if (effectivePlans.length === 0) {
797
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "var(--mk-muted)" }, children: "No plans to compare." });
798
+ }
799
+ const effectiveGroups = groups ?? deriveGroups(effectivePlans);
800
+ const entByPlan = effectivePlans.map(
801
+ (plan) => new Map((plan.entitlements ?? []).map((e) => [e.featureKey, e]))
802
+ );
803
+ return /* @__PURE__ */ jsxRuntime.jsxs(
804
+ "div",
805
+ {
806
+ style: { ...tokensToStyle(tokens), display: "flex", flexDirection: "column", gap: "1rem" },
807
+ "data-mk-component": "pricing-comparison",
808
+ "data-mk-sample": isSample ? "true" : void 0,
809
+ children: [
810
+ isSample ? /* @__PURE__ */ jsxRuntime.jsx(SampleNotice, { children: disclaimer }) : null,
811
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
812
+ "table",
813
+ {
814
+ style: {
815
+ width: "100%",
816
+ borderCollapse: "collapse",
817
+ background: "var(--mk-bg)",
818
+ color: "var(--mk-fg)",
819
+ fontFamily: "var(--mk-font)"
820
+ },
821
+ children: [
822
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
823
+ /* @__PURE__ */ jsxRuntime.jsx("th", { style: { ...cellStyle, textAlign: "left", borderTop: "none" }, children: "Features" }),
824
+ effectivePlans.map((plan) => {
825
+ const highlighted = highlightPlan != null && plan.name.toLowerCase() === highlightPlan.toLowerCase();
826
+ const price = describePlanPrice(plan, locale, billingCycle);
827
+ return /* @__PURE__ */ jsxRuntime.jsxs(
828
+ "th",
829
+ {
830
+ style: {
831
+ ...cellStyle,
832
+ borderTop: "none",
833
+ color: highlighted ? "var(--mk-primary)" : "var(--mk-fg)"
834
+ },
835
+ "data-mk-plan": plan.name,
836
+ "data-mk-highlighted": highlighted ? "true" : void 0,
837
+ children: [
838
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 700 }, children: plan.name }),
839
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.75rem", color: "var(--mk-muted)", fontWeight: 400 }, children: price.contactSales ? "Custom" : price.headline })
840
+ ]
841
+ },
842
+ plan.id
843
+ );
844
+ })
845
+ ] }) }),
846
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: effectiveGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsx(
847
+ FeatureGroupRows,
848
+ {
849
+ group,
850
+ planCount: effectivePlans.length,
851
+ entByPlan,
852
+ locale
853
+ },
854
+ group.title
855
+ )) })
856
+ ]
857
+ }
858
+ ) })
859
+ ]
860
+ }
861
+ );
862
+ }
863
+ function FeatureGroupRows({
864
+ group,
865
+ planCount,
866
+ entByPlan,
867
+ locale
868
+ }) {
869
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
870
+ /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
871
+ "td",
872
+ {
873
+ colSpan: planCount + 1,
874
+ style: {
875
+ padding: "0.625rem 1rem",
876
+ fontSize: "0.8125rem",
877
+ fontWeight: 700,
878
+ background: "color-mix(in srgb, var(--mk-fg) 5%, transparent)",
879
+ borderTop: "1px solid var(--mk-border)"
880
+ },
881
+ children: group.title
882
+ }
883
+ ) }),
884
+ group.features.map((feature) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
885
+ /* @__PURE__ */ jsxRuntime.jsx("td", { style: { ...cellStyle, textAlign: "left", color: "var(--mk-fg)" }, children: feature.label }),
886
+ entByPlan.map((map, i) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: cellStyle, children: entitlementCell(map.get(feature.key), locale) }, i))
887
+ ] }, feature.key))
888
+ ] });
889
+ }
615
890
  var overlayStyle = {
616
891
  border: "1px solid var(--mk-border)",
617
892
  borderRadius: "var(--mk-radius)",
@@ -631,14 +906,15 @@ function Paywall({
631
906
  title = "Upgrade to unlock this feature",
632
907
  description = "This feature isn't included in your current plan.",
633
908
  ctaLabel = "Upgrade",
634
- onUpgrade
909
+ onUpgrade,
910
+ sample = false
635
911
  }) {
636
912
  const { allowed, loading } = useEntitlement(feature);
637
913
  const { tokens } = useMonetizeKit();
638
- if (loading) {
914
+ if (!sample && loading) {
639
915
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-busy": "true", style: { color: "var(--mk-muted)" }, children: "Checking access\u2026" });
640
916
  }
641
- if (allowed) {
917
+ if (!sample && allowed) {
642
918
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
643
919
  }
644
920
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...tokensToStyle(tokens), ...overlayStyle }, "data-mk-component": "paywall", children: [
@@ -717,6 +993,94 @@ function UsageBanner({
717
993
  over ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--mk-danger)", fontSize: "0.75rem" }, children: "Over included allotment \u2014 overage billed per usage pricing." }) : null
718
994
  ] });
719
995
  }
996
+ var VARIANT_COLOR = {
997
+ info: "var(--mk-accent)",
998
+ warning: "var(--mk-warning)",
999
+ danger: "var(--mk-danger)",
1000
+ neutral: "var(--mk-muted)"
1001
+ };
1002
+ function actionStyle(variant, accent) {
1003
+ if (variant === "ghost") {
1004
+ return {
1005
+ background: "transparent",
1006
+ color: "var(--mk-muted)",
1007
+ border: "none",
1008
+ cursor: "pointer",
1009
+ fontSize: "0.8125rem",
1010
+ fontWeight: 600,
1011
+ padding: "0.375rem 0.5rem"
1012
+ };
1013
+ }
1014
+ return {
1015
+ background: accent,
1016
+ color: "var(--mk-card)",
1017
+ border: "none",
1018
+ borderRadius: "var(--mk-radius)",
1019
+ cursor: "pointer",
1020
+ fontSize: "0.8125rem",
1021
+ fontWeight: 600,
1022
+ padding: "0.375rem 0.75rem"
1023
+ };
1024
+ }
1025
+ function AlertBanner({
1026
+ variant = "info",
1027
+ title,
1028
+ description,
1029
+ progress,
1030
+ actions = [],
1031
+ icon
1032
+ }) {
1033
+ const { tokens } = useMonetizeKit();
1034
+ const accent = VARIANT_COLOR[variant];
1035
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1036
+ "div",
1037
+ {
1038
+ role: "status",
1039
+ "data-mk-component": "alert-banner",
1040
+ "data-mk-variant": variant,
1041
+ style: {
1042
+ ...tokensToStyle(tokens),
1043
+ display: "flex",
1044
+ gap: "0.75rem",
1045
+ alignItems: "flex-start",
1046
+ border: `1px solid color-mix(in srgb, ${accent} 35%, var(--mk-border))`,
1047
+ background: `color-mix(in srgb, ${accent} 8%, var(--mk-card))`,
1048
+ color: "var(--mk-card-fg)",
1049
+ borderRadius: "var(--mk-radius)",
1050
+ padding: "0.875rem 1rem",
1051
+ fontFamily: "var(--mk-font)"
1052
+ },
1053
+ children: [
1054
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { color: accent, fontSize: "1.1rem", lineHeight: 1 }, children: icon }) : null,
1055
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
1056
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, fontSize: "0.875rem" }, children: title }),
1057
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.8125rem", color: "var(--mk-muted)" }, children: description }) : null,
1058
+ typeof progress === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
1059
+ "div",
1060
+ {
1061
+ style: { height: 6, borderRadius: 999, background: "var(--mk-border)", overflow: "hidden" },
1062
+ role: "progressbar",
1063
+ "aria-valuenow": Math.round(Math.min(1, Math.max(0, progress)) * 100),
1064
+ "aria-valuemin": 0,
1065
+ "aria-valuemax": 100,
1066
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: `${Math.min(1, Math.max(0, progress)) * 100}%`, height: "100%", background: accent } })
1067
+ }
1068
+ ) : null,
1069
+ actions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: actions.map((action) => /* @__PURE__ */ jsxRuntime.jsx(
1070
+ "button",
1071
+ {
1072
+ type: "button",
1073
+ onClick: action.onClick,
1074
+ style: actionStyle(action.variant, accent),
1075
+ children: action.label
1076
+ },
1077
+ action.label
1078
+ )) }) : null
1079
+ ] })
1080
+ ]
1081
+ }
1082
+ );
1083
+ }
720
1084
  var containerStyle = {
721
1085
  border: "1px solid var(--mk-border)",
722
1086
  borderRadius: "var(--mk-radius)",
@@ -758,10 +1122,38 @@ function SampleUsageRow({
758
1122
  hasLimit ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: 6, borderRadius: 999, background: "var(--mk-border)", overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: `${fraction * 100}%`, height: "100%", background: barColor } }) }) : null
759
1123
  ] });
760
1124
  }
1125
+ var ROW_DIVIDER = { borderTop: "1px solid var(--mk-border)" };
1126
+ var INVOICE_STATUS_COLOR = {
1127
+ paid: "var(--mk-success)",
1128
+ pending: "var(--mk-warning)",
1129
+ overdue: "var(--mk-danger)"
1130
+ };
1131
+ function StatusBadge({ label, color }) {
1132
+ return /* @__PURE__ */ jsxRuntime.jsx(
1133
+ "span",
1134
+ {
1135
+ style: {
1136
+ fontSize: "0.6875rem",
1137
+ fontWeight: 600,
1138
+ textTransform: "capitalize",
1139
+ color,
1140
+ border: `1px solid ${color}`,
1141
+ borderRadius: 999,
1142
+ padding: "0.0625rem 0.5rem"
1143
+ },
1144
+ children: label
1145
+ }
1146
+ );
1147
+ }
761
1148
  function CustomerPortal({
762
1149
  planName,
763
1150
  meterIds,
764
1151
  showCredits = true,
1152
+ showTeam,
1153
+ teamMembers,
1154
+ seats,
1155
+ showInvoices,
1156
+ invoices,
765
1157
  sample = false,
766
1158
  disclaimer,
767
1159
  showBranding = false,
@@ -776,6 +1168,11 @@ function CustomerPortal({
776
1168
  const creditBalance = sample ? SAMPLE_CREDITS.balance : credits.balance;
777
1169
  const creditCurrency = sample ? SAMPLE_CREDITS.currency : credits.currency;
778
1170
  const creditLoading = sample ? false : credits.loading;
1171
+ const teamEnabled = showTeam ?? sample;
1172
+ const resolvedTeam = teamMembers ?? (sample ? SAMPLE_TEAM.members : []);
1173
+ const resolvedSeats = seats ?? (sample ? { used: SAMPLE_TEAM.seats, max: SAMPLE_TEAM.maxSeats } : void 0);
1174
+ const invoicesEnabled = showInvoices ?? sample;
1175
+ const resolvedInvoices = invoices ?? (sample ? SAMPLE_INVOICES : []);
779
1176
  return /* @__PURE__ */ jsxRuntime.jsxs(
780
1177
  "div",
781
1178
  {
@@ -842,6 +1239,64 @@ function CustomerPortal({
842
1239
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontSize: "0.875rem" }, children: "Credits" }),
843
1240
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--mk-muted)" }, children: creditLoading ? "\u2026" : formatMoney(creditBalance, creditCurrency ?? currency, locale) })
844
1241
  ] }) : null,
1242
+ teamEnabled ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
1243
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
1244
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontSize: "0.875rem" }, children: "Team" }),
1245
+ resolvedSeats ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "var(--mk-muted)", fontSize: "0.75rem" }, children: [
1246
+ resolvedSeats.used,
1247
+ "/",
1248
+ resolvedSeats.max >= 9999 ? "Unlimited" : resolvedSeats.max,
1249
+ " seats"
1250
+ ] }) : null
1251
+ ] }),
1252
+ resolvedTeam.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--mk-muted)", fontSize: "0.8125rem" }, children: "No team members." }) : resolvedTeam.map((member, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1253
+ "div",
1254
+ {
1255
+ style: {
1256
+ display: "flex",
1257
+ justifyContent: "space-between",
1258
+ alignItems: "center",
1259
+ gap: "0.75rem",
1260
+ fontSize: "0.8125rem",
1261
+ paddingTop: i === 0 ? 0 : "0.5rem",
1262
+ ...i === 0 ? {} : ROW_DIVIDER
1263
+ },
1264
+ children: [
1265
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minWidth: 0 }, children: [
1266
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600 }, children: member.name }),
1267
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "var(--mk-muted)", fontSize: "0.75rem" }, children: member.email })
1268
+ ] }),
1269
+ /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { label: member.role, color: "var(--mk-muted)" })
1270
+ ]
1271
+ },
1272
+ member.email
1273
+ ))
1274
+ ] }) : null,
1275
+ invoicesEnabled ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
1276
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontSize: "0.875rem" }, children: "Invoices" }),
1277
+ resolvedInvoices.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--mk-muted)", fontSize: "0.8125rem" }, children: "No invoices yet." }) : resolvedInvoices.map((invoice, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1278
+ "div",
1279
+ {
1280
+ style: {
1281
+ display: "flex",
1282
+ justifyContent: "space-between",
1283
+ alignItems: "center",
1284
+ gap: "0.75rem",
1285
+ fontSize: "0.8125rem",
1286
+ paddingTop: i === 0 ? 0 : "0.5rem",
1287
+ ...i === 0 ? {} : ROW_DIVIDER
1288
+ },
1289
+ children: [
1290
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: new Date(invoice.date).toLocaleDateString(locale) }),
1291
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1292
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600 }, children: formatMoney(invoice.amount, invoice.currency, locale) }),
1293
+ /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { label: invoice.status, color: INVOICE_STATUS_COLOR[invoice.status] })
1294
+ ] })
1295
+ ]
1296
+ },
1297
+ invoice.id
1298
+ ))
1299
+ ] }) : null,
845
1300
  showBranding ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", fontSize: "0.625rem", color: "var(--mk-muted)" }, children: "Powered by MonetizeKit" }) : null
846
1301
  ]
847
1302
  }
@@ -858,16 +1313,21 @@ function EntitlementGate({
858
1313
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: allowed ? children : fallback });
859
1314
  }
860
1315
 
1316
+ exports.AlertBanner = AlertBanner;
1317
+ exports.BillingCycleToggle = BillingCycleToggle;
861
1318
  exports.CustomerPortal = CustomerPortal;
862
1319
  exports.EntitlementGate = EntitlementGate;
863
1320
  exports.MonetizeKitClient = MonetizeKitClient;
864
1321
  exports.MonetizeKitProvider = MonetizeKitProvider;
865
1322
  exports.Paywall = Paywall;
1323
+ exports.PricingComparison = PricingComparison;
866
1324
  exports.PricingTable = PricingTable;
867
1325
  exports.SAMPLE_CREDITS = SAMPLE_CREDITS;
1326
+ exports.SAMPLE_INVOICES = SAMPLE_INVOICES;
868
1327
  exports.SAMPLE_NOTICE_TEXT = SAMPLE_NOTICE_TEXT;
869
1328
  exports.SAMPLE_PLANS = SAMPLE_PLANS;
870
1329
  exports.SAMPLE_PORTAL = SAMPLE_PORTAL;
1330
+ exports.SAMPLE_TEAM = SAMPLE_TEAM;
871
1331
  exports.SAMPLE_USAGE = SAMPLE_USAGE;
872
1332
  exports.SampleNotice = SampleNotice;
873
1333
  exports.THEME_PRESETS = THEME_PRESETS;