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

Convert page router to app router #51

Merged
merged 19 commits into from
Sep 6, 2023
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
26 changes: 26 additions & 0 deletions app/about-us/Content/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use client';
import { Box, Heading, useColorModeValue } from '@/components';
export default function Content() {
const color = useColorModeValue('black', 'gray.600');
return (
<Box color={color}>
<Heading fontWeight={800}>ABOUT US</Heading>
<Box border="1.5px solid" borderColor={color} width="120px" />
<Box
marginY={10}
lineHeight={8}
fontSize="lg"
fontStyle="italic"
fontFamily="sans-serif"
>
{`In today's hyper-connected digital landscape, a super-fast website
is no longer just a luxury.
It is an important necessity.
The need for speed goes beyond user convenience and directly impacts your
website's success, search engine rankings, and ultimately your
bottom line. We'll dive into the compelling reasons why having a
lightning-fast website is a must for your online presence.`}
</Box>
</Box>
);
}
23 changes: 23 additions & 0 deletions app/about-us/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { GeneralLayout, Box, Button } from '@/components';
import Content from './Content';
export default function AboutUsPage() {
return (
<GeneralLayout>
<Box
backgroundImage={`url(/img/bgAboutUs.png)`}
backgroundSize="cover"
backgroundRepeat="no-repeat"
backgroundPosition="center"
width="100%"
height="100%"
>
<Box marginTop={50} marginLeft={10} maxWidth="450px">
<Content />
<Button colorScheme="blue" rounded="50px" size="sm" shadow="dark-lg">
CONTACT NOW
</Button>
</Box>
</Box>
</GeneralLayout>
);
}
9 changes: 9 additions & 0 deletions app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import NextAuth from 'next-auth';
import { authOptions } from '@/utils/auth';

if (!process.env.NEXTAUTH_SECRET) {
throw new Error('NEXTAUTH_SECRET variable is not defined');
}
const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };
66 changes: 66 additions & 0 deletions app/api/pages/[pid]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { prisma } from '@/utils/prisma';
import type { NextApiResponse } from 'next';
import { NextResponse } from 'next/server';

export async function GET(req: Request, res: NextApiResponse) {
const { pathname } = new URL(req.url);
const pathUrl = pathname.split('/');
const pid = pathUrl[pathUrl.length - 1];
try {
const post = await getPostById(pid);
if (!post) {
return NextResponse.json(
{
messsage: 'Post not found',
},
{ status: 404 }
);
}
return NextResponse.json(post);
} catch (error) {
return NextResponse.json({ error }); //res.status(400).json(error);
return NextResponse.json({ message: '404s' });
}
}
export async function PATCH(req: Request, res: NextApiResponse) {
const { pathname } = new URL(req.url);
const pathUrl = pathname.split('/');
const id = pathUrl[pathUrl.length - 1];
const data = await req.json();
try {
const updatePost = await prisma.post.update({
where: {
id,
},
data,
});
if (!updatePost) {
return NextResponse.json({ message: 'Post not found' }); // res.status(404).json({ message: 'Post not found' });
}
return res.status(200).json(updatePost);
} catch (error) {
return NextResponse.json({ message: 'Update Error', error }); // res.status(500).json({ message: 'Update Error', error });
}
}
export async function DELETE(req: Request, res: NextApiResponse) {
const { pathname } = new URL(req.url);
const pathUrl = pathname.split('/');
const id = pathUrl[pathUrl.length - 1];
try {
await prisma.post.delete({
where: {
id,
},
});
return NextResponse.json({ mesagge: 'Post has been deleted' }); //res.status(200).json('Post has been deleted');
} catch (error) {
return NextResponse.json({ message: 'GET Error', error }); // res.status(500).json({ message: 'GET Error', error });
}
}
async function getPostById(id: string) {
return await prisma.post.findUnique({
where: {
id,
},
});
}
52 changes: 52 additions & 0 deletions app/api/pages/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { prisma } from '@/utils/prisma';
import type { Post, Prisma } from '@/types';
import type { NextApiResponse } from 'next';
import { NextResponse } from 'next/server';

export async function GET(
req: Request,
res: NextApiResponse<{ posts: Post[]; count: number } | Post>
) {
const { searchParams } = new URL(req.url);
const pageIndex = Number(searchParams.get('pageIndex') ?? 0);
const take = Number(searchParams.get('take') ?? 25);
try {
const data = await getPosts(pageIndex, take);
return NextResponse.json(data);
} catch (error) {
return NextResponse.json({ message: '404', error });
}
}
export async function POST(
req: Request,
res: NextApiResponse<{ posts: Post[]; count: number } | Post>
) {
const data = await req.json();

try {
const newPost = await prisma.post.create({ data });
return NextResponse.json(newPost); //res.status(200).json(newPost);
} catch (error) {
return NextResponse.json({ message: 'POST error', error }, { status: 400 });
}
}

type OrderByType = {
[field: string]: Prisma.SortOrder;
};
const getPosts = async (
pageIndex: number = 0,
take: number = 25,
orderBy: OrderByType = { createdAt: 'desc' }
) => {
const count = await prisma.post.count();
const posts = await prisma.post.findMany({
skip: pageIndex > 0 ? (pageIndex - 1) * take : pageIndex,
take,
orderBy: orderBy,
});
return {
count,
posts,
};
};
11 changes: 11 additions & 0 deletions app/api/users/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createUser, queryUsers } from '@/services/users';
import { getSession } from '@/utils/auth';
import { withRateLimit } from '@/utils/rateLimit';

export const GET = withRateLimit(async (req, res) => {
const session = await getSession();
return queryUsers(req, res, session);
});
export const POST = withRateLimit(async (req: Request, res) => {
return createUser(req, res);
});
29 changes: 29 additions & 0 deletions app/blog/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { type FC } from 'react';
import { headers } from 'next/headers';
import { GeneralLayout, Box, Heading } from '@/components';
import type { Post } from '@/types';

type PropTypes = {
params: { id: string };
searchParams: { [key: string]: string | string[] | undefined };
};
const fetcher = async (url: string) => await fetch(url).then((r) => r.json());
const PagePost: FC<PropTypes> = async ({ params }) => {
const { id } = params;
const headersList = headers();
const host = headersList.get('host');
const protocol = headersList.get('referer')?.split('://')[0];
const res = await fetch(protocol + '://' + host + '/api/pages/' + id);
if (!res.ok) return <>{new Error(res.statusText)}</>;
const data: Post = await res.json();
return (
<GeneralLayout>
<Heading>{data?.title}</Heading>
<Box fontSize={12} color="gray.500">
{data?.createdAt?.toString()}
</Box>
<Box as="div" dangerouslySetInnerHTML={{ __html: data?.content ?? '' }} />
</GeneralLayout>
);
};
export default PagePost;
23 changes: 13 additions & 10 deletions src/pages/blog/blog-editor.tsx → app/blog/blog-editor/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,24 @@ import {
CardFooter,
} from '@chakra-ui/react';
import slugify from 'slugify';
import { useRouter } from 'next/router';
import { useSWR } from '@/hooks';
import { useRouter, useSearchParams } from 'next/navigation';
import { useSWR, useAuth } from '@/hooks';
import { GeneralLayout, TextEditor } from '@/components';
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons';
import { useAuth } from '@/hooks';
import { Post } from '@prisma/client';
import Login from '../../login/page';
import type { Post } from '@/types';

type RequireInputType = {
[key: string]: string;
};
const fetcher = async (url: string) => await fetch(url).then((r) => r.json());
export default function BlogEditor() {
const toast = useToast();
const { session } = useAuth();
const searchParams = useSearchParams();
const postId = searchParams.get('postId');
const route = useRouter();
const { postId } = route.query;
const toast = useToast();
const { session, isAuthenticated } = useAuth();

const { data } = useSWR<Post>(
'/api/pages/' + postId?.toString() ?? null,
fetcher
Expand All @@ -49,14 +51,14 @@ export default function BlogEditor() {
setContent(data.content);
setPublishedAt(data?.publishedAt ?? null);
}
}, [data?.id]);
}, [data?.id, data?.content, data?.publishedAt, data?.title]);

const handleSave = async () => {
const userID = session?.user.id;
const isOk = requiredInput({ title, content });
if (!isOk) return;
setIsLoading(true);
const { status, statusText } = await fetch('/api/pages/posts', {
const { status, statusText } = await fetch('/api/pages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down Expand Up @@ -157,6 +159,7 @@ export default function BlogEditor() {
});
return pass;
};
if (!isAuthenticated) return <Login />;
return (
<GeneralLayout>
<Heading size="lg" fontWeight={400} pb={2}>
Expand All @@ -165,7 +168,7 @@ export default function BlogEditor() {
<Button
onClick={() => {
resetState();
route.push({ pathname: '/blog/blog-editor' });
route.push('/blog/blog-editor');
}}
size="xs"
variant="outline"
Expand Down
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Providers } from './providers';

export const metadata = {
title: 'Sieu toc website',
description: 'Generated by Sieu toc website',
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
Loading