Add enable/disable management for book tools (characters, worlds, and locations)
- Introduced toggling functionality for managing `characters`, `worlds`, and `locations` tool availability per book. - Updated `CharacterComponent`, `WorldSetting`, and `LocationComponent` with toggle switches for tool enablement. - Added `book_tools` database table and related schema migration for storing tool settings. - Extended API calls, models, and IPC handlers to support tool enablement states. - Localized new strings for English with supporting descriptions and messages. - Adjusted conditional rendering logic across components to respect tool enablement.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
import {Dispatch, forwardRef, SetStateAction, useContext, useEffect, useImperativeHandle, useState} from 'react';
|
||||
import {Attribute, CharacterProps} from "@/lib/models/Character";
|
||||
import {Attribute, CharacterProps, CharacterListResponse} from "@/lib/models/Character";
|
||||
import {SessionContext} from "@/context/SessionContext";
|
||||
import CharacterList from './CharacterList';
|
||||
import System from '@/lib/models/System';
|
||||
@@ -13,6 +13,7 @@ import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||
import ToggleSwitch from "@/components/form/ToggleSwitch";
|
||||
|
||||
interface CharacterDetailProps {
|
||||
selectedCharacter: CharacterProps | null;
|
||||
@@ -47,17 +48,18 @@ const initialCharacterState: CharacterProps = {
|
||||
motivations: [],
|
||||
};
|
||||
|
||||
export function CharacterComponent(props: any, ref: any) {
|
||||
export function CharacterComponent({showToggle = true}: {showToggle?: boolean}, ref: any) {
|
||||
const t = useTranslations();
|
||||
const {lang} = useContext<LangContextProps>(LangContext)
|
||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||
const {session} = useContext(SessionContext);
|
||||
const {book} = useContext(BookContext);
|
||||
const {book, setBook} = useContext(BookContext);
|
||||
const {errorMessage, successMessage} = useContext(AlertContext);
|
||||
const [characters, setCharacters] = useState<CharacterProps[]>([]);
|
||||
const [selectedCharacter, setSelectedCharacter] = useState<CharacterProps | null>(null);
|
||||
const [toolEnabled, setToolEnabled] = useState<boolean>(book?.tools?.characters ?? false);
|
||||
|
||||
useImperativeHandle(ref, function () {
|
||||
return {
|
||||
@@ -68,23 +70,61 @@ export function CharacterComponent(props: any, ref: any) {
|
||||
useEffect((): void => {
|
||||
getCharacters().then();
|
||||
}, []);
|
||||
|
||||
async function handleToggleTool(enabled: boolean): Promise<void> {
|
||||
try {
|
||||
let response: boolean;
|
||||
if (isCurrentlyOffline() || book?.localBook) {
|
||||
response = await window.electron.invoke<boolean>('db:book:tool:update', {
|
||||
bookId: book?.bookId,
|
||||
toolName: 'characters',
|
||||
enabled: enabled
|
||||
});
|
||||
} else {
|
||||
response = await System.authPatchToServer<boolean>('book/tool-setting', {
|
||||
bookId: book?.bookId,
|
||||
toolName: 'characters',
|
||||
enabled: enabled
|
||||
}, session.accessToken, lang);
|
||||
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||
addToQueue('db:book:tool:update', {
|
||||
bookId: book?.bookId,
|
||||
toolName: 'characters',
|
||||
enabled: enabled
|
||||
});
|
||||
}
|
||||
}
|
||||
if (response && setBook && book) {
|
||||
setToolEnabled(enabled);
|
||||
setBook({...book, tools: {...book.tools, characters: enabled}});
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getCharacters(): Promise<void> {
|
||||
try {
|
||||
let response: CharacterProps[];
|
||||
let response: CharacterListResponse;
|
||||
if (isCurrentlyOffline()) {
|
||||
response = await window.electron.invoke<CharacterProps[]>('db:character:list', {bookid: book?.bookId});
|
||||
response = await window.electron.invoke<CharacterListResponse>('db:character:list', {bookid: book?.bookId});
|
||||
} else {
|
||||
if (book?.localBook) {
|
||||
response = await window.electron.invoke<CharacterProps[]>('db:character:list', {bookid: book?.bookId});
|
||||
response = await window.electron.invoke<CharacterListResponse>('db:character:list', {bookid: book?.bookId});
|
||||
} else {
|
||||
response = await System.authGetQueryToServer<CharacterProps[]>(`character/list`, session.accessToken, lang, {
|
||||
response = await System.authGetQueryToServer<CharacterListResponse>(`character/list`, session.accessToken, lang, {
|
||||
bookid: book?.bookId,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (response) {
|
||||
setCharacters(response);
|
||||
setCharacters(response.characters);
|
||||
setToolEnabled(response.enabled);
|
||||
if (setBook && book) {
|
||||
setBook({...book, tools: {...book.tools, characters: response.enabled}});
|
||||
}
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
@@ -317,21 +357,35 @@ export function CharacterComponent(props: any, ref: any) {
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
{selectedCharacter ? (
|
||||
<CharacterDetail
|
||||
selectedCharacter={selectedCharacter}
|
||||
setSelectedCharacter={setSelectedCharacter}
|
||||
handleAddElement={handleAddElement}
|
||||
handleRemoveElement={handleRemoveElement}
|
||||
handleCharacterChange={handleCharacterChange}
|
||||
handleSaveCharacter={handleSaveCharacter}
|
||||
/>
|
||||
) : (
|
||||
<CharacterList
|
||||
characters={characters}
|
||||
handleAddCharacter={handleAddCharacter}
|
||||
handleCharacterClick={handleCharacterClick}
|
||||
/>
|
||||
{showToggle && (
|
||||
<div className="bg-secondary/20 rounded-xl p-4 shadow-inner border border-secondary/30">
|
||||
<ToggleSwitch
|
||||
enabled={toolEnabled}
|
||||
setEnabled={handleToggleTool}
|
||||
label={t('characterComponent.enableTool')}
|
||||
description={t('characterComponent.enableToolDescription')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{toolEnabled && (
|
||||
<>
|
||||
{selectedCharacter ? (
|
||||
<CharacterDetail
|
||||
selectedCharacter={selectedCharacter}
|
||||
setSelectedCharacter={setSelectedCharacter}
|
||||
handleAddElement={handleAddElement}
|
||||
handleRemoveElement={handleRemoveElement}
|
||||
handleCharacterChange={handleCharacterChange}
|
||||
handleSaveCharacter={handleSaveCharacter}
|
||||
/>
|
||||
) : (
|
||||
<CharacterList
|
||||
characters={characters}
|
||||
handleAddCharacter={handleAddCharacter}
|
||||
handleCharacterClick={handleCharacterClick}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user