Files
ERitors-Scribe-Desktop/components/book/BookCard.tsx
natreex bb331b5c22 Add BooksSyncContext, refine database schema, and enhance synchronization support
- Introduce `BooksSyncContext` for managing book synchronization states (server-only, local-only, to-sync, etc.).
- Remove `UserContext` and related dependencies.
- Refine localization strings (`en.json`) with sync-related updates (e.g., "toSyncFromServer", "toSyncToServer").
- Extend database schema with additional tables and fields for syncing books, chapters, and related entities.
- Add `last_update` fields and update corresponding repository methods to support synchronization logic.
- Enhance IPC handlers with stricter typing, data validation, and sync-aware operations.
2025-12-07 14:36:03 -05:00

81 lines
4.5 KiB
TypeScript

// Removed Next.js Link import for Electron
import {BookProps} from "@/lib/models/Book";
import DeleteBook from "@/components/book/settings/DeleteBook";
import ExportBook from "@/components/ExportBook";
import {useTranslations} from "next-intl";
import SyncBook from "@/components/SyncBook";
import {SyncType} from "@/context/BooksSyncContext";
import {useEffect} from "react";
interface BookCardProps {
book: BookProps;
onClickCallback: (bookId: string) => void;
index: number;
syncStatus: SyncType;
}
export default function BookCard({book, onClickCallback, index, syncStatus}: BookCardProps) {
const t = useTranslations();
useEffect(() => {
console.log(syncStatus)
}, [syncStatus]);
return (
<div
className="group bg-tertiary/90 backdrop-blur-sm rounded-2xl shadow-lg hover:shadow-2xl transition-all duration-300 h-full border border-secondary/50 hover:border-primary/50 flex flex-col hover:scale-105">
<div className="relative w-full h-[400px] sm:h-32 md:h-48 lg:h-64 xl:h-80 flex-shrink-0 overflow-hidden">
<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 transition-transform duration-500 group-hover:scale-110"
/>
) : (
<div
className="relative w-full h-full bg-gradient-to-br from-secondary via-secondary to-gray-dark flex items-center justify-center overflow-hidden">
<div className="absolute inset-0 bg-primary/5"></div>
<span
className="relative text-primary/80 text-4xl sm:text-5xl md:text-6xl font-['ADLaM_Display'] tracking-wider">
{book.title.charAt(0).toUpperCase()}{t("bookCard.initialsSeparator")}{book.subTitle ? book.subTitle.charAt(0).toUpperCase() : ''}
</span>
<div
className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-primary/30 to-transparent"></div>
<div
className="absolute bottom-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-primary/30 to-transparent"></div>
</div>
)}
</button>
<div
className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-tertiary via-tertiary/50 to-transparent h-24"></div>
</div>
<div className="p-4 flex-1 flex flex-col justify-between">
<div className="flex-1">
<button onClick={(): void => onClickCallback(book.bookId)} className="w-full text-left" type="button">
<h3 className="text-text-primary text-center font-bold text-base mb-2 truncate group-hover:text-primary transition-colors tracking-wide">
{book.title}
</h3>
</button>
<div className="flex items-center justify-center mb-3 h-5">
{book.subTitle ? (
<>
<div className="h-px w-8 bg-primary/30"></div>
<p className="text-muted text-center mx-2 text-xs italic truncate px-2">
{book.subTitle}
</p>
<div className="h-px w-8 bg-primary/30"></div>
</>
) : null}
</div>
</div>
<div className="flex justify-between items-center pt-3 border-t border-secondary/30">
<SyncBook status={syncStatus} bookId={book.bookId}/>
<div className="flex items-center gap-1" {...index === 0 && {'data-guide': 'bottom-book-card'}}>
<ExportBook bookTitle={book.title} bookId={book.bookId}/>
<DeleteBook bookId={book.bookId}/>
</div>
</div>
</div>
</div>
)
}