Enhance security and offline functionality
- Implement stricter security measures in the Electron app, including navigation blocking, URL validation, and external request handling. - Add offline mode handling and UI improvements in components like `ScribeFooterBar` and `AddNewBookForm`. - Refactor `DeleteBook` logic to include offline sync methods. - Improve user feedback for online/offline states and synchronization errors.
This commit is contained in:
@@ -3,12 +3,13 @@ import {EditorContext} from "@/context/EditorContext";
|
||||
import {useContext, useEffect, useState} from "react";
|
||||
import {Editor} from "@tiptap/react";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import {faBook, faChartSimple, faHeart, faSheetPlastic} from "@fortawesome/free-solid-svg-icons";
|
||||
import {faBook, faChartSimple, faHeart, faSheetPlastic, faHardDrive} from "@fortawesome/free-solid-svg-icons";
|
||||
import {SessionContext} from "@/context/SessionContext";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {AlertContext} from "@/context/AlertContext";
|
||||
import {BookContext} from "@/context/BookContext";
|
||||
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||
|
||||
export default function ScribeFooterBar() {
|
||||
const t = useTranslations();
|
||||
@@ -16,6 +17,7 @@ export default function ScribeFooterBar() {
|
||||
const {book} = useContext(BookContext);
|
||||
const editor: Editor | null = useContext(EditorContext).editor;
|
||||
const {errorMessage} = useContext(AlertContext)
|
||||
const {offlineMode} = useContext<OfflineContextType>(OfflineContext)
|
||||
const {serverOnlyBooks,localOnlyBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||
|
||||
const [wordsCount, setWordsCount] = useState<number>(0);
|
||||
@@ -48,6 +50,12 @@ export default function ScribeFooterBar() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log(localOnlyBooks.length > 0 || offlineMode.isOffline);
|
||||
console.log(localOnlyBooks.length);
|
||||
console.log(offlineMode.isOffline);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="px-6 py-3 bg-tertiary/90 backdrop-blur-sm border-t border-secondary/50 text-text-primary flex justify-between items-center shadow-lg">
|
||||
@@ -88,12 +96,20 @@ export default function ScribeFooterBar() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center space-x-3">
|
||||
<div
|
||||
className="flex items-center gap-2 bg-secondary/50 px-4 py-2 rounded-xl border border-secondary shadow-sm">
|
||||
<FontAwesomeIcon icon={faBook} className={'text-primary w-4 h-4'}/>
|
||||
<span className="text-muted text-sm font-medium mr-1">{t('scribeFooterBar.books')}:</span>
|
||||
<span className="text-text-primary font-bold">{(serverOnlyBooks.length+localOnlyBooks.length)}</span>
|
||||
</div>
|
||||
{
|
||||
!offlineMode.isOffline && <div
|
||||
className="flex items-center gap-2 bg-secondary/50 px-4 py-2 rounded-xl border border-secondary shadow-sm">
|
||||
<FontAwesomeIcon icon={faBook} className={'text-primary w-4 h-4'}/>
|
||||
<span className="text-text-primary font-bold">{serverOnlyBooks.length}</span>
|
||||
</div>
|
||||
}
|
||||
{(localOnlyBooks.length > 0 || offlineMode.isOffline) && (
|
||||
<div
|
||||
className="flex items-center gap-2 bg-secondary/50 px-4 py-2 rounded-xl border border-secondary shadow-sm">
|
||||
<FontAwesomeIcon icon={faHardDrive} className={'text-primary w-4 h-4'}/>
|
||||
<span className="text-text-primary font-bold">{localOnlyBooks.length}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -162,6 +162,7 @@ export default function AddNewBookForm({setCloseForm}: { setCloseForm: Dispatch<
|
||||
bookId: bookId,
|
||||
...bookData
|
||||
};
|
||||
console.log(isCurrentlyOffline())
|
||||
if (isCurrentlyOffline()){
|
||||
setLocalOnlyBooks((prevBooks: SyncedBook[]): SyncedBook[] => [...prevBooks, {
|
||||
id: book.bookId,
|
||||
|
||||
@@ -99,6 +99,7 @@ export default function BookList() {
|
||||
session.isConnected,
|
||||
accessToken,
|
||||
offlineMode.isDatabaseInitialized,
|
||||
offlineMode.isOffline,
|
||||
booksToSyncFromServer,
|
||||
booksToSyncToServer,
|
||||
serverOnlyBooks,
|
||||
@@ -350,9 +351,8 @@ export default function BookList() {
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="text-center p-8 max-w-lg">
|
||||
<div
|
||||
className="w-24 h-24 bg-primary/20 text-primary rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg animate-pulse">
|
||||
<FontAwesomeIcon icon={faBook} className={'w-12 h-12'}/>
|
||||
<div className="w-24 h-24 bg-primary/20 text-primary rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg">
|
||||
<FontAwesomeIcon icon={faBook} size={'3x'}/>
|
||||
</div>
|
||||
<h2 className="text-4xl font-['ADLaM_Display'] mb-4 text-text-primary">{t("bookList.welcomeWritingWorkshop")}</h2>
|
||||
<p className="text-muted mb-6 text-lg leading-relaxed">
|
||||
|
||||
@@ -3,7 +3,6 @@ import {faTrash} from "@fortawesome/free-solid-svg-icons";
|
||||
import {useContext, useState} from "react";
|
||||
import System from "@/lib/models/System";
|
||||
import {SessionContext} from "@/context/SessionContext";
|
||||
import {BookProps} from "@/lib/models/Book";
|
||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
|
||||
import AlertBox from "@/components/AlertBox";
|
||||
@@ -43,6 +42,9 @@ export default function DeleteBook({bookId}: DeleteBookProps) {
|
||||
id: bookId,
|
||||
});
|
||||
} else {
|
||||
response = await window.electron.invoke<boolean>('db:book:delete', {
|
||||
id: bookId,
|
||||
});
|
||||
response = await System.authDeleteToServer<boolean>(
|
||||
`book/delete`,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user