UNPKG

@zendesk/retrace

Version:

define and capture Product Operation Traces along with computed metrics with an optional friendly React beacon API

243 lines 13 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CustomerSidebar = void 0; const react_1 = require("react"); const React = __importStar(require("react")); const styled_components_1 = __importDefault(require("styled-components")); const react_avatars_1 = require("@zendeskgarden/react-avatars"); const react_loaders_1 = require("@zendeskgarden/react-loaders"); const react_notifications_1 = require("@zendeskgarden/react-notifications"); const react_theming_1 = require("@zendeskgarden/react-theming"); const react_typography_1 = require("@zendeskgarden/react-typography"); const building_stroke_svg_1 = require("@zendeskgarden/svg-icons/src/16/building-stroke.svg"); const calendar_stroke_svg_1 = require("@zendeskgarden/svg-icons/src/16/calendar-stroke.svg"); const email_stroke_svg_1 = require("@zendeskgarden/svg-icons/src/16/email-stroke.svg"); const notes_stroke_svg_1 = require("@zendeskgarden/svg-icons/src/16/notes-stroke.svg"); const user_solo_stroke_svg_1 = require("@zendeskgarden/svg-icons/src/16/user-solo-stroke.svg"); const mockCustomers_1 = require("./mockCustomers"); const simulateLongTasks_1 = require("./simulateLongTasks"); const traceManager_1 = require("./traceManager"); const SidebarContainer = (0, styled_components_1.default)(react_notifications_1.Well) ` width: 320px; height: fit-content; margin-left: ${react_theming_1.DEFAULT_THEME.space.base * 4}px; padding: ${react_theming_1.DEFAULT_THEME.space.base * 4}px; `; const CustomerSection = styled_components_1.default.div ` display: flex; flex-direction: column; align-items: center; text-align: center; margin-bottom: ${react_theming_1.DEFAULT_THEME.space.base * 4}px; `; const CustomerInfo = styled_components_1.default.div ` display: flex; flex-direction: column; gap: ${react_theming_1.DEFAULT_THEME.space.base * 2}px; width: 100%; `; const InfoRow = styled_components_1.default.div ` display: flex; align-items: center; gap: ${react_theming_1.DEFAULT_THEME.space.base * 2}px; padding: ${react_theming_1.DEFAULT_THEME.space.base * 2}px; background-color: ${react_theming_1.PALETTE.grey[100]}; border-radius: ${react_theming_1.DEFAULT_THEME.borderRadii.md}; `; const StatusBadge = (0, styled_components_1.default)(react_typography_1.Span) ` padding: ${react_theming_1.DEFAULT_THEME.space.base}px ${react_theming_1.DEFAULT_THEME.space.base * 2}px; border-radius: ${react_theming_1.DEFAULT_THEME.borderRadii.sm}; font-size: ${react_theming_1.DEFAULT_THEME.fontSizes.xs}; font-weight: ${react_theming_1.DEFAULT_THEME.fontWeights.semibold}; text-transform: uppercase; color: ${(props) => { switch (props.status) { case 'vip': return react_theming_1.PALETTE.purple[700]; case 'active': return react_theming_1.PALETTE.green[700]; case 'inactive': return react_theming_1.PALETTE.grey[600]; default: return react_theming_1.PALETTE.grey[600]; } }}; background-color: ${(props) => { switch (props.status) { case 'vip': return react_theming_1.PALETTE.purple[100]; case 'active': return react_theming_1.PALETTE.green[100]; case 'inactive': return react_theming_1.PALETTE.grey[200]; default: return react_theming_1.PALETTE.grey[200]; } }}; `; const NotesSection = styled_components_1.default.div ` margin-top: ${react_theming_1.DEFAULT_THEME.space.base * 3}px; padding: ${react_theming_1.DEFAULT_THEME.space.base * 3}px; background-color: ${react_theming_1.PALETTE.blue[100]}; border-radius: ${react_theming_1.DEFAULT_THEME.borderRadii.md}; border-left: 4px solid ${react_theming_1.PALETTE.blue[600]}; `; const CustomerSidebar = ({ ticketId, }) => { const [customer, setCustomer] = (0, react_1.useState)(null); const [isLoading, setIsLoading] = (0, react_1.useState)(true); const [error, setError] = (0, react_1.useState)(null); // Use beacon for tracing (0, traceManager_1.useBeacon)({ name: 'CustomerSidebar', relatedTo: { ticketId }, renderedOutput: isLoading ? 'loading' : customer ? 'content' : 'error', isIdle: !isLoading, error: error ? new Error(error) : undefined, attributes: { customerId: customer?.id, customerStatus: customer?.status, }, }); (0, react_1.useEffect)(() => { const loadCustomerData = async () => { setIsLoading(true); setError(null); // Simulate network request with timing similar to the provided example await new Promise((resolve) => { setTimeout(resolve, 1_800 + Math.random() * 400); }); // Simulate some CPU work (0, simulateLongTasks_1.triggerLongTasks)({ minTime: 20, maxTime: 50, totalClusterDuration: 100, }); try { const customerData = (0, mockCustomers_1.getCustomerByTicketId)(ticketId); if (!customerData) { setError('Customer not found'); setCustomer(null); } else { setCustomer(customerData); } } catch { setError('Failed to load customer data'); setCustomer(null); } finally { setIsLoading(false); } }; void loadCustomerData(); }, [ticketId]); if (isLoading) { return (React.createElement(SidebarContainer, null, React.createElement(react_typography_1.LG, { isBold: true, style: { marginBottom: react_theming_1.DEFAULT_THEME.space.base * 4 } }, "Customer Context"), React.createElement(CustomerSection, null, React.createElement(react_loaders_1.Skeleton, { height: "64px", width: "64px", style: { borderRadius: '50%' } }), React.createElement(react_loaders_1.Skeleton, { height: "20px", width: "140px", style: { marginTop: react_theming_1.DEFAULT_THEME.space.base * 2 } }), React.createElement(react_loaders_1.Skeleton, { height: "16px", width: "180px" })), React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: react_theming_1.DEFAULT_THEME.space.base * 2, } }, React.createElement(react_loaders_1.Skeleton, { height: "40px" }), React.createElement(react_loaders_1.Skeleton, { height: "40px" }), React.createElement(react_loaders_1.Skeleton, { height: "40px" }), React.createElement(react_loaders_1.Skeleton, { height: "60px" })))); } if (error || !customer) { return (React.createElement(SidebarContainer, null, React.createElement(react_typography_1.LG, { isBold: true, style: { marginBottom: react_theming_1.DEFAULT_THEME.space.base * 4 } }, "Customer Context"), React.createElement(react_notifications_1.Alert, { type: "error" }, React.createElement(react_notifications_1.Alert.Title, null, "Unable to load customer data"), error ?? 'Customer information not available for this ticket.'))); } return (React.createElement(SidebarContainer, null, React.createElement(react_typography_1.LG, { isBold: true, style: { marginBottom: react_theming_1.DEFAULT_THEME.space.base * 4 } }, "Customer Context"), React.createElement(CustomerSection, null, React.createElement(react_avatars_1.Avatar, { size: "large", backgroundColor: react_theming_1.PALETTE.grey[600] }, React.createElement("img", { alt: customer.name, src: customer.avatar, style: { width: '100%', height: '100%', objectFit: 'cover' }, onError: (e) => { // Fallback to icon if image fails to load e.currentTarget.style.display = 'none'; e.currentTarget.parentElement.innerHTML = ` <svg width="32" height="32" viewBox="0 0 16 16" fill="currentColor"> <path d="M8 8a3 3 0 100-6 3 3 0 000 6zM8 9a5 5 0 00-5 5h10a5 5 0 00-5-5z"/> </svg> `; } })), React.createElement(react_typography_1.MD, { isBold: true, style: { marginTop: react_theming_1.DEFAULT_THEME.space.base * 2 } }, customer.name), React.createElement(StatusBadge, { status: customer.status }, customer.status)), React.createElement(CustomerInfo, null, React.createElement(InfoRow, null, React.createElement(email_stroke_svg_1.ReactComponent, { style: { color: react_theming_1.PALETTE.grey[600], flexShrink: 0 } }), React.createElement("div", null, React.createElement(react_typography_1.SM, { isBold: true, style: { color: react_theming_1.PALETTE.grey[600], display: 'block' } }, "Email"), React.createElement(react_typography_1.Span, null, customer.email))), React.createElement(InfoRow, null, React.createElement(building_stroke_svg_1.ReactComponent, { style: { color: react_theming_1.PALETTE.grey[600], flexShrink: 0 } }), React.createElement("div", null, React.createElement(react_typography_1.SM, { isBold: true, style: { color: react_theming_1.PALETTE.grey[600], display: 'block' } }, "Company"), React.createElement(react_typography_1.Span, null, customer.company))), React.createElement(InfoRow, null, React.createElement(calendar_stroke_svg_1.ReactComponent, { style: { color: react_theming_1.PALETTE.grey[600], flexShrink: 0 } }), React.createElement("div", null, React.createElement(react_typography_1.SM, { isBold: true, style: { color: react_theming_1.PALETTE.grey[600], display: 'block' } }, "Customer Since"), React.createElement(react_typography_1.Span, null, customer.joined))), React.createElement(InfoRow, null, React.createElement(user_solo_stroke_svg_1.ReactComponent, { style: { color: react_theming_1.PALETTE.grey[600], flexShrink: 0 } }), React.createElement("div", null, React.createElement(react_typography_1.SM, { isBold: true, style: { color: react_theming_1.PALETTE.grey[600], display: 'block' } }, "Total Tickets"), React.createElement(react_typography_1.Span, null, customer.ticketCount)))), React.createElement(NotesSection, null, React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: react_theming_1.DEFAULT_THEME.space.base, marginBottom: react_theming_1.DEFAULT_THEME.space.base * 2, } }, React.createElement(notes_stroke_svg_1.ReactComponent, { style: { color: react_theming_1.PALETTE.blue[600] } }), React.createElement(react_typography_1.SM, { isBold: true, style: { color: react_theming_1.PALETTE.blue[700] } }, "AGENT NOTES")), React.createElement(react_typography_1.Span, { style: { color: react_theming_1.PALETTE.blue[800] } }, customer.notes)))); }; exports.CustomerSidebar = CustomerSidebar; //# sourceMappingURL=CustomerSidebar.js.map