Bundles the prior autonomous-session output that was sitting unstaged: - Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances) - country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk after the per-subpath dynamic-import approach silently failed in webpack) - Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index, redirects (ocr to ai, reports to dashboard, invitations to users), docs/admin-ia-proposal.md - Per-template email tester (registry + endpoint + UI on Email admin page) - Cancel-document mode picker (delete-from-Documenso vs keep-for-audit) - Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers - Customize-widgets per-region sortables at xl+ (charts/rails/feed); single flat sortable below xl when the layout stacks; per-viewport saved orders - Audit doc updates capturing each shipped item - Lint fixes: react-compiler immutability in DonutChart (reduce instead of let-reassign), set-state-in-effect disables in CountryFlag and UploadForSigning preview-bytes effect, unused 'confirm' destructures in interest contract + reservation tabs, unescaped apostrophe in test-template card copy
47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
/**
|
||
* Open-tracking pixel injector (Phase 4b). Appends a 1×1 transparent
|
||
* image pointing at /api/public/email-pixel/[sendId] to outbound HTML
|
||
* emails. The pixel endpoint records the open + cross-posts the event
|
||
* to Umami.
|
||
*
|
||
* Sites that want to opt out of tracking simply don't call this helper.
|
||
* The pixel URL is unguessable per-send (UUID), but a `track_opens=false`
|
||
* row in `document_sends` makes the endpoint a no-op even if someone
|
||
* does guess one.
|
||
*
|
||
* Privacy: respects EMAIL_REDIRECT_TO (no pixel injected when dev
|
||
* redirect is active) so a re-routed message doesn't fire a fake open.
|
||
*/
|
||
|
||
import { env } from '@/lib/env';
|
||
|
||
interface InjectOptions {
|
||
/** Public base URL of the CRM (e.g. https://crm.portnimara.com).
|
||
* Required so the pixel link is absolute - relative URLs break in
|
||
* email clients. */
|
||
appBaseUrl: string;
|
||
/** UUID of the row in `document_sends`. */
|
||
sendId: string;
|
||
}
|
||
|
||
/**
|
||
* Append a 1×1 tracking pixel just before `</body>` (or at the end of the
|
||
* document if no `</body>` is present). Returns the HTML unchanged when
|
||
* EMAIL_REDIRECT_TO is set so dev-mode re-routing doesn't generate
|
||
* misleading open events.
|
||
*/
|
||
export function injectTrackingPixel(html: string, opts: InjectOptions): string {
|
||
if (env.EMAIL_REDIRECT_TO) return html;
|
||
|
||
const base = opts.appBaseUrl.replace(/\/$/, '');
|
||
const pixelUrl = `${base}/api/public/email-pixel/${opts.sendId}`;
|
||
const pixelTag =
|
||
`<img src="${pixelUrl}" width="1" height="1" alt="" ` +
|
||
`style="display:block;border:0;margin:0;padding:0" />`;
|
||
|
||
if (html.includes('</body>')) {
|
||
return html.replace('</body>', `${pixelTag}</body>`);
|
||
}
|
||
return html + pixelTag;
|
||
}
|