- Introduced new translations for terms of use in French and English locales. - Added sync status detection logic for books in `BookList` and `BookCard` components. - Refactored `BookCard` to handle additional props and improve layout flexibility. - Enhanced `TermsOfUse` component with complete localization support and refuse functionality. - Updated data decryption logic in Rust services to handle optional fields and additional metadata consistently. - Improved offline/online synchronization workflows with extended context properties.
66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
import React from "react";
|
|
import {isDesktop} from '@/lib/configs';
|
|
import {BookProps} from "@/lib/types/book";
|
|
import DeleteBook from "@/components/book/settings/DeleteBook";
|
|
import SyncBook from "@/components/SyncBook";
|
|
import {SyncType} from "@/context/BooksSyncContext";
|
|
import {useTranslations} from '@/lib/i18n';
|
|
|
|
interface BookCardProps {
|
|
book: BookProps;
|
|
onClickCallback: (bookId: string) => void;
|
|
index: number;
|
|
syncStatus?: SyncType;
|
|
}
|
|
|
|
export default function BookCard({book, onClickCallback, index, syncStatus}: BookCardProps) {
|
|
const t = useTranslations();
|
|
|
|
return (
|
|
<div
|
|
className="group relative aspect-[2/3] rounded-xl overflow-hidden cursor-pointer transition-all duration-300 hover:ring-1 hover:ring-text-primary/20">
|
|
<button onClick={(): void => onClickCallback(book.bookId)} className="w-full h-full text-left block"
|
|
type="button">
|
|
{book.coverImage ? (
|
|
<img
|
|
src={book.coverImage}
|
|
alt={book.title || t("bookCard.noCoverAlt")}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full bg-secondary flex items-center justify-center">
|
|
<span className="text-muted text-5xl font-['ADLaM_Display']">
|
|
{book.title.charAt(0).toUpperCase()}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</button>
|
|
|
|
{isDesktop && syncStatus && (
|
|
<div className="absolute top-2 left-2 cursor-default" onClick={(e: React.MouseEvent): void => e.stopPropagation()}>
|
|
<SyncBook status={syncStatus} bookId={book.bookId}/>
|
|
</div>
|
|
)}
|
|
|
|
<div className="absolute inset-x-0 bottom-0 bg-darkest-background/70 p-3">
|
|
<h3 className="text-text-primary font-bold text-sm truncate">
|
|
{book.title}
|
|
</h3>
|
|
{book.subTitle && (
|
|
<p className="text-text-secondary text-xs truncate mt-0.5">
|
|
{book.subTitle}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div
|
|
className="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200"
|
|
onClick={(e: React.MouseEvent): void => e.stopPropagation()}
|
|
{...(index === 0 && {'data-guide': 'bottom-book-card'})}
|
|
>
|
|
<DeleteBook bookId={book.bookId}/>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|