trpc demo
This commit is contained in:
@@ -24,6 +24,11 @@
|
|||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@neondatabase/serverless": "^1.0.0",
|
"@neondatabase/serverless": "^1.0.0",
|
||||||
"@t3-oss/env-nextjs": "^0.12.0",
|
"@t3-oss/env-nextjs": "^0.12.0",
|
||||||
|
"@tanstack/react-query": "^5.72.2",
|
||||||
|
"@trpc/client": "^11.1.0",
|
||||||
|
"@trpc/next": "^11.1.0",
|
||||||
|
"@trpc/react-query": "^11.1.0",
|
||||||
|
"@trpc/server": "^11.1.0",
|
||||||
"drizzle-orm": "^0.41.0",
|
"drizzle-orm": "^0.41.0",
|
||||||
"next": "^15.2.3",
|
"next": "^15.2.3",
|
||||||
"postgres": "^3.4.4",
|
"postgres": "^3.4.4",
|
||||||
|
|||||||
98
pnpm-lock.yaml
generated
98
pnpm-lock.yaml
generated
@@ -26,6 +26,21 @@ importers:
|
|||||||
'@t3-oss/env-nextjs':
|
'@t3-oss/env-nextjs':
|
||||||
specifier: ^0.12.0
|
specifier: ^0.12.0
|
||||||
version: 0.12.0(typescript@5.8.3)(zod@3.24.2)
|
version: 0.12.0(typescript@5.8.3)(zod@3.24.2)
|
||||||
|
'@tanstack/react-query':
|
||||||
|
specifier: ^5.72.2
|
||||||
|
version: 5.72.2(react@19.1.0)
|
||||||
|
'@trpc/client':
|
||||||
|
specifier: ^11.1.0
|
||||||
|
version: 11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3)
|
||||||
|
'@trpc/next':
|
||||||
|
specifier: ^11.1.0
|
||||||
|
version: 11.1.0(@tanstack/react-query@5.72.2(react@19.1.0))(@trpc/client@11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3))(@trpc/react-query@11.1.0(@tanstack/react-query@5.72.2(react@19.1.0))(@trpc/client@11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.1.0(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3))(@trpc/server@11.1.0(typescript@5.8.3))(next@15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
|
||||||
|
'@trpc/react-query':
|
||||||
|
specifier: ^11.1.0
|
||||||
|
version: 11.1.0(@tanstack/react-query@5.72.2(react@19.1.0))(@trpc/client@11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.1.0(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
|
||||||
|
'@trpc/server':
|
||||||
|
specifier: ^11.1.0
|
||||||
|
version: 11.1.0(typescript@5.8.3)
|
||||||
drizzle-orm:
|
drizzle-orm:
|
||||||
specifier: ^0.41.0
|
specifier: ^0.41.0
|
||||||
version: 0.41.0(@neondatabase/serverless@1.0.0)(@types/pg@8.11.11)(gel@2.0.2)(postgres@3.4.5)
|
version: 0.41.0(@neondatabase/serverless@1.0.0)(@types/pg@8.11.11)(gel@2.0.2)(postgres@3.4.5)
|
||||||
@@ -750,6 +765,52 @@ packages:
|
|||||||
'@tailwindcss/postcss@4.1.3':
|
'@tailwindcss/postcss@4.1.3':
|
||||||
resolution: {integrity: sha512-6s5nJODm98F++QT49qn8xJKHQRamhYHfMi3X7/ltxiSQ9dyRsaFSfFkfaMsanWzf+TMYQtbk8mt5f6cCVXJwfg==}
|
resolution: {integrity: sha512-6s5nJODm98F++QT49qn8xJKHQRamhYHfMi3X7/ltxiSQ9dyRsaFSfFkfaMsanWzf+TMYQtbk8mt5f6cCVXJwfg==}
|
||||||
|
|
||||||
|
'@tanstack/query-core@5.72.2':
|
||||||
|
resolution: {integrity: sha512-fxl9/0yk3mD/FwTmVEf1/H6N5B975H0luT+icKyX566w6uJG0x6o+Yl+I38wJRCaogiMkstByt+seXfDbWDAcA==}
|
||||||
|
|
||||||
|
'@tanstack/react-query@5.72.2':
|
||||||
|
resolution: {integrity: sha512-SVNHzyBUYiis+XiCl+8yiPZmMYei2AKYY94wM/zpvB5l1jxqOo82FQTziSJ4pBi96jtYqvYrTMxWynmbQh3XKw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^18 || ^19
|
||||||
|
|
||||||
|
'@trpc/client@11.1.0':
|
||||||
|
resolution: {integrity: sha512-Q3pL4p7AddxI/ZJTEFo1utKSdasDFjZPECIPsKDkthEt52k530JkYVltTdLkYFKrNWXKKBo8MN7NwchelczoRw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@trpc/server': 11.1.0
|
||||||
|
typescript: '>=5.7.2'
|
||||||
|
|
||||||
|
'@trpc/next@11.1.0':
|
||||||
|
resolution: {integrity: sha512-P8/qpfvRs7IIDdFBrcyMfxXumgf5p7K+dig6NpxpNYs4bqVJfBnAbATYEplmLhw/Dcksqo5ZoI0+0A19wLm8Ug==}
|
||||||
|
peerDependencies:
|
||||||
|
'@tanstack/react-query': ^5.59.15
|
||||||
|
'@trpc/client': 11.1.0
|
||||||
|
'@trpc/react-query': 11.1.0
|
||||||
|
'@trpc/server': 11.1.0
|
||||||
|
next: '*'
|
||||||
|
react: '>=16.8.0'
|
||||||
|
react-dom: '>=16.8.0'
|
||||||
|
typescript: '>=5.7.2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@tanstack/react-query':
|
||||||
|
optional: true
|
||||||
|
'@trpc/react-query':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@trpc/react-query@11.1.0':
|
||||||
|
resolution: {integrity: sha512-qdqKdFM8hVy/YSBCg1/3VO+IgB6Nbul3Fk1SA3lefGf0bkYZdWVVyKab8HBAfOWlMsuRufhVLPdKYmnjzBrK9g==}
|
||||||
|
peerDependencies:
|
||||||
|
'@tanstack/react-query': ^5.67.1
|
||||||
|
'@trpc/client': 11.1.0
|
||||||
|
'@trpc/server': 11.1.0
|
||||||
|
react: '>=18.2.0'
|
||||||
|
react-dom: '>=18.2.0'
|
||||||
|
typescript: '>=5.7.2'
|
||||||
|
|
||||||
|
'@trpc/server@11.1.0':
|
||||||
|
resolution: {integrity: sha512-uAJ7ikejeujVkf53XFJ/0W8nr7bDjul+Szk5Rsepq97Hb/WS1RkRXdyX4KqAyCE9b1vDFCJVJwSxiIZdRtbTZQ==}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '>=5.7.2'
|
||||||
|
|
||||||
'@types/node@20.17.30':
|
'@types/node@20.17.30':
|
||||||
resolution: {integrity: sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==}
|
resolution: {integrity: sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==}
|
||||||
|
|
||||||
@@ -1697,6 +1758,43 @@ snapshots:
|
|||||||
postcss: 8.5.3
|
postcss: 8.5.3
|
||||||
tailwindcss: 4.1.3
|
tailwindcss: 4.1.3
|
||||||
|
|
||||||
|
'@tanstack/query-core@5.72.2': {}
|
||||||
|
|
||||||
|
'@tanstack/react-query@5.72.2(react@19.1.0)':
|
||||||
|
dependencies:
|
||||||
|
'@tanstack/query-core': 5.72.2
|
||||||
|
react: 19.1.0
|
||||||
|
|
||||||
|
'@trpc/client@11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3)':
|
||||||
|
dependencies:
|
||||||
|
'@trpc/server': 11.1.0(typescript@5.8.3)
|
||||||
|
typescript: 5.8.3
|
||||||
|
|
||||||
|
'@trpc/next@11.1.0(@tanstack/react-query@5.72.2(react@19.1.0))(@trpc/client@11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3))(@trpc/react-query@11.1.0(@tanstack/react-query@5.72.2(react@19.1.0))(@trpc/client@11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.1.0(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3))(@trpc/server@11.1.0(typescript@5.8.3))(next@15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)':
|
||||||
|
dependencies:
|
||||||
|
'@trpc/client': 11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3)
|
||||||
|
'@trpc/server': 11.1.0(typescript@5.8.3)
|
||||||
|
next: 15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
react: 19.1.0
|
||||||
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
typescript: 5.8.3
|
||||||
|
optionalDependencies:
|
||||||
|
'@tanstack/react-query': 5.72.2(react@19.1.0)
|
||||||
|
'@trpc/react-query': 11.1.0(@tanstack/react-query@5.72.2(react@19.1.0))(@trpc/client@11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.1.0(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
|
||||||
|
|
||||||
|
'@trpc/react-query@11.1.0(@tanstack/react-query@5.72.2(react@19.1.0))(@trpc/client@11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.1.0(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)':
|
||||||
|
dependencies:
|
||||||
|
'@tanstack/react-query': 5.72.2(react@19.1.0)
|
||||||
|
'@trpc/client': 11.1.0(@trpc/server@11.1.0(typescript@5.8.3))(typescript@5.8.3)
|
||||||
|
'@trpc/server': 11.1.0(typescript@5.8.3)
|
||||||
|
react: 19.1.0
|
||||||
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
typescript: 5.8.3
|
||||||
|
|
||||||
|
'@trpc/server@11.1.0(typescript@5.8.3)':
|
||||||
|
dependencies:
|
||||||
|
typescript: 5.8.3
|
||||||
|
|
||||||
'@types/node@20.17.30':
|
'@types/node@20.17.30':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.8
|
undici-types: 6.19.8
|
||||||
|
|||||||
3
src/app/_trpc/Client.ts
Normal file
3
src/app/_trpc/Client.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { createTRPCReact } from "@trpc/react-query";
|
||||||
|
import type { TrpcRouter } from "~/server/routers/_app";
|
||||||
|
export const trpc = createTRPCReact<TrpcRouter>({})
|
||||||
22
src/app/_trpc/ServerClient.ts
Normal file
22
src/app/_trpc/ServerClient.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { httpBatchLink } from "@trpc/client";
|
||||||
|
import { trpcRouter } from "~/server/routers/_app";
|
||||||
|
|
||||||
|
function getBaseUrl() {
|
||||||
|
if (typeof window !== 'undefined')
|
||||||
|
// browser should use relative path
|
||||||
|
return '';
|
||||||
|
if (process.env.VERCEL_URL)
|
||||||
|
// reference for vercel.com
|
||||||
|
return `https://${process.env.VERCEL_URL}`;
|
||||||
|
if (process.env.RENDER_INTERNAL_HOSTNAME)
|
||||||
|
// reference for render.com
|
||||||
|
return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;
|
||||||
|
// assume localhost
|
||||||
|
return `http://localhost:${process.env.PORT ?? 3000}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const servTrpc = trpcRouter.createCaller({
|
||||||
|
links: [
|
||||||
|
httpBatchLink({url: `${getBaseUrl()}/api/trpc`}),
|
||||||
|
],
|
||||||
|
});
|
||||||
38
src/app/_trpc/TrpcProvider.tsx
Normal file
38
src/app/_trpc/TrpcProvider.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
'use client'
|
||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
import { httpBatchLink } from "@trpc/client";
|
||||||
|
import React, { useState } from "react"
|
||||||
|
import { trpc } from "./Client";
|
||||||
|
|
||||||
|
function getBaseUrl() {
|
||||||
|
if (typeof window !== 'undefined')
|
||||||
|
// browser should use relative path
|
||||||
|
return '';
|
||||||
|
if (process.env.VERCEL_URL)
|
||||||
|
// reference for vercel.com
|
||||||
|
return `https://${process.env.VERCEL_URL}`;
|
||||||
|
if (process.env.RENDER_INTERNAL_HOSTNAME)
|
||||||
|
// reference for render.com
|
||||||
|
return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;
|
||||||
|
// assume localhost
|
||||||
|
return `http://localhost:${process.env.PORT ?? 3000}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TrpcProvider({children}:{children: React.ReactNode}) {
|
||||||
|
const [queryClient] = useState(() => new QueryClient({}));
|
||||||
|
const [trpcClient] = useState(() => {
|
||||||
|
return trpc.createClient({
|
||||||
|
links: [
|
||||||
|
httpBatchLink({
|
||||||
|
url: `${getBaseUrl()}/api/trpc`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<trpc.Provider client={trpcClient} queryClient={queryClient}>
|
||||||
|
<QueryClientProvider client={queryClient}> {children} </QueryClientProvider>
|
||||||
|
</trpc.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
10
src/app/api/trpc/[trpc]/route.ts
Normal file
10
src/app/api/trpc/[trpc]/route.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
|
||||||
|
import { trpcRouter } from '~/server/routers/_app'
|
||||||
|
const handler = (req: Request) => fetchRequestHandler({
|
||||||
|
endpoint: "/api/trpc",
|
||||||
|
req,
|
||||||
|
router: trpcRouter,
|
||||||
|
createContext: () => ({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export {handler as GET, handler as POST}
|
||||||
26
src/app/cv/_components/CvCategory.tsx
Normal file
26
src/app/cv/_components/CvCategory.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
'use client'
|
||||||
|
import { trpc } from "~/app/_trpc/Client"
|
||||||
|
import CvEntry, { type CvEntryProps } from "./CvEntry"
|
||||||
|
import type { servTrpc } from "~/app/_trpc/ServerClient"
|
||||||
|
type CvCategoryProps = {
|
||||||
|
initialData: Awaited<ReturnType<typeof servTrpc.cvCategory.get>>,
|
||||||
|
children?: React.ReactElement<CvEntryProps>
|
||||||
|
}
|
||||||
|
export default function CvCategory(props:CvCategoryProps) {
|
||||||
|
const cvCategories = trpc.cvCategory.get.useQuery(undefined,{
|
||||||
|
initialData: props.initialData,
|
||||||
|
refetchOnMount: false,
|
||||||
|
refetchOnReconnect: false,
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{cvCategories.data.map((cat) => {
|
||||||
|
return (
|
||||||
|
<div key={cat.id}>
|
||||||
|
{cat.name}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
7
src/app/cv/_components/CvEntry.tsx
Normal file
7
src/app/cv/_components/CvEntry.tsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { cvEntry } from "~/server/db/schema"
|
||||||
|
|
||||||
|
export type CvEntryProps = typeof cvEntry
|
||||||
|
|
||||||
|
export default function CvEntry(cvEntry: CvEntryProps) {
|
||||||
|
return (<></>)
|
||||||
|
}
|
||||||
3
src/app/cv/_components/CvLayout.tsx
Normal file
3
src/app/cv/_components/CvLayout.tsx
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default function CvLayout({children,}: Readonly<{ children: React.ReactNode }>) {
|
||||||
|
return (<></>)
|
||||||
|
}
|
||||||
@@ -1,18 +1,10 @@
|
|||||||
import { getCvCategories } from "~/server/db/query"
|
import { servTrpc } from "~/app/_trpc/ServerClient"
|
||||||
|
import CvCategory from "./_components/CvCategory";
|
||||||
export default async function CvPage() {
|
export default async function CvPage() {
|
||||||
const cvCategories = await getCvCategories();
|
const cvCategories = await servTrpc.cvCategory.get();
|
||||||
return (
|
return (
|
||||||
<div>
|
<CvCategory initialData={cvCategories}>
|
||||||
{cvCategories.map((category) => {
|
<></>
|
||||||
return (
|
</CvCategory>
|
||||||
<div key={category.id}>
|
|
||||||
<div>
|
|
||||||
{category.name}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ClerkProvider } from "@clerk/nextjs";
|
|||||||
import { config } from "@fortawesome/fontawesome-svg-core"
|
import { config } from "@fortawesome/fontawesome-svg-core"
|
||||||
import "@fortawesome/fontawesome-svg-core/styles.css"
|
import "@fortawesome/fontawesome-svg-core/styles.css"
|
||||||
import TopNav from "./_components/TopNav";
|
import TopNav from "./_components/TopNav";
|
||||||
|
import TrpcProvider from "./_trpc/TrpcProvider";
|
||||||
config.autoAddCss = false;
|
config.autoAddCss = false;
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Gregor Lohaus",
|
title: "Gregor Lohaus",
|
||||||
@@ -24,6 +25,7 @@ export default function RootLayout({
|
|||||||
}: Readonly<{ children: React.ReactNode, modal: React.ReactNode }>) {
|
}: Readonly<{ children: React.ReactNode, modal: React.ReactNode }>) {
|
||||||
return (
|
return (
|
||||||
<ClerkProvider>
|
<ClerkProvider>
|
||||||
|
<TrpcProvider>
|
||||||
<html lang="en" className={`${geist.variable}`}>
|
<html lang="en" className={`${geist.variable}`}>
|
||||||
<body className="flex flex-col gap-2 bg-black text-white">
|
<body className="flex flex-col gap-2 bg-black text-white">
|
||||||
<TopNav/>
|
<TopNav/>
|
||||||
@@ -31,6 +33,7 @@ export default function RootLayout({
|
|||||||
{modal}
|
{modal}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
</TrpcProvider>
|
||||||
</ClerkProvider>
|
</ClerkProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import "server-only"
|
|
||||||
import { db } from "."
|
|
||||||
|
|
||||||
export async function getCvCategories() {
|
|
||||||
const categories = await db.query.cvCategory.findMany({
|
|
||||||
orderBy: (model, {desc} ) => desc(model.name)
|
|
||||||
})
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
10
src/server/routers/_app.ts
Normal file
10
src/server/routers/_app.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { router } from "../trpc";
|
||||||
|
import { CvCategoryRouter } from "./cvCategory";
|
||||||
|
import { publicProcedure } from "~/server/trpc";
|
||||||
|
|
||||||
|
export const trpcRouter = router({
|
||||||
|
hello: publicProcedure.query(async () => "world"),
|
||||||
|
cvCategory: CvCategoryRouter
|
||||||
|
})
|
||||||
|
|
||||||
|
export type TrpcRouter = typeof trpcRouter
|
||||||
12
src/server/routers/cvCategory/index.ts
Normal file
12
src/server/routers/cvCategory/index.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { db } from "~/server/db";
|
||||||
|
import { publicProcedure, router } from "~/server/trpc";
|
||||||
|
|
||||||
|
export const CvCategoryRouter = router({
|
||||||
|
get: publicProcedure.query(async () => {
|
||||||
|
const categories = await db.query.cvCategory.findMany({
|
||||||
|
orderBy: (model, {desc} ) => desc(model.name)
|
||||||
|
});
|
||||||
|
return categories;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
5
src/server/trpc.ts
Normal file
5
src/server/trpc.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { initTRPC } from "@trpc/server"
|
||||||
|
|
||||||
|
const t = initTRPC.create();
|
||||||
|
export const router = t.router;
|
||||||
|
export const publicProcedure = t.procedure;
|
||||||
Reference in New Issue
Block a user