UNPKG

@pnp/spfx-controls-react

Version:

Reusable React controls for SharePoint Framework solutions

127 lines • 10.3 kB
"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