@pnp/spfx-controls-react
Version:
Reusable React controls for SharePoint Framework solutions
127 lines • 10.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KPICard = void 0;
var tslib_1 = require("tslib");
var react_components_1 = require("@fluentui/react-components");
var React = tslib_1.__importStar(require("react"));
var Stack_1 = tslib_1.__importDefault(require("./stack/Stack"));
var useKpiStyles_1 = require("./useKpiStyles");
var react_icons_1 = require("@fluentui/react-icons");
var IKpiCardData_1 = require("./IKpiCardData");
var ControlStrings_1 = tslib_1.__importDefault(require("ControlStrings"));
var KPICard = function (props) {
var _a;
var dataCard = props.dataCard;
var styles = (0, useKpiStyles_1.useKpiStyles)();
// State to control InfoLabel popover visibility
var _b = React.useState(false), isInfoLabelOpen = _b[0], setIsInfoLabelOpen = _b[1];
// Handle card mouse leave to auto-dismiss InfoLabel
var handleCardMouseLeave = React.useCallback(function () {
setIsInfoLabelOpen(false);
}, []);
// Determine if KPI is on track based on goal metric type
var isOnTrack = React.useMemo(function () {
return dataCard.goalMetric === IKpiCardData_1.EGoalMetric.LOWER_IS_BETTER
? dataCard.currentValue <= dataCard.goal // Lower is better: on track when current <= goal
: dataCard.currentValue >= dataCard.goal;
}, // Higher is better: on track when current >= goal
[dataCard.currentValue, dataCard.goal, dataCard.goalMetric]);
var progressColor = React.useMemo(function () { return (isOnTrack ? 'success' : 'error'); }, [isOnTrack]);
var goal = React.useMemo(function () { return dataCard.goal.toLocaleString(); }, [dataCard.goal]);
var totalPercent = React.useMemo(function () { return (dataCard.currentValue / dataCard.totalItems) * 100; }, [dataCard.currentValue, dataCard.totalItems]);
// Success / Danger foregrounds
var accentFg = React.useMemo(function () {
return isOnTrack
? react_components_1.tokens.colorPaletteLightGreenForeground2
: react_components_1.tokens.colorPaletteRedForeground2;
}, [isOnTrack]);
// Success / Danger backgrounds (badge pill bg)
var accentBg = React.useMemo(function () {
return isOnTrack
? react_components_1.tokens.colorPaletteLightGreenBackground1
: react_components_1.tokens.colorPaletteRedBackground1;
}, [isOnTrack]);
// Success / Danger borders (badge pill border)
var accentBorder = React.useMemo(function () {
return isOnTrack
? react_components_1.tokens.colorPaletteLightGreenBorder1
: react_components_1.tokens.colorPaletteRedBorder1;
}, [isOnTrack]);
var badgeStyle = React.useMemo(function () { return ({
background: accentBg,
border: "1px solid ".concat(accentBorder),
color: accentFg,
borderRadius: '20px',
padding: '12px 12px',
fontSize: react_components_1.tokens.fontSizeBase200,
fontWeight: react_components_1.tokens.fontWeightSemibold,
letterSpacing: '0.3px',
maxWidth: 'fit-content',
}); }, [accentBg, accentBorder, accentFg]);
return (React.createElement(React.Fragment, null,
React.createElement(react_components_1.Card, { className: styles.card, onMouseLeave: handleCardMouseLeave },
React.createElement("div", { className: isOnTrack ? styles.glowBlobSuccess : styles.glowBlobError }),
React.createElement(Stack_1.default, { gap: "m", padding: "m" },
React.createElement(react_components_1.CardHeader, { header: React.createElement(Stack_1.default, { direction: "vertical", gap: "2px" },
React.createElement(Stack_1.default, { direction: "horizontal", alignItems: "center", gap: "8px" },
React.createElement(react_components_1.InfoLabel, { style: { zIndex: 99999 }, infoButton: {
popover: {
open: isInfoLabelOpen,
onOpenChange: function (_e, data) {
return setIsInfoLabelOpen(data.open);
},
},
}, info: React.createElement(React.Fragment, null,
React.createElement(react_components_1.Text, { size: 300, color: "neutralSecondary" }, dataCard.description || ControlStrings_1.default.KPINoDescription)) },
React.createElement(react_components_1.Text, { weight: "bold", size: 300 }, ((_a = dataCard.title) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || ControlStrings_1.default.KPIDEfaultTitle))),
React.createElement(react_components_1.Text, { size: 200, style: {
color: react_components_1.tokens.colorNeutralForeground3,
fontStyle: 'italic',
} }, dataCard.goalMetric === IKpiCardData_1.EGoalMetric.LOWER_IS_BETTER
? ControlStrings_1.default.KPILowerIsBetter
: ControlStrings_1.default.KPIHigherIsBetter)), action: React.createElement(react_components_1.Tooltip, { content: isOnTrack
? "\u2713 ".concat(ControlStrings_1.default.KPIWithinGoalThreshold)
: "\u26A0 ".concat(ControlStrings_1.default.KPIExceedsGoalTreshhold), relationship: "inaccessible" },
React.createElement(react_components_1.Badge, { className: styles.headerActionBadge, appearance: "ghost", size: "small", icon: isOnTrack ? (React.createElement(react_icons_1.CheckmarkCircleRegular, { style: { color: accentFg, fontSize: '22px' } })) : (React.createElement(react_icons_1.AlertFilled, { style: { color: accentFg, fontSize: '22px' } })) })) }),
React.createElement(Stack_1.default, { gap: "s", direction: "horizontal", alignItems: "baseline", paddingTop: "s" },
React.createElement(react_components_1.Text, { weight: "bold", size: 900 },
dataCard.currentValue,
" ",
React.createElement("br", null)),
React.createElement(react_components_1.Text, { weight: "semibold", size: 300, color: "neutralSecondary" },
"/ ",
dataCard.goal,
" ",
ControlStrings_1.default.KPIGoal)),
React.createElement(Stack_1.default, { gap: "s" },
React.createElement(Stack_1.default, { direction: "horizontal", justifyContent: "space-between" },
React.createElement(react_components_1.Text, { size: 300, color: "neutralSecondary" }, ControlStrings_1.default.KPIProgressGoal),
React.createElement(react_components_1.Text, { size: 300, color: "neutralSecondary", weight: "bold" },
((dataCard.currentValue / dataCard.goal) * 100).toFixed(2),
"%")),
React.createElement(react_components_1.ProgressBar, { value: dataCard.currentValue / dataCard.goal, color: progressColor, style: { height: '8px' }, shape: "rounded" })),
React.createElement(react_components_1.CardFooter, null,
React.createElement(react_components_1.Tooltip, { content: ControlStrings_1.default.KPIMaxAllowedThreshold, relationship: "inaccessible" },
React.createElement(Stack_1.default, { alignItems: "center", gap: react_components_1.tokens.spacingVerticalXXS },
React.createElement(react_icons_1.TargetRegular, { className: styles.footerIcon }),
React.createElement(react_components_1.Text, { className: styles.footerLabel }, "Goal"),
React.createElement(react_components_1.Text, { className: styles.footerValue }, goal))),
React.createElement(react_components_1.Divider, { vertical: true, className: styles.footerDivider }),
React.createElement(react_components_1.Tooltip, { content: ControlStrings_1.default.KPITotalItemsInScope, relationship: "inaccessible" },
React.createElement(Stack_1.default, { alignItems: "center", gap: react_components_1.tokens.spacingVerticalXXS },
React.createElement(react_icons_1.DocumentRegular, { className: styles.footerIcon }),
React.createElement(react_components_1.Text, { className: styles.footerLabel }, ControlStrings_1.default.KPITotalItems),
React.createElement(react_components_1.Text, { className: styles.footerValue }, dataCard.totalItems.toLocaleString()))),
React.createElement(react_components_1.Divider, { vertical: true, className: styles.footerDivider }),
React.createElement(react_components_1.Tooltip, { content: ControlStrings_1.default.KPICurrentValueAsPercent, relationship: "inaccessible" },
React.createElement(Stack_1.default, { alignItems: "center", gap: react_components_1.tokens.spacingVerticalXXS },
React.createElement(react_icons_1.CalculatorRegular, { className: styles.footerIcon }),
React.createElement(react_components_1.Text, { className: styles.footerLabel }, ControlStrings_1.default.KPIPercentOfTotal),
React.createElement(react_components_1.Text, { className: styles.footerValue },
totalPercent.toFixed(2),
"%")))),
React.createElement(Stack_1.default, null,
React.createElement(react_components_1.Badge, { appearance: "outline", size: "small", style: badgeStyle, icon: isOnTrack ? (React.createElement(react_icons_1.CheckmarkCircleRegular, { style: { fontSize: '14px' } })) : (React.createElement(react_icons_1.AlertFilled, { style: { fontSize: '14px' } })) }, isOnTrack ? ControlStrings_1.default.KPIOnTrack : ControlStrings_1.default.KPIExceedGoal))))));
};
exports.KPICard = KPICard;
//# sourceMappingURL=KpiCard.js.map