@mohasinac/appkit 4.41.8 → 4.41.9
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.
|
@@ -77,7 +77,21 @@ export async function handleOrderCreate(input, ctx) {
|
|
|
77
77
|
const firstItem = items[0];
|
|
78
78
|
const firstItemName = firstItem?.productTitle ?? "an item";
|
|
79
79
|
const additionalItemCount = Math.max(0, items.length - 1);
|
|
80
|
-
|
|
80
|
+
/*
|
|
81
|
+
* 🛑 DECRYPT. This handler receives the RAW Firestore snapshot — the type
|
|
82
|
+
* above says so — so it never passes through the repository's `mapDoc`, and
|
|
83
|
+
* `userName` is PII, stored as `enc:v1:…`.
|
|
84
|
+
*
|
|
85
|
+
* Undecrypted, the ciphertext was interpolated straight into the announcement
|
|
86
|
+
* body and PERSISTED there, so every admin alert read
|
|
87
|
+
* "🛍️ New order! enc:v1:67Mn0rITjTWGsZZE:… purchased …". Measured on
|
|
88
|
+
* production: 383 such rows. The message is baked at write time, so the
|
|
89
|
+
* damage is permanent per row — decrypting on read would not repair them.
|
|
90
|
+
*
|
|
91
|
+
* `decryptPii` was already imported in this file and used for the store
|
|
92
|
+
* owner's phone eleven lines up; the buyer's name was simply missed.
|
|
93
|
+
*/
|
|
94
|
+
const buyerName = decryptPii(order.userName) ?? order.userName ?? "A customer";
|
|
81
95
|
const message = buildPurchaseAnnouncementMessage({
|
|
82
96
|
buyerName,
|
|
83
97
|
firstItemName,
|
|
@@ -54,14 +54,24 @@ function AdminCardItem({ row, view, selected, onToggleSelect, onRowClick, render
|
|
|
54
54
|
return (_jsxs(Row, { gap: "sm", className: [
|
|
55
55
|
"px-[var(--appkit-space-4)] py-[var(--appkit-space-3)] cursor-pointer transition-colors hover:bg-surface-hover",
|
|
56
56
|
selected ? "bg-primary-50/40 dark:bg-primary-900/10" : "",
|
|
57
|
-
].filter(Boolean).join(" "), onClick: handleClick, role: onRowClick ? "button" : undefined, children: [onToggleSelect && (_jsx(Div, { "data-no-row-click": true, className: "shrink-0", onClick: (e) => {
|
|
57
|
+
].filter(Boolean).join(" "), onClick: handleClick, role: onRowClick ? "button" : undefined, children: [onToggleSelect && (_jsx(Div, { "data-no-row-click": true, className: "shrink-0", onClick: (e) => {
|
|
58
|
+
e.stopPropagation();
|
|
59
|
+
if (e.target === e.currentTarget)
|
|
60
|
+
onToggleSelect(row.id);
|
|
61
|
+
}, children: _jsx(Checkbox, { bare: true, checked: selected, onChange: () => onToggleSelect(row.id), className: "h-4 w-4 rounded border-zinc-300 text-primary accent-primary cursor-pointer", "aria-label": `Select ${row.primary}` }) })), _jsx(RowAvatar, { image: row.image, alt: row.primary, icon: resourceIcon }), _jsxs(Stack, { gap: "none", className: "flex-1 min-w-0", children: [_jsx(Text, { size: "sm", weight: "semibold", className: "truncate", color: "primary", children: row.primary }), _jsx(Text, { size: "xs", color: "muted", className: "truncate", children: row.secondary }), row.barcodeId && (_jsx(Text, { size: "xs", color: "faint", className: "truncate font-mono", children: row.barcodeId }))] }), flags.length > 0 && (_jsx(Row, { gap: "xs", className: "hidden sm:flex shrink-0", children: flags.map(({ key, label, tone }) => (_jsx(Span, { padding: "pill-2xs", weight: "medium", className: `inline-flex text-[10px] ${STATUS_TONE_CLASSES[tone]}`, rounded: "full", children: label }, key))) })), _jsx(StatusBadge, { status: row.status }), _jsx(Span, { size: "xs", color: "muted", className: "hidden sm:block shrink-0 w-24", align: "end", children: row.updatedAt }), renderRowActions && (_jsx(Div, { "data-no-row-click": true, className: "shrink-0", onClick: (e) => e.stopPropagation(), children: renderRowActions(row) }))] }));
|
|
58
62
|
}
|
|
59
63
|
return (_jsxs(Div, { rounded: "xl", className: [
|
|
60
64
|
"border overflow-hidden cursor-pointer transition-all hover:shadow-md hover:-translate-y-0.5",
|
|
61
65
|
selected
|
|
62
66
|
? "border-primary ring-1 ring-primary/20 bg-primary-50/30 dark:bg-primary-900/10"
|
|
63
67
|
: " border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]",
|
|
64
|
-
].filter(Boolean).join(" "), onClick: handleClick, role: onRowClick ? "button" : undefined, children: [onToggleSelect && (_jsxs(Row, { gap: "xs", "data-no-row-click": true, paddingY: "t-sm", padding: "x-sm",
|
|
68
|
+
].filter(Boolean).join(" "), onClick: handleClick, role: onRowClick ? "button" : undefined, children: [onToggleSelect && (_jsxs(Row, { gap: "xs", "data-no-row-click": true, paddingY: "t-sm", padding: "x-sm",
|
|
69
|
+
// Same double-toggle guard as the compact row above — see that comment.
|
|
70
|
+
onClick: (e) => {
|
|
71
|
+
e.stopPropagation();
|
|
72
|
+
if (e.target === e.currentTarget)
|
|
73
|
+
onToggleSelect(row.id);
|
|
74
|
+
}, children: [_jsx(Checkbox, { bare: true, checked: selected, onChange: () => onToggleSelect(row.id), className: "h-4 w-4 rounded border-zinc-300 text-primary accent-primary cursor-pointer", "aria-label": `Select ${row.primary}` }), flags.length > 0 && (_jsx(Row, { gap: "xs", wrap: true, children: flags.map(({ key, label, tone }) => (_jsx(Span, { padding: "pill-2xs", weight: "medium", className: `inline-flex text-[10px] ${STATUS_TONE_CLASSES[tone]}`, rounded: "full", children: label }, key))) }))] })), _jsxs(Stack, { gap: "xs", className: `${__P.p3}.5`, children: [_jsxs(Row, { gap: "sm", align: "center", children: [_jsx(RowAvatar, { image: row.image, alt: row.primary, icon: resourceIcon, size: "12" }), _jsxs(Stack, { gap: "none", className: "min-w-0 flex-1", children: [_jsx(Text, { size: "sm", weight: "semibold", className: "line-clamp-2 leading-snug", color: "primary", children: row.primary }), _jsx(Text, { size: "xs", color: "muted", className: "truncate", children: row.secondary })] })] }), row.barcodeId && (_jsx(Text, { size: "xs", color: "faint", className: "truncate font-mono", children: row.barcodeId })), _jsxs(Row, { justify: "between", gap: "xs", children: [_jsx(StatusBadge, { status: row.status }), _jsx(Span, { color: "muted", className: "text-[11px] shrink-0", children: row.updatedAt })] }), renderRowActions && (_jsx(Row, { "data-no-row-click": true, justify: "end", gap: "xs", className: "border-t border-[var(--appkit-color-border)] -mx-[var(--appkit-space-3)] -mb-[var(--appkit-space-3)] mt-[var(--appkit-space-1)] px-[var(--appkit-space-3)] py-[var(--appkit-space-2)]", onClick: (e) => e.stopPropagation(), children: renderRowActions(row) }))] })] }));
|
|
65
75
|
}
|
|
66
76
|
export function AdminViewCards({ rows, view, isLoading, emptyLabel = "No items found", onRowClick, selectedIdSet, onToggleSelect, renderRowActions, resourceIcon, }) {
|
|
67
77
|
if (isLoading) {
|