Remove CharacterComponent and CharacterDetail components

- Deleted `CharacterComponent` and `CharacterDetail` files from the project.
- Refactored related logic to improve code maintainability and reduce redundancy.
This commit is contained in:
natreex
2026-02-05 14:12:08 -05:00
parent cec5830360
commit 209dc6f85a
133 changed files with 17673 additions and 3110 deletions

View File

@@ -251,10 +251,6 @@ body {
border: none !important;
}
.setting-container {
height: calc(100vh - 10rem);
}
.composer-panel-h {
height: calc(100vh - 8rem);
}

View File

@@ -34,10 +34,32 @@ import OfflineContext, {OfflineMode} from "@/context/OfflineContext";
import OfflinePinSetup from "@/components/offline/OfflinePinSetup";
import OfflinePinVerify from "@/components/offline/OfflinePinVerify";
import {SyncedBook, BookSyncCompare, compareBookSyncs} from "@/lib/models/SyncedBook";
import {SyncedSeries, SeriesSyncCompare, compareSeriesSyncs} from "@/lib/models/SyncedSeries";
import {BooksSyncContext} from "@/context/BooksSyncContext";
import {SeriesSyncContext} from "@/context/SeriesSyncContext";
import useSyncBooks from "@/hooks/useSyncBooks";
import useSyncSeries from "@/hooks/useSyncSeries";
import {LocalSyncQueueContext, LocalSyncOperation} from "@/context/SyncQueueContext";
interface RemovedItemRecord {
removal_id: string;
table_name: string;
entity_id: string;
book_id: string | null;
user_id: string;
deleted_at: number;
}
interface SyncedBooksResponse {
books: SyncedBook[];
tombstones: RemovedItemRecord[];
}
interface SyncedSeriesResponse {
series: SyncedSeries[];
tombstones: RemovedItemRecord[];
}
const messagesMap = {
fr: frMessages,
en: enMessages
@@ -45,22 +67,59 @@ const messagesMap = {
function AutoSyncOnReconnect() {
const {offlineMode} = useContext(OfflineContext);
const {syncAllToServer, refreshBooks, booksToSyncToServer} = useSyncBooks();
const {syncAllToServer: syncAllBooksToServer, refreshBooks, booksToSyncToServer} = useSyncBooks();
const {syncAllToServer: syncAllSeriesToServer, refreshSeries, seriesToSyncToServer} = useSyncSeries();
const [pendingSync, setPendingSync] = useState<boolean>(false);
const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
const saveLastOnlineTimestamp = (): void => {
const timestamp: number = Math.floor(Date.now() / 1000);
localStorage.setItem('lastOnlineTimestamp', timestamp.toString());
};
useEffect((): void => {
if (!offlineMode.isOffline) {
setPendingSync(true);
refreshBooks();
setIsRefreshing(true);
Promise.all([refreshBooks(), refreshSeries()]).then(() => {
setIsRefreshing(false);
});
}
}, [offlineMode.isOffline]);
useEffect((): void => {
if (pendingSync && booksToSyncToServer.length > 0) {
syncAllToServer();
if (pendingSync && !isRefreshing) {
const syncPromises: Promise<void>[] = [];
if (booksToSyncToServer.length > 0) {
syncPromises.push(syncAllBooksToServer());
}
if (seriesToSyncToServer.length > 0) {
syncPromises.push(syncAllSeriesToServer());
}
if (syncPromises.length > 0) {
Promise.all(syncPromises).then(() => {
saveLastOnlineTimestamp();
});
} else {
saveLastOnlineTimestamp();
}
setPendingSync(false);
}
}, [booksToSyncToServer, pendingSync]);
}, [booksToSyncToServer, seriesToSyncToServer, pendingSync, isRefreshing]);
// Update lastOnlineTimestamp every 5 minutes while online
useEffect((): (() => void) | void => {
if (!offlineMode.isOffline) {
const intervalId: NodeJS.Timeout = setInterval((): void => {
saveLastOnlineTimestamp();
}, 5 * 60 * 1000); // 5 minutes
return (): void => clearInterval(intervalId);
}
}, [offlineMode.isOffline]);
return null;
}
@@ -94,6 +153,13 @@ function ScribeContent() {
const [serverOnlyBooks, setServerOnlyBooks] = useState<SyncedBook[]>([]);
const [localOnlyBooks, setLocalOnlyBooks] = useState<SyncedBook[]>([]);
const [serverSyncedSeries, setServerSyncedSeries] = useState<SyncedSeries[]>([]);
const [localSyncedSeries, setLocalSyncedSeries] = useState<SyncedSeries[]>([]);
const [seriesSyncDiffsFromServer, setSeriesSyncDiffsFromServer] = useState<SeriesSyncCompare[]>([]);
const [seriesSyncDiffsToServer, setSeriesSyncDiffsToServer] = useState<SeriesSyncCompare[]>([]);
const [serverOnlySeries, setServerOnlySeries] = useState<SyncedSeries[]>([]);
const [localOnlySeries, setLocalOnlySeries] = useState<SyncedSeries[]>([]);
const [currentCredits, setCurrentCredits] = useState<number>(160);
const [amountSpent, setAmountSpent] = useState<number>(session.user?.aiUsage || 0);
@@ -218,7 +284,8 @@ function ScribeContent() {
useEffect((): void => {
if (session.isConnected) {
getBooks().then()
refreshBooks().then()
refreshSeries().then()
setIsTermsAccepted(session.user?.termsAccepted ?? false);
setHomeStepsGuide(User.guideTourDone(session.user?.guideTour ?? [], 'home-basic'));
setIsLoading(false);
@@ -230,7 +297,7 @@ function ScribeContent() {
if (currentBook) {
getLastChapter().then();
} else {
getBooks().then();
refreshBooks().then();
}
}
}, [currentBook]);
@@ -269,17 +336,58 @@ function ScribeContent() {
setLocalOnlyBooks(localSyncedBooks.filter((localBook: SyncedBook):boolean => !serverSyncedBooks.find((serverBook: SyncedBook):boolean => serverBook.id === localBook.id)))
}, [localSyncedBooks, serverSyncedBooks]);
async function getBooks(): Promise<void> {
useEffect((): void => {
const diffsFromServer: SeriesSyncCompare[] = [];
const diffsToServer: SeriesSyncCompare[] = [];
serverSyncedSeries.forEach((serverSeries: SyncedSeries): void => {
const localSeries: SyncedSeries | undefined = localSyncedSeries.find((series: SyncedSeries): boolean => series.id === serverSeries.id);
if (!localSeries) {
return;
}
const diff: SeriesSyncCompare | null = compareSeriesSyncs(serverSeries, localSeries);
if (diff) {
diffsFromServer.push(diff);
}
});
localSyncedSeries.forEach((localSeries: SyncedSeries): void => {
const serverSeries: SyncedSeries | undefined = serverSyncedSeries.find((series: SyncedSeries): boolean => series.id === localSeries.id);
if (!serverSeries) {
return;
}
const diff: SeriesSyncCompare | null = compareSeriesSyncs(localSeries, serverSeries);
if (diff) {
diffsToServer.push(diff);
}
});
setSeriesSyncDiffsFromServer(diffsFromServer);
setSeriesSyncDiffsToServer(diffsToServer);
setServerOnlySeries(serverSyncedSeries.filter((serverSeries: SyncedSeries): boolean => !localSyncedSeries.find((localSeries: SyncedSeries): boolean => localSeries.id === serverSeries.id)));
setLocalOnlySeries(localSyncedSeries.filter((localSeries: SyncedSeries): boolean => !serverSyncedSeries.find((serverSeries: SyncedSeries): boolean => serverSeries.id === localSeries.id)));
}, [localSyncedSeries, serverSyncedSeries]);
async function refreshBooks(): Promise<void> {
try {
let localBooksResponse: SyncedBook[] = [];
let serverBooksResponse: SyncedBook[] = [];
if (!isCurrentlyOffline()){
if (!isCurrentlyOffline()) {
if (offlineMode.isDatabaseInitialized) {
localBooksResponse = await window.electron.invoke<SyncedBook[]>('db:books:synced');
const lastOnlineStr: string | null = localStorage.getItem('lastOnlineTimestamp');
const lastOnlineTimestamp: number = lastOnlineStr ? parseInt(lastOnlineStr, 10) : 0;
const localTombstones: RemovedItemRecord[] = await window.electron.invoke<RemovedItemRecord[]>('db:tombstones:since', lastOnlineTimestamp);
const serverResponse: SyncedBooksResponse = await System.authPostToServer<SyncedBooksResponse>('books/synced', { lastOnlineTimestamp, tombstones: localTombstones }, session.accessToken, locale);
serverBooksResponse = serverResponse.books;
await window.electron.invoke<void>('db:tombstones:apply:books', serverResponse.tombstones);
} else {
const serverResponse: SyncedBooksResponse = await System.authPostToServer<SyncedBooksResponse>('books/synced', { lastOnlineTimestamp: 0, tombstones: [] }, session.accessToken, locale);
serverBooksResponse = serverResponse.books;
}
serverBooksResponse = await System.authGetQueryToServer<SyncedBook[]>('books/synced', session.accessToken, locale);
} else {
if (offlineMode.isDatabaseInitialized) {
localBooksResponse = await window.electron.invoke<SyncedBook[]>('db:books:synced');
@@ -296,7 +404,43 @@ function ScribeContent() {
}
}
}
async function refreshSeries(): Promise<void> {
try {
let localSeriesResponse: SyncedSeries[] = [];
let serverSeriesResponse: SyncedSeries[] = [];
if (!isCurrentlyOffline()) {
if (offlineMode.isDatabaseInitialized) {
localSeriesResponse = await window.electron.invoke<SyncedSeries[]>('db:series:synced');
const lastOnlineStr: string | null = localStorage.getItem('lastOnlineTimestamp');
const lastOnlineTimestamp: number = lastOnlineStr ? parseInt(lastOnlineStr, 10) : 0;
const localTombstones: RemovedItemRecord[] = await window.electron.invoke<RemovedItemRecord[]>('db:tombstones:since', lastOnlineTimestamp);
const serverResponse: SyncedSeriesResponse = await System.authPostToServer<SyncedSeriesResponse>('series/synced', { lastOnlineTimestamp, tombstones: localTombstones }, session.accessToken, locale);
serverSeriesResponse = serverResponse.series;
await window.electron.invoke<void>('db:tombstones:apply:series', serverResponse.tombstones);
} else {
const serverResponse: SyncedSeriesResponse = await System.authPostToServer<SyncedSeriesResponse>('series/synced', { lastOnlineTimestamp: 0, tombstones: [] }, session.accessToken, locale);
serverSeriesResponse = serverResponse.series;
}
} else {
if (offlineMode.isDatabaseInitialized) {
localSeriesResponse = await window.electron.invoke<SyncedSeries[]>('db:series:synced');
}
}
setServerSyncedSeries(serverSeriesResponse);
setLocalSyncedSeries(localSeriesResponse);
} catch (e: unknown) {
if (e instanceof Error) {
errorMessage(e.message);
} else {
errorMessage(t("homePage.errors.fetchSeriesError"));
}
}
}
useEffect(():void => {
async function checkPinSetup() {
if (session.isConnected && window.electron) {
@@ -601,7 +745,8 @@ function ScribeContent() {
addToQueue: addToLocalSyncQueue,
isProcessing: isQueueProcessing,
}}>
<BooksSyncContext.Provider value={{serverSyncedBooks, localSyncedBooks, booksToSyncFromServer:bookSyncDiffsFromServer, booksToSyncToServer:bookSyncDiffsToServer, setServerSyncedBooks, setLocalSyncedBooks, setServerOnlyBooks, setLocalOnlyBooks, serverOnlyBooks, localOnlyBooks}}>
<BooksSyncContext.Provider value={{serverSyncedBooks, localSyncedBooks, booksToSyncFromServer:bookSyncDiffsFromServer, booksToSyncToServer:bookSyncDiffsToServer, setServerSyncedBooks, setLocalSyncedBooks, setServerOnlyBooks, setLocalOnlyBooks, setBooksToSyncFromServer:setBookSyncDiffsFromServer, setBooksToSyncToServer:setBookSyncDiffsToServer, serverOnlyBooks, localOnlyBooks}}>
<SeriesSyncContext.Provider value={{serverSyncedSeries, localSyncedSeries, seriesToSyncFromServer:seriesSyncDiffsFromServer, seriesToSyncToServer:seriesSyncDiffsToServer, setServerSyncedSeries, setLocalSyncedSeries, setServerOnlySeries, setLocalOnlySeries, setSeriesToSyncFromServer:setSeriesSyncDiffsFromServer, setSeriesToSyncToServer:setSeriesSyncDiffsToServer, serverOnlySeries, localOnlySeries}}>
<AutoSyncOnReconnect/>
<BookContext.Provider value={{book: currentBook, setBook: setCurrentBook}}>
<ChapterContext.Provider value={{chapter: currentChapter, setChapter: setCurrentChapter}}>
@@ -650,6 +795,7 @@ function ScribeContent() {
</AIUsageContext.Provider>
</ChapterContext.Provider>
</BookContext.Provider>
</SeriesSyncContext.Provider>
</BooksSyncContext.Provider>
</LocalSyncQueueContext.Provider>
</SessionContext.Provider>