@burdenoff/microfe-subscriberbot 2026.1030.5 → 2026.1030.7
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/subscriberbot/SubscriberBotRoutes.d.ts.map +1 -1
- package/dist/subscriberbot/SubscriberBotRoutes.js +10 -6
- package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
- package/dist/subscriberbot/components/savings/SavingsCards.d.ts +2 -2
- package/dist/subscriberbot/components/savings/SavingsCards.d.ts.map +1 -1
- package/dist/subscriberbot/components/savings/SavingsCards.js +128 -104
- package/dist/subscriberbot/components/savings/SavingsCards.js.map +1 -1
- package/dist/subscriberbot/components/savings/savingsModel.d.ts +14 -9
- package/dist/subscriberbot/components/savings/savingsModel.d.ts.map +1 -1
- package/dist/subscriberbot/components/savings/savingsModel.js +9 -7
- package/dist/subscriberbot/components/savings/savingsModel.js.map +1 -1
- package/dist/subscriberbot/hooks/index.d.ts +1 -1
- package/dist/subscriberbot/hooks/index.d.ts.map +1 -1
- package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts +4 -1
- package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts.map +1 -1
- package/dist/subscriberbot/hooks/useSubscriberBotApi.js +137 -72
- package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
- package/dist/subscriberbot/pages/SavingsPage.js +1 -1
- package/dist/subscriberbot/pages/SavingsPage.js.map +1 -1
- package/dist/subscriberbot/pages/enterprise/EnterpriseSpendPage.d.ts +13 -0
- package/dist/subscriberbot/pages/enterprise/EnterpriseSpendPage.d.ts.map +1 -0
- package/dist/subscriberbot/pages/enterprise/EnterpriseSpendPage.js +703 -0
- package/dist/subscriberbot/pages/enterprise/EnterpriseSpendPage.js.map +1 -0
- package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +276 -262
- package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipNewPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +65 -45
- package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -1
- package/dist/subscriberbot/types/index.d.ts +171 -15
- package/dist/subscriberbot/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubscriberBotRoutes.d.ts","sourceRoot":"","sources":["../../src/subscriberbot/SubscriberBotRoutes.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,EAAkB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SubscriberBotRoutes.d.ts","sourceRoot":"","sources":["../../src/subscriberbot/SubscriberBotRoutes.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,EAAkB,MAAM,OAAO,CAAC;AA0FhD,eAAO,MAAM,mBAAmB,EAAE,EAqEjC,CAAC"}
|
|
@@ -5,15 +5,15 @@ import { Navigate as i, Route as a, Routes as o, useLocation as s } from "react-
|
|
|
5
5
|
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
6
6
|
import { Spinner as u } from "@burdenoff/fe-libs/ui";
|
|
7
7
|
//#region src/subscriberbot/SubscriberBotRoutes.tsx
|
|
8
|
-
var d = r(() => import("./pages/relationships/RelationshipsListPage.js").then((e) => ({ default: e.RelationshipsListPage }))), f = r(() => import("./pages/relationships/RelationshipNewPage.js").then((e) => ({ default: e.RelationshipNewPage }))), p = r(() => import("./pages/relationships/RelationshipDetailPage.js").then((e) => ({ default: e.RelationshipDetailPage }))), m = r(() => import("./pages/providers/ProvidersListPage.js").then((e) => ({ default: e.ProvidersListPage }))), h = r(() => import("./pages/providers/ProviderNewPage.js").then((e) => ({ default: e.ProviderNewPage }))), g = r(() => import("./pages/providers/ProviderDetailPage.js").then((e) => ({ default: e.ProviderDetailPage }))), _ = r(() => import("./pages/InboxPage.js").then((e) => ({ default: e.InboxPage }))), v = r(() => import("./pages/InvoicesPage.js").then((e) => ({ default: e.InvoicesPage }))), y = r(() => import("./pages/WorkflowsPage.js").then((e) => ({ default: e.WorkflowsPage }))), b = r(() => import("./pages/agents/AgentsListPage.js").then((e) => ({ default: e.AgentsListPage }))), x = r(() => import("./pages/agents/AgentNewPage.js").then((e) => ({ default: e.AgentNewPage }))), S = r(() => import("./pages/agents/AgentDetailPage.js").then((e) => ({ default: e.AgentDetailPage }))), C = r(() => import("./pages/decisions/DecisionsPage.js").then((e) => ({ default: e.DecisionsPage }))), w = r(() => import("./pages/decisions/DecisionDetailPage.js").then((e) => ({ default: e.DecisionDetailPage }))), T = r(() => import("./pages/SavingsPage.js").then((e) => ({ default: e.SavingsPage }))), E = r(() => import("./pages/InsightsPage.js").then((e) => ({ default: e.InsightsPage }))), D = r(() => import("./pages/AssetVaultPage.js").then((e) => ({ default: e.AssetVaultPage }))), O = () => /* @__PURE__ */ c("div", {
|
|
8
|
+
var d = r(() => import("./pages/relationships/RelationshipsListPage.js").then((e) => ({ default: e.RelationshipsListPage }))), f = r(() => import("./pages/relationships/RelationshipNewPage.js").then((e) => ({ default: e.RelationshipNewPage }))), p = r(() => import("./pages/relationships/RelationshipDetailPage.js").then((e) => ({ default: e.RelationshipDetailPage }))), m = r(() => import("./pages/providers/ProvidersListPage.js").then((e) => ({ default: e.ProvidersListPage }))), h = r(() => import("./pages/providers/ProviderNewPage.js").then((e) => ({ default: e.ProviderNewPage }))), g = r(() => import("./pages/providers/ProviderDetailPage.js").then((e) => ({ default: e.ProviderDetailPage }))), _ = r(() => import("./pages/InboxPage.js").then((e) => ({ default: e.InboxPage }))), v = r(() => import("./pages/InvoicesPage.js").then((e) => ({ default: e.InvoicesPage }))), y = r(() => import("./pages/WorkflowsPage.js").then((e) => ({ default: e.WorkflowsPage }))), b = r(() => import("./pages/agents/AgentsListPage.js").then((e) => ({ default: e.AgentsListPage }))), x = r(() => import("./pages/agents/AgentNewPage.js").then((e) => ({ default: e.AgentNewPage }))), S = r(() => import("./pages/agents/AgentDetailPage.js").then((e) => ({ default: e.AgentDetailPage }))), C = r(() => import("./pages/decisions/DecisionsPage.js").then((e) => ({ default: e.DecisionsPage }))), w = r(() => import("./pages/decisions/DecisionDetailPage.js").then((e) => ({ default: e.DecisionDetailPage }))), T = r(() => import("./pages/SavingsPage.js").then((e) => ({ default: e.SavingsPage }))), E = r(() => import("./pages/InsightsPage.js").then((e) => ({ default: e.InsightsPage }))), D = r(() => import("./pages/AssetVaultPage.js").then((e) => ({ default: e.AssetVaultPage }))), O = r(() => import("./pages/enterprise/EnterpriseSpendPage.js").then((e) => ({ default: e.EnterpriseSpendPage }))), k = () => /* @__PURE__ */ c("div", {
|
|
9
9
|
className: "flex min-h-[400px] items-center justify-center",
|
|
10
10
|
children: /* @__PURE__ */ c(u, { size: "lg" })
|
|
11
|
-
}),
|
|
12
|
-
let { basePath: r, isStandalone: u } = e(),
|
|
13
|
-
return
|
|
11
|
+
}), A = () => {
|
|
12
|
+
let { basePath: r, isStandalone: u } = e(), A = s(), j = r === "/" ? "" : (r ?? "").replace(/\/$/, "");
|
|
13
|
+
return j && !u && !(A.pathname === j || A.pathname.startsWith(j + "/")) ? null : /* @__PURE__ */ c("div", {
|
|
14
14
|
className: "flex min-h-full flex-col",
|
|
15
15
|
children: /* @__PURE__ */ c(n, {
|
|
16
|
-
fallback: /* @__PURE__ */ c(
|
|
16
|
+
fallback: /* @__PURE__ */ c(k, {}),
|
|
17
17
|
children: /* @__PURE__ */ l(o, { children: [
|
|
18
18
|
/* @__PURE__ */ c(a, {
|
|
19
19
|
index: !0,
|
|
@@ -55,6 +55,10 @@ var d = r(() => import("./pages/relationships/RelationshipsListPage.js").then((e
|
|
|
55
55
|
path: "insights",
|
|
56
56
|
element: /* @__PURE__ */ c(E, {})
|
|
57
57
|
}),
|
|
58
|
+
/* @__PURE__ */ c(a, {
|
|
59
|
+
path: "enterprise/spend",
|
|
60
|
+
element: /* @__PURE__ */ c(O, {})
|
|
61
|
+
}),
|
|
58
62
|
/* @__PURE__ */ c(a, {
|
|
59
63
|
path: "vault",
|
|
60
64
|
element: /* @__PURE__ */ c(D, {})
|
|
@@ -99,6 +103,6 @@ var d = r(() => import("./pages/relationships/RelationshipsListPage.js").then((e
|
|
|
99
103
|
});
|
|
100
104
|
};
|
|
101
105
|
//#endregion
|
|
102
|
-
export {
|
|
106
|
+
export { A as SubscriberBotRoutes };
|
|
103
107
|
|
|
104
108
|
//# sourceMappingURL=SubscriberBotRoutes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubscriberBotRoutes.js","names":[],"sources":["../../src/subscriberbot/SubscriberBotRoutes.tsx"],"sourcesContent":["/**\n * SubscriberBot Routes\n * @module subscriberbot\n *\n * Domain routes for the Subscriber Bot product. The dashboard is eager-loaded\n * (primary landing); all other pages are lazy-loaded.\n */\n\nimport { type FC, lazy, Suspense } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useSubscriberBot } from './context/SubscriberBotContext';\n\n// Eager — primary landing\nimport { DashboardPage } from './pages/DashboardPage';\n\n// Relationships\nconst RelationshipsListPage = lazy(() =>\n import('./pages/relationships/RelationshipsListPage').then((m) => ({\n default: m.RelationshipsListPage,\n }))\n);\nconst RelationshipNewPage = lazy(() =>\n import('./pages/relationships/RelationshipNewPage').then((m) => ({\n default: m.RelationshipNewPage,\n }))\n);\nconst RelationshipDetailPage = lazy(() =>\n import('./pages/relationships/RelationshipDetailPage').then((m) => ({\n default: m.RelationshipDetailPage,\n }))\n);\n\n// Providers\nconst ProvidersListPage = lazy(() =>\n import('./pages/providers/ProvidersListPage').then((m) => ({ default: m.ProvidersListPage }))\n);\nconst ProviderNewPage = lazy(() =>\n import('./pages/providers/ProviderNewPage').then((m) => ({ default: m.ProviderNewPage }))\n);\nconst ProviderDetailPage = lazy(() =>\n import('./pages/providers/ProviderDetailPage').then((m) => ({ default: m.ProviderDetailPage }))\n);\n\n// Inbox / Invoices / Workflows\nconst InboxPage = lazy(() => import('./pages/InboxPage').then((m) => ({ default: m.InboxPage })));\nconst InvoicesPage = lazy(() =>\n import('./pages/InvoicesPage').then((m) => ({ default: m.InvoicesPage }))\n);\nconst WorkflowsPage = lazy(() =>\n import('./pages/WorkflowsPage').then((m) => ({ default: m.WorkflowsPage }))\n);\n\n// Agents\nconst AgentsListPage = lazy(() =>\n import('./pages/agents/AgentsListPage').then((m) => ({ default: m.AgentsListPage }))\n);\nconst AgentNewPage = lazy(() =>\n import('./pages/agents/AgentNewPage').then((m) => ({ default: m.AgentNewPage }))\n);\nconst AgentDetailPage = lazy(() =>\n import('./pages/agents/AgentDetailPage').then((m) => ({ default: m.AgentDetailPage }))\n);\n\n// AI decision queue (BOFF-3663)\nconst DecisionsPage = lazy(() =>\n import('./pages/decisions/DecisionsPage').then((m) => ({ default: m.DecisionsPage }))\n);\nconst DecisionDetailPage = lazy(() =>\n import('./pages/decisions/DecisionDetailPage').then((m) => ({ default: m.DecisionDetailPage }))\n);\n\n// Cost optimization dashboard (BOFF-4001)\nconst SavingsPage = lazy(() =>\n import('./pages/SavingsPage').then((m) => ({ default: m.SavingsPage }))\n);\n\n// Insights + Asset Vault (aggregated real data)\nconst InsightsPage = lazy(() =>\n import('./pages/InsightsPage').then((m) => ({ default: m.InsightsPage }))\n);\nconst AssetVaultPage = lazy(() =>\n import('./pages/AssetVaultPage').then((m) => ({ default: m.AssetVaultPage }))\n);\n\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <Spinner size=\"lg\" />\n </div>\n);\n\nexport const SubscriberBotRoutes: FC = () => {\n const { basePath, isStandalone } = useSubscriberBot();\n const location = useLocation();\n\n // Normalize base path\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n // Guard: only render if the current path matches basePath (integrated mode).\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n {/* Overview / dashboard */}\n <Route index element={<DashboardPage />} />\n\n {/* Relationships (the core domain) */}\n <Route path=\"relationships\" element={<RelationshipsListPage />} />\n <Route path=\"relationships/new\" element={<RelationshipNewPage />} />\n <Route path=\"relationships/:id\" element={<RelationshipDetailPage />} />\n\n {/* Providers (registry) */}\n <Route path=\"providers\" element={<ProvidersListPage />} />\n <Route path=\"providers/new\" element={<ProviderNewPage />} />\n <Route path=\"providers/:id\" element={<ProviderDetailPage />} />\n\n {/* Universal Inbox */}\n {/* One optional-segment route so selecting a message never remounts the page */}\n <Route path=\"inbox/:selectedId?\" element={<InboxPage />} />\n\n {/* Invoices */}\n <Route path=\"invoices\" element={<InvoicesPage />} />\n\n {/* Insights (spend analytics + renewal forecast) */}\n <Route path=\"insights\" element={<InsightsPage />} />\n\n {/* Digital Asset Vault */}\n <Route path=\"vault\" element={<AssetVaultPage />} />\n\n {/* AI Agents */}\n <Route path=\"agents\" element={<AgentsListPage />} />\n <Route path=\"agents/new\" element={<AgentNewPage />} />\n <Route path=\"agents/:id\" element={<AgentDetailPage />} />\n\n {/* AI decision queue */}\n <Route path=\"decisions\" element={<DecisionsPage />} />\n <Route path=\"savings\" element={<SavingsPage />} />\n <Route path=\"decisions/:id\" element={<DecisionDetailPage />} />\n\n {/* Workflows */}\n <Route path=\"workflows/:selectedId?\" element={<WorkflowsPage />} />\n\n {/* Fallback */}\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SubscriberBotRoutes.js","names":[],"sources":["../../src/subscriberbot/SubscriberBotRoutes.tsx"],"sourcesContent":["/**\n * SubscriberBot Routes\n * @module subscriberbot\n *\n * Domain routes for the Subscriber Bot product. The dashboard is eager-loaded\n * (primary landing); all other pages are lazy-loaded.\n */\n\nimport { type FC, lazy, Suspense } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useSubscriberBot } from './context/SubscriberBotContext';\n\n// Eager — primary landing\nimport { DashboardPage } from './pages/DashboardPage';\n\n// Relationships\nconst RelationshipsListPage = lazy(() =>\n import('./pages/relationships/RelationshipsListPage').then((m) => ({\n default: m.RelationshipsListPage,\n }))\n);\nconst RelationshipNewPage = lazy(() =>\n import('./pages/relationships/RelationshipNewPage').then((m) => ({\n default: m.RelationshipNewPage,\n }))\n);\nconst RelationshipDetailPage = lazy(() =>\n import('./pages/relationships/RelationshipDetailPage').then((m) => ({\n default: m.RelationshipDetailPage,\n }))\n);\n\n// Providers\nconst ProvidersListPage = lazy(() =>\n import('./pages/providers/ProvidersListPage').then((m) => ({ default: m.ProvidersListPage }))\n);\nconst ProviderNewPage = lazy(() =>\n import('./pages/providers/ProviderNewPage').then((m) => ({ default: m.ProviderNewPage }))\n);\nconst ProviderDetailPage = lazy(() =>\n import('./pages/providers/ProviderDetailPage').then((m) => ({ default: m.ProviderDetailPage }))\n);\n\n// Inbox / Invoices / Workflows\nconst InboxPage = lazy(() => import('./pages/InboxPage').then((m) => ({ default: m.InboxPage })));\nconst InvoicesPage = lazy(() =>\n import('./pages/InvoicesPage').then((m) => ({ default: m.InvoicesPage }))\n);\nconst WorkflowsPage = lazy(() =>\n import('./pages/WorkflowsPage').then((m) => ({ default: m.WorkflowsPage }))\n);\n\n// Agents\nconst AgentsListPage = lazy(() =>\n import('./pages/agents/AgentsListPage').then((m) => ({ default: m.AgentsListPage }))\n);\nconst AgentNewPage = lazy(() =>\n import('./pages/agents/AgentNewPage').then((m) => ({ default: m.AgentNewPage }))\n);\nconst AgentDetailPage = lazy(() =>\n import('./pages/agents/AgentDetailPage').then((m) => ({ default: m.AgentDetailPage }))\n);\n\n// AI decision queue (BOFF-3663)\nconst DecisionsPage = lazy(() =>\n import('./pages/decisions/DecisionsPage').then((m) => ({ default: m.DecisionsPage }))\n);\nconst DecisionDetailPage = lazy(() =>\n import('./pages/decisions/DecisionDetailPage').then((m) => ({ default: m.DecisionDetailPage }))\n);\n\n// Cost optimization dashboard (BOFF-4001)\nconst SavingsPage = lazy(() =>\n import('./pages/SavingsPage').then((m) => ({ default: m.SavingsPage }))\n);\n\n// Insights + Asset Vault (aggregated real data)\nconst InsightsPage = lazy(() =>\n import('./pages/InsightsPage').then((m) => ({ default: m.InsightsPage }))\n);\nconst AssetVaultPage = lazy(() =>\n import('./pages/AssetVaultPage').then((m) => ({ default: m.AssetVaultPage }))\n);\n\n// Enterprise SaaS spend management (BOFF-4008)\nconst EnterpriseSpendPage = lazy(() =>\n import('./pages/enterprise/EnterpriseSpendPage').then((m) => ({\n default: m.EnterpriseSpendPage,\n }))\n);\n\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <Spinner size=\"lg\" />\n </div>\n);\n\nexport const SubscriberBotRoutes: FC = () => {\n const { basePath, isStandalone } = useSubscriberBot();\n const location = useLocation();\n\n // Normalize base path\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n // Guard: only render if the current path matches basePath (integrated mode).\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n {/* Overview / dashboard */}\n <Route index element={<DashboardPage />} />\n\n {/* Relationships (the core domain) */}\n <Route path=\"relationships\" element={<RelationshipsListPage />} />\n <Route path=\"relationships/new\" element={<RelationshipNewPage />} />\n <Route path=\"relationships/:id\" element={<RelationshipDetailPage />} />\n\n {/* Providers (registry) */}\n <Route path=\"providers\" element={<ProvidersListPage />} />\n <Route path=\"providers/new\" element={<ProviderNewPage />} />\n <Route path=\"providers/:id\" element={<ProviderDetailPage />} />\n\n {/* Universal Inbox */}\n {/* One optional-segment route so selecting a message never remounts the page */}\n <Route path=\"inbox/:selectedId?\" element={<InboxPage />} />\n\n {/* Invoices */}\n <Route path=\"invoices\" element={<InvoicesPage />} />\n\n {/* Insights (spend analytics + renewal forecast) */}\n <Route path=\"insights\" element={<InsightsPage />} />\n\n {/* Enterprise SaaS spend management */}\n <Route path=\"enterprise/spend\" element={<EnterpriseSpendPage />} />\n\n {/* Digital Asset Vault */}\n <Route path=\"vault\" element={<AssetVaultPage />} />\n\n {/* AI Agents */}\n <Route path=\"agents\" element={<AgentsListPage />} />\n <Route path=\"agents/new\" element={<AgentNewPage />} />\n <Route path=\"agents/:id\" element={<AgentDetailPage />} />\n\n {/* AI decision queue */}\n <Route path=\"decisions\" element={<DecisionsPage />} />\n <Route path=\"savings\" element={<SavingsPage />} />\n <Route path=\"decisions/:id\" element={<DecisionDetailPage />} />\n\n {/* Workflows */}\n <Route path=\"workflows/:selectedId?\" element={<WorkflowsPage />} />\n\n {/* Fallback */}\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { SubOverlap, SubConsolidationResult, SubDecision } from '../../types';
|
|
3
3
|
|
|
4
4
|
export declare const SavingsCard: FC<{
|
|
5
5
|
decision: SubDecision;
|
|
6
6
|
}>;
|
|
7
7
|
export declare const BundleCard: FC<{
|
|
8
|
-
bundle:
|
|
8
|
+
bundle: SubOverlap;
|
|
9
9
|
onConsolidated?: (result: SubConsolidationResult) => void;
|
|
10
10
|
}>;
|
|
11
11
|
//# sourceMappingURL=SavingsCards.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SavingsCards.d.ts","sourceRoot":"","sources":["../../../../src/subscriberbot/components/savings/SavingsCards.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SavingsCards.d.ts","sourceRoot":"","sources":["../../../../src/subscriberbot/components/savings/SavingsCards.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAY,KAAK,EAAE,EAAkB,MAAM,OAAO,CAAC;AA6B1D,OAAO,KAAK,EAEV,UAAU,EAEV,sBAAsB,EACtB,WAAW,EACZ,MAAM,aAAa,CAAC;AA8BrB,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC;IAAE,QAAQ,EAAE,WAAW,CAAA;CAAE,CA0HrD,CAAC;AAySF,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC3D,CAoIA,CAAC"}
|
|
@@ -134,67 +134,88 @@ var L = ({ decision: r }) => {
|
|
|
134
134
|
})
|
|
135
135
|
]
|
|
136
136
|
});
|
|
137
|
-
}, R =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
137
|
+
}, R = {
|
|
138
|
+
keep: "bg-status-success-bg-subtle text-status-success-text",
|
|
139
|
+
cancel: "bg-status-error-bg-subtle text-status-error-text",
|
|
140
|
+
untouched: "bg-bg-sunken text-text-secondary"
|
|
141
|
+
}, z = ({ role: e }) => {
|
|
142
|
+
let n = a(), r = {
|
|
143
|
+
keep: n("savings.bundle.keep", "Keep"),
|
|
144
|
+
cancel: n("savings.bundle.cancel", "Cancel"),
|
|
145
|
+
untouched: n("savings.bundle.leftAlone", "Left alone")
|
|
146
|
+
}[e];
|
|
147
|
+
return /* @__PURE__ */ A("span", {
|
|
148
|
+
className: t("shrink-0 rounded px-1.5 py-0.5 text-[10px] font-medium uppercase", R[e]),
|
|
149
|
+
children: r
|
|
150
|
+
});
|
|
151
|
+
}, B = ({ member: e, role: t }) => /* @__PURE__ */ j("li", {
|
|
152
|
+
className: "flex items-center gap-2.5 rounded-lg border border-border-subtle px-3 py-2 text-sm",
|
|
153
|
+
"data-role": t,
|
|
154
|
+
children: [
|
|
155
|
+
/* @__PURE__ */ A(z, { role: t }),
|
|
156
|
+
/* @__PURE__ */ A("span", {
|
|
157
|
+
className: "min-w-0 flex-1 truncate text-text-primary",
|
|
158
|
+
children: e.label
|
|
159
|
+
}),
|
|
160
|
+
/* @__PURE__ */ A("span", {
|
|
161
|
+
className: "shrink-0 tabular-nums text-text-secondary",
|
|
162
|
+
children: I(e.amount, e.currency, e.interval)
|
|
163
|
+
})
|
|
164
|
+
]
|
|
165
|
+
}), V = ({ bundle: e, onClose: t, onDone: s }) => {
|
|
166
|
+
let c = a(), l = o(), [u, d] = y(""), [f, p] = y("MONTHLY"), [m, v] = y(!1), [b, x] = y(null), { keep: S, cancel: C, untouched: w } = h(e), T = g(u), E = Number.isNaN(T), D = T !== null && !E ? {
|
|
167
|
+
amount: T,
|
|
168
|
+
interval: f
|
|
169
|
+
} : null, O = _(e, D), k = C.map((e) => `"${e.label}"`).join(", "), M = m && !E && !l.isPending && S !== null;
|
|
142
170
|
return /* @__PURE__ */ A(i, {
|
|
143
|
-
title:
|
|
144
|
-
description:
|
|
145
|
-
onClose:
|
|
171
|
+
title: c("savings.bundle.consolidateTitle", "Consolidate subscriptions"),
|
|
172
|
+
description: c("savings.bundle.consolidateDescription", "Keep one subscription and cancel the others. Each cancel is the same change you could make by hand."),
|
|
173
|
+
onClose: t,
|
|
146
174
|
children: /* @__PURE__ */ j("form", {
|
|
147
|
-
onSubmit: (
|
|
148
|
-
|
|
149
|
-
keepRelationshipId:
|
|
150
|
-
cancelRelationshipIds:
|
|
151
|
-
...
|
|
152
|
-
amount:
|
|
153
|
-
interval:
|
|
175
|
+
onSubmit: (n) => {
|
|
176
|
+
n.preventDefault(), M && (x(null), l.mutate({
|
|
177
|
+
keepRelationshipId: e.keepRelationshipId,
|
|
178
|
+
cancelRelationshipIds: C.map((e) => e.relationshipId),
|
|
179
|
+
...D ? {
|
|
180
|
+
amount: D.amount,
|
|
181
|
+
interval: D.interval
|
|
154
182
|
} : {}
|
|
155
183
|
}, {
|
|
156
184
|
onSuccess: (e) => {
|
|
157
|
-
|
|
185
|
+
s(e), t();
|
|
158
186
|
},
|
|
159
|
-
onError: (e) =>
|
|
187
|
+
onError: (e) => x(F(e, c("savings.bundle.consolidateError", "Could not consolidate.")))
|
|
160
188
|
}));
|
|
161
189
|
},
|
|
162
190
|
className: "space-y-4",
|
|
163
191
|
"data-testid": "consolidate-dialog",
|
|
164
192
|
children: [
|
|
165
|
-
/* @__PURE__ */ j("
|
|
166
|
-
className: "mb-1.5 text-xs font-medium text-text-secondary",
|
|
167
|
-
children: l("savings.bundle.keepLabel", "Keep")
|
|
168
|
-
}), /* @__PURE__ */ A("div", {
|
|
193
|
+
/* @__PURE__ */ j("ul", {
|
|
169
194
|
className: "space-y-1.5",
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
})
|
|
191
|
-
]
|
|
192
|
-
}, n.id))
|
|
193
|
-
})] }),
|
|
195
|
+
"data-testid": "consolidate-members",
|
|
196
|
+
children: [
|
|
197
|
+
S && /* @__PURE__ */ A(B, {
|
|
198
|
+
member: S,
|
|
199
|
+
role: "keep"
|
|
200
|
+
}),
|
|
201
|
+
C.map((e) => /* @__PURE__ */ A(B, {
|
|
202
|
+
member: e,
|
|
203
|
+
role: "cancel"
|
|
204
|
+
}, e.relationshipId)),
|
|
205
|
+
w.map((e) => /* @__PURE__ */ A(B, {
|
|
206
|
+
member: e,
|
|
207
|
+
role: "untouched"
|
|
208
|
+
}, e.relationshipId))
|
|
209
|
+
]
|
|
210
|
+
}),
|
|
211
|
+
w.length > 0 && /* @__PURE__ */ A("p", {
|
|
212
|
+
className: "text-xs text-text-secondary",
|
|
213
|
+
children: c("savings.bundle.untouched", "Subscriptions marked \"Left alone\" cover something the kept one does not, so they are not cancelled.")
|
|
214
|
+
}),
|
|
194
215
|
/* @__PURE__ */ j("div", { children: [
|
|
195
216
|
/* @__PURE__ */ A("p", {
|
|
196
217
|
className: "mb-1.5 text-xs font-medium text-text-secondary",
|
|
197
|
-
children:
|
|
218
|
+
children: c("savings.bundle.planLabel", "Bundled plan price for the kept subscription (optional)")
|
|
198
219
|
}),
|
|
199
220
|
/* @__PURE__ */ j("div", {
|
|
200
221
|
className: "flex gap-2",
|
|
@@ -203,17 +224,17 @@ var L = ({ decision: r }) => {
|
|
|
203
224
|
inputMode: "decimal",
|
|
204
225
|
min: "0",
|
|
205
226
|
step: "0.01",
|
|
206
|
-
value:
|
|
207
|
-
onChange: (e) =>
|
|
208
|
-
placeholder:
|
|
209
|
-
"aria-label":
|
|
210
|
-
"aria-invalid":
|
|
227
|
+
value: u,
|
|
228
|
+
onChange: (e) => d(e.target.value),
|
|
229
|
+
placeholder: S ? String(S.amount) : c("savings.bundle.planPlaceholder", "Same price"),
|
|
230
|
+
"aria-label": c("savings.bundle.planAmount", "Bundled plan amount"),
|
|
231
|
+
"aria-invalid": E,
|
|
211
232
|
"data-testid": "consolidate-amount",
|
|
212
233
|
className: "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
|
|
213
234
|
}), /* @__PURE__ */ A("select", {
|
|
214
|
-
value:
|
|
215
|
-
onChange: (e) =>
|
|
216
|
-
"aria-label":
|
|
235
|
+
value: f,
|
|
236
|
+
onChange: (e) => p(e.target.value),
|
|
237
|
+
"aria-label": c("savings.bundle.planInterval", "Billing interval"),
|
|
217
238
|
className: "rounded-lg border border-border-subtle bg-bg-surface px-2 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
|
|
218
239
|
children: P.map((e) => /* @__PURE__ */ A("option", {
|
|
219
240
|
value: e,
|
|
@@ -221,52 +242,52 @@ var L = ({ decision: r }) => {
|
|
|
221
242
|
}, e))
|
|
222
243
|
})]
|
|
223
244
|
}),
|
|
224
|
-
|
|
245
|
+
E && /* @__PURE__ */ A("p", {
|
|
225
246
|
className: "mt-1 text-xs text-status-error-text",
|
|
226
|
-
children:
|
|
247
|
+
children: c("savings.bundle.planInvalid", "Enter zero or a positive amount.")
|
|
227
248
|
})
|
|
228
249
|
] }),
|
|
229
250
|
/* @__PURE__ */ A("p", {
|
|
230
251
|
className: "text-sm text-text-primary",
|
|
231
252
|
"data-testid": "consolidate-projected",
|
|
232
|
-
children:
|
|
253
|
+
children: c("savings.bundle.projected", "Estimated saving: {{amount}} a year", { amount: n(Math.max(O, 0), e.currency) })
|
|
233
254
|
}),
|
|
234
255
|
/* @__PURE__ */ j("label", {
|
|
235
256
|
className: "flex items-start gap-2.5 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text",
|
|
236
257
|
children: [/* @__PURE__ */ A("input", {
|
|
237
258
|
type: "checkbox",
|
|
238
|
-
checked:
|
|
239
|
-
onChange: (e) =>
|
|
259
|
+
checked: m,
|
|
260
|
+
onChange: (e) => v(e.target.checked),
|
|
240
261
|
className: "mt-0.5 size-4 shrink-0 rounded border-border-subtle",
|
|
241
262
|
"data-testid": "consolidate-acknowledge"
|
|
242
|
-
}), /* @__PURE__ */ A("span", { children:
|
|
243
|
-
names:
|
|
244
|
-
keep:
|
|
263
|
+
}), /* @__PURE__ */ A("span", { children: c("savings.bundle.acknowledge", "I want to cancel {{names}} and keep \"{{keep}}\". I understand the cancelled subscriptions will stop.", {
|
|
264
|
+
names: k,
|
|
265
|
+
keep: S?.label ?? ""
|
|
245
266
|
}) })]
|
|
246
267
|
}),
|
|
247
|
-
|
|
268
|
+
b && /* @__PURE__ */ A("div", {
|
|
248
269
|
className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
|
|
249
|
-
children:
|
|
270
|
+
children: b
|
|
250
271
|
}),
|
|
251
272
|
/* @__PURE__ */ j("div", {
|
|
252
273
|
className: "flex justify-end gap-3",
|
|
253
274
|
children: [/* @__PURE__ */ A("button", {
|
|
254
275
|
type: "button",
|
|
255
|
-
onClick:
|
|
276
|
+
onClick: t,
|
|
256
277
|
className: "rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
|
|
257
|
-
children:
|
|
278
|
+
children: c("decisions.apply.back", "Not now")
|
|
258
279
|
}), /* @__PURE__ */ A("button", {
|
|
259
280
|
type: "submit",
|
|
260
|
-
disabled: !
|
|
281
|
+
disabled: !M,
|
|
261
282
|
"data-testid": "confirm-consolidate",
|
|
262
283
|
className: "rounded-lg bg-action-danger-bg px-4 py-2 text-sm font-medium text-action-danger-text hover:bg-action-danger-bg-hover disabled:cursor-not-allowed disabled:opacity-50",
|
|
263
|
-
children:
|
|
284
|
+
children: l.isPending ? c("savings.bundle.consolidating", "Consolidating…") : c("savings.bundle.consolidateSubmit", "Consolidate")
|
|
264
285
|
})]
|
|
265
286
|
})
|
|
266
287
|
]
|
|
267
288
|
})
|
|
268
289
|
});
|
|
269
|
-
},
|
|
290
|
+
}, H = ({ bundle: e, onClose: t }) => {
|
|
270
291
|
let n = a(), r = s(), [o, c] = y(""), [l, u] = y(null);
|
|
271
292
|
return /* @__PURE__ */ A(i, {
|
|
272
293
|
title: n("savings.bundle.dismissTitle", "Dismiss bundle suggestion"),
|
|
@@ -320,14 +341,18 @@ var L = ({ decision: r }) => {
|
|
|
320
341
|
]
|
|
321
342
|
})
|
|
322
343
|
});
|
|
323
|
-
},
|
|
324
|
-
let
|
|
344
|
+
}, U = ({ bundle: t, onConsolidated: r }) => {
|
|
345
|
+
let i = a(), { navigateTo: o } = e(), [s, c] = y(null), { keep: u, cancel: d } = h(t), f = new Set(t.dropRelationshipIds), p = {
|
|
346
|
+
EXACT_DUPLICATE: i("savings.bundle.exactDuplicate", "Merge duplicate subscriptions"),
|
|
347
|
+
CAPABILITY: i("savings.bundle.capability", "Several services for {{capability}}", { capability: t.title }),
|
|
348
|
+
ENTITLEMENT: i("savings.bundle.entitlement", "Covered by a subscription you keep")
|
|
349
|
+
}[t.type], m = t.annualSpend - t.annualSavings;
|
|
325
350
|
return /* @__PURE__ */ j(M, {
|
|
326
351
|
treatment: "metric",
|
|
327
352
|
className: "flex flex-col gap-3 border border-status-warning-text/30 p-4",
|
|
328
353
|
"data-testid": "bundle-card",
|
|
329
|
-
"data-bundle-id":
|
|
330
|
-
"data-
|
|
354
|
+
"data-bundle-id": t.id,
|
|
355
|
+
"data-type": t.type,
|
|
331
356
|
children: [
|
|
332
357
|
/* @__PURE__ */ j("div", {
|
|
333
358
|
className: "flex items-start gap-3",
|
|
@@ -341,41 +366,39 @@ var L = ({ decision: r }) => {
|
|
|
341
366
|
className: "min-w-0 flex-1",
|
|
342
367
|
children: [/* @__PURE__ */ j("p", {
|
|
343
368
|
className: "text-[11px] font-medium uppercase tracking-wide text-text-secondary",
|
|
344
|
-
children: [
|
|
369
|
+
children: [i("savings.bundle.label", "Bundle suggestion"), t.type === "EXACT_DUPLICATE" && t.title ? ` · ${t.title}` : ""]
|
|
345
370
|
}), /* @__PURE__ */ A("p", {
|
|
346
371
|
className: "text-sm font-semibold text-text-primary",
|
|
347
|
-
children:
|
|
372
|
+
children: p
|
|
348
373
|
})]
|
|
349
374
|
}),
|
|
350
375
|
/* @__PURE__ */ j("p", {
|
|
351
376
|
className: "shrink-0 text-right text-sm font-semibold tabular-nums text-status-success-text",
|
|
352
377
|
"data-testid": "bundle-card-amount",
|
|
353
|
-
children: [
|
|
378
|
+
children: [i("savings.card.save", "Save {{amount}}", { amount: n(t.annualSavings, t.currency) }), /* @__PURE__ */ A("span", {
|
|
354
379
|
className: "block text-[11px] font-normal text-text-secondary",
|
|
355
|
-
children:
|
|
380
|
+
children: i("savings.card.perYear", "per year")
|
|
356
381
|
})]
|
|
357
382
|
})
|
|
358
383
|
]
|
|
359
384
|
}),
|
|
360
385
|
/* @__PURE__ */ A("p", {
|
|
361
386
|
className: "text-sm text-text-secondary",
|
|
362
|
-
children:
|
|
387
|
+
children: t.rationale
|
|
363
388
|
}),
|
|
364
389
|
/* @__PURE__ */ A("ul", {
|
|
365
390
|
className: "space-y-1",
|
|
366
391
|
"data-testid": "bundle-relationships",
|
|
367
|
-
children:
|
|
368
|
-
let n = e.
|
|
392
|
+
children: t.members.map((e) => {
|
|
393
|
+
let n = e.relationshipId === t.keepRelationshipId ? "keep" : f.has(e.relationshipId) ? "cancel" : "untouched";
|
|
369
394
|
return /* @__PURE__ */ A("li", { children: /* @__PURE__ */ j("button", {
|
|
370
395
|
type: "button",
|
|
371
|
-
onClick: () =>
|
|
372
|
-
"data-relationship-id": e.
|
|
396
|
+
onClick: () => o(`/relationships/${e.relationshipId}`),
|
|
397
|
+
"data-relationship-id": e.relationshipId,
|
|
398
|
+
"data-role": n,
|
|
373
399
|
className: "flex w-full items-center gap-2 rounded-md border border-border-subtle bg-bg-sunken px-2.5 py-1.5 text-left text-xs hover:bg-bg-surface",
|
|
374
400
|
children: [
|
|
375
|
-
/* @__PURE__ */ A(
|
|
376
|
-
className: t("shrink-0 rounded px-1.5 py-0.5 text-[10px] font-medium uppercase", n ? "bg-status-success-bg-subtle text-status-success-text" : "bg-status-error-bg-subtle text-status-error-text"),
|
|
377
|
-
children: n ? s("savings.bundle.keep", "Keep") : s("savings.bundle.cancel", "Cancel")
|
|
378
|
-
}),
|
|
401
|
+
/* @__PURE__ */ A(z, { role: n }),
|
|
379
402
|
/* @__PURE__ */ A("span", {
|
|
380
403
|
className: "min-w-0 flex-1 truncate font-medium text-text-primary",
|
|
381
404
|
children: e.label
|
|
@@ -389,60 +412,61 @@ var L = ({ decision: r }) => {
|
|
|
389
412
|
"aria-hidden": !0
|
|
390
413
|
})
|
|
391
414
|
]
|
|
392
|
-
}) }, e.
|
|
415
|
+
}) }, e.relationshipId);
|
|
393
416
|
})
|
|
394
417
|
}),
|
|
395
418
|
/* @__PURE__ */ j("div", {
|
|
396
419
|
className: "flex flex-wrap gap-2 text-xs",
|
|
397
420
|
children: [/* @__PURE__ */ A("span", {
|
|
398
421
|
className: "inline-flex items-center rounded-md bg-bg-sunken px-2 py-0.5 tabular-nums text-text-secondary",
|
|
399
|
-
children:
|
|
400
|
-
before: n(
|
|
401
|
-
after: n(
|
|
422
|
+
children: i("savings.bundle.costChange", "{{before}} → {{after}} a year", {
|
|
423
|
+
before: n(t.annualSpend, t.currency),
|
|
424
|
+
after: n(m, t.currency)
|
|
402
425
|
})
|
|
403
426
|
}), /* @__PURE__ */ j("span", {
|
|
404
427
|
className: "inline-flex items-center gap-1.5 rounded-md bg-bg-sunken px-2 py-0.5 text-text-secondary",
|
|
405
428
|
children: [/* @__PURE__ */ A(T, {
|
|
406
429
|
className: "h-3.5 w-3.5",
|
|
407
430
|
"aria-hidden": !0
|
|
408
|
-
}),
|
|
431
|
+
}), i("decisions.card.confidence", "Confidence {{pct}}%", { pct: l(t.confidence) })]
|
|
409
432
|
})]
|
|
410
433
|
}),
|
|
411
434
|
/* @__PURE__ */ j("div", {
|
|
412
435
|
className: "flex flex-wrap justify-end gap-2 border-t border-border-subtle pt-3",
|
|
413
436
|
children: [/* @__PURE__ */ j("button", {
|
|
414
437
|
type: "button",
|
|
415
|
-
onClick: () =>
|
|
438
|
+
onClick: () => c("dismiss"),
|
|
416
439
|
"data-testid": "bundle-dismiss",
|
|
417
440
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken",
|
|
418
441
|
children: [/* @__PURE__ */ A(k, {
|
|
419
442
|
className: "h-3.5 w-3.5",
|
|
420
443
|
"aria-hidden": !0
|
|
421
|
-
}),
|
|
444
|
+
}), i("decisions.card.dismiss", "Dismiss")]
|
|
422
445
|
}), /* @__PURE__ */ j("button", {
|
|
423
446
|
type: "button",
|
|
424
|
-
onClick: () =>
|
|
447
|
+
onClick: () => c("consolidate"),
|
|
448
|
+
disabled: !u || d.length === 0,
|
|
425
449
|
"data-testid": "bundle-consolidate",
|
|
426
|
-
className: "inline-flex items-center gap-1.5 rounded-lg border border-status-error-text/40 bg-status-error-bg-subtle px-3 py-1.5 text-xs font-medium text-status-error-text hover:opacity-90",
|
|
450
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-status-error-text/40 bg-status-error-bg-subtle px-3 py-1.5 text-xs font-medium text-status-error-text hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50",
|
|
427
451
|
children: [/* @__PURE__ */ A(D, {
|
|
428
452
|
className: "h-3.5 w-3.5",
|
|
429
453
|
"aria-hidden": !0
|
|
430
|
-
}),
|
|
454
|
+
}), i("savings.bundle.consolidate", "Review and consolidate")]
|
|
431
455
|
})]
|
|
432
456
|
}),
|
|
433
|
-
|
|
434
|
-
bundle:
|
|
435
|
-
onClose: () =>
|
|
436
|
-
onDone: (e) =>
|
|
457
|
+
s === "consolidate" && /* @__PURE__ */ A(V, {
|
|
458
|
+
bundle: t,
|
|
459
|
+
onClose: () => c(null),
|
|
460
|
+
onDone: (e) => r?.(e)
|
|
437
461
|
}),
|
|
438
|
-
|
|
439
|
-
bundle:
|
|
440
|
-
onClose: () =>
|
|
462
|
+
s === "dismiss" && /* @__PURE__ */ A(H, {
|
|
463
|
+
bundle: t,
|
|
464
|
+
onClose: () => c(null)
|
|
441
465
|
})
|
|
442
466
|
]
|
|
443
467
|
});
|
|
444
468
|
};
|
|
445
469
|
//#endregion
|
|
446
|
-
export {
|
|
470
|
+
export { U as BundleCard, L as SavingsCard };
|
|
447
471
|
|
|
448
472
|
//# sourceMappingURL=SavingsCards.js.map
|