Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement type-safety for routing system #18

Merged
merged 7 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions app/[org]/[project]/interviews/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { getProjectBySlug } from '~/server/queries/projects';
import { routes } from '~/lib/routes';

export default async function InterviewsPage({
params,
}: {
params: { org: string; project: string };
}) {
const { project: projectSlug } = params;
type InterviewsPageProps = {
// ✅ Never assume the types of your params before validation
params?: unknown;
};

export default async function InterviewsPage({ params }: InterviewsPageProps) {
const { project: projectSlug } =
routes.orgProjectProtocols.$parseParams(params);

const project = await getProjectBySlug(projectSlug);
if (!project) {
Expand Down
37 changes: 29 additions & 8 deletions app/[org]/[project]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
import Link from 'next/link';
import { routes } from '~/lib/routes';

type ProjectLayoutProps = {
children: React.ReactNode;
params: { org: string; project: string };
// ✅ Never assume the types of your params before validation
params?: unknown;
};

const ProjectLayout = ({ children, params }: ProjectLayoutProps) => {
const { org: orgSlug, project: projectSlug } = params;
const { org, project } = routes.orgProject.$parseParams(params);

return (
<>
<div className="flex flex-row space-x-4 border-b p-4 text-lg text-slate-600">
<Link href={`/${orgSlug}/${projectSlug}/participants`}>
Participants
</Link>
<Link href={`/${orgSlug}/${projectSlug}/interviews`}>Interviews</Link>
<Link href={`/${orgSlug}/${projectSlug}/protocols`}>Protocols</Link>
<Link href={`/${orgSlug}/${projectSlug}/settings`}>Settings</Link>
<div>
<Link href={routes.orgProjectParticipants({ org, project })}>
Participants
</Link>{' '}
&#x2794;
</div>
<div>
<Link href={routes.orgProjectInterviews({ org, project })}>
Interviews
</Link>{' '}
&#x2794;
</div>
<div>
<Link href={routes.orgProjectProtocols({ org, project })}>
Protocols
</Link>{' '}
&#x2794;
</div>
<div>
<Link href={routes.orgProjectSettings({ org, project })}>
Settings
</Link>{' '}
&#x2794;
</div>
</div>
{children}
</>
Expand Down
14 changes: 8 additions & 6 deletions app/[org]/[project]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { getProjectBySlug } from '~/server/queries/projects';
import { routes } from '~/lib/routes';

export default async function ProjectPage({
params,
}: {
params: { org: string; project: string };
}) {
const { project: projectSlug } = params;
type ProjectPageProps = {
// ✅ Never assume the types of your params before validation
params?: unknown;
};

export default async function ProjectPage({ params }: ProjectPageProps) {
const { project: projectSlug } = routes.orgProject.$parseParams(params);

const project = await getProjectBySlug(projectSlug);
if (!project) {
Expand Down
13 changes: 9 additions & 4 deletions app/[org]/[project]/participants/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { getProjectBySlug } from '~/server/queries/projects';
import { routes } from '~/lib/routes';

type ParticipantsPageProps = {
// ✅ Never assume the types of your params before validation
params?: unknown;
};

export default async function ParticipantsPage({
params,
}: {
params: { org: string; project: string };
}) {
const { project: projectSlug } = params;
}: ParticipantsPageProps) {
const { project: projectSlug } =
routes.orgProjectProtocols.$parseParams(params);

const project = await getProjectBySlug(projectSlug);
if (!project) {
Expand Down
17 changes: 10 additions & 7 deletions app/[org]/[project]/protocols/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { getProjectBySlug } from '~/server/queries/projects';
import { routes } from '~/lib/routes';

export default async function ProtocolsPage({
params,
}: {
params: { org: string; project: string };
}) {
const { project: projectSlug } = params;
type ProtocolsPageProps = {
// ✅ Never assume the types of your params before validation
params?: unknown;
};

export default async function ProtocolsPage({ params }: ProtocolsPageProps) {
const { project: projectSlug } =
routes.orgProjectProtocols.$parseParams(params);

const project = await getProjectBySlug(projectSlug);
if (!project) {
Expand All @@ -15,7 +18,7 @@ export default async function ProtocolsPage({

return (
<div className="flex flex-col p-12">
<div className="text-4xl">{project.name} Protocols Page </div>
<div className="text-4xl">{project.name} Protocols </div>
<div>slug: {projectSlug}</div>
</div>
);
Expand Down
13 changes: 9 additions & 4 deletions app/[org]/[project]/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { getProjectBySlug } from '~/server/queries/projects';
import { routes } from '~/lib/routes';

type ProjectSettingsPageProps = {
// ✅ Never assume the types of your params before validation
params?: unknown;
};

export default async function ProjectSettingsPage({
params,
}: {
params: { org: string; project: string };
}) {
const { project: projectSlug } = params;
}: ProjectSettingsPageProps) {
const { project: projectSlug } =
routes.orgProjectProtocols.$parseParams(params);

const project = await getProjectBySlug(projectSlug);
if (!project) {
Expand Down
20 changes: 14 additions & 6 deletions app/[org]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
import Link from 'next/link';
import { routes } from '~/lib/routes';

type OrganizationLayoutProps = {
children: React.ReactNode;
params: { org: string };
// ✅ Never assume the types of your params before validation
params?: unknown;
};

const OrganizationLayout = ({ children, params }: OrganizationLayoutProps) => {
const { org: orgSlug } = params;
const { org } = routes.orgDashboard.$parseParams(params);

return (
<main>
<div className="flex flex-row space-x-4 px-4 pt-4 text-lg">
<Link href={`/`}>Studio</Link>
<Link href={`/${orgSlug}`}>Org Dashboard</Link>
<Link href={`/${orgSlug}/settings`}>Org Settings</Link>
<div className="flex flex-row space-x-2 px-4 pt-4 text-lg">
<div>
<Link href={`/`}>Studio</Link> &#x2794;
</div>
<div>
<Link href={routes.orgDashboard({ org })}>Org Dashboard</Link>{' '}
&#x2794;
</div>
<Link href={routes.orgSettings({ org })}>Org Settings</Link>
</div>
{children}
</main>
Expand Down
11 changes: 9 additions & 2 deletions app/[org]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { getProjects } from '~/server/queries/projects';
import CreateProjectForm from '~/app/[org]/_components/CreateProjectForm';
import ProjectCard from './_components/ProjectCard';
import { routes } from '~/lib/routes';

export default async function OrgPage({ params }: { params: { org: string } }) {
const { org } = params;
type OrgPageProps = {
// ✅ Never assume the types of your params before validation
params?: unknown;
};

export default async function OrgPage({ params }: OrgPageProps) {
const { org } = routes.orgDashboard.$parseParams(params);
const allProjects = await getProjects(org);

return (
<div className="flex flex-col p-12">
<h1 className="pb-4 text-4xl">Organization Page</h1>
Expand Down
12 changes: 10 additions & 2 deletions app/[org]/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
export default function Page({ params }: { params: { org: string } }) {
const { org } = params;
import { routes } from '~/lib/routes';

type OrgSettingPageProps = {
// ✅ Never assume the types of your params before validation
params?: unknown;
};

export default function OrgSettingPage({ params }: OrgSettingPageProps) {
const { org } = routes.orgSettings.$parseParams(params);

return (
<div className="flex flex-col p-12">
<div className="text-4xl">Organization Settings Page</div>
Expand Down
6 changes: 5 additions & 1 deletion app/_components/SignOutBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { signout } from '~/server/actions/auth';
import { Button } from '~/components/ui/button';

const SignOutBtn = () => {
return <Button onClick={() => void signout()}>Sign Out</Button>;
return (
<Button className="my-2" onClick={() => void signout()}>
Sign Out
</Button>
);
};

export default SignOutBtn;
15 changes: 10 additions & 5 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@ import { getOrganizations } from '~/server/queries/organizations';
import CreateOrgForm from '~/app/[org]/_components/CreateOrgForm';
import { requirePageAuth } from '~/lib/auth';
import SignOutBtn from './_components/SignOutBtn';
import Link from 'next/link';
import { routes } from '~/lib/routes';

export default async function Home() {
await requirePageAuth();

const allOrgs = await getOrganizations();
return (
<main className="flex flex-col p-12">
<div className="pb-4 text-4xl">Studio MVP</div>
<h1 className="pb-4 text-4xl">Studio MVP</h1>
<CreateOrgForm />
<div>All Organizations</div>
<div className="flex flex-col">
<h2 className="pb-4 text-2xl">All Organizations</h2>
<div className="flex flex-col text-blue-700 underline">
{allOrgs.map((org) => (
<a key={org.public_id} href={`/${org.slug}`}>
<Link
key={org.public_id}
href={routes.orgDashboard({ org: org.slug })}
>
{org.name}
</a>
</Link>
))}
</div>

Expand Down
5 changes: 3 additions & 2 deletions app/signin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import {
} from '~/components/ui/card';
import { validateRequest } from '~/lib/auth';
import SignInForm from './_components/SignInForm';
import { routes } from '~/lib/routes';

export default async function Page() {
const { session, user } = await validateRequest();

if (session && user) {
// If the user is already signed in, redirect to the home page
redirect('/');
redirect(routes.home());
}

return (
Expand All @@ -25,7 +26,7 @@ export default async function Page() {
<CardTitle>Sign in to Studio</CardTitle>
<CardDescription>
Don&apos;t have an account?{' '}
<Link className="text-blue-400 underline" href={'/signup'}>
<Link className="text-blue-400 underline" href={routes.signUp()}>
Sign Up
</Link>
</CardDescription>
Expand Down
5 changes: 3 additions & 2 deletions app/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import {
import SignUpForm from './_components/SignUpForm';
import { validateRequest } from '~/lib/auth';
import { redirect } from 'next/navigation';
import { routes } from '~/lib/routes';

export default async function Page() {
const { session, user } = await validateRequest();

if (session && user) {
// If the user is already signed in, redirect to the home page
redirect('/');
redirect(routes.home());
}

return (
Expand All @@ -25,7 +26,7 @@ export default async function Page() {
<CardTitle>Create an account</CardTitle>
<CardDescription>
Already have an account?{' '}
<Link className="text-blue-400 underline" href={'/signin'}>
<Link className="text-blue-400 underline" href={routes.signIn()}>
Sign In
</Link>
</CardDescription>
Expand Down
3 changes: 2 additions & 1 deletion lib/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
type UserType,
} from '~/lib/db/schema';
import { env } from '~/env';
import { routes } from '../routes';

const adapter = new DrizzlePostgreSQLAdapter(db, sessionTable, userTable);

Expand Down Expand Up @@ -85,7 +86,7 @@ export async function requirePageAuth() {
const { session, user } = await validateRequest();

if (!session || !user) {
redirect('/signin', RedirectType.replace);
redirect(routes.signIn(), RedirectType.replace);
}

return { session, user };
Expand Down
Loading
Loading