Skip to content

Commit

Permalink
Fix trpc, add db relations
Browse files Browse the repository at this point in the history
  • Loading branch information
Lermatroid committed Jul 22, 2024
1 parent bf8f813 commit 7367df7
Show file tree
Hide file tree
Showing 12 changed files with 1,331 additions and 12 deletions.
32 changes: 32 additions & 0 deletions apps/web/src/app/api/trpc/[trpc]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { type NextRequest } from "next/server";

import { env } from "@/env.mjs";
import { appRouter } from "@/server/api/root";
import { createTRPCContext } from "@/server/api/trpc";

/**
* This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
* handling a HTTP request (e.g. when you make requests from Client Components).
*/
const createContext = async (req: NextRequest) => {
return createTRPCContext({
headers: req.headers,
});
};

const handler = (req: NextRequest) =>
fetchRequestHandler({
endpoint: "/api/trpc",
req,
router: appRouter,
createContext: () => createContext(req),
onError:
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`);
}
: undefined,
});

export { handler as GET, handler as POST };
2 changes: 1 addition & 1 deletion apps/web/src/app/dash/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,4 @@ export default async function DashLayout({ children }: DashLayoutProps) {
);
}

export const runtime = "edge";
export const runtime = "edge";
51 changes: 51 additions & 0 deletions apps/web/src/app/dash/tickets/new/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client";
import { useState } from "react";
import { Input } from "@/components/shadcn/ui/input";
import { Label } from "@/components/shadcn/ui/label";
import { Textarea } from "@/components/shadcn/ui/textarea";
import { Button } from "@/components/shadcn/ui/button";
import { api } from "@/trpc/react";
import { toast } from "sonner";

export default function Page() {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");

const createTicket = api.tickets.create.useMutation();

async function runCreateTicket() {
if (title.length > 3 && description.length > 10) {
const result = await createTicket.mutateAsync({ title, description });
if (result.success) {
toast.success("Ticket created successfully!");
console.log(
"created ticket with ID " +
result.ticketID +
" and chat with ID " +
result.chatID
);
}
} else {
toast.error("Your title or description is too short! Please try again.");
}
}

return (
<div className="h-full pt-20">
<div className="mx-auto max-w-3xl">
<h1 className="font-black text-3xl">New Ticket</h1>
<div className="flex items-start flex-col gap-y-5 pt-10">
<div className="w-full">
<Label className="pb-2">Title</Label>
<Input onChange={(e) => setTitle(e.target.value)} />
</div>
<div className="w-full">
<Label className="mb-1">Description</Label>
<Textarea onChange={(e) => setDescription(e.target.value)} />
</div>
<Button onClick={() => runCreateTicket()}>Create Ticket</Button>
</div>
</div>
</div>
);
}
9 changes: 3 additions & 6 deletions apps/web/src/components/dash/tickets/TicketList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,9 @@ export default function TicketList() {

function TicketItem() {
return (
<div className="flex items-center justify-between gap-x-2 p-4 border-b border-b-muted">
<div className="flex items-center gap-x-2">
<div className="h-10 w-10 rounded-full b"></div>
<h1 className="text-lg font-bold">Ticket Name</h1>
</div>
<div className="text-muted-foreground">$100</div>
<div className="border-b border-b-muted h-16 px-5 py-4 flex flex-col justify-center">
<h3 className="font-bold text-sm">Ticket Name</h3>
<p className="text-xs text-muted-foreground">Last Message</p>
</div>
);
}
1 change: 1 addition & 0 deletions apps/web/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const env = createEnv({
AWS_SES_EMAIL_FROM: z.string().min(1),
INTERNAL_AUTH_KEY: z.string().min(64),
BOT_API_URL: z.string().min(1),
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
},
client: {
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/server/api/root.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { postRouter } from "@/server/api/routers/post";
import { ticketsRouter } from "@/server/api/routers/tickets";
import { createCallerFactory, createTRPCRouter } from "@/server/api/trpc";

/**
Expand All @@ -7,7 +7,7 @@ import { createCallerFactory, createTRPCRouter } from "@/server/api/trpc";
* All routers added in /api/routers should be manually added here.
*/
export const appRouter = createTRPCRouter({
post: postRouter,
tickets: ticketsRouter,
});

// export type definition of API
Expand Down
58 changes: 58 additions & 0 deletions apps/web/src/server/api/routers/tickets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { z } from "zod";

import { createTRPCRouter, authedProcedure } from "@/server/api/trpc";
import { chats, tickets } from "db/schema";
import { nanoid } from "nanoid";

export const ticketsRouter = createTRPCRouter({
// hello: publicProcedure.input(z.object({ text: z.string() })).query(({ input }) => {
// return {
// greeting: `Hello ${input.text}`,
// };
// }),
// create: publicProcedure
// .input(z.object({ name: z.string().min(1) }))
// .mutation(async ({ ctx, input }) => {
// // simulate a slow db call
// await new Promise((resolve) => setTimeout(resolve, 1000));
// // await ctx.db.insert(posts).values({
// // name: input.name,
// // });
// }),
// getLatest: publicProcedure.query(({ ctx }) => {
// // return ctx.db.query.posts.findFirst({
// // orderBy: (posts, { desc }) => [desc(posts.createdAt)],
// // });
// return null;
// }),

// TODO: needs error handling
create: authedProcedure
.input(z.object({ title: z.string().min(1), description: z.string().min(1) }))
.mutation(async ({ ctx, input }) => {
const ticketID = nanoid();

const ticket = await ctx.db.insert(tickets).values({
id: ticketID,
title: input.title,
description: input.description,
status: "awaiting",
});

const chatID = nanoid();

const chat = await ctx.db.insert(chats).values({
id: chatID,
type: "ticket",
ticketID: ticketID,
author: ctx.userId,
createdAt: new Date(),
});

return {
success: true,
ticketID: ticketID,
chatID: chatID,
};
}),
});
17 changes: 16 additions & 1 deletion apps/web/src/server/api/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
* TL;DR - This is where all the tRPC server stuff is created and plugged in. The pieces you will
* need to use are documented accordingly near the end.
*/
import { initTRPC } from "@trpc/server";
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";

import { db } from "db";
import { auth } from "@clerk/nextjs";

/**
* 1. CONTEXT
Expand Down Expand Up @@ -83,3 +84,17 @@ export const createTRPCRouter = t.router;
* are logged in.
*/
export const publicProcedure = t.procedure;

// Adds The Clerk ID to the context

export const authedProcedure = t.procedure.use(async (opts) => {
console.log("got here");
const { userId } = await auth();
if (!userId) throw new TRPCError({ code: "UNAUTHORIZED" });

return opts.next({
ctx: {
userId: userId,
},
});
});
36 changes: 36 additions & 0 deletions packages/db/drizzle/0013_tidy_payback.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
CREATE TABLE IF NOT EXISTS "chats_to_users" (
"chat_id" text NOT NULL,
"user_id" text NOT NULL,
CONSTRAINT "chats_to_users_user_id_chat_id_pk" PRIMARY KEY("user_id","chat_id")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "tickets_to_users" (
"ticket_id" text NOT NULL,
"user_id" text NOT NULL,
CONSTRAINT "tickets_to_users_user_id_ticket_id_pk" PRIMARY KEY("user_id","ticket_id")
);
--> statement-breakpoint
ALTER TABLE "chat_messages" RENAME COLUMN "author" TO "author_id";--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "chats_to_users" ADD CONSTRAINT "chats_to_users_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "chats_to_users" ADD CONSTRAINT "chats_to_users_user_id_users_clerk_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("clerk_id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "tickets_to_users" ADD CONSTRAINT "tickets_to_users_ticket_id_tickets_id_fk" FOREIGN KEY ("ticket_id") REFERENCES "public"."tickets"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "tickets_to_users" ADD CONSTRAINT "tickets_to_users_user_id_users_clerk_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("clerk_id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
Loading

0 comments on commit 7367df7

Please sign in to comment.