Skip to content

Commit

Permalink
Merge pull request #40 from hubcio2115/fix/organization-names-in-path…
Browse files Browse the repository at this point in the history
…name

Fix organization names in pathname
  • Loading branch information
hubcio2115 authored Apr 4, 2024
2 parents 740273e + f991a29 commit c5274ce
Show file tree
Hide file tree
Showing 11 changed files with 403 additions and 170 deletions.
1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"db:push": "dotenv drizzle-kit push:pg",
"studio": "dotenv drizzle-kit studio",
"dev": "next dev",
"dev:turbo": "next dev --turbo",
"lint": "next lint",
"start": "next start"
},
Expand Down
10 changes: 9 additions & 1 deletion apps/web/src/app/dashboard/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { redirect } from "next/navigation";
import { type PropsWithChildren } from "react";

import Dashnav from "~/components/dashboard/dashnav";
import Navbar from "~/components/navbar";
import { getServerAuthSession } from "~/server/auth";

export default async function DashboardLayout({ children }: PropsWithChildren) {
const session = await getServerAuthSession();

if (session === null) {
redirect("/");
}

export default function Dashboard({ children }: PropsWithChildren) {
return (
<div className="flex min-h-screen flex-col gap-4">
<div className="flex flex-col items-center justify-between border-b border-slate-200 bg-slate-100 p-2">
Expand Down
13 changes: 11 additions & 2 deletions apps/web/src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
export default function Dashboard() {
return <div></div>;
import { redirect } from "next/navigation";

import { api } from "~/trpc/server";

export const dynamic = "force-dynamic";

export default async function Dashboard() {
const organizations = await api.organization.getOwnOrganizations.query();
const orgNames = organizations.map((org) => org.name!);

redirect(`/dashboard/${orgNames[0]}/overview`);
}
2 changes: 1 addition & 1 deletion apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default async function RootLayout({ children }: PropsWithChildren) {
const session = await getServerAuthSession();

return (
<html lang="en" className={GeistSans.className}>
<html lang="en" className={GeistSans.className} suppressHydrationWarning>
<body>
<TRPCReactProvider headers={headers()}>
<SessionProvider session={session}>
Expand Down
15 changes: 15 additions & 0 deletions apps/web/src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Link from "next/link";

export default function NotFound() {
return (
<div className="flex min-h-screen flex-col items-center justify-center">
<h1 className="text-center text-2xl font-bold">
<span className="text-fuchsia-900">404</span> Not Found :(
</h1>
<p className="text-center">Could not find requested resource</p>
<Link href="/" className="underline">
Return Home
</Link>
</div>
);
}
7 changes: 2 additions & 5 deletions apps/web/src/components/authButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import { signOut } from "next-auth/react";
import { type PropsWithChildren } from "react";

// NOTE: This might not be necessary anymore, it's marked for deletion
export function SignOutButton({ children }: PropsWithChildren) {
return (
<span onClick={() => signOut({ redirect: true, callbackUrl: "/" })}>
{children}
</span>
);
return <span onClick={() => signOut()}>{children}</span>;
}
168 changes: 10 additions & 158 deletions apps/web/src/components/navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,97 +1,27 @@
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { LogOut, Plus } from "lucide-react";
import { useSession } from "next-auth/react";
import { LogOut } from "lucide-react";
import { signOut, useSession } from "next-auth/react";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import { useMemo, useState } from "react";
import {
type SubmitErrorHandler,
type SubmitHandler,
useForm,
} from "react-hook-form";

import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "~/components/ui/select";
import {
type InsertOrganization,
insertOrganizationSchema,
} from "~/lib/validators/organization";
import { api } from "~/trpc/react";
import { usePathname } from "next/navigation";

import { SignOutButton } from "./authButtons";
import OrganizationSelect from "./organization-select";
import Profile from "./profile";
import { Button } from "./ui/button";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from "./ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "./ui/dropdown-menu";
import { Input } from "./ui/input";
import { Label } from "./ui/label";

type OrganizationForm = Omit<InsertOrganization, "owner">;

export default function Navbar() {
const organizationFromPathname = usePathname().split("/").at(2);
const isOnDashboard = usePathname().includes("/dashboard");

const router = useRouter();
const session = useSession();

// FIXME: this tries to fetch the user's organizations even if the user is not authenticated
const { data: organizations } =
api.organization.getOwnOrganizations.useQuery();

const { mutate: createOrganization } =
api.organization.createOrganization.useMutation({
onSuccess: (data) => {
if (!!data) router.push(`/dashboard/${data.name}/overview`);
},
});

const [isModalOpen, setIsModalOpen] = useState(false);

const { register, handleSubmit } = useForm<OrganizationForm>({
resolver: zodResolver(insertOrganizationSchema.omit({ owner: true })),
});

const onSubmit: SubmitHandler<OrganizationForm> = (data) => {
createOrganization({ name: data.name });
setIsModalOpen(false);
};

const onError: SubmitErrorHandler<OrganizationForm> = (error) => {
console.error(error);
};

const selectOrganization = (orgId: string) => {
router.push(`/dashboard/${orgId}/`);
};

const shouldShowOrganizationsSelect = useMemo(
() =>
session.status === "authenticated" &&
organizations?.length !== 0 &&
isOnDashboard,
[session, organizations],
);
const shouldShowOrganizationsSelect =
session.status === "authenticated" && isOnDashboard;

return (
<>
Expand All @@ -102,39 +32,7 @@ export default function Navbar() {
thing
</h1>

{shouldShowOrganizationsSelect && (
<Select
onValueChange={(newValue) => {
selectOrganization(newValue);
}}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder={organizationFromPathname} />
</SelectTrigger>

<SelectContent>
<SelectGroup>
{organizations?.map((org) => (
<SelectItem
value={org.name}
key={org.id}
className="hover:cursor-pointer"
>
{org.name}
</SelectItem>
))}
<div
className="text-slate relative m-auto flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-light text-slate-400 outline-none hover:cursor-pointer focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
onClick={() => {
setIsModalOpen(true);
}}
>
Add new <Plus size={16} />
</div>
</SelectGroup>
</SelectContent>
</Select>
)}
{shouldShowOrganizationsSelect ? <OrganizationSelect /> : null}
</div>

<div>
Expand All @@ -146,36 +44,18 @@ export default function Navbar() {
</DropdownMenuTrigger>

<DropdownMenuContent className="w-[200px]">
{isOnDashboard && (
<DropdownMenuItem
className="hover:cursor-pointer"
onClick={() => {
setIsModalOpen(true);
}}
>
Create Organization
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<DropdownMenuItem>
<DropdownMenuItem onClick={() => signOut()}>
<LogOut
className="mr-2 h-4 w-4 hover:cursor-pointer"
color="red"
/>
{/*TODO: Log Out has some issues on the dashboard page */}
<SignOutButton>Log out</SignOutButton>
<span>Log out</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

{!isOnDashboard && (
<Link
href={
organizations && organizations.length > 0
? `/dashboard/${organizations[0]?.id}/overview`
: "/dashboard/"
}
>
<Link href="/dashboard/">
<Button variant="outline" className="rounded-full">
Go to Dashboard
</Button>
Expand All @@ -189,34 +69,6 @@ export default function Navbar() {
)}
</div>
</div>

<Dialog
open={isModalOpen}
onOpenChange={(open) => {
setIsModalOpen(open);
}}
>
<DialogContent className="sm:max-w-[425px]">
<form
className="flex flex-col gap-4"
onSubmit={handleSubmit(onSubmit, onError)}
>
<DialogHeader>
<DialogTitle>New Organization</DialogTitle>
</DialogHeader>

<div className="mt-4 flex flex-col gap-2">
<Label htmlFor="name">Name</Label>

<Input {...register("name")} id="name" />
</div>

<DialogFooter>
<Button type="submit">Create</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
</>
);
}
Loading

0 comments on commit c5274ce

Please sign in to comment.