@digitaldefiance/express-suite-react-components 4.26.19 → 4.26.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitaldefiance/express-suite-react-components",
3
- "version": "4.26.19",
3
+ "version": "4.26.21",
4
4
  "homepage": "https://github.com/Digital-Defiance/react-components",
5
5
  "description": "React MUI components for Digital Defiance Express Suite",
6
6
  "repository": {
@@ -1 +1 @@
1
- {"version":3,"file":"FakeEmailAdminPanel.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-express-suite-react-components/src/components/FakeEmailAdminPanel.tsx"],"names":[],"mappings":"AAmCA,OAAO,EAAE,EAAE,EAAoC,MAAM,OAAO,CAAC;AAK7D,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAoLD,eAAO,MAAM,mBAAmB,EAAE,EAIjC,CAAC;AAEF,eAAe,mBAAmB,CAAC;AAGnC,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,qBAAqB,EAAE,EAAE,CAAC,0BAA0B,CA8BhE,CAAC"}
1
+ {"version":3,"file":"FakeEmailAdminPanel.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-express-suite-react-components/src/components/FakeEmailAdminPanel.tsx"],"names":[],"mappings":"AAkCA,OAAO,EAAE,EAAE,EAA4C,MAAM,OAAO,CAAC;AAQrE,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAiRD,eAAO,MAAM,mBAAmB,EAAE,EAIjC,CAAC;AAEF,eAAe,mBAAmB,CAAC;AAGnC,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,qBAAqB,EAAE,EAAE,CAAC,0BAA0B,CA8BhE,CAAC"}
@@ -23,12 +23,64 @@ const react_1 = require("react");
23
23
  const contexts_1 = require("../contexts");
24
24
  const ConfirmationDialog_1 = require("./ConfirmationDialog");
25
25
  const useAuthenticatedApi_1 = require("../hooks/useAuthenticatedApi");
26
+ /**
27
+ * Renders email HTML content in a sandboxed iframe so that links are
28
+ * clickable and open in a new tab. Falls back to plain text when no
29
+ * HTML body is available.
30
+ */
31
+ const EmailBodyIframe = ({ html, text, }) => {
32
+ const iframeRef = (0, react_1.useRef)(null);
33
+ (0, react_1.useEffect)(() => {
34
+ const iframe = iframeRef.current;
35
+ if (!iframe)
36
+ return;
37
+ const doc = iframe.contentDocument ?? iframe.contentWindow?.document;
38
+ if (!doc)
39
+ return;
40
+ if (html) {
41
+ // Inject a <base target="_blank"> so every link opens in a new tab,
42
+ // then write the original HTML body.
43
+ doc.open();
44
+ doc.write(`<!DOCTYPE html><html><head><base target="_blank"><style>body{font-family:sans-serif;font-size:14px;margin:8px;}</style></head><body>${html}</body></html>`);
45
+ doc.close();
46
+ }
47
+ else {
48
+ doc.open();
49
+ doc.write(`<!DOCTYPE html><html><head><style>body{font-family:sans-serif;font-size:14px;margin:8px;white-space:pre-wrap;}</style></head><body>${text.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</body></html>`);
50
+ doc.close();
51
+ }
52
+ // Auto-resize iframe height to fit content
53
+ const resize = () => {
54
+ if (doc.body) {
55
+ iframe.style.height = `${doc.body.scrollHeight + 16}px`;
56
+ }
57
+ };
58
+ // Resize after content loads (images, etc.)
59
+ iframe.addEventListener('load', resize);
60
+ resize();
61
+ // Small delay to catch late-rendering content
62
+ const timer = setTimeout(resize, 200);
63
+ return () => {
64
+ iframe.removeEventListener('load', resize);
65
+ clearTimeout(timer);
66
+ };
67
+ }, [html, text]);
68
+ return ((0, jsx_runtime_1.jsx)("iframe", { ref: iframeRef, sandbox: "allow-popups allow-popups-to-escape-sandbox allow-same-origin", style: {
69
+ width: '100%',
70
+ minHeight: 80,
71
+ border: '1px solid #e0e0e0',
72
+ borderRadius: 4,
73
+ background: '#fff',
74
+ }, title: "Email body" }));
75
+ };
26
76
  const FakeEmailAdminPanelContent = () => {
27
77
  const api = (0, useAuthenticatedApi_1.useAuthenticatedApi)();
28
78
  const { tComponent } = (0, contexts_1.useI18n)();
29
79
  const t = (key) => tComponent(suite_core_lib_1.SuiteCoreComponentId, key);
30
80
  const [recipients, setRecipients] = (0, react_1.useState)([]);
31
81
  const [expanded, setExpanded] = (0, react_1.useState)(null);
82
+ /** Tracks which individual email is expanded to show its body (address:idx) */
83
+ const [expandedEmail, setExpandedEmail] = (0, react_1.useState)(null);
32
84
  const [emailsByAddress, setEmailsByAddress] = (0, react_1.useState)({});
33
85
  const [loading, setLoading] = (0, react_1.useState)(false);
34
86
  const [error, setError] = (0, react_1.useState)(null);
@@ -78,7 +130,11 @@ const FakeEmailAdminPanelContent = () => {
78
130
  setError(err instanceof Error ? err.message : String(err));
79
131
  }
80
132
  }, [api]);
81
- return ((0, jsx_runtime_1.jsxs)(material_1.Paper, { variant: "outlined", sx: { p: 2 }, children: [(0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "subtitle1", fontWeight: "bold", sx: { flexGrow: 1 }, children: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_Title) }), (0, jsx_runtime_1.jsx)(material_1.Chip, { label: "DEV", size: "small", color: "warning" }), (0, jsx_runtime_1.jsx)(material_1.IconButton, { size: "small", onClick: () => void loadRecipients(), title: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_Refresh), children: (0, jsx_runtime_1.jsx)(Refresh_1.default, { fontSize: "small" }) }), (0, jsx_runtime_1.jsx)(material_1.IconButton, { size: "small", color: "error", onClick: () => setClearDialogOpen(true), title: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_ClearAll), disabled: recipients.length === 0, children: (0, jsx_runtime_1.jsx)(Delete_1.default, { fontSize: "small" }) })] }), (0, jsx_runtime_1.jsx)(material_1.Divider, { sx: { mb: 1 } }), error && ((0, jsx_runtime_1.jsx)(material_1.Alert, { severity: "error", sx: { mb: 1 }, onClose: () => setError(null), children: error })), loading && ((0, jsx_runtime_1.jsx)(material_1.Box, { sx: { display: 'flex', justifyContent: 'center', py: 2 }, children: (0, jsx_runtime_1.jsx)(material_1.CircularProgress, { size: 24 }) })), !loading && recipients.length === 0 && ((0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", color: "text.secondary", children: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_NoRecipients) })), !loading && recipients.length > 0 && ((0, jsx_runtime_1.jsx)(material_1.List, { dense: true, disablePadding: true, children: recipients.map((r) => ((0, jsx_runtime_1.jsxs)(material_1.Box, { children: [(0, jsx_runtime_1.jsxs)(material_1.ListItemButton, { onClick: () => void toggleExpand(r.address), sx: { px: 0, py: 0.5 }, children: [(0, jsx_runtime_1.jsx)(material_1.ListItemText, { primary: r.address, secondary: `${r.count} ${t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_Recipients)}` }), expanded === r.address ? ((0, jsx_runtime_1.jsx)(ExpandLess_1.default, { fontSize: "small" })) : ((0, jsx_runtime_1.jsx)(ExpandMore_1.default, { fontSize: "small" }))] }), (0, jsx_runtime_1.jsx)(material_1.Collapse, { in: expanded === r.address, unmountOnExit: true, children: emailsByAddress[r.address]?.length === 0 ? ((0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", color: "text.secondary", sx: { pl: 2, py: 0.5 }, children: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_NoEmails) })) : ((0, jsx_runtime_1.jsx)(material_1.List, { dense: true, disablePadding: true, sx: { pl: 2 }, children: (emailsByAddress[r.address] ?? []).map((email, idx) => ((0, jsx_runtime_1.jsx)(material_1.ListItem, { disablePadding: true, sx: { py: 0.25 }, children: (0, jsx_runtime_1.jsx)(material_1.ListItemText, { primary: email.subject || '(no subject)', secondary: `${t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_Timestamp)}: ${new Date(email.timestamp).toLocaleString()}`, primaryTypographyProps: { variant: 'body2' }, secondaryTypographyProps: { variant: 'caption' } }) }, idx))) })) }), (0, jsx_runtime_1.jsx)(material_1.Divider, {})] }, r.address))) })), (0, jsx_runtime_1.jsx)(ConfirmationDialog_1.ConfirmationDialog, { open: clearDialogOpen, title: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_ClearAll), message: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_ClearConfirm), onConfirm: () => void handleClearAll(), onCancel: () => setClearDialogOpen(false) })] }));
133
+ return ((0, jsx_runtime_1.jsxs)(material_1.Paper, { variant: "outlined", sx: { p: 2 }, children: [(0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "subtitle1", fontWeight: "bold", sx: { flexGrow: 1 }, children: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_Title) }), (0, jsx_runtime_1.jsx)(material_1.Chip, { label: "DEV", size: "small", color: "warning" }), (0, jsx_runtime_1.jsx)(material_1.IconButton, { size: "small", onClick: () => void loadRecipients(), title: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_Refresh), children: (0, jsx_runtime_1.jsx)(Refresh_1.default, { fontSize: "small" }) }), (0, jsx_runtime_1.jsx)(material_1.IconButton, { size: "small", color: "error", onClick: () => setClearDialogOpen(true), title: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_ClearAll), disabled: recipients.length === 0, children: (0, jsx_runtime_1.jsx)(Delete_1.default, { fontSize: "small" }) })] }), (0, jsx_runtime_1.jsx)(material_1.Divider, { sx: { mb: 1 } }), error && ((0, jsx_runtime_1.jsx)(material_1.Alert, { severity: "error", sx: { mb: 1 }, onClose: () => setError(null), children: error })), loading && ((0, jsx_runtime_1.jsx)(material_1.Box, { sx: { display: 'flex', justifyContent: 'center', py: 2 }, children: (0, jsx_runtime_1.jsx)(material_1.CircularProgress, { size: 24 }) })), !loading && recipients.length === 0 && ((0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", color: "text.secondary", children: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_NoRecipients) })), !loading && recipients.length > 0 && ((0, jsx_runtime_1.jsx)(material_1.List, { dense: true, disablePadding: true, children: recipients.map((r) => ((0, jsx_runtime_1.jsxs)(material_1.Box, { children: [(0, jsx_runtime_1.jsxs)(material_1.ListItemButton, { onClick: () => void toggleExpand(r.address), sx: { px: 0, py: 0.5 }, children: [(0, jsx_runtime_1.jsx)(material_1.ListItemText, { primary: r.address, secondary: `${r.count} ${t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_Recipients)}` }), expanded === r.address ? ((0, jsx_runtime_1.jsx)(ExpandLess_1.default, { fontSize: "small" })) : ((0, jsx_runtime_1.jsx)(ExpandMore_1.default, { fontSize: "small" }))] }), (0, jsx_runtime_1.jsx)(material_1.Collapse, { in: expanded === r.address, unmountOnExit: true, children: emailsByAddress[r.address]?.length === 0 ? ((0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", color: "text.secondary", sx: { pl: 2, py: 0.5 }, children: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_NoEmails) })) : ((0, jsx_runtime_1.jsx)(material_1.List, { dense: true, disablePadding: true, sx: { pl: 2 }, children: (emailsByAddress[r.address] ?? []).map((email, idx) => {
134
+ const emailKey = `${r.address}:${idx}`;
135
+ const isEmailExpanded = expandedEmail === emailKey;
136
+ return ((0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { py: 0.25 }, children: [(0, jsx_runtime_1.jsxs)(material_1.ListItemButton, { disableGutters: true, onClick: () => setExpandedEmail(isEmailExpanded ? null : emailKey), sx: { py: 0.25, px: 0.5, borderRadius: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.ListItemText, { primary: email.subject || '(no subject)', secondary: `${t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_Timestamp)}: ${new Date(email.timestamp).toLocaleString()}`, primaryTypographyProps: { variant: 'body2' }, secondaryTypographyProps: { variant: 'caption' } }), isEmailExpanded ? ((0, jsx_runtime_1.jsx)(ExpandLess_1.default, { fontSize: "small" })) : ((0, jsx_runtime_1.jsx)(ExpandMore_1.default, { fontSize: "small" }))] }), (0, jsx_runtime_1.jsx)(material_1.Collapse, { in: isEmailExpanded, unmountOnExit: true, children: (0, jsx_runtime_1.jsx)(material_1.Box, { sx: { pl: 1, pr: 1, pb: 1 }, children: (0, jsx_runtime_1.jsx)(EmailBodyIframe, { html: email.html, text: email.text }) }) })] }, idx));
137
+ }) })) }), (0, jsx_runtime_1.jsx)(material_1.Divider, {})] }, r.address))) })), (0, jsx_runtime_1.jsx)(ConfirmationDialog_1.ConfirmationDialog, { open: clearDialogOpen, title: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_ClearAll), message: t(suite_core_lib_1.SuiteCoreStringKey.FakeEmail_Admin_ClearConfirm), onConfirm: () => void handleClearAll(), onCancel: () => setClearDialogOpen(false) })] }));
82
138
  };
83
139
  const FakeEmailAdminPanel = () => ((0, jsx_runtime_1.jsx)(useAuthenticatedApi_1.AuthenticatedApiProvider, { children: (0, jsx_runtime_1.jsx)(FakeEmailAdminPanelContent, {}) }));
84
140
  exports.FakeEmailAdminPanel = FakeEmailAdminPanel;