@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.
Files changed (32) hide show
  1. package/dist/subscriberbot/SubscriberBotRoutes.d.ts.map +1 -1
  2. package/dist/subscriberbot/SubscriberBotRoutes.js +10 -6
  3. package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
  4. package/dist/subscriberbot/components/savings/SavingsCards.d.ts +2 -2
  5. package/dist/subscriberbot/components/savings/SavingsCards.d.ts.map +1 -1
  6. package/dist/subscriberbot/components/savings/SavingsCards.js +128 -104
  7. package/dist/subscriberbot/components/savings/SavingsCards.js.map +1 -1
  8. package/dist/subscriberbot/components/savings/savingsModel.d.ts +14 -9
  9. package/dist/subscriberbot/components/savings/savingsModel.d.ts.map +1 -1
  10. package/dist/subscriberbot/components/savings/savingsModel.js +9 -7
  11. package/dist/subscriberbot/components/savings/savingsModel.js.map +1 -1
  12. package/dist/subscriberbot/hooks/index.d.ts +1 -1
  13. package/dist/subscriberbot/hooks/index.d.ts.map +1 -1
  14. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts +4 -1
  15. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts.map +1 -1
  16. package/dist/subscriberbot/hooks/useSubscriberBotApi.js +137 -72
  17. package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
  18. package/dist/subscriberbot/pages/SavingsPage.js +1 -1
  19. package/dist/subscriberbot/pages/SavingsPage.js.map +1 -1
  20. package/dist/subscriberbot/pages/enterprise/EnterpriseSpendPage.d.ts +13 -0
  21. package/dist/subscriberbot/pages/enterprise/EnterpriseSpendPage.d.ts.map +1 -0
  22. package/dist/subscriberbot/pages/enterprise/EnterpriseSpendPage.js +703 -0
  23. package/dist/subscriberbot/pages/enterprise/EnterpriseSpendPage.js.map +1 -0
  24. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts.map +1 -1
  25. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +276 -262
  26. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  27. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.d.ts.map +1 -1
  28. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +65 -45
  29. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -1
  30. package/dist/subscriberbot/types/index.d.ts +171 -15
  31. package/dist/subscriberbot/types/index.d.ts.map +1 -1
  32. 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;AAmFhD,eAAO,MAAM,mBAAmB,EAAE,EAkEjC,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
- }), k = () => {
12
- let { basePath: r, isStandalone: u } = e(), k = s(), A = r === "/" ? "" : (r ?? "").replace(/\/$/, "");
13
- return A && !u && !(k.pathname === A || k.pathname.startsWith(A + "/")) ? null : /* @__PURE__ */ c("div", {
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(O, {}),
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 { k as SubscriberBotRoutes };
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 { SubBundleRecommendation, SubConsolidationResult, SubDecision } from '../../types';
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: SubBundleRecommendation;
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;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAY,KAAK,EAAE,EAAkB,MAAM,OAAO,CAAC;AA6B1D,OAAO,KAAK,EAEV,uBAAuB,EACvB,sBAAsB,EACtB,WAAW,EACZ,MAAM,aAAa,CAAC;AA8BrB,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC;IAAE,QAAQ,EAAE,WAAW,CAAA;CAAE,CA0HrD,CAAC;AAgRF,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC;IAC1B,MAAM,EAAE,uBAAuB,CAAC;IAChC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC3D,CAkIA,CAAC"}
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 = ({ bundle: e, onClose: s, onDone: c }) => {
138
- let l = a(), u = o(), [d, f] = y(e.keepRelationshipId), [p, m] = y(""), [v, b] = y("MONTHLY"), [x, S] = y(!1), [C, w] = y(null), { keep: T, cancel: E } = h(e, d), D = g(p), O = Number.isNaN(D), k = D !== null && !O ? {
139
- amount: D,
140
- interval: v
141
- } : null, M = _(e, d, k), N = E.map((e) => `"${e.label}"`).join(", "), L = x && !O && !u.isPending && T !== null;
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: l("savings.bundle.consolidateTitle", "Consolidate subscriptions"),
144
- description: l("savings.bundle.consolidateDescription", "Keep one subscription and cancel the others. Each cancel is the same change you could make by hand."),
145
- onClose: s,
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: (e) => {
148
- e.preventDefault(), L && (w(null), u.mutate({
149
- keepRelationshipId: d,
150
- cancelRelationshipIds: E.map((e) => e.id),
151
- ...k ? {
152
- amount: k.amount,
153
- interval: k.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
- c(e), s();
185
+ s(e), t();
158
186
  },
159
- onError: (e) => w(F(e, l("savings.bundle.consolidateError", "Could not consolidate.")))
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("fieldset", { children: [/* @__PURE__ */ A("legend", {
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
- children: e.relationships.map((n) => /* @__PURE__ */ j("label", {
171
- className: t("flex items-center gap-2.5 rounded-lg border px-3 py-2 text-sm", n.id === d ? "border-action-primary-bg bg-bg-sunken" : "border-border-subtle"),
172
- children: [
173
- /* @__PURE__ */ A("input", {
174
- type: "radio",
175
- name: `keep-${e.id}`,
176
- value: n.id,
177
- checked: n.id === d,
178
- onChange: () => {
179
- f(n.id), S(!1);
180
- },
181
- className: "size-4 shrink-0"
182
- }),
183
- /* @__PURE__ */ A("span", {
184
- className: "min-w-0 flex-1 truncate text-text-primary",
185
- children: n.label
186
- }),
187
- /* @__PURE__ */ A("span", {
188
- className: "shrink-0 tabular-nums text-text-secondary",
189
- children: I(n.amount, n.currency, n.interval)
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: l("savings.bundle.planLabel", "Bundled plan price for the kept subscription (optional)")
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: p,
207
- onChange: (e) => m(e.target.value),
208
- placeholder: T ? String(T.amount) : l("savings.bundle.planPlaceholder", "Same price"),
209
- "aria-label": l("savings.bundle.planAmount", "Bundled plan amount"),
210
- "aria-invalid": O,
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: v,
215
- onChange: (e) => b(e.target.value),
216
- "aria-label": l("savings.bundle.planInterval", "Billing interval"),
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
- O && /* @__PURE__ */ A("p", {
245
+ E && /* @__PURE__ */ A("p", {
225
246
  className: "mt-1 text-xs text-status-error-text",
226
- children: l("savings.bundle.planInvalid", "Enter zero or a positive amount.")
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: l("savings.bundle.projected", "Estimated saving: {{amount}} a year", { amount: n(Math.max(M, 0), e.currency) })
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: x,
239
- onChange: (e) => S(e.target.checked),
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: l("savings.bundle.acknowledge", "I want to cancel {{names}} and keep \"{{keep}}\". I understand the cancelled subscriptions will stop.", {
243
- names: N,
244
- keep: T?.label ?? ""
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
- C && /* @__PURE__ */ A("div", {
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: C
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: s,
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: l("decisions.apply.back", "Not now")
278
+ children: c("decisions.apply.back", "Not now")
258
279
  }), /* @__PURE__ */ A("button", {
259
280
  type: "submit",
260
- disabled: !L,
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: u.isPending ? l("savings.bundle.consolidating", "Consolidating…") : l("savings.bundle.consolidateSubmit", "Consolidate")
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
- }, z = ({ bundle: e, onClose: t }) => {
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
- }, B = ({ bundle: i, onConsolidated: o }) => {
324
- let s = a(), { navigateTo: c } = e(), [u, d] = y(null), f = i.basis === "SAME_PROVIDER" ? s("savings.bundle.sameProvider", "Merge duplicate subscriptions") : s("savings.bundle.sameCategory", "Overlapping {{category}} services", { category: r(i.category ?? "OTHER").toLowerCase() });
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": i.id,
330
- "data-basis": i.basis,
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: [s("savings.bundle.label", "Bundle suggestion"), i.providerName ? ` · ${i.providerName}` : ""]
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: f
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: [s("savings.card.save", "Save {{amount}}", { amount: n(i.estimatedSavings, i.currency) }), /* @__PURE__ */ A("span", {
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: s("savings.card.perYear", "per year")
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: i.rationale
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: i.relationships.map((e) => {
368
- let n = e.id === i.keepRelationshipId;
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: () => c(`/relationships/${e.id}`),
372
- "data-relationship-id": e.id,
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("span", {
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.id);
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: s("savings.bundle.costChange", "{{before}} → {{after}} a year", {
400
- before: n(i.currentAnnualCost, i.currency),
401
- after: n(i.projectedAnnualCost, i.currency)
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
- }), s("decisions.card.confidence", "Confidence {{pct}}%", { pct: l(i.confidence) })]
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: () => d("dismiss"),
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
- }), s("decisions.card.dismiss", "Dismiss")]
444
+ }), i("decisions.card.dismiss", "Dismiss")]
422
445
  }), /* @__PURE__ */ j("button", {
423
446
  type: "button",
424
- onClick: () => d("consolidate"),
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
- }), s("savings.bundle.consolidate", "Review and consolidate")]
454
+ }), i("savings.bundle.consolidate", "Review and consolidate")]
431
455
  })]
432
456
  }),
433
- u === "consolidate" && /* @__PURE__ */ A(R, {
434
- bundle: i,
435
- onClose: () => d(null),
436
- onDone: (e) => o?.(e)
457
+ s === "consolidate" && /* @__PURE__ */ A(V, {
458
+ bundle: t,
459
+ onClose: () => c(null),
460
+ onDone: (e) => r?.(e)
437
461
  }),
438
- u === "dismiss" && /* @__PURE__ */ A(z, {
439
- bundle: i,
440
- onClose: () => d(null)
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 { B as BundleCard, L as SavingsCard };
470
+ export { U as BundleCard, L as SavingsCard };
447
471
 
448
472
  //# sourceMappingURL=SavingsCards.js.map