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
98 lines
3.7 KiB
TypeScript
98 lines
3.7 KiB
TypeScript
import {
|
||
SettingsFormCard,
|
||
type SettingFieldDef,
|
||
} from '@/components/admin/shared/settings-form-card';
|
||
import { UmamiTestButton } from '@/components/admin/website-analytics/umami-test-button';
|
||
import { PageHeader } from '@/components/shared/page-header';
|
||
|
||
/**
|
||
* Per-port Umami credentials. Self-hosted Umami uses username + password →
|
||
* JWT bearer token (https://docs.umami.is/docs/api/authentication); the
|
||
* service POSTs to /api/auth/login and caches the JWT in-memory. Umami
|
||
* Cloud installations use a long-lived API key instead; the optional field
|
||
* below covers that case. All credentials are port-scoped so different
|
||
* ports can point at different Umami instances.
|
||
*/
|
||
const FIELDS: SettingFieldDef[] = [
|
||
{
|
||
key: 'umami_api_url',
|
||
label: 'Umami URL',
|
||
description:
|
||
'Base URL of the Umami instance, e.g. https://analytics.portnimara.com (no trailing slash, no /api).',
|
||
type: 'string',
|
||
placeholder: 'https://analytics.portnimara.com',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
key: 'umami_username',
|
||
label: 'Username',
|
||
description: 'Umami login username (self-hosted).',
|
||
type: 'string',
|
||
placeholder: 'admin',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
key: 'umami_password',
|
||
label: 'Password',
|
||
description:
|
||
'Umami login password (self-hosted). Exchanged for a JWT via /api/auth/login on each port; the JWT is cached for 55 minutes. Stored AES-256-GCM at rest.',
|
||
type: 'password',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
key: 'umami_website_id',
|
||
label: 'Website ID',
|
||
description:
|
||
'UUID of this port’s website inside Umami. Find it in Umami → Settings → Websites → Edit → Website ID.',
|
||
type: 'string',
|
||
placeholder: '00000000-0000-0000-0000-000000000000',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
key: 'umami_api_token',
|
||
label: 'API key (Umami Cloud only - optional)',
|
||
description:
|
||
'Only fill this if you use Umami Cloud, which uses a long-lived API key instead of username/password. Leave blank for self-hosted installs - the username + password above are used instead. Stored AES-256-GCM at rest.',
|
||
type: 'password',
|
||
defaultValue: '',
|
||
},
|
||
];
|
||
|
||
// Tracking-pixel kill switch - opt-in per port. When enabled, outbound
|
||
// sales sends embed a 1×1 pixel pointing at /api/public/email-pixel that
|
||
// records opens to `document_send_opens` and cross-posts to Umami.
|
||
const TRACKING_FIELDS: SettingFieldDef[] = [
|
||
{
|
||
key: 'email_open_tracking_enabled',
|
||
label: 'Track email opens',
|
||
description:
|
||
'Embeds an invisible 1×1 tracking pixel in outbound sales emails. Each open is recorded in the CRM and cross-posted to Umami as an "email-opened" event. Apple Mail privacy proxy will over-count; clients that block images will under-count - standard email-tracking caveats apply.',
|
||
type: 'boolean',
|
||
defaultValue: false,
|
||
},
|
||
];
|
||
|
||
export default function WebsiteAnalyticsSettingsPage() {
|
||
return (
|
||
<div className="space-y-6">
|
||
<PageHeader
|
||
title="Website analytics (Umami)"
|
||
description="Connect this port to its Umami website to display traffic, top pages, referrers, and conversion data on the Website Analytics dashboard."
|
||
/>
|
||
|
||
<SettingsFormCard
|
||
title="Umami connection"
|
||
description="Self-hosted Umami: enter URL + username + password + website ID. Umami Cloud: enter URL + API key (Cloud field at the bottom) + website ID. Each port can point at its own Umami instance, or share one instance with different website IDs."
|
||
fields={FIELDS}
|
||
extra={<UmamiTestButton />}
|
||
/>
|
||
|
||
<SettingsFormCard
|
||
title="Email open tracking"
|
||
description="Opt-in tracking for outbound sales emails. Disabled by default."
|
||
fields={TRACKING_FIELDS}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|