Merge branch 'dev' into 3802-team-to-user-switch

This commit is contained in:
Mike Cao 2025-12-01 10:12:19 -08:00 committed by GitHub
commit 3071ee8b88
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
577 changed files with 2413 additions and 3644 deletions

View file

@ -1 +0,0 @@
/src/generated/

View file

@ -1,51 +0,0 @@
{
"env": {
"browser": true,
"es2020": true,
"node": true,
"jquery": true,
"jest": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 11,
"sourceType": "module"
},
"extends": [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"eslint:recommended",
"plugin:prettier/recommended",
"plugin:import/errors",
"plugin:import/typescript",
"plugin:css-modules/recommended",
"plugin:cypress/recommended",
"prettier",
"next"
],
"plugins": ["@typescript-eslint", "prettier", "promise", "css-modules", "cypress"],
"rules": {
"no-console": "error",
"react/display-name": "off",
"react-hooks/exhaustive-deps": "off",
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"import/no-anonymous-default-export": "off",
"import/no-named-as-default": "off",
"css-modules/no-unused-class": "off",
"@next/next/no-img-element": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-unused-vars": ["error", { "ignoreRestSiblings": true }],
"@typescript-eslint/no-namespace": ["error", { "allowDeclarations": true }],
"@typescript-eslint/triple-slash-reference": "off"
},
"globals": {
"React": "writable"
}
}

View file

@ -1,2 +0,0 @@
/public/script.js
/src/generated/

View file

@ -1,7 +0,0 @@
{
"arrowParens": "avoid",
"endOfLine": "lf",
"printWidth": 100,
"singleQuote": true,
"trailingComma": "all"
}

View file

@ -42,10 +42,7 @@ RUN set -x \
&& apk add --no-cache curl
# Script dependencies
RUN pnpm add npm-run-all dotenv chalk semver prisma@6.18.0 @prisma/adapter-pg@6.18.0
# Permissions for prisma
RUN chown -R nextjs:nodejs node_modules/.pnpm/
RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver prisma@6.18.0 @prisma/adapter-pg@6.18.0
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/prisma ./prisma

57
biome.json Normal file
View file

@ -0,0 +1,57 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.6/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"includes": ["**", "!!**/dist"]
},
"formatter": {
"enabled": true,
"lineWidth": 100,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf"
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"a11y": "off",
"correctness": {
"useExhaustiveDependencies": "off"
},
"style": {
"noDescendingSpecificity": "off"
},
"complexity": {
"noImportantStyles": "off"
},
"suspicious": {
"noArrayIndexKey": "off",
"noExplicitAny": "off",
"noImplicitAnyLet": "off"
},
"performance": {
"noImgElement": "off"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "all",
"arrowParentheses": "asNeeded"
}
},
"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": "on"
}
}
}
}

View file

@ -1,4 +1,4 @@
import { NextRequest, NextResponse } from 'next/server';
import { type NextRequest, NextResponse } from 'next/server';
export const config = {
matcher: '/:path*',

View file

@ -1,5 +1,5 @@
import 'dotenv/config';
import pkg from './package.json' assert { type: 'json' };
import pkg from './package.json' with { type: 'json' };
const TRACKER_SCRIPT = '/script.js';

View file

@ -42,24 +42,18 @@
"download-country-names": "node scripts/download-country-names.js",
"download-language-names": "node scripts/download-language-names.js",
"change-password": "node scripts/change-password.js",
"lint": "next lint --quiet",
"prepare": "node -e \"if (process.env.NODE_ENV !== 'production'){process.exit(1)} \" || husky install",
"postbuild": "node scripts/postbuild.js",
"test": "jest",
"cypress-open": "cypress open cypress run",
"cypress-run": "cypress run cypress run"
"cypress-run": "cypress run cypress run",
"lint": "biome lint .",
"format": "biome format --write .",
"check": "biome check --write"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint"
],
"**/*.css": [
"stylelint --fix",
"prettier --write"
],
"**/*.json": [
"prettier --write"
"**/*.{js,jsx,ts,tsx,json,css}": [
"biome check --write --no-errors-on-unmatched --files-ignore-unknown=true"
]
},
"cacheDirectories": [
@ -78,7 +72,7 @@
"@react-spring/web": "^10.0.3",
"@svgr/cli": "^8.1.0",
"@tanstack/react-query": "^5.90.5",
"@umami/react-zen": "^0.207.0",
"@umami/react-zen": "^0.210.0",
"@umami/redis-client": "^0.29.0",
"bcryptjs": "^3.0.2",
"chalk": "^5.6.2",
@ -95,7 +89,6 @@
"detect-browser": "^5.2.0",
"dotenv": "^17.2.3",
"esbuild": "^0.25.11",
"eslint-plugin-promise": "^6.1.1",
"fs-extra": "^11.3.2",
"immer": "^10.2.0",
"ipaddr.js": "^2.0.1",
@ -132,6 +125,7 @@
"zustand": "^5.0.8"
},
"devDependencies": {
"@biomejs/biome": "^2.3.6",
"@formatjs/cli": "^4.2.29",
"@netlify/plugin-nextjs": "^5.14.4",
"@rollup/plugin-alias": "^5.0.0",
@ -146,20 +140,9 @@
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2",
"@types/react-window": "^1.8.8",
"@typescript-eslint/eslint-plugin": "^8.46.2",
"@typescript-eslint/parser": "^8.46.2",
"babel-plugin-react-compiler": "19.1.0-rc.2",
"cross-env": "^10.1.0",
"cypress": "^13.6.6",
"eslint": "^8.33.0",
"eslint-config-next": "^14.2.33",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-css-modules": "^2.12.0",
"eslint-plugin-cypress": "^2.15.1",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest": "^27.9.0",
"eslint-plugin-prettier": "^5.5.3",
"extract-react-intl-messages": "^4.1.1",
"husky": "^9.1.7",
"jest": "^29.7.0",
@ -168,7 +151,6 @@
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-import": "^15.1.0",
"postcss-preset-env": "7.8.3",
"prettier": "^3.6.2",
"prompts": "2.4.2",
"rollup": "^4.52.5",
"rollup-plugin-copy": "^3.4.0",

2885
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

8
prisma.config.ts Normal file
View file

@ -0,0 +1,8 @@
import 'dotenv/config';
import { defineConfig, env } from 'prisma/config';
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
},
});

View file

@ -1,19 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View file

@ -3,8 +3,8 @@ import 'dotenv/config';
import fs from 'node:fs';
import path from 'node:path';
import https from 'https';
import zlib from 'zlib';
import tar from 'tar';
import zlib from 'zlib';
if (process.env.VERCEL && !process.env.BUILD_GEO) {
console.log('Vercel environment detected. Skipping geo setup.');
@ -50,7 +50,9 @@ const downloadDirect = (url, originalUrl) =>
https.get(url, res => {
// Follow redirects
if (res.statusCode === 301 || res.statusCode === 302) {
downloadDirect(res.headers.location, originalUrl || url).then(resolve).catch(reject);
downloadDirect(res.headers.location, originalUrl || url)
.then(resolve)
.catch(reject);
return;
}
@ -78,27 +80,29 @@ if (isDirectMmdb) {
process.exit(1);
});
} else {
downloadCompressed(url).then(
res =>
new Promise((resolve, reject) => {
res.on('entry', entry => {
if (entry.path.endsWith('.mmdb')) {
const filename = path.join(dest, path.basename(entry.path));
entry.pipe(fs.createWriteStream(filename));
downloadCompressed(url)
.then(
res =>
new Promise((resolve, reject) => {
res.on('entry', entry => {
if (entry.path.endsWith('.mmdb')) {
const filename = path.join(dest, path.basename(entry.path));
entry.pipe(fs.createWriteStream(filename));
console.log('Saved geo database:', filename);
}
});
console.log('Saved geo database:', filename);
}
});
res.on('error', e => {
reject(e);
});
res.on('finish', () => {
resolve();
});
}),
).catch(e => {
console.error('Failed to download geo database:', e);
process.exit(1);
});
res.on('error', e => {
reject(e);
});
res.on('finish', () => {
resolve();
});
}),
)
.catch(e => {
console.error('Failed to download geo database:', e);
process.exit(1);
});
}

View file

@ -1,10 +1,10 @@
/* eslint-disable no-console */
import 'dotenv/config';
import { execSync } from 'node:child_process';
import { PrismaPg } from '@prisma/adapter-pg';
import chalk from 'chalk';
import semver from 'semver';
import { PrismaClient } from '../generated/prisma/client.js';
import { PrismaPg } from '@prisma/adapter-pg';
const MIN_VERSION = '9.4.0';

View file

@ -1,8 +1,9 @@
/* eslint-disable no-console */
import fs from 'fs-extra';
import path from 'node:path';
import https from 'https';
import chalk from 'chalk';
import fs from 'fs-extra';
import https from 'https';
const src = path.resolve(process.cwd(), 'src/lang');
const dest = path.resolve(process.cwd(), 'public/intl/country');

View file

@ -1,8 +1,9 @@
/* eslint-disable no-console */
import fs from 'fs-extra';
import path from 'node:path';
import https from 'https';
import chalk from 'chalk';
import fs from 'fs-extra';
import https from 'https';
const src = path.resolve(process.cwd(), 'src/lang');
const dest = path.resolve(process.cwd(), 'public/intl/language');

View file

@ -1,6 +1,6 @@
import path from 'node:path';
import fs from 'fs-extra';
import del from 'del';
import fs from 'fs-extra';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);

View file

@ -1,8 +1,8 @@
/* eslint-disable no-console */
import fs from 'node:fs';
import path from 'node:path';
import prettier from 'prettier';
import { createRequire } from 'module';
import prettier from 'prettier';
const require = createRequire(import.meta.url);

View file

@ -1,11 +1,11 @@
export const dynamic = 'force-dynamic';
import { NextResponse } from 'next/server';
import { notFound } from '@/lib/response';
import redis from '@/lib/redis';
import { findPixel } from '@/queries/prisma';
import { Pixel } from '@/generated/prisma/client';
import { POST } from '@/app/api/send/route';
import type { Pixel } from '@/generated/prisma/client';
import redis from '@/lib/redis';
import { notFound } from '@/lib/response';
import { findPixel } from '@/queries/prisma';
const image = Buffer.from('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw', 'base64');

View file

@ -1,11 +1,11 @@
export const dynamic = 'force-dynamic';
import { NextResponse } from 'next/server';
import { POST } from '@/app/api/send/route';
import type { Link } from '@/generated/prisma/client';
import redis from '@/lib/redis';
import { notFound } from '@/lib/response';
import { findLink } from '@/queries/prisma';
import { POST } from '@/app/api/send/route';
import { Link } from '@/generated/prisma/client';
import redis from '@/lib/redis';
export async function GET(request: Request, { params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;

View file

@ -1,13 +1,13 @@
'use client';
import { Grid, Loading, Column, Row } from '@umami/react-zen';
import { Column, Grid, Loading, Row } from '@umami/react-zen';
import Script from 'next/script';
import { UpdateNotice } from './UpdateNotice';
import { SideNav } from '@/app/(main)/SideNav';
import { useLoginQuery, useConfig, useNavigation } from '@/components/hooks';
import { MobileNav } from '@/app/(main)/MobileNav';
import { useEffect } from 'react';
import { removeItem, setItem } from '@/lib/storage';
import { MobileNav } from '@/app/(main)/MobileNav';
import { SideNav } from '@/app/(main)/SideNav';
import { useConfig, useLoginQuery, useNavigation } from '@/components/hooks';
import { LAST_TEAM_CONFIG } from '@/lib/constants';
import { removeItem, setItem } from '@/lib/storage';
import { UpdateNotice } from './UpdateNotice';
export function App({ children }) {
const { user, isLoading, error } = useLoginQuery();
@ -27,7 +27,9 @@ export function App({ children }) {
}
if (error) {
window.location.href = `${process.env.basePath || ''}/login`;
window.location.href = config.cloudMode
? `${process.env.cloudUrl}/login`
: `${process.env.basePath || ''}/login`;
return null;
}

View file

@ -1,11 +1,11 @@
import { Grid, IconLabel, NavMenu, NavMenuItem, Row, Text } from '@umami/react-zen';
import Link from 'next/link';
import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav';
import { useMessages, useNavigation } from '@/components/hooks';
import { Globe, Grid2x2, LinkIcon } from '@/components/icons';
import { MobileMenuButton } from '@/components/input/MobileMenuButton';
import { NavButton } from '@/components/input/NavButton';
import { Logo } from '@/components/svg';
import { Grid, IconLabel, NavMenu, NavMenuItem, Row, Text } from '@umami/react-zen';
import Link from 'next/link';
import { AdminNav } from './admin/AdminNav';
import { SettingsNav } from './settings/SettingsNav';

View file

@ -1,20 +1,20 @@
import { Key } from 'react';
import Link from 'next/link';
import {
Sidebar,
SidebarSection,
SidebarItem,
SidebarHeader,
Row,
SidebarProps,
Sidebar,
SidebarHeader,
SidebarItem,
type SidebarProps,
SidebarSection,
ThemeButton,
} from '@umami/react-zen';
import { Globe, LinkIcon, Grid2x2, PanelLeft } from '@/components/icons';
import { Logo } from '@/components/svg';
import { useMessages, useNavigation, useGlobalState } from '@/components/hooks';
import Link from 'next/link';
import type { Key } from 'react';
import { useGlobalState, useMessages, useNavigation } from '@/components/hooks';
import { Globe, Grid2x2, LinkIcon, PanelLeft } from '@/components/icons';
import { LanguageButton } from '@/components/input/LanguageButton';
import { NavButton } from '@/components/input/NavButton';
import { PanelButton } from '@/components/input/PanelButton';
import { LanguageButton } from '@/components/input/LanguageButton';
import { Logo } from '@/components/svg';
export function SideNav(props: SidebarProps) {
const { formatMessage, labels } = useMessages();

View file

@ -1,4 +1,4 @@
import { ThemeButton, Row } from '@umami/react-zen';
import { Row, ThemeButton } from '@umami/react-zen';
import { LanguageButton } from '@/components/input/LanguageButton';
import { ProfileButton } from '@/components/input/ProfileButton';

View file

@ -1,10 +1,10 @@
import { useEffect, useCallback, useState } from 'react';
import { Button, AlertBanner, Column, Row } from '@umami/react-zen';
import { setItem } from '@/lib/storage';
import { useVersion, checkVersion } from '@/store/version';
import { REPO_URL, VERSION_CHECK } from '@/lib/constants';
import { useMessages } from '@/components/hooks';
import { AlertBanner, Button, Column, Row } from '@umami/react-zen';
import { usePathname } from 'next/navigation';
import { useCallback, useEffect, useState } from 'react';
import { useMessages } from '@/components/hooks';
import { REPO_URL, VERSION_CHECK } from '@/lib/constants';
import { setItem } from '@/lib/storage';
import { checkVersion, useVersion } from '@/store/version';
export function UpdateNotice({ user, config }) {
const { formatMessage, labels, messages } = useMessages();

View file

@ -1,8 +1,8 @@
'use client';
import { Column, Grid } from '@umami/react-zen';
import type { ReactNode } from 'react';
import { PageBody } from '@/components/common/PageBody';
import { useLoginQuery } from '@/components/hooks';
import { Column, Grid } from '@umami/react-zen';
import { ReactNode } from 'react';
import { AdminNav } from './AdminNav';
export function AdminLayout({ children }: { children: ReactNode }) {

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { AdminLayout } from './AdminLayout';
export default function ({ children }) {

View file

@ -1,7 +1,7 @@
import type { ReactNode } from 'react';
import { DataGrid } from '@/components/common/DataGrid';
import { useTeamsQuery } from '@/components/hooks';
import { AdminTeamsTable } from './AdminTeamsTable';
import { ReactNode } from 'react';
export function AdminTeamsDataTable({
showActions,

View file

@ -1,9 +1,9 @@
'use client';
import { AdminTeamsDataTable } from './AdminTeamsDataTable';
import { Column } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import { PageHeader } from '@/components/common/PageHeader';
import { Panel } from '@/components/common/Panel';
import { useMessages } from '@/components/hooks';
import { AdminTeamsDataTable } from './AdminTeamsDataTable';
export function AdminTeamsPage() {
const { formatMessage, labels } = useMessages();

View file

@ -1,11 +1,11 @@
import { DataColumn, DataTable, Dialog, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen';
import Link from 'next/link';
import { useState } from 'react';
import { DateDistance } from '@/components/common/DateDistance';
import { useMessages } from '@/components/hooks';
import { Edit, Trash } from '@/components/icons';
import { MenuButton } from '@/components/input/MenuButton';
import { DataColumn, DataTable, Dialog, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen';
import { TeamDeleteForm } from '../../teams/[teamId]/TeamDeleteForm';
import Link from 'next/link';
import { useState } from 'react';
export function AdminTeamsTable({
data = [],

View file

@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import { AdminTeamPage } from './AdminTeamPage';
import { Metadata } from 'next';
export default async function ({ params }: { params: Promise<{ teamId: string }> }) {
const { teamId } = await params;

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { AdminTeamsPage } from './AdminTeamsPage';
export default function () {

View file

@ -1,7 +1,7 @@
import { Button, Icon, Text, Modal, DialogTrigger, Dialog, useToast } from '@umami/react-zen';
import { UserAddForm } from './UserAddForm';
import { Button, Dialog, DialogTrigger, Icon, Modal, Text, useToast } from '@umami/react-zen';
import { useMessages, useModified } from '@/components/hooks';
import { Plus } from '@/components/icons';
import { UserAddForm } from './UserAddForm';
export function UserAddButton({ onSave }: { onSave?: () => void }) {
const { formatMessage, labels, messages } = useMessages();

View file

@ -1,13 +1,13 @@
import {
Select,
ListItem,
Form,
FormField,
FormButtons,
FormSubmitButton,
TextField,
PasswordField,
Button,
Form,
FormButtons,
FormField,
FormSubmitButton,
ListItem,
PasswordField,
Select,
TextField,
} from '@umami/react-zen';
import { useMessages, useUpdateQuery } from '@/components/hooks';
import { ROLES } from '@/lib/constants';

View file

@ -1,5 +1,5 @@
import { Button, Icon, Modal, DialogTrigger, Dialog, Text } from '@umami/react-zen';
import { useMessages, useLoginQuery } from '@/components/hooks';
import { Button, Dialog, DialogTrigger, Icon, Modal, Text } from '@umami/react-zen';
import { useLoginQuery, useMessages } from '@/components/hooks';
import { Trash } from '@/components/icons';
import { UserDeleteForm } from './UserDeleteForm';

View file

@ -1,7 +1,7 @@
import type { ReactNode } from 'react';
import { DataGrid } from '@/components/common/DataGrid';
import { useUsersQuery } from '@/components/hooks';
import { UsersTable } from './UsersTable';
import { ReactNode } from 'react';
export function UsersDataTable({ showActions }: { showActions?: boolean; children?: ReactNode }) {
const queryResult = useUsersQuery();

View file

@ -1,10 +1,10 @@
'use client';
import { UsersDataTable } from './UsersDataTable';
import { Column } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import { UserAddButton } from './UserAddButton';
import { PageHeader } from '@/components/common/PageHeader';
import { Panel } from '@/components/common/Panel';
import { useMessages } from '@/components/hooks';
import { UserAddButton } from './UserAddButton';
import { UsersDataTable } from './UsersDataTable';
export function UsersPage() {
const { formatMessage, labels } = useMessages();

View file

@ -1,13 +1,12 @@
import { useState } from 'react';
import { Row, Text, Icon, DataTable, DataColumn, MenuItem, Modal } from '@umami/react-zen';
import { DataColumn, DataTable, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen';
import Link from 'next/link';
import { ROLES } from '@/lib/constants';
import { Trash } from '@/components/icons';
import { useMessages } from '@/components/hooks';
import { Edit } from '@/components/icons';
import { MenuButton } from '@/components/input/MenuButton';
import { UserDeleteForm } from './UserDeleteForm';
import { useState } from 'react';
import { DateDistance } from '@/components/common/DateDistance';
import { useMessages } from '@/components/hooks';
import { Edit, Trash } from '@/components/icons';
import { MenuButton } from '@/components/input/MenuButton';
import { ROLES } from '@/lib/constants';
import { UserDeleteForm } from './UserDeleteForm';
export function UsersTable({
data = [],

View file

@ -1,12 +1,12 @@
import {
Select,
ListItem,
Form,
FormField,
FormButtons,
TextField,
FormField,
FormSubmitButton,
ListItem,
PasswordField,
Select,
TextField,
} from '@umami/react-zen';
import { useLoginQuery, useMessages, useUpdateQuery, useUser } from '@/components/hooks';
import { ROLES } from '@/lib/constants';
@ -30,7 +30,7 @@ export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () =
};
return (
<Form onSubmit={handleSubmit} error={getMessage(error?.['code'])} values={user}>
<Form onSubmit={handleSubmit} error={getMessage(error?.code)} values={user}>
<FormField name="username" label={formatMessage(labels.username)}>
<TextField data-test="input-username" />
</FormField>

View file

@ -1,6 +1,6 @@
import { User } from '@/components/icons';
import { PageHeader } from '@/components/common/PageHeader';
import { useUser } from '@/components/hooks';
import { User } from '@/components/icons';
export function UserHeader() {
const user = useUser();

View file

@ -1,9 +1,9 @@
'use client';
import { Column } from '@umami/react-zen';
import { UserSettings } from './UserSettings';
import { UserProvider } from './UserProvider';
import { UserHeader } from '@/app/(main)/admin/users/[userId]/UserHeader';
import { Panel } from '@/components/common/Panel';
import { UserProvider } from './UserProvider';
import { UserSettings } from './UserSettings';
export function UserPage({ userId }: { userId: string }) {
return (

View file

@ -1,7 +1,7 @@
import { createContext, ReactNode } from 'react';
import { Loading } from '@umami/react-zen';
import { User } from '@/generated/prisma/client';
import { createContext, type ReactNode } from 'react';
import { useUserQuery } from '@/components/hooks/queries/useUserQuery';
import type { User } from '@/generated/prisma/client';
export const UserContext = createContext<User>(null);

View file

@ -1,6 +1,6 @@
import { Column, Tabs, Tab, TabList, TabPanel } from '@umami/react-zen';
import { UserEditForm } from './UserEditForm';
import { Column, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import { UserEditForm } from './UserEditForm';
import { UserWebsites } from './UserWebsites';
export function UserSettings({ userId }: { userId: string }) {

View file

@ -1,6 +1,6 @@
import { WebsitesTable } from '@/app/(main)/websites/WebsitesTable';
import { DataGrid } from '@/components/common/DataGrid';
import { useUserWebsitesQuery } from '@/components/hooks';
import { WebsitesTable } from '@/app/(main)/websites/WebsitesTable';
export function UserWebsites({ userId }) {
const queryResult = useUserWebsitesQuery({ userId });

View file

@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import { UserPage } from './UserPage';
import { Metadata } from 'next';
export default async function ({ params }: { params: Promise<{ userId: string }> }) {
const { userId } = await params;

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { UsersPage } from './UsersPage';
export default function () {

View file

@ -1,9 +1,9 @@
'use client';
import { AdminWebsitesDataTable } from './AdminWebsitesDataTable';
import { Column } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import { PageHeader } from '@/components/common/PageHeader';
import { Panel } from '@/components/common/Panel';
import { useMessages } from '@/components/hooks';
import { AdminWebsitesDataTable } from './AdminWebsitesDataTable';
export function AdminWebsitesPage() {
const { formatMessage, labels } = useMessages();

View file

@ -1,12 +1,11 @@
import { useState } from 'react';
import { DataColumn, DataTable, Dialog, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen';
import Link from 'next/link';
import { Row, Text, Icon, DataTable, DataColumn, MenuItem, Modal, Dialog } from '@umami/react-zen';
import { Trash, Users } from '@/components/icons';
import { useMessages } from '@/components/hooks';
import { Edit } from '@/components/icons';
import { MenuButton } from '@/components/input/MenuButton';
import { DateDistance } from '@/components/common/DateDistance';
import { useState } from 'react';
import { WebsiteDeleteForm } from '@/app/(main)/websites/[websiteId]/settings/WebsiteDeleteForm';
import { DateDistance } from '@/components/common/DateDistance';
import { useMessages } from '@/components/hooks';
import { Edit, Trash, Users } from '@/components/icons';
import { MenuButton } from '@/components/input/MenuButton';
export function AdminWebsitesTable({ data = [] }: { data: any[] }) {
const { formatMessage, labels } = useMessages();

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { WebsiteSettingsPage } from '@/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage';
export default async function ({ params }: { params: Promise<{ websiteId: string }> }) {

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { AdminWebsitesPage } from './AdminWebsitesPage';
export default function () {

View file

@ -1,5 +1,5 @@
import { Button, Dialog, DialogTrigger, Icon, Modal, Text, useToast } from '@umami/react-zen';
import { useMessages, useModified, useNavigation } from '@/components/hooks';
import { Button, Icon, Modal, Dialog, DialogTrigger, Text, useToast } from '@umami/react-zen';
import { Plus } from '@/components/icons';
import { BoardAddForm } from './BoardAddForm';

View file

@ -1,5 +1,5 @@
import { Form, FormField, FormSubmitButton, Row, TextField, Button } from '@umami/react-zen';
import { useUpdateQuery, useMessages } from '@/components/hooks';
import { Button, Form, FormField, FormSubmitButton, Row, TextField } from '@umami/react-zen';
import { useMessages, useUpdateQuery } from '@/components/hooks';
import { DOMAIN_REGEX } from '@/lib/constants';
export function BoardAddForm({

View file

@ -1,7 +1,7 @@
'use client';
import { Column } from '@umami/react-zen';
import { PageHeader } from '@/components/common/PageHeader';
import { PageBody } from '@/components/common/PageBody';
import { PageHeader } from '@/components/common/PageHeader';
import { BoardAddButton } from './BoardAddButton';
export function BoardsPage() {

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { Board } from './Board';
export default async function ({ params }: { params: Promise<{ boardId: string }> }) {

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { BoardsPage } from './BoardsPage';
export default function () {

View file

@ -1,25 +1,25 @@
'use client';
import { Button, Grid, Column, Heading } from '@umami/react-zen';
import { Button, Column, Grid, Heading } from '@umami/react-zen';
import Link from 'next/link';
import Script from 'next/script';
import { Panel } from '@/components/common/Panel';
import { PageBody } from '@/components/common/PageBody';
import { EventsChart } from '@/components/metrics/EventsChart';
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { useWebsiteQuery } from '@/components/hooks';
import { PageBody } from '@/components/common/PageBody';
import { PageHeader } from '@/components/common/PageHeader';
import { Panel } from '@/components/common/Panel';
import { useWebsiteQuery } from '@/components/hooks';
import { EventsChart } from '@/components/metrics/EventsChart';
export function TestConsolePage({ websiteId }: { websiteId: string }) {
const { data } = useWebsiteQuery(websiteId);
function handleRunScript() {
window['umami'].track(props => ({
window.umami.track(props => ({
...props,
url: '/page-view',
referrer: 'https://www.google.com',
}));
window['umami'].track('track-event-no-data');
window['umami'].track('track-event-with-data', {
window.umami.track('track-event-no-data');
window.umami.track('track-event-with-data', {
test: 'test-data',
boolean: true,
booleanError: 'true',
@ -40,32 +40,32 @@ export function TestConsolePage({ websiteId }: { websiteId: string }) {
}
function handleRunRevenue() {
window['umami'].track(props => ({
window.umami.track(props => ({
...props,
url: '/checkout-cart',
referrer: 'https://www.google.com',
}));
window['umami'].track('checkout-cart', {
window.umami.track('checkout-cart', {
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
currency: 'USD',
});
window['umami'].track('affiliate-link', {
window.umami.track('affiliate-link', {
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
currency: 'USD',
});
window['umami'].track('promotion-link', {
window.umami.track('promotion-link', {
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
currency: 'USD',
});
window['umami'].track('checkout-cart', {
window.umami.track('checkout-cart', {
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
currency: 'EUR',
});
window['umami'].track('promotion-link', {
window.umami.track('promotion-link', {
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
currency: 'EUR',
});
window['umami'].track('affiliate-link', {
window.umami.track('affiliate-link', {
item1: {
productIdentity: 'ABC424',
revenue: parseFloat((Math.random() * 10000).toFixed(2)),
@ -80,7 +80,7 @@ export function TestConsolePage({ websiteId }: { websiteId: string }) {
}
function handleRunIdentify() {
window['umami'].identify({
window.umami.identify({
userId: 123,
name: 'brian',
number: Math.random() * 100,

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { TestConsolePage } from './TestConsolePage';
async function getEnabled() {

View file

@ -1,8 +1,8 @@
'use client';
import { Column } from '@umami/react-zen';
import { PageBody } from '@/components/common/PageBody';
import { PageHeader } from '@/components/common/PageHeader';
import { useMessages } from '@/components/hooks';
import { PageBody } from '@/components/common/PageBody';
export function DashboardPage() {
const { formatMessage, labels } = useMessages();

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { DashboardPage } from './DashboardPage';
export default async function () {

View file

@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import { Suspense } from 'react';
import { Metadata } from 'next';
import { App } from './App';
export default function ({ children }) {

View file

@ -1,7 +1,7 @@
import { useMessages } from '@/components/hooks';
import { Plus } from '@/components/icons';
import { LinkEditForm } from './LinkEditForm';
import { DialogButton } from '@/components/input/DialogButton';
import { LinkEditForm } from './LinkEditForm';
export function LinkAddButton({ teamId }: { teamId?: string }) {
const { formatMessage, labels } = useMessages();

View file

@ -1,8 +1,8 @@
import { Trash } from '@/components/icons';
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
import { messages } from '@/components/messages';
import { useDeleteQuery, useMessages } from '@/components/hooks';
import { Trash } from '@/components/icons';
import { DialogButton } from '@/components/input/DialogButton';
import { messages } from '@/components/messages';
export function LinkDeleteButton({
linkId,

View file

@ -1,7 +1,7 @@
import { Edit } from '@/components/icons';
import { LinkEditForm } from './LinkEditForm';
import { useMessages } from '@/components/hooks';
import { Edit } from '@/components/icons';
import { DialogButton } from '@/components/input/DialogButton';
import { LinkEditForm } from './LinkEditForm';
export function LinkEditButton({ linkId }: { linkId: string }) {
const { formatMessage, labels } = useMessages();

View file

@ -1,22 +1,21 @@
import { useState, useEffect } from 'react';
import {
Button,
Column,
Form,
FormField,
FormSubmitButton,
Icon,
Label,
Loading,
Row,
TextField,
Button,
Label,
Column,
Icon,
Loading,
} from '@umami/react-zen';
import { useConfig, useLinkQuery } from '@/components/hooks';
import { useMessages } from '@/components/hooks';
import { RefreshCw } from '@/components/icons';
import { getRandomChars } from '@/lib/generate';
import { useEffect, useState } from 'react';
import { useConfig, useLinkQuery, useMessages } from '@/components/hooks';
import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery';
import { RefreshCw } from '@/components/icons';
import { LINKS_URL } from '@/lib/constants';
import { getRandomChars } from '@/lib/generate';
import { isValidUrl } from '@/lib/url';
const generateId = () => getRandomChars(9);

View file

@ -1,8 +1,8 @@
'use client';
import { createContext, ReactNode } from 'react';
import { Loading } from '@umami/react-zen';
import { Link } from '@/generated/prisma/client';
import { createContext, type ReactNode } from 'react';
import { useLinkQuery } from '@/components/hooks/queries/useLinkQuery';
import type { Link } from '@/generated/prisma/client';
export const LinkContext = createContext<Link>(null);

View file

@ -1,6 +1,6 @@
import { DataGrid } from '@/components/common/DataGrid';
import { useLinksQuery, useNavigation } from '@/components/hooks';
import { LinksTable } from './LinksTable';
import { DataGrid } from '@/components/common/DataGrid';
export function LinksDataTable() {
const { teamId } = useNavigation();

View file

@ -1,11 +1,11 @@
'use client';
import { PageBody } from '@/components/common/PageBody';
import { Column } from '@umami/react-zen';
import { PageHeader } from '@/components/common/PageHeader';
import { LinkAddButton } from './LinkAddButton';
import { useMessages, useNavigation } from '@/components/hooks';
import { LinksDataTable } from '@/app/(main)/links/LinksDataTable';
import { PageBody } from '@/components/common/PageBody';
import { PageHeader } from '@/components/common/PageHeader';
import { Panel } from '@/components/common/Panel';
import { useMessages, useNavigation } from '@/components/hooks';
import { LinkAddButton } from './LinkAddButton';
export function LinksPage() {
const { formatMessage, labels } = useMessages();

View file

@ -1,10 +1,10 @@
import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen';
import Link from 'next/link';
import { DataTable, DataColumn, Row, DataTableProps } from '@umami/react-zen';
import { useMessages, useNavigation, useSlug } from '@/components/hooks';
import { DateDistance } from '@/components/common/DateDistance';
import { ExternalLink } from '@/components/common/ExternalLink';
import { LinkEditButton } from './LinkEditButton';
import { useMessages, useNavigation, useSlug } from '@/components/hooks';
import { LinkDeleteButton } from './LinkDeleteButton';
import { LinkEditButton } from './LinkEditButton';
export function LinksTable(props: DataTableProps) {
const { formatMessage, labels } = useMessages();

View file

@ -1,9 +1,9 @@
import { Column, Row } from '@umami/react-zen';
import { WebsiteFilterButton } from '@/components/input/WebsiteFilterButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { ExportButton } from '@/components/input/ExportButton';
import { FilterBar } from '@/components/input/FilterBar';
import { MonthFilter } from '@/components/input/MonthFilter';
import { ExportButton } from '@/components/input/ExportButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { WebsiteFilterButton } from '@/components/input/WebsiteFilterButton';
export function LinkControls({
linkId: websiteId,

View file

@ -1,8 +1,8 @@
import { useLink, useMessages, useSlug } from '@/components/hooks';
import { PageHeader } from '@/components/common/PageHeader';
import { Icon, Text } from '@umami/react-zen';
import { ExternalLink, Link } from '@/components/icons';
import { LinkButton } from '@/components/common/LinkButton';
import { PageHeader } from '@/components/common/PageHeader';
import { useLink, useMessages, useSlug } from '@/components/hooks';
import { ExternalLink, Link } from '@/components/icons';
export function LinkHeader() {
const { formatMessage, labels } = useMessages();

View file

@ -1,9 +1,9 @@
import { LoadingPanel } from '@/components/common/LoadingPanel';
import { useDateRange, useMessages } from '@/components/hooks';
import { useWebsiteStatsQuery } from '@/components/hooks/queries/useWebsiteStatsQuery';
import { MetricCard } from '@/components/metrics/MetricCard';
import { MetricsBar } from '@/components/metrics/MetricsBar';
import { formatLongNumber } from '@/lib/format';
import { useWebsiteStatsQuery } from '@/components/hooks/queries/useWebsiteStatsQuery';
import { LoadingPanel } from '@/components/common/LoadingPanel';
export function LinkMetricsBar({
linkId,

View file

@ -1,14 +1,14 @@
'use client';
import { PageBody } from '@/components/common/PageBody';
import { LinkProvider } from '@/app/(main)/links/LinkProvider';
import { LinkHeader } from '@/app/(main)/links/[linkId]/LinkHeader';
import { Panel } from '@/components/common/Panel';
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { LinkMetricsBar } from '@/app/(main)/links/[linkId]/LinkMetricsBar';
import { LinkControls } from '@/app/(main)/links/[linkId]/LinkControls';
import { LinkPanels } from '@/app/(main)/links/[linkId]/LinkPanels';
import { Column, Grid } from '@umami/react-zen';
import { LinkControls } from '@/app/(main)/links/[linkId]/LinkControls';
import { LinkHeader } from '@/app/(main)/links/[linkId]/LinkHeader';
import { LinkMetricsBar } from '@/app/(main)/links/[linkId]/LinkMetricsBar';
import { LinkPanels } from '@/app/(main)/links/[linkId]/LinkPanels';
import { LinkProvider } from '@/app/(main)/links/LinkProvider';
import { ExpandedViewModal } from '@/app/(main)/websites/[websiteId]/ExpandedViewModal';
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { PageBody } from '@/components/common/PageBody';
import { Panel } from '@/components/common/Panel';
const excludedIds = ['path', 'entry', 'exit', 'title', 'language', 'screen', 'event'];

View file

@ -1,9 +1,9 @@
import { Grid, Tabs, Tab, TabList, TabPanel, Heading } from '@umami/react-zen';
import { Grid, Heading, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
import { GridRow } from '@/components/common/GridRow';
import { Panel } from '@/components/common/Panel';
import { WorldMap } from '@/components/metrics/WorldMap';
import { MetricsTable } from '@/components/metrics/MetricsTable';
import { useMessages } from '@/components/hooks';
import { MetricsTable } from '@/components/metrics/MetricsTable';
import { WorldMap } from '@/components/metrics/WorldMap';
export function LinkPanels({ linkId }: { linkId: string }) {
const { formatMessage, labels } = useMessages();

View file

@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import { LinkPage } from './LinkPage';
import { Metadata } from 'next';
export default async function ({ params }: { params: Promise<{ linkId: string }> }) {
const { linkId } = await params;

View file

@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import { LinksPage } from './LinksPage';
import { Metadata } from 'next';
export default function () {
return <LinksPage />;

View file

@ -1,7 +1,7 @@
import { useMessages } from '@/components/hooks';
import { Plus } from '@/components/icons';
import { PixelEditForm } from './PixelEditForm';
import { DialogButton } from '@/components/input/DialogButton';
import { PixelEditForm } from './PixelEditForm';
export function PixelAddButton({ teamId }: { teamId?: string }) {
const { formatMessage, labels } = useMessages();

View file

@ -1,8 +1,8 @@
import { Trash } from '@/components/icons';
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
import { messages } from '@/components/messages';
import { useDeleteQuery, useMessages, useModified } from '@/components/hooks';
import { Trash } from '@/components/icons';
import { DialogButton } from '@/components/input/DialogButton';
import { messages } from '@/components/messages';
export function PixelDeleteButton({
pixelId,

View file

@ -1,7 +1,7 @@
import { Edit } from '@/components/icons';
import { PixelEditForm } from './PixelEditForm';
import { useMessages } from '@/components/hooks';
import { Edit } from '@/components/icons';
import { DialogButton } from '@/components/input/DialogButton';
import { PixelEditForm } from './PixelEditForm';
export function PixelEditButton({ pixelId }: { pixelId: string }) {
const { formatMessage, labels } = useMessages();

View file

@ -1,22 +1,21 @@
import {
Button,
Column,
Form,
FormField,
FormSubmitButton,
Icon,
Label,
Loading,
Row,
TextField,
Button,
Label,
Column,
Icon,
Loading,
} from '@umami/react-zen';
import { useConfig, usePixelQuery } from '@/components/hooks';
import { useMessages } from '@/components/hooks';
import { RefreshCw } from '@/components/icons';
import { getRandomChars } from '@/lib/generate';
import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery';
import { useEffect, useState } from 'react';
import { useConfig, useMessages, usePixelQuery } from '@/components/hooks';
import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery';
import { RefreshCw } from '@/components/icons';
import { PIXELS_URL } from '@/lib/constants';
import { getRandomChars } from '@/lib/generate';
const generateId = () => getRandomChars(9);

View file

@ -1,8 +1,8 @@
'use client';
import { createContext, ReactNode } from 'react';
import { Loading } from '@umami/react-zen';
import { Pixel } from '@/generated/prisma/client';
import { createContext, type ReactNode } from 'react';
import { usePixelQuery } from '@/components/hooks/queries/usePixelQuery';
import type { Pixel } from '@/generated/prisma/client';
export const PixelContext = createContext<Pixel>(null);

View file

@ -1,6 +1,6 @@
import { usePixelsQuery, useNavigation } from '@/components/hooks';
import { PixelsTable } from './PixelsTable';
import { DataGrid } from '@/components/common/DataGrid';
import { useNavigation, usePixelsQuery } from '@/components/hooks';
import { PixelsTable } from './PixelsTable';
export function PixelsDataTable() {
const { teamId } = useNavigation();

View file

@ -1,11 +1,11 @@
'use client';
import { PageBody } from '@/components/common/PageBody';
import { Column } from '@umami/react-zen';
import { PageBody } from '@/components/common/PageBody';
import { PageHeader } from '@/components/common/PageHeader';
import { PixelAddButton } from './PixelAddButton';
import { useMessages, useNavigation } from '@/components/hooks';
import { PixelsDataTable } from './PixelsDataTable';
import { Panel } from '@/components/common/Panel';
import { useMessages, useNavigation } from '@/components/hooks';
import { PixelAddButton } from './PixelAddButton';
import { PixelsDataTable } from './PixelsDataTable';
export function PixelsPage() {
const { formatMessage, labels } = useMessages();

View file

@ -1,10 +1,10 @@
import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen';
import Link from 'next/link';
import { DataTable, DataColumn, Row, DataTableProps } from '@umami/react-zen';
import { useMessages, useNavigation, useSlug } from '@/components/hooks';
import { DateDistance } from '@/components/common/DateDistance';
import { PixelEditButton } from './PixelEditButton';
import { PixelDeleteButton } from './PixelDeleteButton';
import { ExternalLink } from '@/components/common/ExternalLink';
import { useMessages, useNavigation, useSlug } from '@/components/hooks';
import { PixelDeleteButton } from './PixelDeleteButton';
import { PixelEditButton } from './PixelEditButton';
export function PixelsTable(props: DataTableProps) {
const { formatMessage, labels } = useMessages();

View file

@ -1,9 +1,9 @@
import { Column, Row } from '@umami/react-zen';
import { WebsiteFilterButton } from '@/components/input/WebsiteFilterButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { ExportButton } from '@/components/input/ExportButton';
import { FilterBar } from '@/components/input/FilterBar';
import { MonthFilter } from '@/components/input/MonthFilter';
import { ExportButton } from '@/components/input/ExportButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { WebsiteFilterButton } from '@/components/input/WebsiteFilterButton';
export function PixelControls({
pixelId: websiteId,

View file

@ -1,8 +1,8 @@
import { usePixel, useMessages, useSlug } from '@/components/hooks';
import { PageHeader } from '@/components/common/PageHeader';
import { Icon, Text } from '@umami/react-zen';
import { ExternalLink, Grid2x2 } from '@/components/icons';
import { LinkButton } from '@/components/common/LinkButton';
import { PageHeader } from '@/components/common/PageHeader';
import { useMessages, usePixel, useSlug } from '@/components/hooks';
import { ExternalLink, Grid2x2 } from '@/components/icons';
export function PixelHeader() {
const { formatMessage, labels } = useMessages();

View file

@ -1,9 +1,9 @@
import { LoadingPanel } from '@/components/common/LoadingPanel';
import { useDateRange, useMessages } from '@/components/hooks';
import { useWebsiteStatsQuery } from '@/components/hooks/queries/useWebsiteStatsQuery';
import { MetricCard } from '@/components/metrics/MetricCard';
import { MetricsBar } from '@/components/metrics/MetricsBar';
import { formatLongNumber } from '@/lib/format';
import { useWebsiteStatsQuery } from '@/components/hooks/queries/useWebsiteStatsQuery';
import { LoadingPanel } from '@/components/common/LoadingPanel';
export function PixelMetricsBar({
pixelId,

View file

@ -1,14 +1,14 @@
'use client';
import { PageBody } from '@/components/common/PageBody';
import { PixelProvider } from '@/app/(main)/pixels/PixelProvider';
import { PixelHeader } from '@/app/(main)/pixels/[pixelId]/PixelHeader';
import { Panel } from '@/components/common/Panel';
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { PixelMetricsBar } from '@/app/(main)/pixels/[pixelId]/PixelMetricsBar';
import { PixelControls } from '@/app/(main)/pixels/[pixelId]/PixelControls';
import { PixelPanels } from '@/app/(main)/pixels/[pixelId]/PixelPanels';
import { Column, Grid } from '@umami/react-zen';
import { PixelControls } from '@/app/(main)/pixels/[pixelId]/PixelControls';
import { PixelHeader } from '@/app/(main)/pixels/[pixelId]/PixelHeader';
import { PixelMetricsBar } from '@/app/(main)/pixels/[pixelId]/PixelMetricsBar';
import { PixelPanels } from '@/app/(main)/pixels/[pixelId]/PixelPanels';
import { PixelProvider } from '@/app/(main)/pixels/PixelProvider';
import { ExpandedViewModal } from '@/app/(main)/websites/[websiteId]/ExpandedViewModal';
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { PageBody } from '@/components/common/PageBody';
import { Panel } from '@/components/common/Panel';
const excludedIds = ['path', 'entry', 'exit', 'title', 'language', 'screen', 'event'];

View file

@ -1,9 +1,9 @@
import { Grid, Tabs, Tab, TabList, TabPanel, Heading } from '@umami/react-zen';
import { Grid, Heading, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
import { GridRow } from '@/components/common/GridRow';
import { Panel } from '@/components/common/Panel';
import { WorldMap } from '@/components/metrics/WorldMap';
import { MetricsTable } from '@/components/metrics/MetricsTable';
import { useMessages } from '@/components/hooks';
import { MetricsTable } from '@/components/metrics/MetricsTable';
import { WorldMap } from '@/components/metrics/WorldMap';
export function PixelPanels({ pixelId }: { pixelId: string }) {
const { formatMessage, labels } = useMessages();

View file

@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import { PixelPage } from './PixelPage';
import { Metadata } from 'next';
export default async function ({ params }: { params: { pixelId: string } }) {
const { pixelId } = await params;

View file

@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import { PixelsPage } from './PixelsPage';
import { Metadata } from 'next';
export default function () {
return <PixelsPage />;

View file

@ -1,7 +1,7 @@
'use client';
import { PageBody } from '@/components/common/PageBody';
import { Column, Grid } from '@umami/react-zen';
import { ReactNode } from 'react';
import type { ReactNode } from 'react';
import { PageBody } from '@/components/common/PageBody';
import { SettingsNav } from './SettingsNav';
export function SettingsLayout({ children }: { children: ReactNode }) {

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { SettingsLayout } from './SettingsLayout';
export default function ({ children }) {

View file

@ -1,9 +1,9 @@
import { useState } from 'react';
import { DateFilter } from '@/components/input/DateFilter';
import { Button, Row } from '@umami/react-zen';
import { useState } from 'react';
import { useMessages } from '@/components/hooks';
import { DateFilter } from '@/components/input/DateFilter';
import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants';
import { setItem, getItem } from '@/lib/storage';
import { getItem, setItem } from '@/lib/storage';
export function DateRangeSetting() {
const { formatMessage, labels } = useMessages();

View file

@ -1,5 +1,5 @@
import { Button, ListItem, Row, Select } from '@umami/react-zen';
import { useState } from 'react';
import { Button, Select, ListItem, Row } from '@umami/react-zen';
import { useLocale, useMessages } from '@/components/hooks';
import { DEFAULT_LOCALE } from '@/lib/constants';
import { languages } from '@/lib/lang';

View file

@ -1,9 +1,9 @@
import { Column, Label } from '@umami/react-zen';
import { useLoginQuery, useMessages } from '@/components/hooks';
import { TimezoneSetting } from './TimezoneSetting';
import { DateRangeSetting } from './DateRangeSetting';
import { LanguageSetting } from './LanguageSetting';
import { ThemeSetting } from './ThemeSetting';
import { TimezoneSetting } from './TimezoneSetting';
export function PreferenceSettings() {
const { user } = useLoginQuery();

View file

@ -1,10 +1,10 @@
'use client';
import { Column } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import { Panel } from '@/components/common/Panel';
import { PreferenceSettings } from './PreferenceSettings';
import { PageHeader } from '@/components/common/PageHeader';
import { PageBody } from '@/components/common/PageBody';
import { PageHeader } from '@/components/common/PageHeader';
import { Panel } from '@/components/common/Panel';
import { useMessages } from '@/components/hooks';
import { PreferenceSettings } from './PreferenceSettings';
export function PreferencesPage() {
const { formatMessage, labels } = useMessages();

View file

@ -1,5 +1,5 @@
import { Row, Button, Icon, useTheme } from '@umami/react-zen';
import { Sun, Moon } from '@/components/icons';
import { Button, Icon, Row, useTheme } from '@umami/react-zen';
import { Moon, Sun } from '@/components/icons';
export function ThemeSetting() {
const { theme, setTheme } = useTheme();

View file

@ -1,6 +1,6 @@
import { Button, ListItem, Row, Select } from '@umami/react-zen';
import { useState } from 'react';
import { Row, Select, ListItem, Button } from '@umami/react-zen';
import { useTimezone, useMessages } from '@/components/hooks';
import { useMessages, useTimezone } from '@/components/hooks';
import { getTimezone } from '@/lib/date';
const timezones = Intl.supportedValuesOf('timeZone');

View file

@ -1,4 +1,4 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import { PreferencesPage } from './PreferencesPage';
export default function () {

View file

@ -1,7 +1,7 @@
import { Button, Icon, Text, useToast, DialogTrigger, Dialog, Modal } from '@umami/react-zen';
import { PasswordEditForm } from './PasswordEditForm';
import { LockKeyhole } from '@/components/icons';
import { Button, Dialog, DialogTrigger, Icon, Modal, Text, useToast } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import { LockKeyhole } from '@/components/icons';
import { PasswordEditForm } from './PasswordEditForm';
export function PasswordChangeButton() {
const { formatMessage, labels, messages } = useMessages();

Some files were not shown because too many files have changed in this diff Show more