Refactor IPC handlers, types, and models for streamlined data handling

- Unified return types across IPC handlers (`Character`, `Location`, `World`, and `Book`) for consistency.
- Replaced `BookListProps` with `BookProps` for simplified type usage in components and handlers.
- Cleaned up obsolete `BookListProps` interface and applied consistent typings throughout.
- Updated imports to include revised response types (`CharacterListResponse`, `LocationListResponse`, `WorldListResponse`).
- Adjusted data transformation logic in `BookList` and related components to align with new type definitions.
This commit is contained in:
natreex
2026-01-15 16:12:20 -05:00
parent e45a15225b
commit 3d4feaa680
6 changed files with 33 additions and 50 deletions

View File

@@ -9,7 +9,7 @@ import {faGear, faGlobe, faHome} from "@fortawesome/free-solid-svg-icons";
import {SelectBoxProps} from "@/shared/interface";
import {AlertContext} from "@/context/AlertContext";
import {SessionContext} from "@/context/SessionContext";
import Book, {BookListProps} from "@/lib/models/Book";
import Book, {BookProps} from "@/lib/models/Book";
import Modal from "@/components/Modal";
import BookSetting from "@/components/book/settings/BookSetting";
import SelectBox from "@/components/form/SelectBox";
@@ -61,7 +61,7 @@ export default function ScribeControllerBar() {
async function getBook(bookId: string): Promise<void> {
try {
const response: BookListProps = await System.authGetQueryToServer<BookListProps>(`book/basic-information`, session.accessToken, lang, {
const response: BookProps = await System.authGetQueryToServer<BookProps>(`book/basic-information`, session.accessToken, lang, {
id: bookId,
});
if (!response) {
@@ -69,12 +69,12 @@ export default function ScribeControllerBar() {
return;
}
setBook!!({
bookId: response.id,
bookId: response.bookId,
type: response.type,
title: response.title,
subTitle: response.subTitle,
summary: response.summary,
publicationDate: response.desiredReleaseDate,
publicationDate: response.publicationDate,
desiredWordCount: response.desiredWordCount,
totalWordCount: response.desiredWordCount,
quillsenseEnabled: response.quillsenseEnabled,

View File

@@ -6,7 +6,7 @@ import SearchBook from "./SearchBook";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faBook, faDownload, faGear, faTrash} from "@fortawesome/free-solid-svg-icons";
import {SessionContext} from "@/context/SessionContext";
import Book, {BookListProps, BookProps} from "@/lib/models/Book";
import Book, {BookProps} from "@/lib/models/Book";
import BookCard from "@/components/book/BookCard";
import BookCardSkeleton from "@/components/book/BookCardSkeleton";
import GuideTour, {GuideStep} from "@/components/GuideTour";
@@ -139,40 +139,40 @@ export default function BookList() {
async function getBooks(): Promise<void> {
setIsLoadingBooks(true);
try {
let bookResponse: (BookListProps & { itIsLocal: boolean })[] = [];
let bookResponse: (BookProps & { itIsLocal: boolean })[] = [];
if (!isCurrentlyOffline()) {
const [onlineBooks, localBooks]: [BookListProps[], BookListProps[]] = await Promise.all([
System.authGetQueryToServer<BookListProps[]>('books', accessToken, lang),
const [onlineBooks, localBooks]: [BookProps[], BookProps[]] = await Promise.all([
System.authGetQueryToServer<BookProps[]>('books', accessToken, lang),
offlineMode.isDatabaseInitialized
? window.electron.invoke<BookListProps[]>('db:book:books')
? window.electron.invoke<BookProps[]>('db:book:books')
: Promise.resolve([])
]);
const onlineBookIds: Set<string> = new Set(onlineBooks.map((book: BookListProps): string => book.id));
const uniqueLocalBooks: BookListProps[] = localBooks.filter((book: BookListProps): boolean => !onlineBookIds.has(book.id));
const onlineBookIds: Set<string> = new Set(onlineBooks.map((book: BookProps): string => book.bookId));
const uniqueLocalBooks: BookProps[] = localBooks.filter((book: BookProps): boolean => !onlineBookIds.has(book.bookId));
bookResponse = [
...onlineBooks.map((book: BookListProps): BookListProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: false })),
...uniqueLocalBooks.map((book: BookListProps): BookListProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: true }))
...onlineBooks.map((book: BookProps): BookProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: false })),
...uniqueLocalBooks.map((book: BookProps): BookProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: true }))
];
} else {
if (!offlineMode.isDatabaseInitialized) {
setIsLoadingBooks(false);
return;
}
const localBooks: BookListProps[] = await window.electron.invoke<BookListProps[]>('db:book:books');
bookResponse = localBooks.map((book: BookListProps): BookListProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: true }));
const localBooks: BookProps[] = await window.electron.invoke<BookProps[]>('db:book:books');
bookResponse = localBooks.map((book: BookProps): BookProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: true }));
}
if (bookResponse) {
const booksByType: Record<string, BookProps[]> = bookResponse.reduce((groups: Record<string, BookProps[]>, book: BookListProps): Record<string, BookProps[]> => {
const booksByType: Record<string, BookProps[]> = bookResponse.reduce((groups: Record<string, BookProps[]>, book: BookProps): Record<string, BookProps[]> => {
const imageDataUrl: string = book.coverImage ? 'data:image/jpeg;base64,' + book.coverImage : '';
const categoryLabel: string = Book.getBookTypeLabel(book.type);
const transformedBook: BookProps = {
bookId: book.id,
bookId: book.bookId,
type: categoryLabel,
title: book.title,
subTitle: book.subTitle,
summary: book.summary,
serie: book.serieId,
publicationDate: book.desiredReleaseDate,
serie: book.serie,
publicationDate: book.publicationDate,
desiredWordCount: book.desiredWordCount,
totalWordCount: 0,
coverImage: imageDataUrl,
@@ -229,7 +229,7 @@ export default function BookList() {
async function getBook(bookId: string): Promise<void> {
try {
let localBookOnly: boolean = false;
let bookResponse: BookListProps|null = null;
let bookResponse: BookProps|null = null;
if (isCurrentlyOffline()){
if (!offlineMode.isDatabaseInitialized) {
errorMessage(t("bookList.errorBookDetails"));
@@ -246,7 +246,7 @@ export default function BookList() {
localBookOnly = true;
}
if (!bookResponse) {
bookResponse = await System.authGetQueryToServer<BookListProps>(`book/basic-information`, accessToken, lang, {id: bookId});
bookResponse = await System.authGetQueryToServer<BookProps>(`book/basic-information`, accessToken, lang, {id: bookId});
}
}
if (!bookResponse) {
@@ -260,8 +260,8 @@ export default function BookList() {
subTitle: bookResponse?.subTitle || '',
summary: bookResponse?.summary || '',
type: bookResponse?.type || '',
serie: bookResponse?.serieId,
publicationDate: bookResponse?.desiredReleaseDate || '',
serie: bookResponse?.serie,
publicationDate: bookResponse?.publicationDate || '',
desiredWordCount: bookResponse?.desiredWordCount || 0,
totalWordCount: 0,
localBook: localBookOnly,

View File

@@ -12,7 +12,7 @@ import Upload from "../database/models/Upload.js";
import GuideLine, {GuideLineAI} from "../database/models/GuideLine.js";
import Incident from "../database/models/Incident.js";
import PlotPoint from "../database/models/PlotPoint.js";
import World, {WorldProps} from "../database/models/World.js";
import World, {WorldListResponse, WorldProps} from "../database/models/World.js";
interface UpdateBookBasicData {
title: string;
@@ -330,8 +330,8 @@ ipcMain.handle('db:book:issue:remove', createHandler<RemoveIssueData, boolean>(
interface GetWorldsData {
bookid: string;
}
ipcMain.handle('db:book:worlds:get', createHandler<GetWorldsData, WorldProps[]>(
function(userId: string, data: GetWorldsData, lang: 'fr' | 'en') {
ipcMain.handle('db:book:worlds:get', createHandler<GetWorldsData, WorldListResponse>(
function(userId: string, data: GetWorldsData, lang: 'fr' | 'en'): WorldListResponse {
return World.getWorlds(userId, data.bookid, lang);
}
)

View File

@@ -1,7 +1,7 @@
import { ipcMain } from 'electron';
import { createHandler } from '../database/LocalSystem.js';
import Character from '../database/models/Character.js';
import type { CharacterProps, CharacterPropsPost, CharacterAttribute } from '../database/models/Character.js';
import Character, {CharacterListResponse} from '../database/models/Character.js';
import type { CharacterPropsPost, CharacterAttribute } from '../database/models/Character.js';
interface AddCharacterData {
character: CharacterPropsPost;
@@ -20,8 +20,8 @@ interface AddAttributeData {
interface GetCharacterListData {
bookid: string;
}
ipcMain.handle('db:character:list', createHandler<GetCharacterListData, CharacterProps[]>(
function(userId: string, data: GetCharacterListData, lang: 'fr' | 'en'): CharacterProps[] {
ipcMain.handle('db:character:list', createHandler<GetCharacterListData, CharacterListResponse>(
function(userId: string, data: GetCharacterListData, lang: 'fr' | 'en'): CharacterListResponse {
return Character.getCharacterList(userId, data.bookid, lang);
}
)

View File

@@ -1,6 +1,6 @@
import { ipcMain } from 'electron';
import { createHandler } from '../database/LocalSystem.js';
import Location from '../database/models/Location.js';
import Location, {LocationListResponse} from '../database/models/Location.js';
import type { LocationProps } from '../database/models/Location.js';
interface UpdateLocationResponse {
@@ -34,8 +34,8 @@ interface UpdateLocationData {
interface GetAllLocationsData {
bookid: string;
}
ipcMain.handle('db:location:all', createHandler<GetAllLocationsData, LocationProps[]>(
function(userId: string, data: GetAllLocationsData, lang: 'fr' | 'en'): LocationProps[] {
ipcMain.handle('db:location:all', createHandler<GetAllLocationsData, LocationListResponse>(
function(userId: string, data: GetAllLocationsData, lang: 'fr' | 'en'): LocationListResponse {
return Location.getAllLocations(userId, data.bookid, lang);
}
)

View File

@@ -81,23 +81,6 @@ export interface BookProps {
tools?: BookToolsSettings;
}
export interface BookListProps {
id: string;
type: string;
authorId: string;
title: string;
subTitle?: string;
summary?: string;
serieId?: number;
desiredReleaseDate?: string;
desiredWordCount?: number;
wordCount?: number;
coverImage?: string;
bookMeta?: string;
itIsLocal?: boolean;
quillsenseEnabled?: boolean;
}
export interface GuideLine {
tone: string;
atmosphere: string;