Skip to content

Commit 89d4b56

Browse files
committed
migrate to Next.js app dir
1 parent f716aa9 commit 89d4b56

39 files changed

+1574
-832
lines changed

.babelrc

Lines changed: 0 additions & 6 deletions
This file was deleted.

.env.sample

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
POSTGRES_URL=
2+
POSTGRES_URL_NON_POOLING=
3+
AUTH_GITHUB_ID=
4+
AUTH_GITHUB_SECRET=
5+
AUTH_SECRET=

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ node_modules/
44
.env.local
55
.next
66
.zenstack_repl*
7+
.env

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# A Collaborative Todo Sample - ZenStack + Next.js
22

3-
This project is a collaborative todo app built with [Next.js](https://nextjs.org), [Next-Auth](nextauth.org), and [ZenStack](https://zenstack.dev).
3+
This project is a collaborative todo app built with [Next.js](https://nextjs.org) (app router), [Auth.js](https://authjs.dev/), and [ZenStack](https://zenstack.dev).
4+
5+
> See the [pages-route](https://github.com/zenstackhq/sample-todo-nextjs-tanstack/tree/pages-route) branch for an implementation using Next.js's old pages router.
46
57
In this fictitious app, users can be invited to workspaces where they can collaborate on todos. Public todo lists are visible to all members in the workspace.
68

@@ -24,6 +26,10 @@ See a live deployment at: https://zenstack-todo.vercel.app/.
2426
npm install
2527
```
2628

29+
1. Configure environment variables
30+
31+
Copy the `.env.example` file to `.env` and set the values for your environment. Github related variables can be left empty if you don't need GitHub OAuth login.
32+
2733
1. Generate server and client-side code from model
2834
2935
```bash
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { handlers } from 'server/auth';
2+
export const { GET, POST } = handlers;

app/api/model/[...path]/route.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { enhance } from '@zenstackhq/runtime';
2+
import { NextRequestHandler } from '@zenstackhq/server/next';
3+
import { auth } from 'server/auth';
4+
import { prisma } from 'server/db';
5+
6+
// create an enhanced Prisma client with user context
7+
async function getPrisma() {
8+
const authObj = await auth();
9+
return enhance(prisma, { user: authObj?.user });
10+
}
11+
12+
const handler = NextRequestHandler({ getPrisma, useAppDir: true });
13+
14+
export { handler as DELETE, handler as GET, handler as PATCH, handler as POST, handler as PUT };
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
'use client';
2+
13
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
24
/* eslint-disable @typescript-eslint/no-explicit-any */
3-
import { useCreateSpace } from '@lib/hooks';
45
import { SpaceUserRole } from '@prisma/client';
56
import WithNavBar from 'components/WithNavBar';
7+
import { useCreateSpace } from 'lib/hooks';
68
import { NextPage } from 'next';
79
import { useSession } from 'next-auth/react';
8-
import { useRouter } from 'next/router';
10+
import { useRouter } from 'next/navigation';
911
import { FormEvent, useState } from 'react';
1012
import { toast } from 'react-toastify';
1113

app/layout.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use client';
2+
3+
import 'assets/styles/globals.css';
4+
import { ToastContainer } from 'react-toastify';
5+
import 'react-toastify/dist/ReactToastify.css';
6+
import Providers from './providers';
7+
8+
export default function RootLayout({ children }: { children: React.ReactNode }) {
9+
return (
10+
<html lang="en">
11+
<body>
12+
<Providers>
13+
<div className="h-screen flex flex-col">{children}</div>
14+
</Providers>
15+
<ToastContainer position="top-center" autoClose={2000} hideProgressBar={true} />{' '}
16+
</body>
17+
</html>
18+
);
19+
}

app/page.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use client';
2+
3+
import Spaces from 'components/Spaces';
4+
import WithNavBar from 'components/WithNavBar';
5+
import { useCurrentUser } from 'lib/context';
6+
import { useFindManySpace } from 'lib/hooks';
7+
import Link from 'next/link';
8+
9+
const Home = () => {
10+
const user = useCurrentUser();
11+
const { data: spaces } = useFindManySpace();
12+
13+
if (!spaces || !user) {
14+
return <div>Loading...</div>;
15+
}
16+
17+
return (
18+
<WithNavBar>
19+
<div className="mt-8 text-center flex flex-col items-center w-full">
20+
<h1 className="text-2xl text-gray-800">Welcome {user.name || user.email}!</h1>
21+
22+
<div className="w-full p-8">
23+
<h2 className="text-lg md:text-xl text-left mb-8 text-gray-700">
24+
Choose a space to start, or{' '}
25+
<Link href="/create-space" className="link link-primary">
26+
create a new one.
27+
</Link>
28+
</h2>
29+
<Spaces spaces={spaces} />
30+
</div>
31+
</div>
32+
</WithNavBar>
33+
);
34+
};
35+
36+
export default Home;

app/providers.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use client';
2+
3+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4+
import { SpaceContext, useCurrentSpace, useCurrentUser, UserContext } from 'lib/context';
5+
import { SessionProvider } from 'next-auth/react';
6+
import type { ReactNode } from 'react';
7+
8+
const queryClient = new QueryClient();
9+
10+
function UserSpaceProvider({ children }: { children: ReactNode }) {
11+
const user = useCurrentUser();
12+
const space = useCurrentSpace();
13+
return (
14+
<UserContext.Provider value={user}>
15+
<SpaceContext.Provider value={space}>{children}</SpaceContext.Provider>
16+
</UserContext.Provider>
17+
);
18+
}
19+
20+
export default function Providers({ children }: { children: ReactNode }) {
21+
return (
22+
<QueryClientProvider client={queryClient}>
23+
<SessionProvider>
24+
<UserSpaceProvider>{children}</UserSpaceProvider>
25+
</SessionProvider>
26+
</QueryClientProvider>
27+
);
28+
}

0 commit comments

Comments
 (0)