ln/app/client/pages/work/book/$bookId/overview.tsx
2025-06-01 17:54:57 +03:00

110 lines
3.4 KiB
TypeScript

import { gql, useQuery } from '@apollo/client';
import { WorkingProgressStatusBadge } from '@app/client/components/WorkingProgressStatusBadge';
import { WorkingRatingBadge } from '@app/client/components/WorkingRatingBadge';
import { WorkingReviewsBadge } from '@app/client/components/WorkingReviewsTotalBadge';
import { bookFragment } from '@app/client/fragments';
import { toFormattedDate } from '@app/client/helpers';
import { BookOne } from '@app/client/interfaces';
import { Heading, HStack, Skeleton, SkeletonText, Stack, Text } from '@chakra-ui/react';
import { BookOverviewQuery } from '@generated/types';
import { createFileRoute, Link, Outlet } from '@tanstack/react-router';
export const Route = createFileRoute('/work/book/$bookId/overview')({
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 book={bookData.bookOne} /> : <BookOverviewSkeleton />}
</Stack>
);
}
function BookOverview({ book }: { readonly book: BookOne }) {
return (
<Stack width={{ base: '100%', md: '80%' }} maxWidth="840px" gap={3}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Heading color="colorPalette.400" size="2xl" overflow="auto">
{book.title}
</Heading>
</Stack>
<Stack direction="column" gap={1}>
<Stack direction="row">
<Link>
<Text fontWeight="bold">by:</Text>
</Link>
<Link to={`/profile/${book.author.username}`}>
<Text
color="colorPalette.400"
_hover={{
textDecoration: 'underline',
textDecorationColor: 'colorPalette.700'
}}
>
{book.author.username}
</Text>
</Link>
</Stack>
<Stack direction="row">
<Text fontWeight="bold">created at:</Text>
<Text>{toFormattedDate({ value: book.createdAt })}</Text>
</Stack>
<Stack direction="row">
<Text fontWeight="bold">last updated:</Text>
<Text>{toFormattedDate({ value: book.updatedAt })}</Text>
</Stack>
<Stack direction="row">
<Text fontWeight="bold">chapters:</Text>
<Text>{book.chaptersTotal}</Text>
</Stack>
<Stack direction="row">
<Text fontWeight="bold">words:</Text>
<Text>{book.wordsTotal}</Text>
</Stack>
</Stack>
<Stack direction="row" justifyContent="left" alignItems="center">
<WorkingRatingBadge ratingTotal={book.ratingTotal} />
<WorkingReviewsBadge reviewsTotal={book.reviewsTotal} />
<WorkingProgressStatusBadge progressStatus={book.progressStatus} />
</Stack>
<Text>{book.description}</Text>
<Outlet />
</Stack>
);
}
function BookOverviewSkeleton() {
return (
<Stack width={{ base: '100%', md: '80%' }} maxWidth="840px">
<Stack gap="6" maxWidth="100%">
<HStack width="full">
<SkeletonText noOfLines={5} />
</HStack>
<Skeleton height="200px" />
</Stack>
</Stack>
);
}
export const bookQuery = gql`
query BookOverview($id: ID!) {
bookOne(id: $id) {
...Book
}
}
${bookFragment}
`;