Skip to content

Commit 0ff928d

Browse files
committed
feat: umami transformer v1
1 parent 25561b9 commit 0ff928d

File tree

14 files changed

+330
-26
lines changed

14 files changed

+330
-26
lines changed

apps/dashboard/app/(main)/websites/[id]/_components/tabs/audience-tab.tsx

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import type { FullTabProps } from "../utils/types";
2525
import dayjs from "dayjs";
2626
import utc from "dayjs/plugin/utc";
2727
import timezone from "dayjs/plugin/timezone";
28+
import { ErrorBoundary } from "@/components/error-boundary";
2829
dayjs.extend(utc);
2930
dayjs.extend(timezone);
3031

@@ -582,6 +583,18 @@ export function WebsiteAudienceTab({
582583
[]
583584
);
584585

586+
// Feature detection for Intl.DisplayNames
587+
const canUseDisplayNames = useMemo(() => {
588+
if (typeof window === "undefined") return false;
589+
try {
590+
// Try to construct and use .of
591+
const dn = new Intl.DisplayNames([navigator.language || "en"], { type: "language" });
592+
return typeof dn.of === "function" && !!dn.of("en");
593+
} catch {
594+
return false;
595+
}
596+
}, []);
597+
585598
const displayNames = useMemo(
586599
() =>
587600
typeof window !== "undefined"
@@ -600,7 +613,12 @@ export function WebsiteAudienceTab({
600613
const entry = info.row.original;
601614
const language = entry.name;
602615
const code = (entry as any).code;
603-
const readableName = displayNames?.of(language) || language;
616+
let readableName = language;
617+
try {
618+
readableName = displayNames?.of(language) || language;
619+
} catch {
620+
readableName = language;
621+
}
604622
return (
605623
<div className="flex items-center gap-2">
606624
<Languages className="h-4 w-4 text-primary" />
@@ -688,7 +706,6 @@ export function WebsiteAudienceTab({
688706
[]
689707
);
690708

691-
// Prepare tabs for enhanced geographic data with unique keys
692709
const geographicTabs = useMemo(
693710
() => [
694711
{
@@ -718,15 +735,21 @@ export function WebsiteAudienceTab({
718735
})),
719736
columns: cityColumns,
720737
},
721-
{
722-
id: "languages",
723-
label: "Languages",
724-
data: processedData.geographic.languages.map((item, index) => ({
725-
...item,
726-
_uniqueKey: `language-${item.name}-${index}`,
727-
})),
728-
columns: languageColumns,
729-
},
738+
...(
739+
canUseDisplayNames
740+
? [
741+
{
742+
id: "languages",
743+
label: "Languages",
744+
data: processedData.geographic.languages.map((item, index) => ({
745+
...item,
746+
_uniqueKey: `language-${item.name}-${index}`,
747+
})),
748+
columns: languageColumns,
749+
},
750+
]
751+
: []
752+
),
730753
{
731754
id: "timezones",
732755
label: "Timezones",
@@ -748,6 +771,7 @@ export function WebsiteAudienceTab({
748771
cityColumns,
749772
languageColumns,
750773
timezoneColumns,
774+
canUseDisplayNames,
751775
]
752776
);
753777

@@ -831,14 +855,16 @@ export function WebsiteAudienceTab({
831855

832856
{/* Enhanced Geographic Data */}
833857
<div className="grid grid-cols-1 gap-4">
834-
<DataTable
835-
description="Visitors by location, timezone, and language (limit: 100 per category)"
836-
initialPageSize={8}
837-
isLoading={isLoading}
838-
minHeight={400}
839-
tabs={geographicTabs}
840-
title="Geographic Distribution"
841-
/>
858+
<ErrorBoundary>
859+
<DataTable
860+
description="Visitors by location, timezone, and language (limit: 100 per category)"
861+
initialPageSize={8}
862+
isLoading={isLoading}
863+
minHeight={400}
864+
tabs={geographicTabs}
865+
title="Geographic Distribution"
866+
/>
867+
</ErrorBoundary>
842868
</div>
843869

844870
{/* Screen Resolutions */}

bun.lock

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
"workspaces": {
44
"": {
55
"name": "databuddy",
6+
"dependencies": {
7+
"csv-parse": "^6.1.0",
8+
},
69
"devDependencies": {
710
"@biomejs/biome": "2.1.2",
11+
"@types/bun": "latest",
812
"turbo": "^2.5.2",
913
"typescript": "^5.8.3",
1014
},
@@ -389,6 +393,19 @@
389393
"react-email": "^4.0.17",
390394
},
391395
},
396+
"packages/mapper": {
397+
"name": "mapper",
398+
"dependencies": {
399+
"csv-parse": "^6.1.0",
400+
"zod": "4",
401+
},
402+
"devDependencies": {
403+
"@types/bun": "latest",
404+
},
405+
"peerDependencies": {
406+
"typescript": "^5",
407+
},
408+
},
392409
"packages/redis": {
393410
"name": "@databuddy/redis",
394411
"version": "1.0.0",
@@ -420,10 +437,10 @@
420437
},
421438
"packages/sdk": {
422439
"name": "@databuddy/sdk",
423-
"version": "1.4.0",
440+
"version": "1.4.1",
424441
"devDependencies": {
425442
"@types/node": "^20.0.0",
426-
"typescript": "^5.0.0",
443+
"typescript": "^5.8.3",
427444
},
428445
},
429446
"packages/shared": {
@@ -1533,6 +1550,8 @@
15331550

15341551
"csstype": ["[email protected]", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
15351552

1553+
"csv-parse": ["[email protected]", "", {}, "sha512-CEE+jwpgLn+MmtCpVcPtiCZpVtB6Z2OKPTr34pycYYoL7sxdOkXDdQ4lRiw6ioC0q6BLqhc6cKweCVvral8yhw=="],
1554+
15361555
"d3-array": ["[email protected]", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
15371556

15381557
"d3-color": ["[email protected]", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
@@ -2155,6 +2174,8 @@
21552174

21562175
"make-dir": ["[email protected]", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="],
21572176

2177+
"mapper": ["mapper@workspace:packages/mapper"],
2178+
21582179
"markdown-extensions": ["[email protected]", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="],
21592180

21602181
"markdown-table": ["[email protected]", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
@@ -3181,6 +3202,8 @@
31813202

31823203
"make-dir/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
31833204

3205+
"mapper/zod": ["[email protected]", "", {}, "sha512-/5UuuRPStvHXu7RS+gmvRf4NXrNxpSllGwDnCBcJZtQsKrviYXm54yDGV2KYNLT5kq0lHGcl7lqWJLgSaG+tgA=="],
3206+
31843207
"mdast-util-find-and-replace/escape-string-regexp": ["[email protected]", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
31853208

31863209
"mdast-util-mdx-jsx/parse-entities": ["[email protected]", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],

index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log("Hello via Bun!");

package.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"devDependencies": {
2121
"@biomejs/biome": "2.1.2",
2222
"turbo": "^2.5.2",
23-
"typescript": "^5.8.3"
23+
"typescript": "^5.8.3",
24+
"@types/bun": "latest"
2425
},
2526
"engines": {
2627
"node": ">=20"
@@ -29,5 +30,10 @@
2930
"workspaces": [
3031
"apps/*",
3132
"packages/*"
32-
]
33-
}
33+
],
34+
"dependencies": {
35+
"csv-parse": "^6.1.0"
36+
},
37+
"module": "index.ts",
38+
"type": "module"
39+
}

packages/mapper/.gitignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# dependencies (bun install)
2+
node_modules
3+
4+
# output
5+
out
6+
dist
7+
*.tgz
8+
9+
# code coverage
10+
coverage
11+
*.lcov
12+
13+
# logs
14+
logs
15+
_.log
16+
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
17+
18+
# dotenv environment variable files
19+
.env
20+
.env.development.local
21+
.env.test.local
22+
.env.production.local
23+
.env.local
24+
25+
# caches
26+
.eslintcache
27+
.cache
28+
*.tsbuildinfo
29+
30+
# IntelliJ based IDEs
31+
.idea
32+
33+
# Finder (MacOS) folder config
34+
.DS_Store

packages/mapper/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Entry point for analytics event mapping adapters
2+
3+
export * from './src';

packages/mapper/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "@databuddy/mapper",
3+
"module": "index.ts",
4+
"type": "module",
5+
"private": true,
6+
"devDependencies": {
7+
"@types/bun": "latest"
8+
},
9+
"peerDependencies": {
10+
"typescript": "^5"
11+
},
12+
"dependencies": {
13+
"csv-parse": "^6.1.0",
14+
"zod": "4"
15+
}
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './umami';

0 commit comments

Comments
 (0)