From 396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b Mon Sep 17 00:00:00 2001
From: Fuwn <50817549+Fuwn@users.noreply.github.com>
Date: Sat, 24 Jan 2026 13:09:50 +0000
Subject: Initial commit
Created from https://vercel.com/new
---
src/app/(main)/admin/AdminLayout.tsx | 33 ++++++++
src/app/(main)/admin/AdminNav.tsx | 48 ++++++++++++
src/app/(main)/admin/layout.tsx | 17 +++++
src/app/(main)/admin/teams/AdminTeamsDataTable.tsx | 19 +++++
src/app/(main)/admin/teams/AdminTeamsPage.tsx | 19 +++++
src/app/(main)/admin/teams/AdminTeamsTable.tsx | 86 +++++++++++++++++++++
.../(main)/admin/teams/[teamId]/AdminTeamPage.tsx | 11 +++
src/app/(main)/admin/teams/[teamId]/page.tsx | 12 +++
src/app/(main)/admin/teams/page.tsx | 9 +++
src/app/(main)/admin/users/UserAddButton.tsx | 32 ++++++++
src/app/(main)/admin/users/UserAddForm.tsx | 71 +++++++++++++++++
src/app/(main)/admin/users/UserDeleteButton.tsx | 35 +++++++++
src/app/(main)/admin/users/UserDeleteForm.tsx | 41 ++++++++++
src/app/(main)/admin/users/UsersDataTable.tsx | 14 ++++
src/app/(main)/admin/users/UsersPage.tsx | 24 ++++++
src/app/(main)/admin/users/UsersTable.tsx | 84 ++++++++++++++++++++
.../(main)/admin/users/[userId]/UserEditForm.tsx | 73 ++++++++++++++++++
src/app/(main)/admin/users/[userId]/UserHeader.tsx | 9 +++
src/app/(main)/admin/users/[userId]/UserPage.tsx | 19 +++++
.../(main)/admin/users/[userId]/UserProvider.tsx | 20 +++++
.../(main)/admin/users/[userId]/UserSettings.tsx | 25 ++++++
.../(main)/admin/users/[userId]/UserWebsites.tsx | 15 ++++
src/app/(main)/admin/users/[userId]/page.tsx | 12 +++
src/app/(main)/admin/users/page.tsx | 9 +++
.../admin/websites/AdminWebsitesDataTable.tsx | 13 ++++
.../(main)/admin/websites/AdminWebsitesPage.tsx | 19 +++++
.../(main)/admin/websites/AdminWebsitesTable.tsx | 89 ++++++++++++++++++++++
.../websites/[websiteId]/AdminWebsitePage.tsx | 14 ++++
src/app/(main)/admin/websites/[websiteId]/page.tsx | 12 +++
src/app/(main)/admin/websites/page.tsx | 9 +++
30 files changed, 893 insertions(+)
create mode 100644 src/app/(main)/admin/AdminLayout.tsx
create mode 100644 src/app/(main)/admin/AdminNav.tsx
create mode 100644 src/app/(main)/admin/layout.tsx
create mode 100644 src/app/(main)/admin/teams/AdminTeamsDataTable.tsx
create mode 100644 src/app/(main)/admin/teams/AdminTeamsPage.tsx
create mode 100644 src/app/(main)/admin/teams/AdminTeamsTable.tsx
create mode 100644 src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx
create mode 100644 src/app/(main)/admin/teams/[teamId]/page.tsx
create mode 100644 src/app/(main)/admin/teams/page.tsx
create mode 100644 src/app/(main)/admin/users/UserAddButton.tsx
create mode 100644 src/app/(main)/admin/users/UserAddForm.tsx
create mode 100644 src/app/(main)/admin/users/UserDeleteButton.tsx
create mode 100644 src/app/(main)/admin/users/UserDeleteForm.tsx
create mode 100644 src/app/(main)/admin/users/UsersDataTable.tsx
create mode 100644 src/app/(main)/admin/users/UsersPage.tsx
create mode 100644 src/app/(main)/admin/users/UsersTable.tsx
create mode 100644 src/app/(main)/admin/users/[userId]/UserEditForm.tsx
create mode 100644 src/app/(main)/admin/users/[userId]/UserHeader.tsx
create mode 100644 src/app/(main)/admin/users/[userId]/UserPage.tsx
create mode 100644 src/app/(main)/admin/users/[userId]/UserProvider.tsx
create mode 100644 src/app/(main)/admin/users/[userId]/UserSettings.tsx
create mode 100644 src/app/(main)/admin/users/[userId]/UserWebsites.tsx
create mode 100644 src/app/(main)/admin/users/[userId]/page.tsx
create mode 100644 src/app/(main)/admin/users/page.tsx
create mode 100644 src/app/(main)/admin/websites/AdminWebsitesDataTable.tsx
create mode 100644 src/app/(main)/admin/websites/AdminWebsitesPage.tsx
create mode 100644 src/app/(main)/admin/websites/AdminWebsitesTable.tsx
create mode 100644 src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx
create mode 100644 src/app/(main)/admin/websites/[websiteId]/page.tsx
create mode 100644 src/app/(main)/admin/websites/page.tsx
(limited to 'src/app/(main)/admin')
diff --git a/src/app/(main)/admin/AdminLayout.tsx b/src/app/(main)/admin/AdminLayout.tsx
new file mode 100644
index 0000000..3c8fa20
--- /dev/null
+++ b/src/app/(main)/admin/AdminLayout.tsx
@@ -0,0 +1,33 @@
+'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 { AdminNav } from './AdminNav';
+
+export function AdminLayout({ children }: { children: ReactNode }) {
+ const { user } = useLoginQuery();
+
+ if (!user.isAdmin || process.env.cloudMode) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+ {children}
+
+
+ );
+}
diff --git a/src/app/(main)/admin/AdminNav.tsx b/src/app/(main)/admin/AdminNav.tsx
new file mode 100644
index 0000000..20c0115
--- /dev/null
+++ b/src/app/(main)/admin/AdminNav.tsx
@@ -0,0 +1,48 @@
+import { SideMenu } from '@/components/common/SideMenu';
+import { useMessages, useNavigation } from '@/components/hooks';
+import { Globe, User, Users } from '@/components/icons';
+
+export function AdminNav({ onItemClick }: { onItemClick?: () => void }) {
+ const { formatMessage, labels } = useMessages();
+ const { pathname } = useNavigation();
+
+ const items = [
+ {
+ label: formatMessage(labels.manage),
+ items: [
+ {
+ id: 'users',
+ label: formatMessage(labels.users),
+ path: '/admin/users',
+ icon: ,
+ },
+ {
+ id: 'websites',
+ label: formatMessage(labels.websites),
+ path: '/admin/websites',
+ icon: ,
+ },
+ {
+ id: 'teams',
+ label: formatMessage(labels.teams),
+ path: '/admin/teams',
+ icon: ,
+ },
+ ],
+ },
+ ];
+
+ const selectedKey = items
+ .flatMap(e => e.items)
+ ?.find(({ path }) => path && pathname.startsWith(path))?.id;
+
+ return (
+
+ );
+}
diff --git a/src/app/(main)/admin/layout.tsx b/src/app/(main)/admin/layout.tsx
new file mode 100644
index 0000000..34cdd0b
--- /dev/null
+++ b/src/app/(main)/admin/layout.tsx
@@ -0,0 +1,17 @@
+import type { Metadata } from 'next';
+import { AdminLayout } from './AdminLayout';
+
+export default function ({ children }) {
+ if (process.env.cloudMode) {
+ return null;
+ }
+
+ return {children};
+}
+
+export const metadata: Metadata = {
+ title: {
+ template: '%s | Admin | Umami',
+ default: 'Admin | Umami',
+ },
+};
diff --git a/src/app/(main)/admin/teams/AdminTeamsDataTable.tsx b/src/app/(main)/admin/teams/AdminTeamsDataTable.tsx
new file mode 100644
index 0000000..7da8531
--- /dev/null
+++ b/src/app/(main)/admin/teams/AdminTeamsDataTable.tsx
@@ -0,0 +1,19 @@
+import type { ReactNode } from 'react';
+import { DataGrid } from '@/components/common/DataGrid';
+import { useTeamsQuery } from '@/components/hooks';
+import { AdminTeamsTable } from './AdminTeamsTable';
+
+export function AdminTeamsDataTable({
+ showActions,
+}: {
+ showActions?: boolean;
+ children?: ReactNode;
+}) {
+ const queryResult = useTeamsQuery();
+
+ return (
+
+ {({ data }) => }
+
+ );
+}
diff --git a/src/app/(main)/admin/teams/AdminTeamsPage.tsx b/src/app/(main)/admin/teams/AdminTeamsPage.tsx
new file mode 100644
index 0000000..41e6f4a
--- /dev/null
+++ b/src/app/(main)/admin/teams/AdminTeamsPage.tsx
@@ -0,0 +1,19 @@
+'use client';
+import { Column } from '@umami/react-zen';
+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();
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/teams/AdminTeamsTable.tsx b/src/app/(main)/admin/teams/AdminTeamsTable.tsx
new file mode 100644
index 0000000..9f2abd5
--- /dev/null
+++ b/src/app/(main)/admin/teams/AdminTeamsTable.tsx
@@ -0,0 +1,86 @@
+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 { TeamDeleteForm } from '../../teams/[teamId]/TeamDeleteForm';
+
+export function AdminTeamsTable({
+ data = [],
+ showActions = true,
+}: {
+ data: any[];
+ showActions?: boolean;
+}) {
+ const { formatMessage, labels } = useMessages();
+ const [deleteTeam, setDeleteTeam] = useState(null);
+
+ return (
+ <>
+
+
+ {(row: any) => {row.name}}
+
+
+ {(row: any) => row?._count?.members}
+
+
+ {(row: any) => row?._count?.websites}
+
+
+ {(row: any) => {
+ const name = row?.members?.[0]?.user?.username;
+
+ return (
+
+ {name}
+
+ );
+ }}
+
+
+ {(row: any) => }
+
+ {showActions && (
+
+ {(row: any) => {
+ const { id } = row;
+
+ return (
+
+
+
+
+ );
+ }}
+
+ )}
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx b/src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx
new file mode 100644
index 0000000..2150197
--- /dev/null
+++ b/src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx
@@ -0,0 +1,11 @@
+'use client';
+import { TeamSettings } from '@/app/(main)/teams/[teamId]/TeamSettings';
+import { TeamProvider } from '@/app/(main)/teams/TeamProvider';
+
+export function AdminTeamPage({ teamId }: { teamId: string }) {
+ return (
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/teams/[teamId]/page.tsx b/src/app/(main)/admin/teams/[teamId]/page.tsx
new file mode 100644
index 0000000..104766a
--- /dev/null
+++ b/src/app/(main)/admin/teams/[teamId]/page.tsx
@@ -0,0 +1,12 @@
+import type { Metadata } from 'next';
+import { AdminTeamPage } from './AdminTeamPage';
+
+export default async function ({ params }: { params: Promise<{ teamId: string }> }) {
+ const { teamId } = await params;
+
+ return ;
+}
+
+export const metadata: Metadata = {
+ title: 'Team',
+};
diff --git a/src/app/(main)/admin/teams/page.tsx b/src/app/(main)/admin/teams/page.tsx
new file mode 100644
index 0000000..987f02b
--- /dev/null
+++ b/src/app/(main)/admin/teams/page.tsx
@@ -0,0 +1,9 @@
+import type { Metadata } from 'next';
+import { AdminTeamsPage } from './AdminTeamsPage';
+
+export default function () {
+ return ;
+}
+export const metadata: Metadata = {
+ title: 'Teams',
+};
diff --git a/src/app/(main)/admin/users/UserAddButton.tsx b/src/app/(main)/admin/users/UserAddButton.tsx
new file mode 100644
index 0000000..0525082
--- /dev/null
+++ b/src/app/(main)/admin/users/UserAddButton.tsx
@@ -0,0 +1,32 @@
+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();
+ const { toast } = useToast();
+ const { touch } = useModified();
+
+ const handleSave = () => {
+ toast(formatMessage(messages.saved));
+ touch('users');
+ onSave?.();
+ };
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/users/UserAddForm.tsx b/src/app/(main)/admin/users/UserAddForm.tsx
new file mode 100644
index 0000000..6c36551
--- /dev/null
+++ b/src/app/(main)/admin/users/UserAddForm.tsx
@@ -0,0 +1,71 @@
+import {
+ Button,
+ Form,
+ FormButtons,
+ FormField,
+ FormSubmitButton,
+ ListItem,
+ PasswordField,
+ Select,
+ TextField,
+} from '@umami/react-zen';
+import { useMessages, useUpdateQuery } from '@/components/hooks';
+import { ROLES } from '@/lib/constants';
+
+export function UserAddForm({ onSave, onClose }) {
+ const { mutateAsync, error, isPending } = useUpdateQuery(`/users`);
+ const { formatMessage, labels, getErrorMessage } = useMessages();
+
+ const handleSubmit = async (data: any) => {
+ await mutateAsync(data, {
+ onSuccess: async () => {
+ onSave(data);
+ onClose();
+ },
+ });
+ };
+
+ return (
+
+ );
+}
diff --git a/src/app/(main)/admin/users/UserDeleteButton.tsx b/src/app/(main)/admin/users/UserDeleteButton.tsx
new file mode 100644
index 0000000..ee8f2c1
--- /dev/null
+++ b/src/app/(main)/admin/users/UserDeleteButton.tsx
@@ -0,0 +1,35 @@
+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';
+
+export function UserDeleteButton({
+ userId,
+ username,
+ onDelete,
+}: {
+ userId: string;
+ username: string;
+ onDelete?: () => void;
+}) {
+ const { formatMessage, labels } = useMessages();
+ const { user } = useLoginQuery();
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/users/UserDeleteForm.tsx b/src/app/(main)/admin/users/UserDeleteForm.tsx
new file mode 100644
index 0000000..8f6fd50
--- /dev/null
+++ b/src/app/(main)/admin/users/UserDeleteForm.tsx
@@ -0,0 +1,41 @@
+import { AlertDialog, Row } from '@umami/react-zen';
+import { useDeleteQuery, useMessages, useModified } from '@/components/hooks';
+
+export function UserDeleteForm({
+ userId,
+ username,
+ onSave,
+ onClose,
+}: {
+ userId: string;
+ username: string;
+ onSave?: () => void;
+ onClose?: () => void;
+}) {
+ const { messages, labels, formatMessage } = useMessages();
+ const { mutateAsync } = useDeleteQuery(`/users/${userId}`);
+ const { touch } = useModified();
+
+ const handleConfirm = async () => {
+ await mutateAsync(null, {
+ onSuccess: async () => {
+ touch('users');
+ touch(`users:${userId}`);
+ onSave?.();
+ onClose?.();
+ },
+ });
+ };
+
+ return (
+
+ {formatMessage(messages.confirmDelete, { target: username })}
+
+ );
+}
diff --git a/src/app/(main)/admin/users/UsersDataTable.tsx b/src/app/(main)/admin/users/UsersDataTable.tsx
new file mode 100644
index 0000000..8467bd2
--- /dev/null
+++ b/src/app/(main)/admin/users/UsersDataTable.tsx
@@ -0,0 +1,14 @@
+import type { ReactNode } from 'react';
+import { DataGrid } from '@/components/common/DataGrid';
+import { useUsersQuery } from '@/components/hooks';
+import { UsersTable } from './UsersTable';
+
+export function UsersDataTable({ showActions }: { showActions?: boolean; children?: ReactNode }) {
+ const queryResult = useUsersQuery();
+
+ return (
+
+ {({ data }) => }
+
+ );
+}
diff --git a/src/app/(main)/admin/users/UsersPage.tsx b/src/app/(main)/admin/users/UsersPage.tsx
new file mode 100644
index 0000000..7e1b0f4
--- /dev/null
+++ b/src/app/(main)/admin/users/UsersPage.tsx
@@ -0,0 +1,24 @@
+'use client';
+import { Column } from '@umami/react-zen';
+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();
+
+ const handleSave = () => {};
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/users/UsersTable.tsx b/src/app/(main)/admin/users/UsersTable.tsx
new file mode 100644
index 0000000..9c10f3e
--- /dev/null
+++ b/src/app/(main)/admin/users/UsersTable.tsx
@@ -0,0 +1,84 @@
+import { DataColumn, DataTable, 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 { ROLES } from '@/lib/constants';
+import { UserDeleteForm } from './UserDeleteForm';
+
+export function UsersTable({
+ data = [],
+ showActions = true,
+}: {
+ data: any[];
+ showActions?: boolean;
+}) {
+ const { formatMessage, labels } = useMessages();
+ const [deleteUser, setDeleteUser] = useState(null);
+
+ return (
+ <>
+
+
+ {(row: any) => {row.username}}
+
+
+ {(row: any) =>
+ formatMessage(
+ labels[Object.keys(ROLES).find(key => ROLES[key] === row.role)] || labels.unknown,
+ )
+ }
+
+
+ {(row: any) => row._count.websites}
+
+
+ {(row: any) => }
+
+ {showActions && (
+
+ {(row: any) => {
+ const { id } = row;
+
+ return (
+
+
+
+
+ );
+ }}
+
+ )}
+
+
+ {
+ setDeleteUser(null);
+ }}
+ />
+
+ >
+ );
+}
diff --git a/src/app/(main)/admin/users/[userId]/UserEditForm.tsx b/src/app/(main)/admin/users/[userId]/UserEditForm.tsx
new file mode 100644
index 0000000..28bf030
--- /dev/null
+++ b/src/app/(main)/admin/users/[userId]/UserEditForm.tsx
@@ -0,0 +1,73 @@
+import {
+ Form,
+ FormButtons,
+ FormField,
+ FormSubmitButton,
+ ListItem,
+ PasswordField,
+ Select,
+ TextField,
+} from '@umami/react-zen';
+import { useLoginQuery, useMessages, useUpdateQuery, useUser } from '@/components/hooks';
+import { ROLES } from '@/lib/constants';
+
+export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () => void }) {
+ const { formatMessage, labels, messages, getMessage } = useMessages();
+ const user = useUser();
+ const { user: login } = useLoginQuery();
+
+ const { mutateAsync, error, toast, touch } = useUpdateQuery(`/users/${userId}`);
+
+ const handleSubmit = async (data: any) => {
+ await mutateAsync(data, {
+ onSuccess: async () => {
+ toast(formatMessage(messages.saved));
+ touch('users');
+ touch(`user:${user.id}`);
+ onSave?.();
+ },
+ });
+ };
+
+ return (
+
+ );
+}
diff --git a/src/app/(main)/admin/users/[userId]/UserHeader.tsx b/src/app/(main)/admin/users/[userId]/UserHeader.tsx
new file mode 100644
index 0000000..1f82897
--- /dev/null
+++ b/src/app/(main)/admin/users/[userId]/UserHeader.tsx
@@ -0,0 +1,9 @@
+import { PageHeader } from '@/components/common/PageHeader';
+import { useUser } from '@/components/hooks';
+import { User } from '@/components/icons';
+
+export function UserHeader() {
+ const user = useUser();
+
+ return } />;
+}
diff --git a/src/app/(main)/admin/users/[userId]/UserPage.tsx b/src/app/(main)/admin/users/[userId]/UserPage.tsx
new file mode 100644
index 0000000..5e0f8d1
--- /dev/null
+++ b/src/app/(main)/admin/users/[userId]/UserPage.tsx
@@ -0,0 +1,19 @@
+'use client';
+import { Column } from '@umami/react-zen';
+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 (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/users/[userId]/UserProvider.tsx b/src/app/(main)/admin/users/[userId]/UserProvider.tsx
new file mode 100644
index 0000000..ea01915
--- /dev/null
+++ b/src/app/(main)/admin/users/[userId]/UserProvider.tsx
@@ -0,0 +1,20 @@
+import { Loading } from '@umami/react-zen';
+import { createContext, type ReactNode } from 'react';
+import { useUserQuery } from '@/components/hooks/queries/useUserQuery';
+import type { User } from '@/generated/prisma/client';
+
+export const UserContext = createContext(null);
+
+export function UserProvider({ userId, children }: { userId: string; children: ReactNode }) {
+ const { data: user, isFetching, isLoading } = useUserQuery(userId);
+
+ if (isFetching && isLoading) {
+ return ;
+ }
+
+ if (!user) {
+ return null;
+ }
+
+ return {children};
+}
diff --git a/src/app/(main)/admin/users/[userId]/UserSettings.tsx b/src/app/(main)/admin/users/[userId]/UserSettings.tsx
new file mode 100644
index 0000000..3f17f3e
--- /dev/null
+++ b/src/app/(main)/admin/users/[userId]/UserSettings.tsx
@@ -0,0 +1,25 @@
+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 }) {
+ const { formatMessage, labels } = useMessages();
+
+ return (
+
+
+
+ {formatMessage(labels.details)}
+ {formatMessage(labels.websites)}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/users/[userId]/UserWebsites.tsx b/src/app/(main)/admin/users/[userId]/UserWebsites.tsx
new file mode 100644
index 0000000..eeb173e
--- /dev/null
+++ b/src/app/(main)/admin/users/[userId]/UserWebsites.tsx
@@ -0,0 +1,15 @@
+import { WebsitesTable } from '@/app/(main)/websites/WebsitesTable';
+import { DataGrid } from '@/components/common/DataGrid';
+import { useUserWebsitesQuery } from '@/components/hooks';
+
+export function UserWebsites({ userId }) {
+ const queryResult = useUserWebsitesQuery({ userId });
+
+ return (
+
+ {({ data }) => (
+
+ )}
+
+ );
+}
diff --git a/src/app/(main)/admin/users/[userId]/page.tsx b/src/app/(main)/admin/users/[userId]/page.tsx
new file mode 100644
index 0000000..16c9f36
--- /dev/null
+++ b/src/app/(main)/admin/users/[userId]/page.tsx
@@ -0,0 +1,12 @@
+import type { Metadata } from 'next';
+import { UserPage } from './UserPage';
+
+export default async function ({ params }: { params: Promise<{ userId: string }> }) {
+ const { userId } = await params;
+
+ return ;
+}
+
+export const metadata: Metadata = {
+ title: 'User',
+};
diff --git a/src/app/(main)/admin/users/page.tsx b/src/app/(main)/admin/users/page.tsx
new file mode 100644
index 0000000..96e69eb
--- /dev/null
+++ b/src/app/(main)/admin/users/page.tsx
@@ -0,0 +1,9 @@
+import type { Metadata } from 'next';
+import { UsersPage } from './UsersPage';
+
+export default function () {
+ return ;
+}
+export const metadata: Metadata = {
+ title: 'Users',
+};
diff --git a/src/app/(main)/admin/websites/AdminWebsitesDataTable.tsx b/src/app/(main)/admin/websites/AdminWebsitesDataTable.tsx
new file mode 100644
index 0000000..2105992
--- /dev/null
+++ b/src/app/(main)/admin/websites/AdminWebsitesDataTable.tsx
@@ -0,0 +1,13 @@
+import { DataGrid } from '@/components/common/DataGrid';
+import { useWebsitesQuery } from '@/components/hooks';
+import { AdminWebsitesTable } from './AdminWebsitesTable';
+
+export function AdminWebsitesDataTable() {
+ const query = useWebsitesQuery();
+
+ return (
+
+ {props => }
+
+ );
+}
diff --git a/src/app/(main)/admin/websites/AdminWebsitesPage.tsx b/src/app/(main)/admin/websites/AdminWebsitesPage.tsx
new file mode 100644
index 0000000..1c2ac92
--- /dev/null
+++ b/src/app/(main)/admin/websites/AdminWebsitesPage.tsx
@@ -0,0 +1,19 @@
+'use client';
+import { Column } from '@umami/react-zen';
+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();
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/websites/AdminWebsitesTable.tsx b/src/app/(main)/admin/websites/AdminWebsitesTable.tsx
new file mode 100644
index 0000000..cfda595
--- /dev/null
+++ b/src/app/(main)/admin/websites/AdminWebsitesTable.tsx
@@ -0,0 +1,89 @@
+import { DataColumn, DataTable, Dialog, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen';
+import Link from 'next/link';
+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();
+ const [deleteWebsite, setDeleteWebsite] = useState(null);
+
+ return (
+ <>
+
+
+ {(row: any) => (
+
+ {row.name}
+
+ )}
+
+
+ {(row: any) => {row.domain}}
+
+
+ {(row: any) => {
+ if (row?.team) {
+ return (
+
+
+
+
+
+ {row?.team?.name}
+
+
+ );
+ }
+ return (
+
+ {row?.user?.username}
+
+ );
+ }}
+
+
+ {(row: any) => }
+
+
+ {(row: any) => {
+ const { id } = row;
+
+ return (
+
+
+
+
+ );
+ }}
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx b/src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx
new file mode 100644
index 0000000..5da82af
--- /dev/null
+++ b/src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx
@@ -0,0 +1,14 @@
+'use client';
+import { WebsiteSettings } from '@/app/(main)/websites/[websiteId]/settings/WebsiteSettings';
+import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider';
+import { Panel } from '@/components/common/Panel';
+
+export function AdminWebsitePage({ websiteId }: { websiteId: string }) {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/admin/websites/[websiteId]/page.tsx b/src/app/(main)/admin/websites/[websiteId]/page.tsx
new file mode 100644
index 0000000..557adbd
--- /dev/null
+++ b/src/app/(main)/admin/websites/[websiteId]/page.tsx
@@ -0,0 +1,12 @@
+import type { Metadata } from 'next';
+import { WebsiteSettingsPage } from '@/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage';
+
+export default async function ({ params }: { params: Promise<{ websiteId: string }> }) {
+ const { websiteId } = await params;
+
+ return ;
+}
+
+export const metadata: Metadata = {
+ title: 'Website',
+};
diff --git a/src/app/(main)/admin/websites/page.tsx b/src/app/(main)/admin/websites/page.tsx
new file mode 100644
index 0000000..d6da9f6
--- /dev/null
+++ b/src/app/(main)/admin/websites/page.tsx
@@ -0,0 +1,9 @@
+import type { Metadata } from 'next';
+import { AdminWebsitesPage } from './AdminWebsitesPage';
+
+export default function () {
+ return ;
+}
+export const metadata: Metadata = {
+ title: 'Websites',
+};
--
cgit v1.2.3