- Implemented auto-update logic in `ScribeTopBar` with update notification and user interaction. - Integrated `@tauri-apps/plugin-updater` and `@tauri-apps/plugin-process` for updater functionality. - Added automatic migration feature with `autoMigrateElectron` support and UI feedback. - Refactored app architecture with new routing, components, and layout for better modularity. - Enhanced JSON response handling in API client for robust data parsing. - Updated locales to include new translations for update and migration-related UI.
87 lines
3.9 KiB
TypeScript
87 lines
3.9 KiB
TypeScript
'use client';
|
|
import React, {ReactNode, useContext, useEffect} from 'react';
|
|
import {useParams} from '@/lib/navigation';
|
|
import {BookContext, BookContextProps} from '@/context/BookContext';
|
|
import {SessionContext, SessionContextProps} from '@/context/SessionContext';
|
|
import {LangContext, LangContextProps} from '@/context/LangContext';
|
|
import {AlertContext, AlertContextProps} from '@/context/AlertContext';
|
|
import {apiGet} from '@/lib/api/client';
|
|
import {isDesktop} from '@/lib/configs';
|
|
import * as tauri from '@/lib/tauri';
|
|
import OfflineContext, {OfflineContextType} from '@/context/OfflineContext';
|
|
import {BookProps} from '@/lib/types/book';
|
|
import {useTranslations} from '@/lib/i18n';
|
|
import {BooksSyncContext, BooksSyncContextProps} from '@/context/BooksSyncContext';
|
|
import {SyncedBook} from '@/lib/types/synced-book';
|
|
|
|
export default function BookLayout({children}: { children: ReactNode }) {
|
|
const params: { bookId: string } = useParams<{ bookId: string }>();
|
|
const {book, setBook}: BookContextProps = useContext<BookContextProps>(BookContext);
|
|
const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
|
|
const {lang}: LangContextProps = useContext<LangContextProps>(LangContext);
|
|
const {errorMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
|
|
const {isCurrentlyOffline}: OfflineContextType = useContext<OfflineContextType>(OfflineContext);
|
|
const {localOnlyBooks}: BooksSyncContextProps = useContext<BooksSyncContextProps>(BooksSyncContext);
|
|
const t = useTranslations();
|
|
|
|
useEffect((): void => {
|
|
if (session.accessToken && params.bookId) {
|
|
if (!book || book.bookId !== params.bookId) {
|
|
fetchBook().then();
|
|
}
|
|
}
|
|
}, [params.bookId, session.accessToken]);
|
|
|
|
async function fetchBook(): Promise<void> {
|
|
try {
|
|
let localBookOnly: boolean = false;
|
|
let bookResponse: BookProps | null = null;
|
|
|
|
if (isCurrentlyOffline()) {
|
|
bookResponse = await tauri.getBookBasicInformation(params.bookId);
|
|
if (bookResponse) localBookOnly = true;
|
|
} else {
|
|
const isOfflineBook = localOnlyBooks.find((b: SyncedBook): boolean => b.id === params.bookId);
|
|
if (isOfflineBook) {
|
|
bookResponse = await tauri.getBookBasicInformation(params.bookId);
|
|
localBookOnly = true;
|
|
}
|
|
if (!bookResponse) {
|
|
bookResponse = await apiGet<BookProps>(
|
|
'book/basic-information', session.accessToken, lang, {id: params.bookId}
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!bookResponse) {
|
|
errorMessage(t('controllerBar.bookNotFound'));
|
|
return;
|
|
}
|
|
setBook({
|
|
bookId: bookResponse.bookId,
|
|
type: bookResponse.type,
|
|
title: bookResponse.title,
|
|
subTitle: bookResponse.subTitle,
|
|
summary: bookResponse.summary,
|
|
publicationDate: bookResponse.publicationDate,
|
|
desiredWordCount: bookResponse.desiredWordCount,
|
|
totalWordCount: bookResponse.totalWordCount ?? 0,
|
|
quillsenseEnabled: bookResponse.quillsenseEnabled,
|
|
tools: bookResponse.tools,
|
|
seriesId: bookResponse.seriesId,
|
|
serie: bookResponse.serie,
|
|
coverImage: bookResponse.coverImage ? 'data:image/jpeg;base64,' + bookResponse.coverImage : '',
|
|
localBook: localBookOnly,
|
|
});
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error) {
|
|
errorMessage(e.message);
|
|
} else {
|
|
errorMessage(t('controllerBar.unknownBookError'));
|
|
}
|
|
}
|
|
}
|
|
|
|
return <>{children}</>;
|
|
}
|