refactor, added slate, added editor, added book

This commit is contained in:
lnn0q 2025-05-28 23:25:46 +03:00
parent bc250e73bb
commit 029b7e9353
33 changed files with 714 additions and 496 deletions

View file

@ -0,0 +1,185 @@
import { gql, useQuery } from '@apollo/client';
import { PaginatedListSkeleton } from '@app/client/components/PaginatedListSkeleton';
import { Pagination } from '@app/client/components/Pagination';
import { WorkingProgressStatusBadge } from '@app/client/components/WorkingProgressStatusBadge';
import { WorkingRatingBadge } from '@app/client/components/WorkingRatingBadge';
import { WorkingReviewsBadge } from '@app/client/components/WorkingReviewsTotalBadge';
import { bookChapterFragment, bookFragment } from '@app/client/fragments';
import { toFormattedDate } from '@app/client/helpers';
import { usePaginatedQuery } from '@app/client/hooks/usePaginatedQuery';
import { BookOne } from '@app/client/interfaces';
import {
Heading,
HStack,
Skeleton,
SkeletonCircle,
SkeletonText,
Stack,
Text
} from '@chakra-ui/react';
import { BookChapterListQuery, BookOverviewQuery } from '@generated/types';
import { createFileRoute, Link } from '@tanstack/react-router';
import { useState } from 'react';
export const Route = createFileRoute('/work/book/$bookId')({
component: RouteComponent
});
function RouteComponent() {
const { bookId: id } = Route.useParams();
const { data: bookData } = useQuery<BookOverviewQuery>(bookQuery, { variables: { id } });
return (
<Stack width="100%" justifyContent="center" alignItems="center" padding={3}>
{bookData != null ? <BookOverview {...bookData.bookOne} /> : <BookOverviewSkeleton />}
</Stack>
);
}
function BookOverview({
id,
title,
description,
author,
progressStatus,
createdAt,
updatedAt,
wordsTotal,
chaptersTotal,
reviewsTotal,
ratingTotal
}: BookOne) {
return (
<Stack width="80%" maxWidth="840px" gap={3}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Heading color="colorPalette.400" size="2xl" overflow="auto">
{title}
</Heading>
</Stack>
<Stack direction="column" gap={1}>
<Stack direction="row">
<Link>
<Text fontWeight="bold">by:</Text>
</Link>
<Link to={`/profile/${author.username}`}>
<Text
color="colorPalette.400"
_hover={{
textDecoration: 'underline',
textDecorationColor: 'colorPalette.700'
}}
>
{author.username}
</Text>
</Link>
</Stack>
<Stack direction="row">
<Text fontWeight="bold">created at:</Text>
<Text>{toFormattedDate({ value: createdAt })}</Text>
</Stack>
<Stack direction="row">
<Text fontWeight="bold">last updated:</Text>
<Text>{toFormattedDate({ value: updatedAt })}</Text>
</Stack>
<Stack direction="row">
<Text fontWeight="bold">chapters:</Text>
<Text>{chaptersTotal}</Text>
</Stack>
<Stack direction="row">
<Text fontWeight="bold">words:</Text>
<Text>{wordsTotal}</Text>
</Stack>
</Stack>
<Stack direction="row" justifyContent="left" alignItems="center">
<WorkingRatingBadge ratingTotal={ratingTotal} />
<WorkingReviewsBadge reviewsTotal={reviewsTotal} />
<WorkingProgressStatusBadge progressStatus={progressStatus} />
</Stack>
<Text>{description}</Text>
<BookChapterList id={id} />
</Stack>
);
}
function BookChapterList({ id }: { readonly id: string }) {
const [chaptersListPage, setChaptersListPage] = useState<number>(1);
const [chaptersListPageSize, setChaptersListPageSize] = useState<number>(10);
const startIndex = (chaptersListPage - 1) * chaptersListPageSize;
const { data } = usePaginatedQuery<BookChapterListQuery>({
query: bookChapterListQuery,
input: {
bookId: id,
filter: {
offset: startIndex,
size: chaptersListPageSize
}
}
});
return (
<Stack>
{data != null ? (
<>
<Stack>...chapters</Stack>
{data.bookChapterMany.total > chaptersListPageSize && (
<Stack justifyContent="center" alignItems="center">
<Pagination
total={data.bookChapterMany.total}
page={chaptersListPage}
setPage={setChaptersListPage}
pageSize={chaptersListPageSize}
setPageSize={setChaptersListPageSize}
/>
</Stack>
)}
</>
) : (
<PaginatedListSkeleton disableSearch />
)}
</Stack>
);
}
function BookOverviewSkeleton() {
return (
<Stack width="80%" maxWidth="840px">
<Stack gap="6" maxWidth="100%">
<HStack width="full">
<SkeletonCircle size="10" />
<SkeletonText noOfLines={5} />
</HStack>
<Skeleton height="200px" />
</Stack>
</Stack>
);
}
const bookQuery = gql`
query BookOverview($id: ID!) {
bookOne(id: $id) {
...Book
}
}
${bookFragment}
`;
const bookChapterListQuery = gql`
query BookChapterList($input: BookChapterManyInput!) {
bookChapterMany(input: $input) {
items {
...BookChapter
}
total
}
}
${bookChapterFragment}
`;