Add create team page
This commit is contained in:
@@ -31,6 +31,7 @@ import { Sheet, SheetContent, SheetTrigger } from "@unsend/ui/src/sheet";
|
||||
import { NextAuthProvider } from "~/providers/next-auth";
|
||||
import { getServerAuthSession } from "~/server/auth";
|
||||
import { NavButton } from "./nav-button";
|
||||
import { db } from "~/server/db";
|
||||
|
||||
export const metadata = {
|
||||
title: "Unsend",
|
||||
@@ -53,6 +54,16 @@ export default async function AuthenticatedDashboardLayout({
|
||||
redirect("/wait-list");
|
||||
}
|
||||
|
||||
const teamUser = await db.teamUser.findFirst({
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!teamUser) {
|
||||
redirect("/create-team");
|
||||
}
|
||||
|
||||
return (
|
||||
<NextAuthProvider session={session}>
|
||||
<div className="flex min-h-screen w-full h-full">
|
||||
|
92
apps/web/src/app/create-team/page.tsx
Normal file
92
apps/web/src/app/create-team/page.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Button } from "@unsend/ui/src/button";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormMessage,
|
||||
} from "@unsend/ui/src/form";
|
||||
import { Input } from "@unsend/ui/src/input";
|
||||
import { Spinner } from "@unsend/ui/src/spinner";
|
||||
import { api } from "~/trpc/react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
name: z.string().min(2, {
|
||||
message: "Team name must be at least 2 characters.",
|
||||
}),
|
||||
});
|
||||
|
||||
export default function CreateTeam() {
|
||||
const createTeam = api.team.createTeam.useMutation();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
name: "",
|
||||
},
|
||||
});
|
||||
|
||||
function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||
createTeam.mutate(data, {
|
||||
onSuccess: () => {
|
||||
router.replace("/dashboard");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen ">
|
||||
<div className=" w-[300px] flex flex-col gap-8">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold text-center">Create Team</h1>
|
||||
</div>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className=" flex flex-col gap-8 w-full"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field, formState }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Team name"
|
||||
className="w-full"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
{formState.errors.name ? (
|
||||
<FormMessage />
|
||||
) : (
|
||||
<FormDescription>
|
||||
Request admin to join existing team
|
||||
</FormDescription>
|
||||
)}
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" disabled={createTeam.isPending}>
|
||||
{createTeam.isPending ? (
|
||||
<Spinner className="w-5 h-5" />
|
||||
) : (
|
||||
"Create"
|
||||
)}
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,33 +1,16 @@
|
||||
import Link from "next/link";
|
||||
|
||||
import { getServerAuthSession } from "~/server/auth";
|
||||
import { Button } from "@unsend/ui/src/button";
|
||||
import { SendHorizonal } from "lucide-react";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function Home() {
|
||||
const session = await getServerAuthSession();
|
||||
|
||||
return (
|
||||
<main className="h-screen">
|
||||
<h1 className="text-center text-4xl mt-20 flex gap-4 justify-center items-center">
|
||||
<SendHorizonal />
|
||||
Send emails in minutes. Completely open source
|
||||
</h1>
|
||||
<div className="flex justify-center mt-10">
|
||||
{session?.user ? (
|
||||
<Button className="mx-auto">
|
||||
<Link href="/dashboard" className="mx-auto">
|
||||
Send email
|
||||
</Link>
|
||||
</Button>
|
||||
) : (
|
||||
<Button className="mx-auto">
|
||||
<Link href="api/auth/signin" className="mx-auto">
|
||||
Signin
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
if (!session?.user) {
|
||||
redirect("/login");
|
||||
}
|
||||
|
||||
if (!session.user.isBetaUser) {
|
||||
redirect("/wait-list");
|
||||
} else {
|
||||
redirect("/dashboard");
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ import { domainRouter } from "~/server/api/routers/domain";
|
||||
import { createCallerFactory, createTRPCRouter } from "~/server/api/trpc";
|
||||
import { apiRouter } from "./routers/api";
|
||||
import { emailRouter } from "./routers/email";
|
||||
import { teamRouter } from "./routers/team";
|
||||
|
||||
/**
|
||||
* This is the primary router for your server.
|
||||
@@ -12,6 +13,7 @@ export const appRouter = createTRPCRouter({
|
||||
domain: domainRouter,
|
||||
apiKey: apiRouter,
|
||||
email: emailRouter,
|
||||
team: teamRouter,
|
||||
});
|
||||
|
||||
// export type definition of API
|
||||
|
50
apps/web/src/server/api/routers/team.ts
Normal file
50
apps/web/src/server/api/routers/team.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
|
||||
export const teamRouter = createTRPCRouter({
|
||||
createTeam: protectedProcedure
|
||||
.input(z.object({ name: z.string() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const teams = await ctx.db.team.findMany({
|
||||
where: {
|
||||
teamUsers: {
|
||||
some: {
|
||||
userId: ctx.session.user.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (teams) {
|
||||
console.log("User already has a team");
|
||||
return;
|
||||
}
|
||||
|
||||
return ctx.db.team.create({
|
||||
data: {
|
||||
name: input.name,
|
||||
teamUsers: {
|
||||
create: {
|
||||
userId: ctx.session.user.id,
|
||||
role: "ADMIN",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}),
|
||||
|
||||
getTeams: protectedProcedure.query(async ({ ctx }) => {
|
||||
const teams = await ctx.db.team.findMany({
|
||||
where: {
|
||||
teamUsers: {
|
||||
some: {
|
||||
userId: ctx.session.user.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return teams;
|
||||
}),
|
||||
});
|
Reference in New Issue
Block a user