From b37efc0ff9699d8bd8581c5e9c3af175c9c11978 Mon Sep 17 00:00:00 2001 From: ErikaKK <491649804@qq.com> Date: Sun, 1 Feb 2026 22:23:46 +0800 Subject: [PATCH 1/3] add export button for project and payment table --- .../admin/{@users => @tools}/export.tsx | 26 ++++++++++++++----- src/app/dashboard/admin/@tools/page.tsx | 10 +++++++ src/app/dashboard/admin/@users/table.tsx | 12 ++++----- src/app/profile/[id]/profile.tsx | 13 +++++++++- .../routers/admin/analytics/get-payments.ts | 12 +++++++++ .../api/routers/admin/analytics/index.ts | 2 ++ .../api/routers/admin/projects/get-all.ts | 12 +++++++++ .../api/routers/admin/projects/index.ts | 2 ++ src/server/api/routers/admin/users/get-all.ts | 6 ----- 9 files changed, 75 insertions(+), 20 deletions(-) rename src/app/dashboard/admin/{@users => @tools}/export.tsx (67%) create mode 100644 src/server/api/routers/admin/analytics/get-payments.ts create mode 100644 src/server/api/routers/admin/projects/get-all.ts diff --git a/src/app/dashboard/admin/@users/export.tsx b/src/app/dashboard/admin/@tools/export.tsx similarity index 67% rename from src/app/dashboard/admin/@users/export.tsx rename to src/app/dashboard/admin/@tools/export.tsx index 5ecb0ba4c..b264d2143 100644 --- a/src/app/dashboard/admin/@users/export.tsx +++ b/src/app/dashboard/admin/@tools/export.tsx @@ -5,9 +5,14 @@ import { useEffect, useState } from "react" import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert" import { Button } from "~/components/ui/button" -import { TableProps } from "./table" +import { type Payment, type Project, type User } from "~/server/db/types" -export default function ExportButton({ data }: TableProps) { +export interface ExportButtonProps { + data: Array + label: string +} + +export default function ExportButton({ data, label }: ExportButtonProps) { const [open, setOpen] = useState(false) useEffect(() => { if (!open) return @@ -17,19 +22,26 @@ export default function ExportButton({ data }: TableProps) { const downloadCSV = () => { if (!data || data.length === 0) { setOpen(true) - console.log("open") return } const headers = Object.keys(data[0] as Record).join(",") - const rows = data.map((row) => Object.values(row).join(",")).join("\n") + const escapeCSV = (value: unknown) => { + if (value == null) return "" + const str = String(value) + if (/[",\n]/.test(str)) { + return `"${str.replace(/"/g, '""')}"` + } + return str + } + const rows = data.map((row) => Object.values(row).map(escapeCSV).join(",")).join("\n") const csv = headers + "\n" + rows const blob = new Blob([csv], { type: "text/csv" }) const url = window.URL.createObjectURL(blob) const a = document.createElement("a") a.setAttribute("href", url) - a.setAttribute("download", "output.csv") + a.setAttribute("download", `${label}.csv`) a.click() window.URL.revokeObjectURL(url) setOpen(true) @@ -38,7 +50,7 @@ export default function ExportButton({ data }: TableProps) { return (
{open && (!data || data.length === 0) && ( @@ -49,7 +61,7 @@ export default function ExportButton({ data }: TableProps) { {open && data && data.length > 0 && ( Export Successful - Your data has been exported as `output.csv`. + Your data has been exported as {`${label}.csv`}. )}
diff --git a/src/app/dashboard/admin/@tools/page.tsx b/src/app/dashboard/admin/@tools/page.tsx index b334cc783..38fc1e1ac 100644 --- a/src/app/dashboard/admin/@tools/page.tsx +++ b/src/app/dashboard/admin/@tools/page.tsx @@ -1,6 +1,12 @@ +import { api } from "~/trpc/server" + +import ExportButton from "./export" import UpdateEmail from "./update-email" export default async function AdminUserTable() { + const projects = await api.admin.projects.getAllProjects.query() + const payments = await api.admin.analytics.getAllPayments.query() + return ( <>
@@ -9,6 +15,10 @@ export default async function AdminUserTable() {
+
+ + +
) } diff --git a/src/app/dashboard/admin/@users/table.tsx b/src/app/dashboard/admin/@users/table.tsx index b6840dbd0..5adb01847 100644 --- a/src/app/dashboard/admin/@users/table.tsx +++ b/src/app/dashboard/admin/@users/table.tsx @@ -63,13 +63,13 @@ import { cn } from "~/lib/utils" import { type User } from "~/server/db/types" import { api } from "~/trpc/react" -import ExportButton from "./export" +import ExportButton from "../@tools/export" import AddUserForm from "./form" -type UserProps = Omit +type DisplayColumn = Omit export interface TableProps { - data: Array + data: Array } interface UserTableProps extends TableProps { refetch: () => void @@ -92,7 +92,7 @@ const sortIcon = (sortOrder: string | boolean) => { } } -const columns = (updateRole: ({ id, role }: UpdateUserRoleFunctionProps) => void): ColumnDef[] => [ +const columns = (updateRole: ({ id, role }: UpdateUserRoleFunctionProps) => void): ColumnDef[] => [ { id: "Select", enableSorting: false, @@ -341,7 +341,7 @@ const UserTable = ({ data, isRefetching, ...props }: UserTableProps) => { return ( <> -
+
{data.length > 0 && ( <> {selectedRowIDs.length > 0 && ( @@ -418,7 +418,7 @@ const UserTable = ({ data, isRefetching, ...props }: UserTableProps) => { })} - +