@burdenoff/microfe-planmagnet 2026.1002.1 → 2026.1002.3
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/generated/wspace-operations.d.ts +2533 -546
- package/dist/generated/wspace-operations.d.ts.map +1 -1
- package/dist/generated/wspace-types.d.ts +5654 -71
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +180 -162
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +100 -84
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/board/BulkActions.d.ts.map +1 -1
- package/dist/planmagnet/board/BulkActions.js +106 -55
- package/dist/planmagnet/board/BulkActions.js.map +1 -1
- package/dist/planmagnet/controls/Pickers.d.ts +10 -5
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +10 -9
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/dashboards/DashboardUI.d.ts +0 -4
- package/dist/planmagnet/dashboards/DashboardUI.d.ts.map +1 -1
- package/dist/planmagnet/dashboards/DashboardUI.js +6 -13
- package/dist/planmagnet/dashboards/DashboardUI.js.map +1 -1
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.d.ts.map +1 -1
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js +70 -59
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js.map +1 -1
- package/dist/planmagnet/forecast/ResourceForecastCard.js +1 -1
- package/dist/planmagnet/forecast/ResourceForecastCard.js.map +1 -1
- package/dist/planmagnet/index.d.ts +1 -1
- package/dist/planmagnet/index.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.d.ts +3 -3
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.js +26 -19
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.js.map +1 -1
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.d.ts +2 -2
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.js +18 -12
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.js +251 -0
- package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js +4 -4
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +133 -131
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +5 -5
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +6 -6
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +107 -82
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.js +174 -0
- package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.js +350 -0
- package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsProductLinesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsProductLinesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsProductLinesPagePage.js +168 -0
- package/dist/planmagnet/pages/ProductsProductLinesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +116 -114
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +174 -159
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +159 -145
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js +161 -143
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +160 -156
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryKpisCard.d.ts.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js +97 -99
- package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js.map +1 -1
- package/dist/planmagnet/product/FeatureLinkPanels.d.ts +29 -0
- package/dist/planmagnet/product/FeatureLinkPanels.d.ts.map +1 -0
- package/dist/planmagnet/product/FeatureLinkPanels.js +373 -0
- package/dist/planmagnet/product/FeatureLinkPanels.js.map +1 -0
- package/dist/planmagnet/product/ProductControls.js +1 -1
- package/dist/planmagnet/product/ProductControls.js.map +1 -1
- package/dist/planmagnet/product/ProductFeatureControls.d.ts +39 -0
- package/dist/planmagnet/product/ProductFeatureControls.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductFeatureControls.js +315 -0
- package/dist/planmagnet/product/ProductFeatureControls.js.map +1 -0
- package/dist/planmagnet/product/ProductFeatureLinkCard.d.ts +4 -0
- package/dist/planmagnet/product/ProductFeatureLinkCard.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductFeatureLinkCard.js +192 -0
- package/dist/planmagnet/product/ProductFeatureLinkCard.js.map +1 -0
- package/dist/planmagnet/product/ProductLineControls.d.ts +52 -0
- package/dist/planmagnet/product/ProductLineControls.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductLineControls.js +417 -0
- package/dist/planmagnet/product/ProductLineControls.js.map +1 -0
- package/dist/planmagnet/product/ProductTeamsPanel.d.ts +4 -0
- package/dist/planmagnet/product/ProductTeamsPanel.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductTeamsPanel.js +129 -0
- package/dist/planmagnet/product/ProductTeamsPanel.js.map +1 -0
- package/dist/planmagnet/product/WorkItemProductFeatureChip.d.ts +4 -0
- package/dist/planmagnet/product/WorkItemProductFeatureChip.d.ts.map +1 -0
- package/dist/planmagnet/product/WorkItemProductFeatureChip.js +41 -0
- package/dist/planmagnet/product/WorkItemProductFeatureChip.js.map +1 -0
- package/dist/planmagnet/product/hierarchy.d.ts +127 -0
- package/dist/planmagnet/product/hierarchy.d.ts.map +1 -0
- package/dist/planmagnet/product/hierarchy.js +173 -0
- package/dist/planmagnet/product/hierarchy.js.map +1 -0
- package/dist/planmagnet/product/hierarchyOperations.d.ts +35 -0
- package/dist/planmagnet/product/hierarchyOperations.d.ts.map +1 -0
- package/dist/planmagnet/product/hierarchyOperations.js +440 -0
- package/dist/planmagnet/product/hierarchyOperations.js.map +1 -0
- package/dist/planmagnet/product/refusal.d.ts +14 -0
- package/dist/planmagnet/product/refusal.d.ts.map +1 -0
- package/dist/planmagnet/product/refusal.js +10 -0
- package/dist/planmagnet/product/refusal.js.map +1 -0
- package/dist/planmagnet/product/routes.d.ts +10 -0
- package/dist/planmagnet/product/routes.d.ts.map +1 -1
- package/dist/planmagnet/product/routes.js +2 -2
- package/dist/planmagnet/product/routes.js.map +1 -1
- package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.d.ts +20 -0
- package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.js +55 -0
- package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionFigures.d.ts +30 -0
- package/dist/planmagnet/satisfaction/SatisfactionFigures.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionFigures.js +282 -0
- package/dist/planmagnet/satisfaction/SatisfactionFigures.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionImportDialog.d.ts +9 -0
- package/dist/planmagnet/satisfaction/SatisfactionImportDialog.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionImportDialog.js +390 -0
- package/dist/planmagnet/satisfaction/SatisfactionImportDialog.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionLinkFields.d.ts +17 -0
- package/dist/planmagnet/satisfaction/SatisfactionLinkFields.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionLinkFields.js +77 -0
- package/dist/planmagnet/satisfaction/SatisfactionLinkFields.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.d.ts +18 -0
- package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.js +87 -0
- package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.d.ts +13 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.js +326 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.d.ts +23 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.js +258 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.d.ts +6 -0
- package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.js +56 -0
- package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.d.ts +16 -0
- package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.js +102 -0
- package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.js.map +1 -0
- package/dist/planmagnet/satisfaction/satisfaction.d.ts +154 -0
- package/dist/planmagnet/satisfaction/satisfaction.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/satisfaction.js +210 -0
- package/dist/planmagnet/satisfaction/satisfaction.js.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionCsv.d.ts +108 -0
- package/dist/planmagnet/satisfaction/satisfactionCsv.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionCsv.js +211 -0
- package/dist/planmagnet/satisfaction/satisfactionCsv.js.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionForm.d.ts +90 -0
- package/dist/planmagnet/satisfaction/satisfactionForm.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionForm.js +90 -0
- package/dist/planmagnet/satisfaction/satisfactionForm.js.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionOperations.d.ts +116 -0
- package/dist/planmagnet/satisfaction/satisfactionOperations.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionOperations.js +86 -0
- package/dist/planmagnet/satisfaction/satisfactionOperations.js.map +1 -0
- package/dist/planmagnet/satisfaction/useSatisfactionAccess.d.ts +20 -0
- package/dist/planmagnet/satisfaction/useSatisfactionAccess.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/useSatisfactionAccess.js +31 -0
- package/dist/planmagnet/satisfaction/useSatisfactionAccess.js.map +1 -0
- package/dist/planmagnet/skills/RequiredSkillsEditor.d.ts +35 -0
- package/dist/planmagnet/skills/RequiredSkillsEditor.d.ts.map +1 -0
- package/dist/planmagnet/skills/RequiredSkillsEditor.js +124 -0
- package/dist/planmagnet/skills/RequiredSkillsEditor.js.map +1 -0
- package/dist/planmagnet/skills/SkillChips.d.ts +30 -0
- package/dist/planmagnet/skills/SkillChips.d.ts.map +1 -0
- package/dist/planmagnet/skills/SkillChips.js +57 -0
- package/dist/planmagnet/skills/SkillChips.js.map +1 -0
- package/dist/planmagnet/skills/SkillCoverageCard.d.ts +24 -0
- package/dist/planmagnet/skills/SkillCoverageCard.d.ts.map +1 -0
- package/dist/planmagnet/skills/SkillCoverageCard.js +256 -0
- package/dist/planmagnet/skills/SkillCoverageCard.js.map +1 -0
- package/dist/planmagnet/skills/WorkItemRequiredSkills.d.ts +10 -0
- package/dist/planmagnet/skills/WorkItemRequiredSkills.d.ts.map +1 -0
- package/dist/planmagnet/skills/WorkItemRequiredSkills.js +65 -0
- package/dist/planmagnet/skills/WorkItemRequiredSkills.js.map +1 -0
- package/dist/planmagnet/skills/skillOperations.d.ts +52 -0
- package/dist/planmagnet/skills/skillOperations.d.ts.map +1 -0
- package/dist/planmagnet/skills/skillOperations.js +44 -0
- package/dist/planmagnet/skills/skillOperations.js.map +1 -0
- package/dist/planmagnet/skills/skillTags.d.ts +103 -0
- package/dist/planmagnet/skills/skillTags.d.ts.map +1 -0
- package/dist/planmagnet/skills/skillTags.js +115 -0
- package/dist/planmagnet/skills/skillTags.js.map +1 -0
- package/dist/planmagnet/skills/useRequiredSkillsDraft.d.ts +28 -0
- package/dist/planmagnet/skills/useRequiredSkillsDraft.d.ts.map +1 -0
- package/dist/planmagnet/skills/useRequiredSkillsDraft.js +30 -0
- package/dist/planmagnet/skills/useRequiredSkillsDraft.js.map +1 -0
- package/dist/shared/utils/i18n.d.ts +3 -0
- package/dist/shared/utils/i18n.d.ts.map +1 -1
- package/dist/shared/utils/i18n.js +1 -1
- package/dist/shared/utils/i18n.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SatisfactionFigures.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/satisfaction/SatisfactionFigures.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAEjD,OAAO,EAAgD,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAClG,OAAO,KAAK,EAEV,2BAA2B,EAE3B,sBAAsB,EACvB,MAAM,0BAA0B,CAAC;AAElC;;;;GAIG;AAEH,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AAEnC,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAUzE;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GAAG,MAAM,CAa1F;AAUD;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAOxD,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,aAAa,GAAG,MAAM,CAarE;AA8JD,iDAAiD;AACjD,wBAAgB,uBAAuB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,2BAA2B,CAAA;CAAE,2CAO5F;AA+BD,+GAA+G;AAC/G,wBAAgB,0BAA0B,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,2BAA2B,CAAA;CAAE,2CAuC/F"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { cn as t } from "../utils/cn.js";
|
|
3
|
+
import { formatCsat as n, formatNps as r, formatUtcDay as i, shareOf as a } from "./satisfaction.js";
|
|
4
|
+
import { Gauge as o, Smile as s } from "lucide-react";
|
|
5
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
6
|
+
import { Card as u, CardContent as d, CardHeader as f, CardTitle as p } from "@burdenoff/fe-libs/ui";
|
|
7
|
+
//#region src/planmagnet/satisfaction/SatisfactionFigures.tsx
|
|
8
|
+
function m(e, t) {
|
|
9
|
+
return t === 0 ? e("planmagnet.satisfaction.responses.none", "No responses") : t === 1 ? e("planmagnet.satisfaction.responses.one", "1 response") : e("planmagnet.satisfaction.responses.many", "{{count}} responses", { count: t });
|
|
10
|
+
}
|
|
11
|
+
function h(e, t) {
|
|
12
|
+
let n = e("planmagnet.satisfaction.window.span", "{{from}} – {{to}}", {
|
|
13
|
+
from: i(t.from),
|
|
14
|
+
to: i(t.to)
|
|
15
|
+
});
|
|
16
|
+
return t.preset === "CUSTOM" ? n : e("planmagnet.satisfaction.window.presetWithSpan", "{{preset}} ({{span}})", {
|
|
17
|
+
preset: g(e, t.preset),
|
|
18
|
+
span: n
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function g(e, t) {
|
|
22
|
+
switch (t) {
|
|
23
|
+
case "LAST_30_DAYS": return e("planmagnet.satisfaction.window.last30", "Last 30 days");
|
|
24
|
+
case "LAST_90_DAYS": return e("planmagnet.satisfaction.window.last90", "Last 90 days");
|
|
25
|
+
case "LAST_180_DAYS": return e("planmagnet.satisfaction.window.last180", "Last 180 days");
|
|
26
|
+
case "LAST_365_DAYS": return e("planmagnet.satisfaction.window.last365", "Last 365 days");
|
|
27
|
+
default: return e("planmagnet.satisfaction.window.custom", "Custom");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function _(e, t) {
|
|
31
|
+
return e("planmagnet.satisfaction.notEnoughDetail", "{{count}} so far — a score needs at least {{minimum}} responses.", {
|
|
32
|
+
count: t.responseCount,
|
|
33
|
+
minimum: t.minimumResponses
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
var v = {
|
|
37
|
+
satisfied: "bg-status-success-bg-subtle text-status-success-text",
|
|
38
|
+
promoter: "bg-status-success-bg-subtle text-status-success-text",
|
|
39
|
+
passive: "bg-status-warning-bg-subtle text-foreground",
|
|
40
|
+
notSatisfied: "bg-status-error-bg-subtle text-status-error-text",
|
|
41
|
+
detractor: "bg-status-error-bg-subtle text-status-error-text"
|
|
42
|
+
};
|
|
43
|
+
function y(e, t) {
|
|
44
|
+
switch (t) {
|
|
45
|
+
case "satisfied": return e("planmagnet.satisfaction.category.satisfied", "Satisfied");
|
|
46
|
+
case "notSatisfied": return e("planmagnet.satisfaction.category.notSatisfied", "Not satisfied");
|
|
47
|
+
case "promoter": return e("planmagnet.satisfaction.category.promoter", "Promoter");
|
|
48
|
+
case "passive": return e("planmagnet.satisfaction.category.passive", "Passive");
|
|
49
|
+
default: return e("planmagnet.satisfaction.category.detractor", "Detractor");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function b({ nps: n }) {
|
|
53
|
+
let r = e(), i = [
|
|
54
|
+
{
|
|
55
|
+
key: "promoters",
|
|
56
|
+
label: r("planmagnet.satisfaction.nps.promoters", "Promoters (9–10)"),
|
|
57
|
+
count: n.promoterCount,
|
|
58
|
+
bar: "bg-status-success-bg"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: "passives",
|
|
62
|
+
label: r("planmagnet.satisfaction.nps.passives", "Passives (7–8)"),
|
|
63
|
+
count: n.passiveCount,
|
|
64
|
+
bar: "bg-status-warning-bg"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
key: "detractors",
|
|
68
|
+
label: r("planmagnet.satisfaction.nps.detractors", "Detractors (0–6)"),
|
|
69
|
+
count: n.detractorCount,
|
|
70
|
+
bar: "bg-status-error-bg"
|
|
71
|
+
}
|
|
72
|
+
], o = !n.notEnoughResponses && n.responseCount > 0;
|
|
73
|
+
return /* @__PURE__ */ l("div", {
|
|
74
|
+
className: "space-y-2",
|
|
75
|
+
"data-testid": "satisfaction-nps-split",
|
|
76
|
+
children: [o && /* @__PURE__ */ c("div", {
|
|
77
|
+
className: "flex h-2 w-full overflow-hidden rounded-full bg-muted",
|
|
78
|
+
"aria-hidden": !0,
|
|
79
|
+
children: i.map((e) => /* @__PURE__ */ c("div", {
|
|
80
|
+
className: e.bar,
|
|
81
|
+
style: { width: `${e.count * 100 / n.responseCount}%` }
|
|
82
|
+
}, e.key))
|
|
83
|
+
}), /* @__PURE__ */ c("dl", {
|
|
84
|
+
className: "grid grid-cols-3 gap-2 text-xs",
|
|
85
|
+
children: i.map((e) => /* @__PURE__ */ l("div", {
|
|
86
|
+
className: "min-w-0",
|
|
87
|
+
children: [/* @__PURE__ */ l("dt", {
|
|
88
|
+
className: "flex items-center gap-1.5 text-muted-foreground",
|
|
89
|
+
children: [/* @__PURE__ */ c("span", {
|
|
90
|
+
className: t("h-2 w-2 shrink-0 rounded-full", e.bar),
|
|
91
|
+
"aria-hidden": !0
|
|
92
|
+
}), /* @__PURE__ */ c("span", {
|
|
93
|
+
className: "truncate",
|
|
94
|
+
children: e.label
|
|
95
|
+
})]
|
|
96
|
+
}), /* @__PURE__ */ c("dd", {
|
|
97
|
+
className: "mt-0.5 font-medium tabular-nums",
|
|
98
|
+
children: o ? r("planmagnet.satisfaction.nps.countWithShare", "{{count}} ({{share}}%)", {
|
|
99
|
+
count: e.count,
|
|
100
|
+
share: a(e.count, n.responseCount)
|
|
101
|
+
}) : e.count
|
|
102
|
+
})]
|
|
103
|
+
}, e.key))
|
|
104
|
+
})]
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function x({ value: t, notEnough: n, testId: r }) {
|
|
108
|
+
let i = e();
|
|
109
|
+
return n || t === null ? /* @__PURE__ */ c("p", {
|
|
110
|
+
className: "text-lg font-semibold text-muted-foreground",
|
|
111
|
+
"data-testid": r,
|
|
112
|
+
children: i("planmagnet.satisfaction.notEnough", "Not enough responses")
|
|
113
|
+
}) : /* @__PURE__ */ c("p", {
|
|
114
|
+
className: "text-3xl font-semibold tabular-nums",
|
|
115
|
+
"data-testid": r,
|
|
116
|
+
children: t
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function S({ csat: t, window: r }) {
|
|
120
|
+
let i = e();
|
|
121
|
+
return /* @__PURE__ */ l(u, {
|
|
122
|
+
"data-testid": "satisfaction-csat-card",
|
|
123
|
+
children: [/* @__PURE__ */ l(f, {
|
|
124
|
+
className: "pb-2",
|
|
125
|
+
children: [/* @__PURE__ */ l(p, {
|
|
126
|
+
className: "flex items-center gap-2 text-base",
|
|
127
|
+
children: [/* @__PURE__ */ c(s, {
|
|
128
|
+
className: "h-4 w-4",
|
|
129
|
+
"aria-hidden": !0
|
|
130
|
+
}), i("planmagnet.satisfaction.csat.title", "CSAT")]
|
|
131
|
+
}), /* @__PURE__ */ c("p", {
|
|
132
|
+
className: "text-xs text-muted-foreground",
|
|
133
|
+
children: i("planmagnet.satisfaction.csat.subtitle", "Customer satisfaction: the share of answers that were a 4 or a 5 on a 1–5 scale. The default delivery KPI.")
|
|
134
|
+
})]
|
|
135
|
+
}), /* @__PURE__ */ l(d, {
|
|
136
|
+
className: "space-y-2",
|
|
137
|
+
children: [
|
|
138
|
+
/* @__PURE__ */ c(x, {
|
|
139
|
+
value: n(t.score),
|
|
140
|
+
notEnough: t.notEnoughResponses,
|
|
141
|
+
testId: "satisfaction-csat-value"
|
|
142
|
+
}),
|
|
143
|
+
/* @__PURE__ */ c("p", {
|
|
144
|
+
className: "text-sm text-muted-foreground",
|
|
145
|
+
children: t.notEnoughResponses ? _(i, t) : i("planmagnet.satisfaction.csat.satisfied", "{{satisfied}} of {{count}} answers were a 4 or a 5.", {
|
|
146
|
+
satisfied: t.satisfiedCount,
|
|
147
|
+
count: t.responseCount
|
|
148
|
+
})
|
|
149
|
+
}),
|
|
150
|
+
/* @__PURE__ */ l("p", {
|
|
151
|
+
className: "text-xs text-muted-foreground",
|
|
152
|
+
"data-testid": "satisfaction-csat-basis",
|
|
153
|
+
children: [
|
|
154
|
+
m(i, t.responseCount),
|
|
155
|
+
" · ",
|
|
156
|
+
h(i, r)
|
|
157
|
+
]
|
|
158
|
+
})
|
|
159
|
+
]
|
|
160
|
+
})]
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
function C({ nps: t, window: n }) {
|
|
164
|
+
let i = e();
|
|
165
|
+
return /* @__PURE__ */ l(u, {
|
|
166
|
+
"data-testid": "satisfaction-nps-card",
|
|
167
|
+
children: [/* @__PURE__ */ l(f, {
|
|
168
|
+
className: "pb-2",
|
|
169
|
+
children: [/* @__PURE__ */ l(p, {
|
|
170
|
+
className: "flex items-center gap-2 text-base",
|
|
171
|
+
children: [/* @__PURE__ */ c(o, {
|
|
172
|
+
className: "h-4 w-4",
|
|
173
|
+
"aria-hidden": !0
|
|
174
|
+
}), i("planmagnet.satisfaction.nps.title", "NPS")]
|
|
175
|
+
}), /* @__PURE__ */ c("p", {
|
|
176
|
+
className: "text-xs text-muted-foreground",
|
|
177
|
+
children: i("planmagnet.satisfaction.nps.subtitle", "Net Promoter Score: % promoters (9–10) minus % detractors (0–6) on a 0–10 scale, from −100 to +100.")
|
|
178
|
+
})]
|
|
179
|
+
}), /* @__PURE__ */ l(d, {
|
|
180
|
+
className: "space-y-3",
|
|
181
|
+
children: [
|
|
182
|
+
/* @__PURE__ */ c(x, {
|
|
183
|
+
value: r(t.score),
|
|
184
|
+
notEnough: t.notEnoughResponses,
|
|
185
|
+
testId: "satisfaction-nps-value"
|
|
186
|
+
}),
|
|
187
|
+
t.notEnoughResponses && /* @__PURE__ */ c("p", {
|
|
188
|
+
className: "text-sm text-muted-foreground",
|
|
189
|
+
children: _(i, t)
|
|
190
|
+
}),
|
|
191
|
+
/* @__PURE__ */ c(b, { nps: t }),
|
|
192
|
+
/* @__PURE__ */ l("p", {
|
|
193
|
+
className: "text-xs text-muted-foreground",
|
|
194
|
+
"data-testid": "satisfaction-nps-basis",
|
|
195
|
+
children: [
|
|
196
|
+
m(i, t.responseCount),
|
|
197
|
+
" · ",
|
|
198
|
+
h(i, n)
|
|
199
|
+
]
|
|
200
|
+
})
|
|
201
|
+
]
|
|
202
|
+
})]
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function w({ summary: e }) {
|
|
206
|
+
return /* @__PURE__ */ l("div", {
|
|
207
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
208
|
+
"data-testid": "satisfaction-figures",
|
|
209
|
+
children: [/* @__PURE__ */ c(S, {
|
|
210
|
+
csat: e.csat,
|
|
211
|
+
window: e.window
|
|
212
|
+
}), /* @__PURE__ */ c(C, {
|
|
213
|
+
nps: e.nps,
|
|
214
|
+
window: e.window
|
|
215
|
+
})]
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
function T({ label: t, value: n, notEnough: r, responseCount: i, testId: a }) {
|
|
219
|
+
let o = e();
|
|
220
|
+
return /* @__PURE__ */ l("div", {
|
|
221
|
+
className: "rounded-md border p-3",
|
|
222
|
+
"data-testid": a,
|
|
223
|
+
children: [
|
|
224
|
+
/* @__PURE__ */ c("p", {
|
|
225
|
+
className: "text-xs text-muted-foreground",
|
|
226
|
+
children: t
|
|
227
|
+
}),
|
|
228
|
+
r || n === null ? /* @__PURE__ */ c("p", {
|
|
229
|
+
className: "mt-1 text-sm font-semibold text-muted-foreground",
|
|
230
|
+
children: o("planmagnet.satisfaction.notEnough", "Not enough responses")
|
|
231
|
+
}) : /* @__PURE__ */ c("p", {
|
|
232
|
+
className: "mt-1 text-2xl font-semibold tabular-nums",
|
|
233
|
+
children: n
|
|
234
|
+
}),
|
|
235
|
+
/* @__PURE__ */ c("p", {
|
|
236
|
+
className: "mt-0.5 text-xs text-muted-foreground",
|
|
237
|
+
children: m(o, i)
|
|
238
|
+
})
|
|
239
|
+
]
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function E({ summary: t }) {
|
|
243
|
+
let i = e(), { csat: a, nps: o } = t;
|
|
244
|
+
return /* @__PURE__ */ l("div", {
|
|
245
|
+
className: "space-y-2",
|
|
246
|
+
children: [
|
|
247
|
+
/* @__PURE__ */ l("div", {
|
|
248
|
+
className: "grid grid-cols-2 gap-3",
|
|
249
|
+
children: [/* @__PURE__ */ c(T, {
|
|
250
|
+
label: i("planmagnet.satisfaction.csat.compactLabel", "CSAT (% of answers 4–5)"),
|
|
251
|
+
value: n(a.score),
|
|
252
|
+
notEnough: a.notEnoughResponses,
|
|
253
|
+
responseCount: a.responseCount,
|
|
254
|
+
testId: "satisfaction-compact-csat"
|
|
255
|
+
}), /* @__PURE__ */ c(T, {
|
|
256
|
+
label: i("planmagnet.satisfaction.nps.compactLabel", "NPS"),
|
|
257
|
+
value: r(o.score),
|
|
258
|
+
notEnough: o.notEnoughResponses,
|
|
259
|
+
responseCount: o.responseCount,
|
|
260
|
+
testId: "satisfaction-compact-nps"
|
|
261
|
+
})]
|
|
262
|
+
}),
|
|
263
|
+
!o.notEnoughResponses && /* @__PURE__ */ c("p", {
|
|
264
|
+
className: "text-xs text-muted-foreground",
|
|
265
|
+
children: i("planmagnet.satisfaction.nps.compactSplit", "NPS: {{promoters}} promoters · {{passives}} passives · {{detractors}} detractors", {
|
|
266
|
+
promoters: o.promoterCount,
|
|
267
|
+
passives: o.passiveCount,
|
|
268
|
+
detractors: o.detractorCount
|
|
269
|
+
})
|
|
270
|
+
}),
|
|
271
|
+
/* @__PURE__ */ c("p", {
|
|
272
|
+
className: "text-xs text-muted-foreground",
|
|
273
|
+
"data-testid": "satisfaction-compact-window",
|
|
274
|
+
children: h(i, t.window)
|
|
275
|
+
})
|
|
276
|
+
]
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
//#endregion
|
|
280
|
+
export { v as CATEGORY_CLASS, E as CompactSatisfactionFigures, w as SatisfactionFigureCards, y as categoryLabel, g as windowPresetLabel };
|
|
281
|
+
|
|
282
|
+
//# sourceMappingURL=SatisfactionFigures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SatisfactionFigures.js","names":[],"sources":["../../../src/planmagnet/satisfaction/SatisfactionFigures.tsx"],"sourcesContent":["import { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { Gauge, Smile } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { cn } from '../utils/cn';\nimport { formatCsat, formatNps, formatUtcDay, shareOf, type ScoreCategory } from './satisfaction';\nimport type {\n CsatFigure,\n CustomerSatisfactionSummary,\n NpsFigure,\n SatisfactionWindowEcho,\n} from './satisfactionOperations';\n\n/**\n * ANR-21 figures. Every figure carries its response count and the window it covers (owner decision 2026-10-02), and\n * a metric below its minimum responses reads \"Not enough responses\" — never 0 and never a score computed from too few\n * answers. CSAT and NPS are counted separately: twelve NPS answers never lend a score to four CSAT answers.\n */\n\ntype Tr = ReturnType<typeof useTr>;\n\nexport function responseCountText(tr: Tr, count: number): string {\n if (count === 0) return tr('planmagnet.satisfaction.responses.none', 'No responses');\n return count === 1\n ? tr('planmagnet.satisfaction.responses.one', '1 response')\n : tr('planmagnet.satisfaction.responses.many', '{{count}} responses', { count });\n}\n\nexport function windowText(tr: Tr, window: SatisfactionWindowEcho): string {\n const span = tr('planmagnet.satisfaction.window.span', '{{from}} – {{to}}', {\n from: formatUtcDay(window.from),\n to: formatUtcDay(window.to),\n });\n if (window.preset === 'CUSTOM') return span;\n return tr('planmagnet.satisfaction.window.presetWithSpan', '{{preset}} ({{span}})', {\n preset: windowPresetLabel(tr, window.preset),\n span,\n });\n}\n\nexport function windowPresetLabel(tr: Tr, preset: SatisfactionWindowEcho['preset']): string {\n switch (preset) {\n case 'LAST_30_DAYS':\n return tr('planmagnet.satisfaction.window.last30', 'Last 30 days');\n case 'LAST_90_DAYS':\n return tr('planmagnet.satisfaction.window.last90', 'Last 90 days');\n case 'LAST_180_DAYS':\n return tr('planmagnet.satisfaction.window.last180', 'Last 180 days');\n case 'LAST_365_DAYS':\n return tr('planmagnet.satisfaction.window.last365', 'Last 365 days');\n default:\n return tr('planmagnet.satisfaction.window.custom', 'Custom');\n }\n}\n\nfunction notEnoughText(tr: Tr, figure: { responseCount: number; minimumResponses: number }) {\n return tr(\n 'planmagnet.satisfaction.notEnoughDetail',\n '{{count}} so far — a score needs at least {{minimum}} responses.',\n { count: figure.responseCount, minimum: figure.minimumResponses }\n );\n}\n\n/**\n * Badge colours for one answer's category — semantic status tokens only, and only those the host shells' Tailwind\n * theme maps (planmagnet-app styles.css @theme): `bg-status-*-bg`, `bg-status-*-bg-subtle`, `text-status-success-text`,\n * `text-status-error-text`. A token missing there generates no CSS at all.\n */\nexport const CATEGORY_CLASS: Record<ScoreCategory, string> = {\n satisfied: 'bg-status-success-bg-subtle text-status-success-text',\n promoter: 'bg-status-success-bg-subtle text-status-success-text',\n // The shells' Tailwind theme maps no warning TEXT colour (only its backgrounds), so a passive reads in the body colour.\n passive: 'bg-status-warning-bg-subtle text-foreground',\n notSatisfied: 'bg-status-error-bg-subtle text-status-error-text',\n detractor: 'bg-status-error-bg-subtle text-status-error-text',\n};\n\nexport function categoryLabel(tr: Tr, category: ScoreCategory): string {\n switch (category) {\n case 'satisfied':\n return tr('planmagnet.satisfaction.category.satisfied', 'Satisfied');\n case 'notSatisfied':\n return tr('planmagnet.satisfaction.category.notSatisfied', 'Not satisfied');\n case 'promoter':\n return tr('planmagnet.satisfaction.category.promoter', 'Promoter');\n case 'passive':\n return tr('planmagnet.satisfaction.category.passive', 'Passive');\n default:\n return tr('planmagnet.satisfaction.category.detractor', 'Detractor');\n }\n}\n\n/** Promoters / passives / detractors as a bar (only once there is a score) and as counts (always). */\nfunction NpsSplit({ nps }: { nps: NpsFigure }) {\n const tr = useTr();\n const parts = [\n {\n key: 'promoters',\n label: tr('planmagnet.satisfaction.nps.promoters', 'Promoters (9–10)'),\n count: nps.promoterCount,\n bar: 'bg-status-success-bg',\n },\n {\n key: 'passives',\n label: tr('planmagnet.satisfaction.nps.passives', 'Passives (7–8)'),\n count: nps.passiveCount,\n bar: 'bg-status-warning-bg',\n },\n {\n key: 'detractors',\n label: tr('planmagnet.satisfaction.nps.detractors', 'Detractors (0–6)'),\n count: nps.detractorCount,\n bar: 'bg-status-error-bg',\n },\n ];\n const showShares = !nps.notEnoughResponses && nps.responseCount > 0;\n return (\n <div className=\"space-y-2\" data-testid=\"satisfaction-nps-split\">\n {showShares && (\n <div className=\"flex h-2 w-full overflow-hidden rounded-full bg-muted\" aria-hidden={true}>\n {parts.map((part) => (\n <div\n key={part.key}\n className={part.bar}\n style={{ width: `${(part.count * 100) / nps.responseCount}%` }}\n />\n ))}\n </div>\n )}\n <dl className=\"grid grid-cols-3 gap-2 text-xs\">\n {parts.map((part) => (\n <div key={part.key} className=\"min-w-0\">\n <dt className=\"flex items-center gap-1.5 text-muted-foreground\">\n <span className={cn('h-2 w-2 shrink-0 rounded-full', part.bar)} aria-hidden={true} />\n <span className=\"truncate\">{part.label}</span>\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums\">\n {showShares\n ? tr('planmagnet.satisfaction.nps.countWithShare', '{{count}} ({{share}}%)', {\n count: part.count,\n share: shareOf(part.count, nps.responseCount),\n })\n : part.count}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n );\n}\n\nfunction FigureValue({\n value,\n notEnough,\n testId,\n}: {\n value: string | null;\n notEnough: boolean;\n testId: string;\n}) {\n const tr = useTr();\n if (notEnough || value === null) {\n return (\n <p className=\"text-lg font-semibold text-muted-foreground\" data-testid={testId}>\n {tr('planmagnet.satisfaction.notEnough', 'Not enough responses')}\n </p>\n );\n }\n return (\n <p className=\"text-3xl font-semibold tabular-nums\" data-testid={testId}>\n {value}\n </p>\n );\n}\n\nfunction CsatCard({ csat, window }: { csat: CsatFigure; window: SatisfactionWindowEcho }) {\n const tr = useTr();\n return (\n <Card data-testid=\"satisfaction-csat-card\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Smile className=\"h-4 w-4\" aria-hidden={true} />\n {tr('planmagnet.satisfaction.csat.title', 'CSAT')}\n </CardTitle>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\n 'planmagnet.satisfaction.csat.subtitle',\n 'Customer satisfaction: the share of answers that were a 4 or a 5 on a 1–5 scale. The default delivery KPI.'\n )}\n </p>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <FigureValue\n value={formatCsat(csat.score)}\n notEnough={csat.notEnoughResponses}\n testId=\"satisfaction-csat-value\"\n />\n <p className=\"text-sm text-muted-foreground\">\n {csat.notEnoughResponses\n ? notEnoughText(tr, csat)\n : tr(\n 'planmagnet.satisfaction.csat.satisfied',\n '{{satisfied}} of {{count}} answers were a 4 or a 5.',\n { satisfied: csat.satisfiedCount, count: csat.responseCount }\n )}\n </p>\n <p className=\"text-xs text-muted-foreground\" data-testid=\"satisfaction-csat-basis\">\n {responseCountText(tr, csat.responseCount)} · {windowText(tr, window)}\n </p>\n </CardContent>\n </Card>\n );\n}\n\nfunction NpsCard({ nps, window }: { nps: NpsFigure; window: SatisfactionWindowEcho }) {\n const tr = useTr();\n return (\n <Card data-testid=\"satisfaction-nps-card\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Gauge className=\"h-4 w-4\" aria-hidden={true} />\n {tr('planmagnet.satisfaction.nps.title', 'NPS')}\n </CardTitle>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\n 'planmagnet.satisfaction.nps.subtitle',\n 'Net Promoter Score: % promoters (9–10) minus % detractors (0–6) on a 0–10 scale, from −100 to +100.'\n )}\n </p>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <FigureValue\n value={formatNps(nps.score)}\n notEnough={nps.notEnoughResponses}\n testId=\"satisfaction-nps-value\"\n />\n {nps.notEnoughResponses && (\n <p className=\"text-sm text-muted-foreground\">{notEnoughText(tr, nps)}</p>\n )}\n <NpsSplit nps={nps} />\n <p className=\"text-xs text-muted-foreground\" data-testid=\"satisfaction-nps-basis\">\n {responseCountText(tr, nps.responseCount)} · {windowText(tr, window)}\n </p>\n </CardContent>\n </Card>\n );\n}\n\n/** The page's two figure cards, side by side. */\nexport function SatisfactionFigureCards({ summary }: { summary: CustomerSatisfactionSummary }) {\n return (\n <div className=\"grid gap-4 md:grid-cols-2\" data-testid=\"satisfaction-figures\">\n <CsatCard csat={summary.csat} window={summary.window} />\n <NpsCard nps={summary.nps} window={summary.window} />\n </div>\n );\n}\n\nfunction CompactTile({\n label,\n value,\n notEnough,\n responseCount,\n testId,\n}: {\n label: string;\n value: string | null;\n notEnough: boolean;\n responseCount: number;\n testId: string;\n}) {\n const tr = useTr();\n return (\n <div className=\"rounded-md border p-3\" data-testid={testId}>\n <p className=\"text-xs text-muted-foreground\">{label}</p>\n {notEnough || value === null ? (\n <p className=\"mt-1 text-sm font-semibold text-muted-foreground\">\n {tr('planmagnet.satisfaction.notEnough', 'Not enough responses')}\n </p>\n ) : (\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">{value}</p>\n )}\n <p className=\"mt-0.5 text-xs text-muted-foreground\">{responseCountText(tr, responseCount)}</p>\n </div>\n );\n}\n\n/** CSAT and NPS as two small tiles with their counts, and the window under them — for cards on other pages. */\nexport function CompactSatisfactionFigures({ summary }: { summary: CustomerSatisfactionSummary }) {\n const tr = useTr();\n const { csat, nps } = summary;\n return (\n <div className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-3\">\n <CompactTile\n label={tr('planmagnet.satisfaction.csat.compactLabel', 'CSAT (% of answers 4–5)')}\n value={formatCsat(csat.score)}\n notEnough={csat.notEnoughResponses}\n responseCount={csat.responseCount}\n testId=\"satisfaction-compact-csat\"\n />\n <CompactTile\n label={tr('planmagnet.satisfaction.nps.compactLabel', 'NPS')}\n value={formatNps(nps.score)}\n notEnough={nps.notEnoughResponses}\n responseCount={nps.responseCount}\n testId=\"satisfaction-compact-nps\"\n />\n </div>\n {!nps.notEnoughResponses && (\n <p className=\"text-xs text-muted-foreground\">\n {tr(\n 'planmagnet.satisfaction.nps.compactSplit',\n 'NPS: {{promoters}} promoters · {{passives}} passives · {{detractors}} detractors',\n {\n promoters: nps.promoterCount,\n passives: nps.passiveCount,\n detractors: nps.detractorCount,\n }\n )}\n </p>\n )}\n <p className=\"text-xs text-muted-foreground\" data-testid=\"satisfaction-compact-window\">\n {windowText(tr, summary.window)}\n </p>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DefaultLinks } from './satisfactionCsv';
|
|
2
|
+
import { ImportCustomerSatisfactionResult } from './satisfactionOperations';
|
|
3
|
+
|
|
4
|
+
export declare function SatisfactionImportDialog({ links, onImported, }: {
|
|
5
|
+
/** Starting links for rows that name none — the page's product / release / project filters. */
|
|
6
|
+
links: DefaultLinks;
|
|
7
|
+
onImported: (result: ImportCustomerSatisfactionResult) => void;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=SatisfactionImportDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SatisfactionImportDialog.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/satisfaction/SatisfactionImportDialog.tsx"],"names":[],"mappings":"AA+BA,OAAO,EAQL,KAAK,YAAY,EAOlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAGL,KAAK,gCAAgC,EACtC,MAAM,0BAA0B,CAAC;AAkPlC,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,UAAU,GACX,EAAE;IACD,+FAA+F;IAC/F,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,CAAC,MAAM,EAAE,gCAAgC,KAAK,IAAI,CAAC;CAChE,2CA8aA"}
|