From 07b08ee568a42d27df5bb168e4686e919df0f309 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Thu, 26 Dec 2024 23:39:05 +0100 Subject: [PATCH] Optimize book details modal (#47) --- .../src/components/BookDetailModal.tsx | 200 +++++++++--------- 1 file changed, 103 insertions(+), 97 deletions(-) diff --git a/apps/readest-app/src/components/BookDetailModal.tsx b/apps/readest-app/src/components/BookDetailModal.tsx index 2553534f..a5001d23 100644 --- a/apps/readest-app/src/components/BookDetailModal.tsx +++ b/apps/readest-app/src/components/BookDetailModal.tsx @@ -1,23 +1,24 @@ +import clsx from 'clsx'; import React, { useEffect, useState } from 'react'; - -import { Book } from '@/types/book'; -import { EnvConfigType } from '@/services/environment'; -import { useSettingsStore } from '@/store/settingsStore'; import Image from 'next/image'; +import { Book } from '@/types/book'; +import { useEnv } from '@/context/EnvContext'; +import { useSettingsStore } from '@/store/settingsStore'; +import { useTranslation } from '@/hooks/useTranslation'; +import { formatDate, formatSubject } from '@/utils/book'; import WindowButtons from '@/components/WindowButtons'; +import Spinner from './Spinner'; -const BookDetailModal = ({ - isOpen, - onClose, - book, - envConfig, -}: { +interface BookDetailModalProps { + book: Book; isOpen: boolean; onClose: () => void; - book: Book; - envConfig: EnvConfigType; -}) => { +} + +const BookDetailModal = ({ book, isOpen, onClose }: BookDetailModalProps) => { + const _ = useTranslation(); + const [loading, setLoading] = useState(false); const [bookMeta, setBookMeta] = useState(null); - + const { envConfig } = useEnv(); const { settings } = useSettingsStore(); useEffect(() => { + const loadingTimeout = setTimeout(() => setLoading(true), 300); const fetchBookDetails = async () => { const appService = await envConfig.getAppService(); const details = await appService.fetchBookDetails(book, settings); setBookMeta(details); + setLoading(false); + if (loadingTimeout) clearTimeout(loadingTimeout); }; fetchBookDetails(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [book]); + const handleClose = () => { + setBookMeta(null); + onClose(); + }; + if (!isOpen) return null; if (!bookMeta) return ( -
-
+ loading && ( +
+ +
+ ) + ); -
+ return ( +
+
+
+ +
-

- Loading Book Details... -

-
-
- ); - return ( -
-
- -
-
- -
- -
- {book.coverImageUrl ? ( - {book.title} - ) : ( -
- No Image +
+
+ {book.title} { + (e.target as HTMLImageElement).style.display = 'none'; + (e.target as HTMLImageElement).nextElementSibling?.classList.remove('invisible'); + }} + /> +
+ {book.title} +
- )} -
-

- {bookMeta.title || 'Untitled'} -

-

{book.author || 'Unknown Author'}

- -
-
- -
-
-
- Publisher: -

{bookMeta.publisher || 'Unknown'}

-
-
- Published: -

{bookMeta.published || 'Unknown Date'}

-
-
- Updated: -

- {book.lastUpdated - ? new Date(book.lastUpdated).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) - : 'Unknown Date'} -

+
+
+

+ {bookMeta.title || _('Untitled')} +

+

{book.author || _('Unknown')}

+
+
-
-
- Language: -

{bookMeta.language || 'Unknown'}

+
+
+
+ {_('Publisher:')} +

+ {bookMeta.publisher || _('Unknown')} +

+
+
+ {_('Published:')} +

+ {formatDate(bookMeta.published) || _('Unknown')} +

+
+
+ {_('Updated:')} +

{formatDate(book.lastUpdated) || ''}

+
-
- Identifier: -

- {bookMeta.identifier ? bookMeta.identifier.slice(-8) : 'N/A'} -

{' '} - {/* Show last 8 characters */} -
-
- Subjects: -

{bookMeta.subject?.join(', ') || 'None'}

+ +
+
+ {_('Language:')} +

{bookMeta.language || _('Unknown')}

+
+
+ {_('Identifier:')} +

+ {bookMeta.identifier || 'N/A'} +

+
+
+ {_('Subjects:')} +

+ {formatSubject(bookMeta.subject) || _('Unknown')} +

+