93 lines
2.9 KiB
TypeScript
Executable file
93 lines
2.9 KiB
TypeScript
Executable file
import { Comic } from '@prisma/client';
|
|
import type { GetServerSideProps, NextPage } from 'next';
|
|
import Head from 'next/head';
|
|
import { LinkButton } from '../components/Button';
|
|
import CompletionBar from '../components/CompletionBar';
|
|
import { prisma } from '../src/db';
|
|
|
|
interface Props {
|
|
comics: {
|
|
comic: Comic;
|
|
completion: {
|
|
completePages: number;
|
|
totalPages: number;
|
|
};
|
|
}[];
|
|
}
|
|
|
|
const Home: NextPage<Props> = (props) => {
|
|
return (
|
|
<main className='p-4'>
|
|
<Head>
|
|
<title>Comicbox</title>
|
|
</Head>
|
|
|
|
<table className='border-separate border-spacing-x-2'>
|
|
<thead>
|
|
<tr className='text-left'>
|
|
<th>Comic</th>
|
|
<th>Completion</th>
|
|
<th>Links</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{props.comics.map(({ comic, completion }) => {
|
|
return <tr key={comic.id}>
|
|
<td>
|
|
<LinkButton href={`/comic/${comic.slug}`}>
|
|
{comic.title}
|
|
</LinkButton>
|
|
</td>
|
|
<td className='w-96 flex flex-row items-center'>
|
|
<CompletionBar inline total={completion.totalPages} completed={completion.completePages} />
|
|
<span className='whitespace-nowrap pl-2'>
|
|
({completion.completePages}/{completion.totalPages} pages)
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<LinkButton href={comic.url} target='_blank'>
|
|
{new URL(comic.url).host}
|
|
</LinkButton>
|
|
</td>
|
|
</tr>
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</main>
|
|
);
|
|
};
|
|
|
|
export default Home;
|
|
|
|
export const getServerSideProps: GetServerSideProps<Props> = async () => {
|
|
const comics = await prisma.comic.findMany();
|
|
const comicsWithCompletions = await Promise.all(comics.map(async (comic) => {
|
|
const pages = await prisma.comicPage.findMany({
|
|
where: {
|
|
comicId: comic.id,
|
|
},
|
|
select: {
|
|
_count: {
|
|
select: {
|
|
bubbles: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
return {
|
|
comic,
|
|
completion: {
|
|
totalPages: pages.length,
|
|
completePages: pages.filter((page) => page._count.bubbles !== 0)
|
|
.length,
|
|
},
|
|
}
|
|
}));
|
|
|
|
return {
|
|
props: {
|
|
comics: comicsWithCompletions,
|
|
}
|
|
}
|
|
}
|