Skip to content

Commit

Permalink
Izaak/orgs 17 setactive by url (#14)
Browse files Browse the repository at this point in the history
* Using middleware to control the active org via the url

* Renaming and reorganizing

* Minor polish

* Fixing personal workspace navigation highlights

And cleaning up unused code.

* Removing unused sign-in page

* Cleaning up yalc dependencies

* Minor cleanups

* Adding loading state to client-side components.
  • Loading branch information
izaaklauer authored Oct 31, 2024
1 parent d4cd4dd commit 216badf
Show file tree
Hide file tree
Showing 15 changed files with 309 additions and 338 deletions.
2 changes: 2 additions & 0 deletions examples/sync-org-with-url/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

.env.*
79 changes: 38 additions & 41 deletions examples/sync-org-with-url/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion examples/sync-org-with-url/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
"lint": "next lint"
},
"dependencies": {
"@clerk/nextjs": "5.2.9",
"@clerk/backend": "^1.13.9",
"@clerk/clerk-react": "^5.11.0",
"@clerk/nextjs": "^5.7.2",
"@clerk/types": "^4.25.0",
"@radix-ui/react-slot": "^1.1.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
Expand Down
120 changes: 107 additions & 13 deletions examples/sync-org-with-url/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,134 @@
import type { Metadata } from "next";
import { Button } from "@/components/ui/button";
'use client'

import { Inter } from "next/font/google";
import "./globals.css";
import Link from "next/link";
import {
ClerkProvider,
OrganizationSwitcher,
SignInButton,
SignedIn,
SignedOut,
UserButton,
} from "@clerk/nextjs";
import {OrganizationSync} from "@/app/utils/organization-sync";
import { useAuth } from "@clerk/nextjs";
import { usePathname } from 'next/navigation'

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Clerk Orgs: Set Active via URL",
description: "",
};
const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
// <ClerkProvider clerkJSUrl={"https://localhost:4000"}>
<ClerkProvider>
<html lang="en">
<body className={inter.className}>
<main>
{children}
<LayoutContent>
{children}
</LayoutContent>
</main>
</body>
</html>
</ClerkProvider>
);
}

function LayoutContent({ children }: Readonly<{
children: React.ReactNode;
}>) {
const { orgSlug } = useAuth();
const pathname = usePathname()

let prefix = "/me"
if (orgSlug) {
prefix = `/orgs/${orgSlug}`
}

return (
<div>
<div className="grid min-h-screen w-full overflow-hidden lg:grid-cols-[280px_1fr]">
<div className="hidden border-r bg-muted/40 lg:block">
<div className="flex flex-col gap-2">
<div className="flex h-[70px] items-center pl-6">
<OrganizationSwitcher
hidePersonal={false}
hideSlug={false}
afterCreateOrganizationUrl='/orgs/:slug'
afterSelectOrganizationUrl='/orgs/:slug'
afterSelectPersonalUrl='/me'
/>
</div>
<div className="flex-1">
<nav className="grid items-start px-4 text-sm font-medium">
<Link
href={prefix}
className={`flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary ${pathname === urlPrefix(orgSlug) ? 'text-primary' : 'text-muted-foreground'}`}
prefetch={false}
>
Home
</Link>
<Link
href="#"
className={`flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary ${pathname === `${urlPrefix(orgSlug)}/apps` ? 'text-primary' : 'text-muted-foreground'}`}
prefetch={false}
>
Apps{" "}
</Link>
<Link
href="#"
className={`flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary ${pathname === `${urlPrefix(orgSlug)}/activity` ? 'text-primary' : 'text-muted-foreground'}`}
prefetch={false}
>
Activity
</Link>
<Link
href="#"
className={`flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary ${pathname === `${urlPrefix(orgSlug)}/integrations` ? 'text-primary' : 'text-muted-foreground'}`}
prefetch={false}
>
Integrations
</Link>
<Link
href={`${prefix}/settings`}
className={`flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary ${pathname === `${urlPrefix(orgSlug)}/settings` ? 'text-primary' : 'text-muted-foreground'}`}
prefetch={false}
>
Settings
</Link>
</nav>
</div>
</div>
</div>
<div className="flex flex-col">
<header className="flex h-14 lg:h-[60px] items-center gap-4 border-b bg-muted/40 px-6">
<Link href="#" className="lg:hidden" prefetch={false}>
<span className="sr-only">Home</span>
</Link>
<div className="flex-1">
<h1 className="font-semibold text-lg">Dashboard</h1>
</div>
<div className="flex flex-1 items-center gap-4 md:ml-auto md:gap-2 lg:gap-4 fixed right-6">
<UserButton/>
</div>
</header>
<main className="flex flex-1 flex-col gap-4 p-4 md:gap-8 md:p-6">
{children}
</main>
</div>
</div>
</div>
)
}

/**
* Gets the application-global URL prefix for the given organization slug.
* If the organization slug is null or undefined, returns the URL prefix for the personal account, '/me/'
* If the organization slug is defined, returns the URL prefix for the organization, '/orgs/:slug'
*/
function urlPrefix(orgSlug: string | null | undefined): string {
if (orgSlug) {
return `/orgs/${orgSlug}`
}
return "/me"
}
21 changes: 21 additions & 0 deletions examples/sync-org-with-url/src/app/me/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { auth } from '@clerk/nextjs/server';
import {notFound} from "next/navigation";
import {OrganizationProfile} from "@clerk/nextjs";

export default function Home():{} {
const authObject = auth();
const orgId = authObject.orgId

if (orgId != null ) {
console.log("Some org other than the personal account is active!")
notFound()
}

return (
<div className="max-w-md mx-auto my-8 p-6 bg-white rounded-lg shadow-md">
<h2 className="text-2xl font-bold mb-4">
Welcome to your personal account!
</h2>
</div>
)
}
17 changes: 17 additions & 0 deletions examples/sync-org-with-url/src/app/me/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { auth } from '@clerk/nextjs/server';
import {notFound} from "next/navigation";

export default function Home():{} {
const authObject = auth();

if (authObject.orgId != null ) {
console.log("Some org other than the personal account is active!")
notFound();
}

return (
<>
<p className="pb-8">Welcome, user {authObject.userId} to your own personal account settings!</p>
</>
)
}
11 changes: 11 additions & 0 deletions examples/sync-org-with-url/src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Link from 'next/link'

export default function NotFound() {
return (
<div>
<h2>Not Found</h2>
<p>Could not find requested resource</p>
<Link href="/">Return Home</Link>
</div>
)
}
Loading

0 comments on commit 216badf

Please sign in to comment.