before remove routers

This commit is contained in:
2025-07-30 09:28:25 +02:00
parent b58024b66a
commit 2816842b5d
20 changed files with 1202 additions and 900 deletions

View File

@@ -18,12 +18,12 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@clerk/nextjs": "^6.23.2",
"@clerk/nextjs": "^6.27.1",
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"@fortawesome/react-fontawesome": "^0.2.3",
"@gsap/react": "^2.1.2",
"@hookform/resolvers": "^5.1.1",
"@hookform/resolvers": "^5.2.0",
"@neondatabase/serverless": "^1.0.1",
"@radix-ui/react-accordion": "^1.2.11",
"@radix-ui/react-alert-dialog": "^1.1.14",
@@ -52,13 +52,13 @@
"@radix-ui/react-toggle-group": "^1.1.10",
"@radix-ui/react-tooltip": "^1.2.7",
"@t3-oss/env-nextjs": "^0.12.0",
"@tanstack/react-query": "^5.81.5",
"@tanstack/react-query-next-experimental": "^5.81.5",
"@tanstack/react-query": "^5.83.0",
"@tanstack/react-query-next-experimental": "^5.83.0",
"@trpc/client": "^11.4.3",
"@trpc/next": "^11.4.3",
"@trpc/react-query": "^11.4.3",
"@trpc/server": "^11.4.3",
"@uiw/react-md-editor": "^4.0.7",
"@uiw/react-md-editor": "^4.0.8",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
@@ -74,33 +74,33 @@
"next": "15.4.0-canary.17",
"next-themes": "^0.4.6",
"postgres": "^3.4.7",
"react": "^19.1.0",
"react": "^19.1.1",
"react-day-picker": "8.10.1",
"react-dom": "^19.1.0",
"react-hook-form": "^7.59.0",
"react-dom": "^19.1.1",
"react-hook-form": "^7.61.1",
"react-markdown": "^10.1.0",
"react-resizable-panels": "^3.0.3",
"recharts": "^2.15.4",
"rehype-highlight": "^7.0.2",
"rehype-raw": "^7.0.0",
"server-only": "^0.0.1",
"sonner": "^2.0.5",
"sonner": "^2.0.6",
"tailwind-merge": "^3.3.1",
"tailwindcss-motion": "^1.1.1",
"type-fest": "^4.41.0",
"vaul": "^1.1.2",
"zod": "^3.25.70"
"zod": "^3.25.76"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@tailwindcss/postcss": "^4.1.11",
"@types/node": "^20.19.4",
"@types/node": "^20.19.9",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"drizzle-kit": "^0.30.6",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.3.4",
"tw-animate-css": "^1.3.6",
"typescript": "^5.8.3"
},
"ct3aMetadata": {

1597
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
import Link from "next/link";
import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarTrigger } from "~/components/ui/sidebar";
import SimpleSidebarGroup from "~/components/ui/simple-sidebar-group";
export default async function AdminSideBar() {
return (
@@ -8,63 +9,19 @@ export default async function AdminSideBar() {
<Sidebar className="z-[51]">
<SidebarTrigger className="absolute z-[52] left-65 top-100" />
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>
CV
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<SimpleSidebarGroup lable="CV">
<Link href={"/admin/cv/category/create"}> Create Category </Link>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<Link href={"/admin/cv/entry/create"}> Create Entry </Link>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<Link href={"/admin/cv/category/list"}> Category List </Link>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<Link href={"/admin/cv/entry/list"}> Entry List </Link>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>
Projects
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton asChild>
</SimpleSidebarGroup>
<SimpleSidebarGroup lable="Projects">
<Link href={"/admin/project/create"}> Create Project </Link>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>
Blog
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<Link href={"/admin/project/techStack/create"}> Create Stack </Link>
</SimpleSidebarGroup>
<SimpleSidebarGroup lable="Blog">
<Link href={"/"}> Some Blog Action </Link>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SimpleSidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>

View File

@@ -7,6 +7,6 @@ export default async function Page({params}:{params: Promise<{id:string}>}) {
console.log(params)
const {id} = await params;
return (
<UpdateCvCategoryForm id={id} className={undefined}/>
<UpdateCvCategoryForm id={id} />
)
}

View File

@@ -6,7 +6,7 @@ import type { CategoryRouterOutputs } from "~/server/routers/cv/category";
import { type Element } from "~/lib/utils";
import UpdateCvCategoryForm from "./UpdateForm";
import CreateCvCategoryForm from "./CreateForm";
export default function CollapsibleCvCategoryForm(params:{category:Element<CategoryRouterOutputs['list']>|undefined}) {
export default function CollapsibleCvCategoryForm(params:{category?:Element<CategoryRouterOutputs['list']>}) {
return (
<Collapsible >
<CollapsibleTrigger asChild>

View File

@@ -9,20 +9,35 @@ import { Select, SelectContent, SelectTrigger, SelectItem, SelectValue } from "~
import { trpc } from "~/app/_trpc/Client";
import { Button } from "~/components/ui/button";
import * as Card from '~/components/ui/card'
export default function CreateCvCategoryForm(params:{className:string|undefined}) {
const form = useForm<z.infer<typeof insertSchema>>({
resolver: zodResolver(insertSchema),
import type { IterableElement } from 'type-fest'
import { usePathname, useRouter } from "next/navigation";
import { entitySchemas } from "~/lib/utils";
import type { RouterOutputs } from "~/server/routers/_app";
export default function CreateCvCategoryForm(params:{className?:string,category?:IterableElement<RouterOutputs['cv']['categoryv2']['select']>}) {
const schemas = entitySchemas('cvCategory')
const pathname = usePathname();
const router = useRouter();
const form = useForm<z.infer<typeof schemas.insert>>({
resolver: zodResolver(schemas.insert),
defaultValues: {
id: crypto.randomUUID(),
layoutPosition: "col1"
}
})
const mutation = trpc.cv.category.create.useMutation()
function onSubmit(values: z.infer<typeof insertSchema>) {
mutation.mutate(values)
form.setValue("id",crypto.randomUUID())
const createMutation = trpc.cv.categoryv2.insert.useMutation()
function onSubmit(values: z.infer<typeof schemas.insert>) {
const res = createMutation.mutate(values)
}
const updateMutation = trpc.cv.categoryv2.update.useMutation()
const deleteMutation = trpc.cv.categoryv2.delete.useMutation({
onSuccess: () => {
if (pathname.includes('list')) {
router.refresh()
} else {
router.back()
}
}
})
return (
<Card.Card className={params.className ? params.className : "w-5/6 lg:w-1/2"}>
<Card.CardHeader>
@@ -76,8 +91,8 @@ export default function CreateCvCategoryForm(params:{className:string|undefined}
>
</FormField>
<Button type="submit"> Create </Button>
<FormMessage className={mutation.status == "success" ? "text-green-500" : "text-red-500"}>
{mutation.error ? mutation.error.message : mutation.status}
<FormMessage className={createMutation.status == "success" ? "text-green-500" : "text-red-500"}>
{createMutation.error ? createMutation.error.message : createMutation.status}
</FormMessage>
</form>
</Form>

View File

@@ -12,11 +12,10 @@ import * as Card from '~/components/ui/card'
import { useRouter, usePathname } from "next/navigation";
import { Delete } from "lucide-react";
import { cn } from "~/lib/utils";
export default function UpdateCvCategoryForm(params: { id: string, className: string | undefined }) {
export default function UpdateCvCategoryForm(params: { id: string, className?: string }) {
const router = useRouter();
const pathname = usePathname();
const id = params.id;
console.log(id)
const category = trpc.cv.category.get.useQuery({ id: id })
const form = useForm<z.infer<typeof updateRouteSchema>>({
resolver: zodResolver(updateRouteSchema),

View File

@@ -41,21 +41,21 @@ export default function CvPage() {
cat.cvEntry.length > 0 ? (
<>
{cat.cvEntry.map((entry) => (
<CollapsibleCvEntryForm key={entry.id} entry={entry} categoryId={undefined} />
<CollapsibleCvEntryForm key={entry.id} entry={entry}/>
))}
</>
) : (<></>)
}
</div>
<div className="flex flex-col w-full">
<CollapsibleCvEntryForm entry={undefined} categoryId={cat.id} />
<CollapsibleCvEntryForm categoryId={cat.id} />
</div>
</div>
</Card.CardContent>
</Card.Card>
)
})}
<CollapsibleCvCategoryForm category={undefined} />
<CollapsibleCvCategoryForm />
</>
}
</div>

View File

@@ -6,7 +6,7 @@ import type { CategoryRouterOutputs } from "~/server/routers/cv/category";
import { type Element } from "~/lib/utils";
import UpdateCvEntryForm from "./UpdateForm";
import CreateCvEntryForm from "./CreateForm";
export default function CollapsibleCvEntryForm(params:{entry:Element<Element<CategoryRouterOutputs['list']>['cvEntry']>|EntryRouterOutputs['get']|Element<EntryRouterOutputs['list']>|undefined, categoryId: string|undefined}) {
export default function CollapsibleCvEntryForm(params:{entry?:Element<Element<CategoryRouterOutputs['list']>['cvEntry']>|EntryRouterOutputs['get']|Element<EntryRouterOutputs['list']>, categoryId?: string}) {
return (
<Collapsible>
<CollapsibleTrigger asChild>

View File

@@ -13,7 +13,7 @@ import type { Entries } from 'type-fest'
import { type Element } from "~/lib/utils";
import type { ProjectRouterOutputs } from "~/server/routers/project";
import { Suspense } from "react";
export default function CreateUpdateProjectForm(params:{className:string|undefined, project:Element<ProjectRouterOutputs['list']>|undefined}) {
export default function CreateUpdateProjectForm(params:{className?:string, project?:Element<ProjectRouterOutputs['list']>}) {
const [techStacks,] = trpc.project.stack.list.useSuspenseQuery()
const form = useForm<z.infer<typeof insertSchema>>({
resolver: zodResolver(insertSchema),
@@ -26,8 +26,8 @@ export default function CreateUpdateProjectForm(params:{className:string|undefin
})
const updateMutation = trpc.project.update.useMutation({
onSuccess: (data) => {
if (null !== data) {
let entries = Object.entries(data) as Entries<typeof data>
if (data.length > 0 && data[0] !== undefined) {
let entries = Object.entries(data[0]) as Entries<typeof data[0]>
entries.forEach( (entry) => {
form.setValue(entry[0],entry[1])
})

View File

@@ -1,7 +1,7 @@
import CreateUpdateProjectForm from "../_components/CreateForm";
import CreateUpdateProjectForm from "../_components/CreateUpdateProjectForm";
export default function Page() {
return (
<CreateUpdateProjectForm className="" project={undefined}/>
<CreateUpdateProjectForm />
)
}

View File

@@ -0,0 +1,27 @@
import { ChevronsUpDown, Plus } from "lucide-react"
import { Button } from "~/components/ui/button";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "~/components/ui/collapsible";
import { type Element } from "~/lib/utils";
import CreateUpdateProjectForm from "./CreateForm";
import type { ProjectRouterOutputs } from "~/server/routers/project";
export default function CollapsibleForm(params:{project:Element<ProjectRouterOutputs['list']>|undefined}) {
return (
<Collapsible >
<CollapsibleTrigger asChild>
<Button variant={"ghost"}>
{ params.project ?
<>{params.project.title} <ChevronsUpDown/></> : <>New <Plus/></>
}
</Button>
</CollapsibleTrigger>
<CollapsibleContent className="autoAlpha">
{
params.project ?
<CreateUpdateProjectForm className="w-full" project={params.project}/> :
<CreateUpdateProjectForm className="w-full" project={params.project}/>
}
</CollapsibleContent>
</Collapsible>
)
}

View File

@@ -0,0 +1,100 @@
"use client"
import { insertSchema } from "~/lib/schema/project/techStack"
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { z } from "zod";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "~/components/ui/form";
import { trpc } from "~/app/_trpc/Client";
import { Button } from "~/components/ui/button";
import * as Card from '~/components/ui/card'
import type { Entries } from 'type-fest'
import { type Element } from "~/lib/utils";
import type { StackRouter, StackRouterOutputs } from "~/server/routers/project/techStack";
import { stackItemEnum } from "~/server/db/schema";
import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";
export default function CreateUpdateForm(params:{className:string|undefined, techStack?:Element<StackRouterOutputs['list']>}) {
const form = useForm<z.infer<typeof insertSchema>>({
resolver: zodResolver(insertSchema),
defaultValues: {
id: params.techStack ? params.techStack.id : crypto.randomUUID(),
stackItems: params.techStack ? params.techStack.stackItems : [],
}
})
const createMutation = trpc.project.stack.create.useMutation({
onSuccess: (data) => { form.setValue("id", data[0] ? data[0].id : "") }
})
const updateMutation = trpc.project.stack.update.useMutation({
onSuccess: (data) => {
if (data.length > 0 && data[0] !== undefined) {
let entries = Object.entries(data[0]) as Entries<typeof data[0]>
entries.forEach( (entry) => {
form.setValue(entry[0],entry[1])
})
}
}
})
function onSubmit(values: z.infer<typeof insertSchema>) {
params.techStack ?
updateMutation.mutate({by: {id: values.id}, update: { ...values}}) :
createMutation.mutate(values)
}
return (
<Card.Card className={params.className ? params.className : "w-5/6 lg:w-1/2"}>
<Card.CardHeader>
<Card.CardTitle>
{params.techStack ? "Update" : "Create"} Tech Stack
</Card.CardTitle>
</Card.CardHeader>
<Card.CardContent>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8"
>
<FormField
control={form.control}
name="stackItems"
render={({ field }) => (
<FormItem>
<FormLabel>
Stack Items
</FormLabel>
<FormControl>
<ToggleGroup
variant="outline"
type="multiple"
onValueChange={field.onChange}
className="flex flex-wrap"
>
{stackItemEnum.enumValues.map((v) => {
return (
<ToggleGroupItem className="w-fit" key={v} value={v}>
{v}
</ToggleGroupItem>
)
})}
</ToggleGroup>
</FormControl>
</FormItem>
)}
/>
<Button type="submit"> {params.techStack ? "Update" : "Create"} </Button>
<FormMessage className={updateMutation.status == "success" || createMutation.status == "success" ? "text-green-500" : "text-red-500"}>
{ params.techStack ?
(
<>{updateMutation.error ? updateMutation.error.message : updateMutation.status}</>
) :
(
<>{createMutation.error ? createMutation.error.message : createMutation.status}</>
)
}
</FormMessage>
</form>
</Form>
</Card.CardContent>
</Card.Card>
)
}

View File

@@ -0,0 +1,7 @@
import CreateUpdateForm from "../_components/CreateUpdateForm";
export default function Page() {
return (
<CreateUpdateForm className=""/>
)
}

View File

@@ -0,0 +1,24 @@
import type { ReactNode } from "react";
import { SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "./sidebar";
export default function SimpleSidebarGroup(params: { lable: string, children: ReactNode|ReactNode[] }) {
return (
<SidebarGroup>
<SidebarGroupLabel>
{params.lable}
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{ (params.children instanceof Array) ? params.children.map((n) => {
return (
<SidebarMenuItem key={crypto.randomUUID()}>
<SidebarMenuButton asChild>
{n}
</SidebarMenuButton>
</SidebarMenuItem>
)
}) : <>{params.children}</> }
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
)
}

View File

@@ -1,8 +1,36 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
import { createInsertSchema, createUpdateSchema, createSelectSchema, type BuildSchema } from 'drizzle-zod'
import * as schema from "~/server/db/schema";
import { PgColumn, PgTable } from "drizzle-orm/pg-core";
import type { Entries } from "type-fest";
import z from "zod";
import type { Prettify } from "node_modules/zod/v4/core/util.cjs";
import type { ExtractTablesWithRelations } from "drizzle-orm";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
export type Element<T extends Iterable<any>|undefined|null> = T extends Iterable<infer E> ? E : never;
export type Element<T extends Iterable<any> | undefined | null> = T extends Iterable<infer E> ? E : never;
export type Schema = typeof schema;
export type SchemaKeys<S> = {
[K in keyof S]: S[K] extends PgTable ? K : never
}[keyof S]
export function entitySchemas<T extends SchemaKeys<Schema>>(table: T): {
insert: BuildSchema<'insert', Schema[T]['_']['columns'], undefined>
update: BuildSchema<'update', Schema[T]['_']['columns'], undefined>
select: BuildSchema<'select', Schema[T]['_']['columns'], undefined>
} {
const insertSchema = createInsertSchema<Schema[T]>(schema[table]);
const updateSchema = createUpdateSchema<Schema[T]>(schema[table]);
const selectSchema = createSelectSchema<Schema[T]>(schema[table]);
return {
insert: insertSchema,
update: updateSchema,
select: selectSchema,
}
}

View File

@@ -2,7 +2,7 @@
// https://orm.drizzle.team/docs/sql-schema-declaration
import { relations, sql } from "drizzle-orm";
import { index, pgEnum, pgTableCreator } from "drizzle-orm/pg-core";
import { index, pgEnum, pgSchema, pgTableCreator } from "drizzle-orm/pg-core";
/**
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
@@ -63,7 +63,9 @@ export const project = createTable(
id: d.uuid().primaryKey().notNull(),
title: d.varchar({length: 50}).notNull(),
sourceType: sourceTypeEnum(),
sourceLink: d.varchar({length: 200}),
releaseStatus: releaseStatus(),
releaseLink: d.varchar({length: 200}),
stackId: d.uuid(),
})
)

136
src/server/lib.ts Normal file
View File

@@ -0,0 +1,136 @@
import type { Entries } from "type-fest";
import { publicProcedure, router } from "~/server/trpc";
import { db } from "~/server/db";
import * as schema from "~/server/db/schema";
import { isAdmin } from "~/app/actions";
import { TRPCError } from "@trpc/server";
import { entitySchemas, type Schema, type SchemaKeys } from "~/lib/utils";
import { eq, and } from "drizzle-orm";
function isKeyOf<T extends object>(k: any, obj: T): k is keyof T {
return k in obj
}
export function trpcCrudRouterFromDrizzleEntity<T extends SchemaKeys<Schema>>(table: T) {
const schemas = entitySchemas<T>(table)
if (!isKeyOf(table, schema)) {
throw new Error('table not found')
}
let r = router({
select: publicProcedure.input(schemas.update).query(async (opts) => {
const { input } = opts;
if (input === undefined) {
return await db.select().from(schema[table]).execute();
}
const conds = (Object.entries(input) as Entries<typeof input>).map(([k, v]) => {
if (!isKeyOf(k, schema[table])) {
throw new TRPCError({ message: "Invalid key for column", code: "BAD_REQUEST" });
}
return eq(schema[table][k], v)
})
if (conds.length > 0) {
return await db.select().from(schema[table]).where(and(...conds)).execute();
}
return await db.select().from(schema[table]).execute();
}),
update: publicProcedure.input(schemas.update).mutation(async (opts) => {
let admin = await isAdmin();
if (!admin) {
throw new TRPCError(
{ message: "Access denied", code: "FORBIDDEN", }
)
}
const { input } = opts;
if (input === undefined) {
throw new TRPCError({ message: "no update input", code: "BAD_REQUEST" })
}
const conds = (Object.entries(input) as Entries<typeof input>).map(([k, v]) => {
if (!isKeyOf(k, schema[table])) {
throw new TRPCError({ message: "Invalid key for column", code: "BAD_REQUEST" });
}
return eq(schema[table][k], v)
})
if (conds.length > 0) {
return await db.update(schema[table]).set(input).where(and(...conds)).returning().execute();
}
throw new TRPCError({ message: "trying to update all entities", code: "BAD_REQUEST" })
}),
insert: publicProcedure.input(schemas.insert).mutation(async (opts) => {
let admin = await isAdmin();
if (!admin) {
throw new TRPCError(
{ message: "Access denied", code: "FORBIDDEN", }
)
}
const { input } = opts;
return await db.insert(schema[table]).values(input).returning().execute();
}),
delete: publicProcedure.input(schemas.update).mutation(async (opts) => {
let admin = await isAdmin();
if (!admin) {
throw new TRPCError(
{ message: "Access denied", code: "FORBIDDEN", }
)
}
const { input } = opts;
const inputEntrie = Object.entries(input) as Entries<typeof input>;
const conds = (Object.entries(input) as Entries<typeof input>).map(([k, v]) => {
if (!isKeyOf(k, schema[table])) {
throw new TRPCError({ message: "Invalid key for column", code: "BAD_REQUEST" });
}
return eq(schema[table][k], v)
})
if (conds.length > 0) {
return await db.update(schema[table]).where(and(...conds)).returning().execute();
}
throw new TRPCError({ message: "trying to delete all entities", code: "BAD_REQUEST" })
}),
// list: publicProcedure.input(z.optional(z.object({
// orderBy: selectSchema.keyof(),
// direction: z.enum(["asc","desc"])
// }))).query(async (opts) => {
// const { input } = opts;
// const query = db.select().from(schema[table])
// if (input !== undefined) {
// switch (input.direction) {
// case "asc" :
// query.orderBy(asc(schema[table]['_']['columns'][input.orderBy]));
// case "desc" :
// query.orderBy(desc(schema[table]['_']['columns'][input.orderBy]));
// }
// }
// return await query.execute()
// }),
// get: publicProcedure.input(z.optional(insertSchema)).query(async (opts) => {
// const { input } = opts
// return await db.select().from(schema[table]).where(eq(schema[table]['_']['columns']['id'], input)).limit(1)
// }),
// delete: publicProcedure.input(z.string()).query(async (opts) => {
// const { input } = opts
// let admin = await isAdmin();
// if (!admin) {
// throw new TRPCError(
// { message: "Access denied", code: "FORBIDDEN", }
// )
// }
// return await db.delete(schema[table]).where(eq(schema[table]['_']['columns']['id'], input)).returning()
// }),
// create: publicProcedure.input(insertSchema).mutation(async (opts) => {
// let admin = await isAdmin();
// if (!admin) {
// throw new TRPCError(
// { message: "Access denied", code: "FORBIDDEN", }
// )
// }
// const { input } = opts;
// return await db.insert(schema[table]).values(input).returning().execute();
// })
});
return { router: r };
}

View File

@@ -1,8 +1,12 @@
import { router } from "~/server/trpc"
import { CategoryRouter } from "./category"
import { EntryRouter } from "./entry"
import { trpcCrudRouterFromDrizzleEntity } from "~/server/lib"
import * as schema from '~/server/db/schema'
const { router : categoryv2 } = trpcCrudRouterFromDrizzleEntity('cvCategory')
const { router : entryv2 } = trpcCrudRouterFromDrizzleEntity('cvEntry')
export const CvRouter = router({
category: CategoryRouter,
entry: EntryRouter
category: categoryv2,
entry:entryv2
})

View File

@@ -7,6 +7,9 @@ import { isAdmin } from "~/app/actions";
import z from "zod";
import { StackRouter } from "./techStack";
import { TRPCError, type inferRouterOutputs} from "@trpc/server";
import { trpcCrudRouterFromDrizzleEntity } from "~/server/lib";
const { router : project } = trpcCrudRouterFromDrizzleEntity('project')
const { router : techStack } = trpcCrudRouterFromDrizzleEntity('techStack')
export const ProjectRouter = router({
list: publicProcedure.query(async () => {
return await db.query.project.findMany({
@@ -61,15 +64,10 @@ export const ProjectRouter = router({
)
}
const { input } = opts;
const updateProj = await db.update(project)
return await db.update(project)
.set(input.update)
.returning()
.where(eq(project.id,input.by.id));
if (updateProj[0] !== undefined) {
return updateProj[0]
} else {
return null
}
}),
stack: StackRouter,
})