Refactor imports, streamline database IPC handlers, and improve offline support
- Replace absolute import paths with relative paths for consistency across files. - Transition database operations in Electron main process to modular handlers in `ipc/book.ipc.ts` using the `createHandler` pattern. - Update database sync service to use `window.electron.invoke()` for improved reliability and structure. - Refactor `AddNewBookForm` to handle both online and offline book creation seamlessly.
This commit is contained in:
@@ -27,7 +27,7 @@ import GuideTour, {GuideStep} from "@/components/GuideTour";
|
||||
import {UserProps} from "@/lib/models/User";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||
// TODO: Refactor to use window.electron.invoke() instead of OfflineDataService
|
||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||
|
||||
interface MinMax {
|
||||
min: number;
|
||||
@@ -39,6 +39,7 @@ export default function AddNewBookForm({setCloseForm}: { setCloseForm: Dispatch<
|
||||
const {lang} = useContext<LangContextProps>(LangContext);
|
||||
const {session, setSession} = useContext(SessionContext);
|
||||
const {errorMessage} = useContext(AlertContext);
|
||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||
const modalRef: React.RefObject<HTMLDivElement | null> = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [title, setTitle] = useState<string>('');
|
||||
@@ -123,7 +124,6 @@ export default function AddNewBookForm({setCloseForm}: { setCloseForm: Dispatch<
|
||||
}
|
||||
setIsAddingBook(true);
|
||||
try {
|
||||
const offlineDataService = getOfflineDataService();
|
||||
const bookData = {
|
||||
title,
|
||||
subTitle: subtitle,
|
||||
@@ -134,12 +134,10 @@ export default function AddNewBookForm({setCloseForm}: { setCloseForm: Dispatch<
|
||||
desiredWordCount: wordCount
|
||||
};
|
||||
|
||||
const bookId: string = await offlineDataService.createBook(
|
||||
bookData,
|
||||
session.user?.id || '',
|
||||
async () => {
|
||||
// Only called if online
|
||||
const id = await System.authPostToServer<string>('book/add', {
|
||||
let bookId: string;
|
||||
if (!isCurrentlyOffline()) {
|
||||
// Online - call API server
|
||||
bookId = await System.authPostToServer<string>('book/add', {
|
||||
title: title,
|
||||
subTitle: subtitle,
|
||||
type: selectedBookType,
|
||||
@@ -148,12 +146,13 @@ export default function AddNewBookForm({setCloseForm}: { setCloseForm: Dispatch<
|
||||
publicationDate: publicationDate,
|
||||
desiredWordCount: wordCount,
|
||||
}, token, lang);
|
||||
if (!id) {
|
||||
if (!bookId) {
|
||||
throw new Error(t('addNewBookForm.error.addingBook'));
|
||||
}
|
||||
return id;
|
||||
} else {
|
||||
// Offline - call local database
|
||||
bookId = await window.electron.invoke<string>('db:book:create', bookData);
|
||||
}
|
||||
);
|
||||
|
||||
const book: BookProps = {
|
||||
bookId: bookId,
|
||||
|
||||
@@ -18,8 +18,7 @@ import fs from "fs";
|
||||
import BookRepo from "../repositories/book.repository.js";
|
||||
import Chapter, {ActChapter, ChapterContentData, ChapterProps} from "./Chapter.js";
|
||||
import UserRepo from "../repositories/user.repository.js";
|
||||
import ChapterRepo from "@/electron/database/repositories/chapter.repository";
|
||||
import {mainStyle} from "@/electron/database/models/EpubStyle";
|
||||
import ChapterRepo from "../repositories/chapter.repository.js";
|
||||
|
||||
export interface BookProps{
|
||||
id:string;
|
||||
|
||||
@@ -8,9 +8,9 @@ import ChapterRepo, {
|
||||
CompanionContentQueryResult,
|
||||
ChapterStoryQueryResult,
|
||||
ContentQueryResult
|
||||
} from "@/electron/database/repositories/chapter.repository";
|
||||
import System from "../System";
|
||||
import {getUserEncryptionKey} from "../keyManager";
|
||||
} from "../repositories/chapter.repository.js";
|
||||
import System from "../System.js";
|
||||
import {getUserEncryptionKey} from "../keyManager.js";
|
||||
import { generateHTML } from "@tiptap/react";
|
||||
|
||||
export interface ChapterContent {
|
||||
|
||||
@@ -2,9 +2,9 @@ import CharacterRepo, {
|
||||
AttributeResult,
|
||||
CharacterResult,
|
||||
CompleteCharacterResult
|
||||
} from "@/electron/database/repositories/character.repository";
|
||||
import System from "@/electron/database/System";
|
||||
import {getUserEncryptionKey} from "../keyManager";
|
||||
} from "../repositories/character.repository.js";
|
||||
import System from "../System.js";
|
||||
import {getUserEncryptionKey} from "../keyManager.js";
|
||||
|
||||
export type CharacterCategory = 'Main' | 'Secondary' | 'Recurring';
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ import LocationRepo, {
|
||||
LocationByTagResult,
|
||||
LocationElementQueryResult,
|
||||
LocationQueryResult
|
||||
} from "@/electron/database/repositories/location.repository";
|
||||
import System from "@/electron/database/System";
|
||||
import {getUserEncryptionKey} from "../keyManager";
|
||||
} from "../repositories/location.repository.js";
|
||||
import System from "../System.js";
|
||||
import {getUserEncryptionKey} from "../keyManager.js";
|
||||
|
||||
export interface SubElement {
|
||||
id: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import UserRepo, {UserAccountQuery, UserInfosQueryResponse} from "@/electron/database/repositories/user.repository";
|
||||
import System from "@/electron/database/System";
|
||||
import Book, {BookProps} from "@/electron/database/models/Book";
|
||||
import {getUserEncryptionKey} from "@/electron/database/keyManager";
|
||||
import UserRepo, {UserAccountQuery, UserInfosQueryResponse} from "../repositories/user.repository.js";
|
||||
import System from "../System.js";
|
||||
import Book, {BookProps} from "./Book.js";
|
||||
import {getUserEncryptionKey} from "../keyManager.js";
|
||||
|
||||
interface UserAccount{
|
||||
firstName:string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Database, QueryResult, RunResult, SQLiteValue} from 'node-sqlite3-wasm';
|
||||
import System from "@/electron/database/System";
|
||||
import System from "../System.js";
|
||||
|
||||
export interface BookQuery extends Record<string, SQLiteValue> {
|
||||
book_id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Database, RunResult, SQLiteValue} from 'node-sqlite3-wasm';
|
||||
import System from "../System";
|
||||
import System from "../System.js";
|
||||
|
||||
export interface ChapterContentQueryResult extends Record<string, SQLiteValue>{
|
||||
chapter_id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Database, RunResult, SQLiteValue} from 'node-sqlite3-wasm';
|
||||
import System from "../System";
|
||||
import System from "../System.js";
|
||||
|
||||
export interface CharacterResult extends Record<string, SQLiteValue> {
|
||||
character_id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Database, RunResult, SQLiteValue} from 'node-sqlite3-wasm';
|
||||
import System from "../System";
|
||||
import System from "../System.js";
|
||||
|
||||
export interface LocationQueryResult extends Record<string, SQLiteValue> {
|
||||
loc_id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Database, RunResult, SQLiteValue} from 'node-sqlite3-wasm';
|
||||
import System from "../System";
|
||||
import System from "../System.js";
|
||||
|
||||
export interface UserInfosQueryResponse extends Record<string, SQLiteValue> {
|
||||
first_name: string;
|
||||
|
||||
188
electron/main.ts
188
electron/main.ts
@@ -222,192 +222,8 @@ ipcMain.handle('db-initialize', (_event, userId: string, encryptionKey: string)
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get all books
|
||||
*/
|
||||
ipcMain.handle('db-get-books', () => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
const books = db.getBooks();
|
||||
return { success: true, data: books };
|
||||
} catch (error) {
|
||||
console.error('Failed to get books:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get single book with all data
|
||||
*/
|
||||
ipcMain.handle('db-get-book', (_event, bookId: string) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
const book = db.getBook(bookId);
|
||||
return { success: true, data: book };
|
||||
} catch (error) {
|
||||
console.error('Failed to get book:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Save book
|
||||
*/
|
||||
ipcMain.handle('db-save-book', (_event, book: any, authorId?: string) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
db.saveBook(book, authorId);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Failed to save book:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Delete book
|
||||
*/
|
||||
ipcMain.handle('db-delete-book', (_event, bookId: string) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
db.deleteBook(bookId);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Failed to delete book:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Save chapter
|
||||
*/
|
||||
ipcMain.handle('db-save-chapter', (_event, chapter: any, bookId: string, contentId?: string) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
db.saveChapter(chapter, bookId, contentId);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Failed to save chapter:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get characters for a book
|
||||
*/
|
||||
ipcMain.handle('db-get-characters', (_event, bookId: string) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
const characters = db.getCharacters(bookId);
|
||||
return { success: true, data: characters };
|
||||
} catch (error) {
|
||||
console.error('Failed to get characters:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Save character
|
||||
*/
|
||||
ipcMain.handle('db-save-character', (_event, character: any, bookId: string) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
db.saveCharacter(character, bookId);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Failed to save character:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get AI conversations for a book
|
||||
*/
|
||||
ipcMain.handle('db-get-conversations', (_event, bookId: string) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
const conversations = db.getConversations(bookId);
|
||||
return { success: true, data: conversations };
|
||||
} catch (error) {
|
||||
console.error('Failed to get conversations:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Save AI conversation
|
||||
*/
|
||||
ipcMain.handle('db-save-conversation', (_event, conversation: any, bookId: string) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
db.saveConversation(conversation, bookId);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Failed to save conversation:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get sync status
|
||||
*/
|
||||
ipcMain.handle('db-get-sync-status', () => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
const status = db.getSyncStatus();
|
||||
return { success: true, data: status };
|
||||
} catch (error) {
|
||||
console.error('Failed to get sync status:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get pending changes
|
||||
*/
|
||||
ipcMain.handle('db-get-pending-changes', (_event, limit: number = 100) => {
|
||||
try {
|
||||
const db = getDatabaseService();
|
||||
const changes = db.getPendingChanges(limit);
|
||||
return { success: true, data: changes };
|
||||
} catch (error) {
|
||||
console.error('Failed to get pending changes:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
});
|
||||
// NOTE: All database IPC handlers have been moved to ./ipc/book.ipc.ts
|
||||
// and use the new createHandler() pattern with auto userId/lang injection
|
||||
|
||||
app.whenReady().then(() => {
|
||||
console.log('App ready, isDev:', isDev);
|
||||
|
||||
@@ -21,11 +21,8 @@ export async function getSyncStatus(): Promise<SyncProgress> {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await window.electron.dbGetSyncStatus();
|
||||
if (!result.success) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
return result.data;
|
||||
const result = await window.electron.invoke<SyncProgress>('db:sync:status');
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Failed to get sync status:', error);
|
||||
return {
|
||||
@@ -46,11 +43,8 @@ export async function getPendingChanges(limit: number = 100) {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await window.electron.dbGetPendingChanges(limit);
|
||||
if (!result.success) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
return result.data || [];
|
||||
const result = await window.electron.invoke<any[]>('db:sync:pending-changes', limit);
|
||||
return result || [];
|
||||
} catch (error) {
|
||||
console.error('Failed to get pending changes:', error);
|
||||
return [];
|
||||
|
||||
Reference in New Issue
Block a user