Enhance synchronization logic and offline handling
- Refactor components to support conditional offline and online CRUD operations. - Introduce `addToQueue` mechanism for syncing offline changes to the server. - Add `isChapterContentExist` method and related existence checks in repositories. - Consolidate data structures and streamline book, chapter, character, and guideline synchronization workflows. - Encrypt additional character fields and adjust repository inserts for offline data.
This commit is contained in:
93
app/page.tsx
93
app/page.tsx
@@ -35,12 +35,36 @@ import OfflinePinSetup from "@/components/offline/OfflinePinSetup";
|
|||||||
import OfflinePinVerify from "@/components/offline/OfflinePinVerify";
|
import OfflinePinVerify from "@/components/offline/OfflinePinVerify";
|
||||||
import {SyncedBook, BookSyncCompare, compareBookSyncs} from "@/lib/models/SyncedBook";
|
import {SyncedBook, BookSyncCompare, compareBookSyncs} from "@/lib/models/SyncedBook";
|
||||||
import {BooksSyncContext} from "@/context/BooksSyncContext";
|
import {BooksSyncContext} from "@/context/BooksSyncContext";
|
||||||
|
import useSyncBooks from "@/hooks/useSyncBooks";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncOperation} from "@/context/SyncQueueContext";
|
||||||
|
|
||||||
const messagesMap = {
|
const messagesMap = {
|
||||||
fr: frMessages,
|
fr: frMessages,
|
||||||
en: enMessages
|
en: enMessages
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function AutoSyncOnReconnect() {
|
||||||
|
const {offlineMode} = useContext(OfflineContext);
|
||||||
|
const {syncAllToServer, refreshBooks, booksToSyncToServer} = useSyncBooks();
|
||||||
|
const [pendingSync, setPendingSync] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect((): void => {
|
||||||
|
if (!offlineMode.isOffline) {
|
||||||
|
setPendingSync(true);
|
||||||
|
refreshBooks();
|
||||||
|
}
|
||||||
|
}, [offlineMode.isOffline]);
|
||||||
|
|
||||||
|
useEffect((): void => {
|
||||||
|
if (pendingSync && booksToSyncToServer.length > 0) {
|
||||||
|
syncAllToServer();
|
||||||
|
setPendingSync(false);
|
||||||
|
}
|
||||||
|
}, [booksToSyncToServer, pendingSync]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function ScribeContent() {
|
function ScribeContent() {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang: locale} = useContext(LangContext);
|
const {lang: locale} = useContext(LangContext);
|
||||||
@@ -79,7 +103,48 @@ function ScribeContent() {
|
|||||||
const [homeStepsGuide, setHomeStepsGuide] = useState<boolean>(false);
|
const [homeStepsGuide, setHomeStepsGuide] = useState<boolean>(false);
|
||||||
const [showPinSetup, setShowPinSetup] = useState<boolean>(false);
|
const [showPinSetup, setShowPinSetup] = useState<boolean>(false);
|
||||||
const [showPinVerify, setShowPinVerify] = useState<boolean>(false);
|
const [showPinVerify, setShowPinVerify] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const [localSyncQueue, setLocalSyncQueue] = useState<LocalSyncOperation[]>([]);
|
||||||
|
const [isQueueProcessing, setIsQueueProcessing] = useState<boolean>(false);
|
||||||
|
|
||||||
|
|
||||||
|
function addToLocalSyncQueue(channel: string, data: Record<string, unknown>): void {
|
||||||
|
const operation: LocalSyncOperation = {
|
||||||
|
id: `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,
|
||||||
|
channel,
|
||||||
|
data,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
};
|
||||||
|
setLocalSyncQueue((prev: LocalSyncOperation[]): LocalSyncOperation[] => [...prev, operation]);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect((): void => {
|
||||||
|
if (localSyncQueue.length === 0 || isQueueProcessing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processQueue(): Promise<void> {
|
||||||
|
setIsQueueProcessing(true);
|
||||||
|
|
||||||
|
const queueCopy: LocalSyncOperation[] = [...localSyncQueue];
|
||||||
|
|
||||||
|
for (const operation of queueCopy) {
|
||||||
|
try {
|
||||||
|
await window.electron.invoke(operation.channel, operation.data);
|
||||||
|
setLocalSyncQueue((prev: LocalSyncOperation[]): LocalSyncOperation[] =>
|
||||||
|
prev.filter((op: LocalSyncOperation): boolean => op.id !== operation.id)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[LocalSyncQueue] Failed to process operation ${operation.channel}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsQueueProcessing(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
processQueue().then();
|
||||||
|
}, [localSyncQueue, isQueueProcessing]);
|
||||||
|
|
||||||
const homeSteps: GuideStep[] = [
|
const homeSteps: GuideStep[] = [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
@@ -212,6 +277,7 @@ function ScribeContent() {
|
|||||||
console.log('bookSyncDiffsFromServer', bookSyncDiffsFromServer);
|
console.log('bookSyncDiffsFromServer', bookSyncDiffsFromServer);
|
||||||
console.log('bookSyncDiffsToServer', bookSyncDiffsToServer);
|
console.log('bookSyncDiffsToServer', bookSyncDiffsToServer);
|
||||||
}, [localSyncedBooks, serverSyncedBooks,localOnlyBooks, bookSyncDiffsFromServer, bookSyncDiffsToServer]);
|
}, [localSyncedBooks, serverSyncedBooks,localOnlyBooks, bookSyncDiffsFromServer, bookSyncDiffsToServer]);
|
||||||
|
|
||||||
|
|
||||||
async function getBooks(): Promise<void> {
|
async function getBooks(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@@ -313,7 +379,6 @@ function ScribeContent() {
|
|||||||
setHomeStepsGuide(false);
|
setHomeStepsGuide(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Mode offline: stocker dans localStorage
|
|
||||||
const completedGuides = JSON.parse(localStorage.getItem('completedGuides') || '[]');
|
const completedGuides = JSON.parse(localStorage.getItem('completedGuides') || '[]');
|
||||||
if (!completedGuides.includes('home-basic')) {
|
if (!completedGuides.includes('home-basic')) {
|
||||||
completedGuides.push('home-basic');
|
completedGuides.push('home-basic');
|
||||||
@@ -535,10 +600,17 @@ function ScribeContent() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SessionContext.Provider value={{session: session, setSession: setSession}}>
|
<SessionContext.Provider value={{session: session, setSession: setSession}}>
|
||||||
<BooksSyncContext.Provider value={{serverSyncedBooks, localSyncedBooks, booksToSyncFromServer:bookSyncDiffsFromServer, booksToSyncToServer:bookSyncDiffsToServer, setServerOnlyBooks, setLocalOnlyBooks, serverOnlyBooks, localOnlyBooks}}>
|
<LocalSyncQueueContext.Provider value={{
|
||||||
<BookContext.Provider value={{book: currentBook, setBook: setCurrentBook}}>
|
queue: localSyncQueue,
|
||||||
<ChapterContext.Provider value={{chapter: currentChapter, setChapter: setCurrentChapter}}>
|
setQueue: setLocalSyncQueue,
|
||||||
<AIUsageContext.Provider value={{
|
addToQueue: addToLocalSyncQueue,
|
||||||
|
isProcessing: isQueueProcessing,
|
||||||
|
}}>
|
||||||
|
<BooksSyncContext.Provider value={{serverSyncedBooks, localSyncedBooks, booksToSyncFromServer:bookSyncDiffsFromServer, booksToSyncToServer:bookSyncDiffsToServer, setServerSyncedBooks, setLocalSyncedBooks, setServerOnlyBooks, setLocalOnlyBooks, serverOnlyBooks, localOnlyBooks}}>
|
||||||
|
<AutoSyncOnReconnect/>
|
||||||
|
<BookContext.Provider value={{book: currentBook, setBook: setCurrentBook}}>
|
||||||
|
<ChapterContext.Provider value={{chapter: currentChapter, setChapter: setCurrentChapter}}>
|
||||||
|
<AIUsageContext.Provider value={{
|
||||||
totalCredits: currentCredits,
|
totalCredits: currentCredits,
|
||||||
setTotalCredits: setCurrentCredits,
|
setTotalCredits: setCurrentCredits,
|
||||||
totalPrice: amountSpent,
|
totalPrice: amountSpent,
|
||||||
@@ -586,10 +658,11 @@ function ScribeContent() {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</AIUsageContext.Provider>
|
</AIUsageContext.Provider>
|
||||||
</ChapterContext.Provider>
|
</ChapterContext.Provider>
|
||||||
</BookContext.Provider>
|
</BookContext.Provider>
|
||||||
</BooksSyncContext.Provider>
|
</BooksSyncContext.Provider>
|
||||||
|
</LocalSyncQueueContext.Provider>
|
||||||
</SessionContext.Provider>
|
</SessionContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export default function ScribeFooterBar() {
|
|||||||
}, [editor?.state.doc.textContent]);
|
}, [editor?.state.doc.textContent]);
|
||||||
|
|
||||||
function getWordCount(): void {
|
function getWordCount(): void {
|
||||||
console.log(editor)
|
|
||||||
if (editor) {
|
if (editor) {
|
||||||
try {
|
try {
|
||||||
const content: string = editor?.state.doc.textContent;
|
const content: string = editor?.state.doc.textContent;
|
||||||
|
|||||||
@@ -3,13 +3,8 @@ import {faCloud, faCloudArrowDown, faCloudArrowUp, faSpinner} from "@fortawesome
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {useState, useContext} from "react";
|
import {useState, useContext} from "react";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
import System from "@/lib/models/System";
|
import {SyncType} from "@/context/BooksSyncContext";
|
||||||
import {SessionContext, SessionContextProps} from "@/context/SessionContext";
|
import useSyncBooks from "@/hooks/useSyncBooks";
|
||||||
import {LangContext} from "@/context/LangContext";
|
|
||||||
import {CompleteBook} from "@/lib/models/Book";
|
|
||||||
import {BooksSyncContext, BooksSyncContextProps, SyncType} from "@/context/BooksSyncContext";
|
|
||||||
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
|
|
||||||
import {BookSyncCompare, SyncedBook} from "@/lib/models/SyncedBook";
|
|
||||||
|
|
||||||
interface SyncBookProps {
|
interface SyncBookProps {
|
||||||
bookId: string;
|
bookId: string;
|
||||||
@@ -18,148 +13,43 @@ interface SyncBookProps {
|
|||||||
|
|
||||||
export default function SyncBook({bookId, status}: SyncBookProps) {
|
export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {session} = useContext<SessionContextProps>(SessionContext);
|
|
||||||
const {lang} = useContext(LangContext);
|
|
||||||
const {errorMessage} = useContext<AlertContextProps>(AlertContext);
|
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const [currentStatus, setCurrentStatus] = useState<SyncType>(status);
|
const [currentStatus, setCurrentStatus] = useState<SyncType>(status);
|
||||||
const {booksToSyncToServer, booksToSyncFromServer,serverSyncedBooks,localSyncedBooks,setLocalOnlyBooks, setServerOnlyBooks} = useContext<BooksSyncContextProps>(BooksSyncContext)
|
const {upload: hookUpload, download: hookDownload, syncFromServer: hookSyncFromServer, syncToServer: hookSyncToServer} = useSyncBooks();
|
||||||
|
|
||||||
const isOffline: boolean = isCurrentlyOffline();
|
const isOffline: boolean = isCurrentlyOffline();
|
||||||
|
|
||||||
async function upload(): Promise<void> {
|
async function upload(): Promise<void> {
|
||||||
if (isOffline) {
|
if (isOffline) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
const success = await hookUpload(bookId);
|
||||||
const bookToSync: CompleteBook = await window.electron.invoke<CompleteBook>('db:book:uploadToServer', bookId);
|
if (success) setCurrentStatus('synced');
|
||||||
if (!bookToSync) {
|
setIsLoading(false);
|
||||||
errorMessage(t("bookCard.uploadError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response: boolean = await System.authPostToServer('book/sync/upload', {
|
|
||||||
book: bookToSync
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
if (!response) {
|
|
||||||
errorMessage(t("bookCard.uploadError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setCurrentStatus('synced');
|
|
||||||
setLocalOnlyBooks((prevBooks: SyncedBook[]): SyncedBook[] => {
|
|
||||||
return prevBooks.filter((book: SyncedBook): boolean => book.id !== bookId)
|
|
||||||
});
|
|
||||||
} catch (e:unknown) {
|
|
||||||
if (e instanceof Error) {
|
|
||||||
errorMessage(e.message);
|
|
||||||
} else {
|
|
||||||
errorMessage(t("bookCard.uploadError"));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function download(): Promise<void> {
|
async function download(): Promise<void> {
|
||||||
if (isOffline) {
|
if (isOffline) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
const success = await hookDownload(bookId);
|
||||||
const response: CompleteBook = await System.authGetQueryToServer('book/sync/download', session.accessToken, lang, {bookId});
|
if (success) setCurrentStatus('synced');
|
||||||
if (!response) {
|
setIsLoading(false);
|
||||||
errorMessage(t("bookCard.downloadError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const syncStatus:boolean = await window.electron.invoke<boolean>('db:book:syncSave', response);
|
|
||||||
if (!syncStatus) {
|
|
||||||
errorMessage(t("bookCard.downloadError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setCurrentStatus('synced');
|
|
||||||
setServerOnlyBooks((prevBooks: SyncedBook[]): SyncedBook[] => {
|
|
||||||
return prevBooks.filter((book: SyncedBook): boolean => book.id !== bookId)
|
|
||||||
});
|
|
||||||
} catch (e:unknown) {
|
|
||||||
if (e instanceof Error) {
|
|
||||||
errorMessage(e.message);
|
|
||||||
} else {
|
|
||||||
errorMessage(t("bookCard.downloadError"));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncFromServer(): Promise<void> {
|
async function syncFromServer(): Promise<void> {
|
||||||
if (isOffline) {
|
if (isOffline) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
const success = await hookSyncFromServer(bookId);
|
||||||
const bookToFetch:BookSyncCompare|undefined = booksToSyncFromServer.find((book:BookSyncCompare):boolean => book.id === bookId);
|
if (success) setCurrentStatus('synced');
|
||||||
if (!bookToFetch) {
|
setIsLoading(false);
|
||||||
errorMessage(t("bookCard.syncFromServerError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response: CompleteBook = await System.authPostToServer('book/sync/server-to-client', {
|
|
||||||
bookToSync: bookToFetch
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
if (!response) {
|
|
||||||
errorMessage(t("bookCard.syncFromServerError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const syncStatus:boolean = await window.electron.invoke<boolean>('db:book:sync:toClient', response);
|
|
||||||
if (!syncStatus) {
|
|
||||||
errorMessage(t("bookCard.syncFromServerError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setCurrentStatus('synced');
|
|
||||||
} catch (e:unknown) {
|
|
||||||
if (e instanceof Error) {
|
|
||||||
errorMessage(e.message);
|
|
||||||
} else {
|
|
||||||
errorMessage(t("bookCard.syncFromServerError"));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncToServer(): Promise<void> {
|
async function syncToServer(): Promise<void> {
|
||||||
if (isOffline) {
|
if (isOffline) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
const success = await hookSyncToServer(bookId);
|
||||||
const bookToFetch:BookSyncCompare|undefined = booksToSyncToServer.find((book:BookSyncCompare):boolean => book.id === bookId);
|
if (success) setCurrentStatus('synced');
|
||||||
if (!bookToFetch) {
|
setIsLoading(false);
|
||||||
errorMessage(t("bookCard.syncToServerError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const bookToSync: CompleteBook = await window.electron.invoke<CompleteBook>('db:book:sync:toServer', bookToFetch);
|
|
||||||
if (!bookToSync) {
|
|
||||||
errorMessage(t("bookCard.syncToServerError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response: boolean = await System.authPatchToServer('book/sync/client-to-server', {
|
|
||||||
book: bookToSync
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
if (!response) {
|
|
||||||
errorMessage(t("bookCard.syncToServerError"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setCurrentStatus('synced');
|
|
||||||
} catch (e:unknown) {
|
|
||||||
if (e instanceof Error) {
|
|
||||||
errorMessage(e.message);
|
|
||||||
} else {
|
|
||||||
errorMessage(t("bookCard.syncToServerError"));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
|||||||
@@ -138,19 +138,11 @@ export default function AddNewBookForm({setCloseForm}: { setCloseForm: Dispatch<
|
|||||||
};
|
};
|
||||||
|
|
||||||
let bookId: string;
|
let bookId: string;
|
||||||
if (!isCurrentlyOffline()) {
|
if (isCurrentlyOffline()) {
|
||||||
// Online - call API server
|
|
||||||
bookId = await System.authPostToServer<string>('book/add', {
|
|
||||||
title: title,
|
|
||||||
subTitle: subtitle,
|
|
||||||
type: selectedBookType,
|
|
||||||
summary: summary,
|
|
||||||
serie: 0,
|
|
||||||
publicationDate: publicationDate,
|
|
||||||
desiredWordCount: wordCount,
|
|
||||||
}, token, lang);
|
|
||||||
} else {
|
|
||||||
bookId = await window.electron.invoke<string>('db:book:create', bookData);
|
bookId = await window.electron.invoke<string>('db:book:create', bookData);
|
||||||
|
} else {
|
||||||
|
// Online - call API server
|
||||||
|
bookId = await System.authPostToServer<string>('book/add', bookData, token, lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bookId) {
|
if (!bookId) {
|
||||||
|
|||||||
@@ -17,11 +17,16 @@ import {useTranslations} from "next-intl";
|
|||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import {BookProps} from "@/lib/models/Book";
|
import {BookProps} from "@/lib/models/Book";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
function BasicInformationSetting(props: any, ref: any) {
|
function BasicInformationSetting(props: any, ref: any) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext<LangContextProps>(LangContext)
|
const {lang} = useContext<LangContextProps>(LangContext)
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
|
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {book, setBook} = useContext(BookContext);
|
const {book, setBook} = useContext(BookContext);
|
||||||
@@ -117,34 +122,21 @@ function BasicInformationSetting(props: any, ref: any) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
const basicInfoData = {
|
||||||
response = await window.electron.invoke<boolean>('db:book:updateBasicInformation', {
|
title: title,
|
||||||
title: title,
|
subTitle: subTitle,
|
||||||
subTitle: subTitle,
|
summary: summary,
|
||||||
summary: summary,
|
publicationDate: publicationDate,
|
||||||
publicationDate: publicationDate,
|
wordCount: wordCount,
|
||||||
wordCount: wordCount,
|
bookId: bookId
|
||||||
bookId: bookId
|
};
|
||||||
});
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
|
response = await window.electron.invoke<boolean>('db:book:updateBasicInformation', basicInfoData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authPostToServer<boolean>('book/basic-information', basicInfoData, userToken, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:book:updateBasicInformation', {
|
|
||||||
title: title,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
subTitle: subTitle,
|
addToQueue('db:book:updateBasicInformation', basicInfoData);
|
||||||
summary: summary,
|
|
||||||
publicationDate: publicationDate,
|
|
||||||
wordCount: wordCount,
|
|
||||||
bookId: bookId
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
response = await System.authPostToServer<boolean>('book/basic-information', {
|
|
||||||
title: title,
|
|
||||||
subTitle: subTitle,
|
|
||||||
summary: summary,
|
|
||||||
publicationDate: publicationDate,
|
|
||||||
wordCount: wordCount,
|
|
||||||
bookId: bookId
|
|
||||||
}, userToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {LangContext, LangContextProps} from "@/context/LangContext";
|
|||||||
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
|
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
|
||||||
import AlertBox from "@/components/AlertBox";
|
import AlertBox from "@/components/AlertBox";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
import {BookContext} from "@/context/BookContext";
|
|
||||||
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
import {SyncedBook} from "@/lib/models/SyncedBook";
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
@@ -19,7 +18,6 @@ export default function DeleteBook({bookId}: DeleteBookProps) {
|
|||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {lang} = useContext<LangContextProps>(LangContext)
|
const {lang} = useContext<LangContextProps>(LangContext)
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
const {book} = useContext(BookContext);
|
|
||||||
const [showConfirmBox, setShowConfirmBox] = useState<boolean>(false);
|
const [showConfirmBox, setShowConfirmBox] = useState<boolean>(false);
|
||||||
const {errorMessage} = useContext<AlertContextProps>(AlertContext)
|
const {errorMessage} = useContext<AlertContextProps>(AlertContext)
|
||||||
const {serverOnlyBooks,setServerOnlyBooks,localOnlyBooks,setLocalOnlyBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
const {serverOnlyBooks,setServerOnlyBooks,localOnlyBooks,setLocalOnlyBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
@@ -31,38 +29,26 @@ export default function DeleteBook({bookId}: DeleteBookProps) {
|
|||||||
async function handleDeleteBook(): Promise<void> {
|
async function handleDeleteBook(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
const deleteData = { id: bookId };
|
||||||
response = await window.electron.invoke<boolean>('db:book:delete', {
|
const ifLocalBook: SyncedBook | undefined = localOnlyBooks.find((book: SyncedBook): boolean => book.id === bookId);
|
||||||
id: bookId,
|
|
||||||
});
|
if (isCurrentlyOffline() || ifLocalBook) {
|
||||||
|
response = await window.electron.invoke<boolean>('db:book:delete', deleteData);
|
||||||
} else {
|
} else {
|
||||||
const ifLocalBook:SyncedBook|undefined = localOnlyBooks.find((book: SyncedBook):boolean => book.id === bookId);
|
response = await System.authDeleteToServer<boolean>(
|
||||||
if (ifLocalBook) {
|
`book/delete`,
|
||||||
response = await window.electron.invoke<boolean>('db:book:delete', {
|
deleteData,
|
||||||
id: bookId,
|
session.accessToken,
|
||||||
});
|
lang
|
||||||
} else {
|
);
|
||||||
response = await window.electron.invoke<boolean>('db:book:delete', {
|
|
||||||
id: bookId,
|
|
||||||
});
|
|
||||||
response = await System.authDeleteToServer<boolean>(
|
|
||||||
`book/delete`,
|
|
||||||
{
|
|
||||||
id: bookId,
|
|
||||||
},
|
|
||||||
session.accessToken,
|
|
||||||
lang
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (response) {
|
if (response) {
|
||||||
setShowConfirmBox(false);
|
setShowConfirmBox(false);
|
||||||
if (book?.localBook){
|
if (ifLocalBook) {
|
||||||
setLocalOnlyBooks(localOnlyBooks.filter((book:SyncedBook):boolean => book.id !== bookId));
|
setLocalOnlyBooks(localOnlyBooks.filter((b: SyncedBook): boolean => b.id !== bookId));
|
||||||
return;
|
} else {
|
||||||
|
setServerOnlyBooks(serverOnlyBooks.filter((b: SyncedBook): boolean => b.id !== bookId));
|
||||||
}
|
}
|
||||||
setServerOnlyBooks(serverOnlyBooks.filter((book:SyncedBook):boolean => book.id !== bookId));
|
|
||||||
setShowConfirmBox(false);
|
|
||||||
}
|
}
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import CharacterDetail from "@/components/book/settings/characters/CharacterDeta
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
interface CharacterDetailProps {
|
interface CharacterDetailProps {
|
||||||
selectedCharacter: CharacterProps | null;
|
selectedCharacter: CharacterProps | null;
|
||||||
@@ -48,6 +51,8 @@ export function CharacterComponent(props: any, ref: any) {
|
|||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext<LangContextProps>(LangContext)
|
const {lang} = useContext<LangContextProps>(LangContext)
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
const {errorMessage, successMessage} = useContext(AlertContext);
|
const {errorMessage, successMessage} = useContext(AlertContext);
|
||||||
@@ -120,22 +125,23 @@ export function CharacterComponent(props: any, ref: any) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let characterId: string;
|
let characterId: string;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
characterId = await window.electron.invoke<string>('db:character:create', {
|
characterId = await window.electron.invoke<string>('db:character:create', {
|
||||||
bookId: book?.bookId,
|
bookId: book?.bookId,
|
||||||
character: updatedCharacter,
|
character: updatedCharacter,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
characterId = await System.authPostToServer<string>(`character/add`, {
|
||||||
characterId = await window.electron.invoke<string>('db:character:create', {
|
bookId: book?.bookId,
|
||||||
|
character: updatedCharacter,
|
||||||
|
}, session.accessToken, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
|
addToQueue('db:character:create', {
|
||||||
bookId: book?.bookId,
|
bookId: book?.bookId,
|
||||||
|
characterId,
|
||||||
character: updatedCharacter,
|
character: updatedCharacter,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
characterId = await System.authPostToServer<string>(`character/add`, {
|
|
||||||
bookId: book?.bookId,
|
|
||||||
character: updatedCharacter,
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!characterId) {
|
if (!characterId) {
|
||||||
@@ -157,19 +163,19 @@ export function CharacterComponent(props: any, ref: any) {
|
|||||||
async function updateCharacter(updatedCharacter: CharacterProps,): Promise<void> {
|
async function updateCharacter(updatedCharacter: CharacterProps,): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:character:update', {
|
response = await window.electron.invoke<boolean>('db:character:update', {
|
||||||
character: updatedCharacter,
|
character: updatedCharacter,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authPostToServer<boolean>(`character/update`, {
|
||||||
response = await window.electron.invoke<boolean>('db:character:update', {
|
character: updatedCharacter,
|
||||||
|
}, session.accessToken, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
|
addToQueue('db:character:update', {
|
||||||
character: updatedCharacter,
|
character: updatedCharacter,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
response = await System.authPostToServer<boolean>(`character/update`, {
|
|
||||||
character: updatedCharacter,
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -215,25 +221,26 @@ export function CharacterComponent(props: any, ref: any) {
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
let attributeId: string;
|
let attributeId: string;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
attributeId = await window.electron.invoke<string>('db:character:attribute:add', {
|
attributeId = await window.electron.invoke<string>('db:character:attribute:add', {
|
||||||
characterId: selectedCharacter.id,
|
characterId: selectedCharacter.id,
|
||||||
type: section,
|
type: section,
|
||||||
name: value.name,
|
name: value.name,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
attributeId = await System.authPostToServer<string>(`character/attribute/add`, {
|
||||||
attributeId = await window.electron.invoke<string>('db:character:attribute:add', {
|
characterId: selectedCharacter.id,
|
||||||
|
type: section,
|
||||||
|
name: value.name,
|
||||||
|
}, session.accessToken, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
|
addToQueue('db:character:attribute:add', {
|
||||||
characterId: selectedCharacter.id,
|
characterId: selectedCharacter.id,
|
||||||
|
attributeId,
|
||||||
type: section,
|
type: section,
|
||||||
name: value.name,
|
name: value.name,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
attributeId = await System.authPostToServer<string>(`character/attribute/add`, {
|
|
||||||
characterId: selectedCharacter.id,
|
|
||||||
type: section,
|
|
||||||
name: value.name,
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!attributeId) {
|
if (!attributeId) {
|
||||||
@@ -271,19 +278,19 @@ export function CharacterComponent(props: any, ref: any) {
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:character:attribute:delete', {
|
response = await window.electron.invoke<boolean>('db:character:attribute:delete', {
|
||||||
attributeId: attrId,
|
attributeId: attrId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>(`character/attribute/delete`, {
|
||||||
response = await window.electron.invoke<boolean>('db:character:attribute:delete', {
|
attributeId: attrId,
|
||||||
|
}, session.accessToken, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
|
addToQueue('db:character:attribute:delete', {
|
||||||
attributeId: attrId,
|
attributeId: attrId,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>(`character/attribute/delete`, {
|
|
||||||
attributeId: attrId,
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import SelectBox from "@/components/form/SelectBox";
|
|||||||
import {AlertContext} from "@/context/AlertContext";
|
import {AlertContext} from "@/context/AlertContext";
|
||||||
import {SessionContext} from "@/context/SessionContext";
|
import {SessionContext} from "@/context/SessionContext";
|
||||||
import {
|
import {
|
||||||
|
Attribute,
|
||||||
CharacterAttribute,
|
CharacterAttribute,
|
||||||
characterCategories,
|
characterCategories,
|
||||||
CharacterElement,
|
CharacterElement,
|
||||||
@@ -32,6 +33,8 @@ import {LangContext} from "@/context/LangContext";
|
|||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
import {BookContext} from "@/context/BookContext";
|
import {BookContext} from "@/context/BookContext";
|
||||||
|
|
||||||
|
type AttributeResponse = { type: string; values: Attribute[] }[];
|
||||||
|
|
||||||
interface CharacterDetailProps {
|
interface CharacterDetailProps {
|
||||||
selectedCharacter: CharacterProps | null;
|
selectedCharacter: CharacterProps | null;
|
||||||
setSelectedCharacter: Dispatch<SetStateAction<CharacterProps | null>>;
|
setSelectedCharacter: Dispatch<SetStateAction<CharacterProps | null>>;
|
||||||
@@ -70,23 +73,31 @@ export default function CharacterDetail(
|
|||||||
|
|
||||||
async function getAttributes(): Promise<void> {
|
async function getAttributes(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: CharacterAttribute;
|
let response: AttributeResponse;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline()) {
|
||||||
response = await window.electron.invoke<CharacterAttribute>('db:character:attributes', {
|
response = await window.electron.invoke<AttributeResponse>('db:character:attributes', {
|
||||||
characterId: selectedCharacter?.id,
|
characterId: selectedCharacter?.id,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
if (book?.localBook) {
|
||||||
response = await window.electron.invoke<CharacterAttribute>('db:character:attributes', {
|
response = await window.electron.invoke<AttributeResponse>('db:character:attributes', {
|
||||||
characterId: selectedCharacter?.id,
|
characterId: selectedCharacter?.id,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
response = await System.authGetQueryToServer<CharacterAttribute>(`character/attribute`, session.accessToken, lang, {
|
response = await System.authGetQueryToServer<AttributeResponse>(`character/attribute`, session.accessToken, lang, {
|
||||||
characterId: selectedCharacter?.id,
|
characterId: selectedCharacter?.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (response) {
|
if (response) {
|
||||||
|
const attributes: CharacterAttribute = {};
|
||||||
|
response.forEach((item: {
|
||||||
|
type: string
|
||||||
|
values: Attribute[]
|
||||||
|
}):void => {
|
||||||
|
attributes[item.type] = item.values;
|
||||||
|
});
|
||||||
|
|
||||||
setSelectedCharacter({
|
setSelectedCharacter({
|
||||||
id: selectedCharacter?.id ?? '',
|
id: selectedCharacter?.id ?? '',
|
||||||
name: selectedCharacter?.name ?? '',
|
name: selectedCharacter?.name ?? '',
|
||||||
@@ -97,14 +108,14 @@ export default function CharacterDetail(
|
|||||||
biography: selectedCharacter?.biography,
|
biography: selectedCharacter?.biography,
|
||||||
history: selectedCharacter?.history,
|
history: selectedCharacter?.history,
|
||||||
role: selectedCharacter?.role ?? '',
|
role: selectedCharacter?.role ?? '',
|
||||||
physical: response.physical ?? [],
|
physical: attributes.physical ?? [],
|
||||||
psychological: response.psychological ?? [],
|
psychological: attributes.psychological ?? [],
|
||||||
relations: response.relations ?? [],
|
relations: attributes.relations ?? [],
|
||||||
skills: response.skills ?? [],
|
skills: attributes.skills ?? [],
|
||||||
weaknesses: response.weaknesses ?? [],
|
weaknesses: attributes.weaknesses ?? [],
|
||||||
strengths: response.strengths ?? [],
|
strengths: attributes.strengths ?? [],
|
||||||
goals: response.goals ?? [],
|
goals: attributes.goals ?? [],
|
||||||
motivations: response.motivations ?? [],
|
motivations: attributes.motivations ?? [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
|||||||
@@ -22,11 +22,16 @@ import {
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {LangContext} from "@/context/LangContext";
|
import {LangContext} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
function GuideLineSetting(props: any, ref: any) {
|
function GuideLineSetting(props: any, ref: any) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext(LangContext);
|
const {lang} = useContext(LangContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const userToken: string = session?.accessToken ? session?.accessToken : '';
|
const userToken: string = session?.accessToken ? session?.accessToken : '';
|
||||||
@@ -159,18 +164,18 @@ function GuideLineSetting(props: any, ref: any) {
|
|||||||
intendedAudience: intendedAudience,
|
intendedAudience: intendedAudience,
|
||||||
keyMessages: keyMessages,
|
keyMessages: keyMessages,
|
||||||
};
|
};
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:book:guideline:update', guidelineData);
|
response = await window.electron.invoke<boolean>('db:book:guideline:update', guidelineData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authPostToServer<boolean>(
|
||||||
response = await window.electron.invoke<boolean>('db:book:guideline:update', guidelineData);
|
'book/guide-line',
|
||||||
} else {
|
guidelineData,
|
||||||
response = await System.authPostToServer<boolean>(
|
userToken,
|
||||||
'book/guide-line',
|
lang,
|
||||||
guidelineData,
|
);
|
||||||
userToken,
|
|
||||||
lang,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
);
|
addToQueue('db:book:guideline:update', guidelineData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -190,45 +195,28 @@ function GuideLineSetting(props: any, ref: any) {
|
|||||||
async function saveQuillSense(): Promise<void> {
|
async function saveQuillSense(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
const aiGuidelineData = {
|
||||||
response = await window.electron.invoke<boolean>('db:book:guideline:ai:update', {
|
bookId: bookId,
|
||||||
bookId: bookId,
|
plotSummary: plotSummary,
|
||||||
plotSummary: plotSummary,
|
verbTense: verbTense,
|
||||||
verbTense: verbTense,
|
narrativeType: narrativeType,
|
||||||
narrativeType: narrativeType,
|
dialogueType: dialogueType,
|
||||||
dialogueType: dialogueType,
|
toneAtmosphere: toneAtmosphere,
|
||||||
toneAtmosphere: toneAtmosphere,
|
language: language,
|
||||||
language: language,
|
themes: themes,
|
||||||
themes: themes,
|
};
|
||||||
});
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
|
response = await window.electron.invoke<boolean>('db:book:guideline:ai:update', aiGuidelineData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authPostToServer<boolean>(
|
||||||
response = await window.electron.invoke<boolean>('db:book:guideline:ai:update', {
|
'quillsense/book/guide-line',
|
||||||
bookId: bookId,
|
aiGuidelineData,
|
||||||
plotSummary: plotSummary,
|
userToken,
|
||||||
verbTense: verbTense,
|
lang,
|
||||||
narrativeType: narrativeType,
|
);
|
||||||
dialogueType: dialogueType,
|
|
||||||
toneAtmosphere: toneAtmosphere,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
language: language,
|
addToQueue('db:book:guideline:ai:update', aiGuidelineData);
|
||||||
themes: themes,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
response = await System.authPostToServer<boolean>(
|
|
||||||
'quillsense/book/guide-line',
|
|
||||||
{
|
|
||||||
bookId: bookId,
|
|
||||||
plotSummary: plotSummary,
|
|
||||||
verbTense: verbTense,
|
|
||||||
narrativeType: narrativeType,
|
|
||||||
dialogueType: dialogueType,
|
|
||||||
toneAtmosphere: toneAtmosphere,
|
|
||||||
language: language,
|
|
||||||
themes: themes,
|
|
||||||
},
|
|
||||||
userToken,
|
|
||||||
lang,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (response) {
|
if (response) {
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import TexteAreaInput from "@/components/form/TexteAreaInput";
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
interface SubElement {
|
interface SubElement {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -36,6 +39,8 @@ export function LocationComponent(props: any, ref: any) {
|
|||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext<LangContextProps>(LangContext);
|
const {lang} = useContext<LangContextProps>(LangContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {successMessage, errorMessage} = useContext(AlertContext);
|
const {successMessage, errorMessage} = useContext(AlertContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
@@ -91,22 +96,23 @@ export function LocationComponent(props: any, ref: any) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let sectionId: string;
|
let sectionId: string;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
sectionId = await window.electron.invoke<string>('db:location:section:add', {
|
sectionId = await window.electron.invoke<string>('db:location:section:add', {
|
||||||
bookId: bookId,
|
bookId: bookId,
|
||||||
locationName: newSectionName,
|
locationName: newSectionName,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
sectionId = await System.authPostToServer<string>(`location/section/add`, {
|
||||||
sectionId = await window.electron.invoke<string>('db:location:section:add', {
|
bookId: bookId,
|
||||||
|
locationName: newSectionName,
|
||||||
|
}, token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:location:section:add', {
|
||||||
bookId: bookId,
|
bookId: bookId,
|
||||||
|
sectionId,
|
||||||
locationName: newSectionName,
|
locationName: newSectionName,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
sectionId = await System.authPostToServer<string>(`location/section/add`, {
|
|
||||||
bookId: bookId,
|
|
||||||
locationName: newSectionName,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sectionId) {
|
if (!sectionId) {
|
||||||
@@ -136,26 +142,27 @@ export function LocationComponent(props: any, ref: any) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let elementId: string;
|
let elementId: string;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
elementId = await window.electron.invoke<string>('db:location:element:add', {
|
elementId = await window.electron.invoke<string>('db:location:element:add', {
|
||||||
bookId: bookId,
|
bookId: bookId,
|
||||||
locationId: sectionId,
|
locationId: sectionId,
|
||||||
elementName: newElementNames[sectionId],
|
elementName: newElementNames[sectionId],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
elementId = await System.authPostToServer<string>(`location/element/add`, {
|
||||||
elementId = await window.electron.invoke<string>('db:location:element:add', {
|
|
||||||
bookId: bookId,
|
bookId: bookId,
|
||||||
locationId: sectionId,
|
locationId: sectionId,
|
||||||
elementName: newElementNames[sectionId],
|
elementName: newElementNames[sectionId],
|
||||||
|
},
|
||||||
|
token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:location:element:add', {
|
||||||
|
bookId: bookId,
|
||||||
|
locationId: sectionId,
|
||||||
|
elementId,
|
||||||
|
elementName: newElementNames[sectionId],
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
elementId = await System.authPostToServer<string>(`location/element/add`, {
|
|
||||||
bookId: bookId,
|
|
||||||
locationId: sectionId,
|
|
||||||
elementName: newElementNames[sectionId],
|
|
||||||
},
|
|
||||||
token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!elementId) {
|
if (!elementId) {
|
||||||
@@ -211,22 +218,24 @@ export function LocationComponent(props: any, ref: any) {
|
|||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
let subElementId: string;
|
let subElementId: string;
|
||||||
if (isCurrentlyOffline()) {
|
const elementId = sections[sectionIndex].elements[elementIndex].id;
|
||||||
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
subElementId = await window.electron.invoke<string>('db:location:subelement:add', {
|
subElementId = await window.electron.invoke<string>('db:location:subelement:add', {
|
||||||
elementId: sections[sectionIndex].elements[elementIndex].id,
|
elementId: elementId,
|
||||||
subElementName: newSubElementNames[elementIndex],
|
subElementName: newSubElementNames[elementIndex],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
subElementId = await System.authPostToServer<string>(`location/sub-element/add`, {
|
||||||
subElementId = await window.electron.invoke<string>('db:location:subelement:add', {
|
elementId: elementId,
|
||||||
elementId: sections[sectionIndex].elements[elementIndex].id,
|
subElementName: newSubElementNames[elementIndex],
|
||||||
|
}, token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:location:subelement:add', {
|
||||||
|
elementId: elementId,
|
||||||
|
subElementId,
|
||||||
subElementName: newSubElementNames[elementIndex],
|
subElementName: newSubElementNames[elementIndex],
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
subElementId = await System.authPostToServer<string>(`location/sub-element/add`, {
|
|
||||||
elementId: sections[sectionIndex].elements[elementIndex].id,
|
|
||||||
subElementName: newSubElementNames[elementIndex],
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!subElementId) {
|
if (!subElementId) {
|
||||||
@@ -275,19 +284,19 @@ export function LocationComponent(props: any, ref: any) {
|
|||||||
let response: boolean;
|
let response: boolean;
|
||||||
const elementId = sections.find((section: LocationProps): boolean => section.id === sectionId)
|
const elementId = sections.find((section: LocationProps): boolean => section.id === sectionId)
|
||||||
?.elements[elementIndex].id;
|
?.elements[elementIndex].id;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:location:element:delete', {
|
response = await window.electron.invoke<boolean>('db:location:element:delete', {
|
||||||
elementId: elementId,
|
elementId: elementId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>(`location/element/delete`, {
|
||||||
response = await window.electron.invoke<boolean>('db:location:element:delete', {
|
elementId: elementId,
|
||||||
|
}, token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:location:element:delete', {
|
||||||
elementId: elementId,
|
elementId: elementId,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>(`location/element/delete`, {
|
|
||||||
elementId: elementId,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -315,19 +324,19 @@ export function LocationComponent(props: any, ref: any) {
|
|||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
const subElementId = sections.find((section: LocationProps): boolean => section.id === sectionId)?.elements[elementIndex].subElements[subElementIndex].id;
|
const subElementId = sections.find((section: LocationProps): boolean => section.id === sectionId)?.elements[elementIndex].subElements[subElementIndex].id;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:location:subelement:delete', {
|
response = await window.electron.invoke<boolean>('db:location:subelement:delete', {
|
||||||
subElementId: subElementId,
|
subElementId: subElementId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>(`location/sub-element/delete`, {
|
||||||
response = await window.electron.invoke<boolean>('db:location:subelement:delete', {
|
subElementId: subElementId,
|
||||||
|
}, token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:location:subelement:delete', {
|
||||||
subElementId: subElementId,
|
subElementId: subElementId,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>(`location/sub-element/delete`, {
|
|
||||||
subElementId: subElementId,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -350,19 +359,19 @@ export function LocationComponent(props: any, ref: any) {
|
|||||||
async function handleRemoveSection(sectionId: string): Promise<void> {
|
async function handleRemoveSection(sectionId: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:location:delete', {
|
response = await window.electron.invoke<boolean>('db:location:delete', {
|
||||||
locationId: sectionId,
|
locationId: sectionId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>(`location/delete`, {
|
||||||
response = await window.electron.invoke<boolean>('db:location:delete', {
|
locationId: sectionId,
|
||||||
|
}, token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:location:delete', {
|
||||||
locationId: sectionId,
|
locationId: sectionId,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>(`location/delete`, {
|
|
||||||
locationId: sectionId,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -383,19 +392,19 @@ export function LocationComponent(props: any, ref: any) {
|
|||||||
async function handleSave(): Promise<void> {
|
async function handleSave(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:location:update', {
|
response = await window.electron.invoke<boolean>('db:location:update', {
|
||||||
locations: sections,
|
locations: sections,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authPostToServer<boolean>(`location/update`, {
|
||||||
response = await window.electron.invoke<boolean>('db:location:update', {
|
locations: sections,
|
||||||
|
}, token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:location:update', {
|
||||||
locations: sections,
|
locations: sections,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
response = await System.authPostToServer<boolean>(`location/update`, {
|
|
||||||
locations: sections,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import ActPlotPoints from '@/components/book/settings/story/act/ActPlotPoints';
|
|||||||
import {useTranslations} from 'next-intl';
|
import {useTranslations} from 'next-intl';
|
||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
interface ActProps {
|
interface ActProps {
|
||||||
acts: ActType[];
|
acts: ActType[];
|
||||||
@@ -32,6 +35,8 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
|
|||||||
const t = useTranslations('actComponent');
|
const t = useTranslations('actComponent');
|
||||||
const {lang} = useContext<LangContextProps>(LangContext);
|
const {lang} = useContext<LangContextProps>(LangContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {errorMessage, successMessage} = useContext(AlertContext);
|
const {errorMessage, successMessage} = useContext(AlertContext);
|
||||||
@@ -74,22 +79,23 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
let incidentId: string;
|
let incidentId: string;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
incidentId = await window.electron.invoke<string>('db:book:incident:add', {
|
incidentId = await window.electron.invoke<string>('db:book:incident:add', {
|
||||||
bookId,
|
bookId,
|
||||||
name: newIncidentTitle,
|
name: newIncidentTitle,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
incidentId = await System.authPostToServer<string>('book/incident/new', {
|
||||||
incidentId = await window.electron.invoke<string>('db:book:incident:add', {
|
bookId,
|
||||||
|
name: newIncidentTitle,
|
||||||
|
}, token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:book:incident:add', {
|
||||||
bookId,
|
bookId,
|
||||||
|
incidentId,
|
||||||
name: newIncidentTitle,
|
name: newIncidentTitle,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
incidentId = await System.authPostToServer<string>('book/incident/new', {
|
|
||||||
bookId,
|
|
||||||
name: newIncidentTitle,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!incidentId) {
|
if (!incidentId) {
|
||||||
@@ -104,7 +110,7 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
|
|||||||
summary: '',
|
summary: '',
|
||||||
chapters: [],
|
chapters: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...act,
|
...act,
|
||||||
incidents: [...(act.incidents || []), newIncident],
|
incidents: [...(act.incidents || []), newIncident],
|
||||||
@@ -126,22 +132,14 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
|
|||||||
async function deleteIncident(actId: number, incidentId: string): Promise<void> {
|
async function deleteIncident(actId: number, incidentId: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
const deleteData = { bookId, incidentId };
|
||||||
response = await window.electron.invoke<boolean>('db:book:incident:remove', {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
bookId,
|
response = await window.electron.invoke<boolean>('db:book:incident:remove', deleteData);
|
||||||
incidentId,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>('book/incident/remove', deleteData, token, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:book:incident:remove', {
|
|
||||||
bookId,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
incidentId,
|
addToQueue('db:book:incident:remove', deleteData);
|
||||||
});
|
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>('book/incident/remove', {
|
|
||||||
bookId,
|
|
||||||
incidentId,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -173,25 +171,21 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
|
|||||||
if (newPlotPointTitle.trim() === '') return;
|
if (newPlotPointTitle.trim() === '') return;
|
||||||
try {
|
try {
|
||||||
let plotId: string;
|
let plotId: string;
|
||||||
if (isCurrentlyOffline()) {
|
const plotData = {
|
||||||
plotId = await window.electron.invoke<string>('db:book:plot:add', {
|
bookId,
|
||||||
bookId,
|
name: newPlotPointTitle,
|
||||||
name: newPlotPointTitle,
|
incidentId: selectedIncidentId,
|
||||||
incidentId: selectedIncidentId,
|
};
|
||||||
});
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
|
plotId = await window.electron.invoke<string>('db:book:plot:add', plotData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
plotId = await System.authPostToServer<string>('book/plot/new', plotData, token, lang);
|
||||||
plotId = await window.electron.invoke<string>('db:book:plot:add', {
|
|
||||||
bookId,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
name: newPlotPointTitle,
|
addToQueue('db:book:plot:add', {
|
||||||
incidentId: selectedIncidentId,
|
...plotData,
|
||||||
|
plotId,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
plotId = await System.authPostToServer<string>('book/plot/new', {
|
|
||||||
bookId,
|
|
||||||
name: newPlotPointTitle,
|
|
||||||
incidentId: selectedIncidentId,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!plotId) {
|
if (!plotId) {
|
||||||
@@ -229,19 +223,14 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
|
|||||||
async function deletePlotPoint(actId: number, plotPointId: string): Promise<void> {
|
async function deletePlotPoint(actId: number, plotPointId: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
const deleteData = { plotId: plotPointId };
|
||||||
response = await window.electron.invoke<boolean>('db:book:plot:remove', {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
plotId: plotPointId,
|
response = await window.electron.invoke<boolean>('db:book:plot:remove', deleteData);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>('book/plot/remove', deleteData, token, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:book:plot:remove', {
|
|
||||||
plotId: plotPointId,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
});
|
addToQueue('db:book:plot:remove', deleteData);
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>('book/plot/remove', {
|
|
||||||
plotId: plotPointId,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -289,13 +278,16 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
|
|||||||
plotId: destination === 'plotPoint' ? itemId : null,
|
plotId: destination === 'plotPoint' ? itemId : null,
|
||||||
incidentId: destination === 'incident' ? itemId : null,
|
incidentId: destination === 'incident' ? itemId : null,
|
||||||
};
|
};
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
linkId = await window.electron.invoke<string>('db:chapter:information:add', linkData);
|
linkId = await window.electron.invoke<string>('db:chapter:information:add', linkData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
linkId = await System.authPostToServer<string>('chapter/resume/add', linkData, token, lang);
|
||||||
linkId = await window.electron.invoke<string>('db:chapter:information:add', linkData);
|
|
||||||
} else {
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
linkId = await System.authPostToServer<string>('chapter/resume/add', linkData, token, lang);
|
addToQueue('db:chapter:information:add', {
|
||||||
|
...linkData,
|
||||||
|
chapterInfoId: linkId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!linkId) {
|
if (!linkId) {
|
||||||
@@ -373,19 +365,14 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
const unlinkData = { chapterInfoId };
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:information:remove', {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
chapterInfoId,
|
response = await window.electron.invoke<boolean>('db:chapter:information:remove', unlinkData);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>('chapter/resume/remove', unlinkData, token, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:information:remove', {
|
|
||||||
chapterInfoId,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
});
|
addToQueue('db:chapter:information:remove', unlinkData);
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>('chapter/resume/remove', {
|
|
||||||
chapterInfoId,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import CollapsableArea from "@/components/CollapsableArea";
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
interface IssuesProps {
|
interface IssuesProps {
|
||||||
issues: Issue[];
|
issues: Issue[];
|
||||||
@@ -20,6 +23,8 @@ export default function Issues({issues, setIssues}: IssuesProps) {
|
|||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext<LangContextProps>(LangContext);
|
const {lang} = useContext<LangContextProps>(LangContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {errorMessage} = useContext(AlertContext);
|
const {errorMessage} = useContext(AlertContext);
|
||||||
@@ -36,22 +41,23 @@ export default function Issues({issues, setIssues}: IssuesProps) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let issueId: string;
|
let issueId: string;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
issueId = await window.electron.invoke<string>('db:book:issue:add', {
|
issueId = await window.electron.invoke<string>('db:book:issue:add', {
|
||||||
bookId,
|
bookId,
|
||||||
name: newIssueName,
|
name: newIssueName,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
issueId = await System.authPostToServer<string>('book/issue/add', {
|
||||||
issueId = await window.electron.invoke<string>('db:book:issue:add', {
|
bookId,
|
||||||
|
name: newIssueName,
|
||||||
|
}, token, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:book:issue:add', {
|
||||||
bookId,
|
bookId,
|
||||||
|
issueId,
|
||||||
name: newIssueName,
|
name: newIssueName,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
issueId = await System.authPostToServer<string>('book/issue/add', {
|
|
||||||
bookId,
|
|
||||||
name: newIssueName,
|
|
||||||
}, token, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!issueId) {
|
if (!issueId) {
|
||||||
@@ -62,7 +68,7 @@ export default function Issues({issues, setIssues}: IssuesProps) {
|
|||||||
name: newIssueName,
|
name: newIssueName,
|
||||||
id: issueId,
|
id: issueId,
|
||||||
};
|
};
|
||||||
|
|
||||||
setIssues([...issues, newIssue]);
|
setIssues([...issues, newIssue]);
|
||||||
setNewIssueName('');
|
setNewIssueName('');
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
@@ -77,32 +83,32 @@ export default function Issues({issues, setIssues}: IssuesProps) {
|
|||||||
async function deleteIssue(issueId: string): Promise<void> {
|
async function deleteIssue(issueId: string): Promise<void> {
|
||||||
if (issueId === undefined) {
|
if (issueId === undefined) {
|
||||||
errorMessage(t("issues.errorInvalidId"));
|
errorMessage(t("issues.errorInvalidId"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:book:issue:remove', {
|
response = await window.electron.invoke<boolean>('db:book:issue:remove', {
|
||||||
bookId,
|
bookId,
|
||||||
issueId,
|
issueId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>(
|
||||||
response = await window.electron.invoke<boolean>('db:book:issue:remove', {
|
'book/issue/remove',
|
||||||
|
{
|
||||||
|
bookId,
|
||||||
|
issueId,
|
||||||
|
},
|
||||||
|
token,
|
||||||
|
lang
|
||||||
|
);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:book:issue:remove', {
|
||||||
bookId,
|
bookId,
|
||||||
issueId,
|
issueId,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>(
|
|
||||||
'book/issue/remove',
|
|
||||||
{
|
|
||||||
bookId,
|
|
||||||
issueId,
|
|
||||||
},
|
|
||||||
token,
|
|
||||||
lang
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (response) {
|
if (response) {
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import CollapsableArea from "@/components/CollapsableArea";
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {LangContext} from "@/context/LangContext";
|
import {LangContext} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
interface MainChapterProps {
|
interface MainChapterProps {
|
||||||
chapters: ChapterListProps[];
|
chapters: ChapterListProps[];
|
||||||
@@ -23,6 +26,8 @@ export default function MainChapter({chapters, setChapters}: MainChapterProps) {
|
|||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext(LangContext)
|
const {lang} = useContext(LangContext)
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {errorMessage, successMessage} = useContext(AlertContext);
|
const {errorMessage, successMessage} = useContext(AlertContext);
|
||||||
@@ -85,13 +90,13 @@ export default function MainChapter({chapters, setChapters}: MainChapterProps) {
|
|||||||
bookId,
|
bookId,
|
||||||
chapterId: chapterIdToRemove,
|
chapterId: chapterIdToRemove,
|
||||||
};
|
};
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:remove', deleteData);
|
response = await window.electron.invoke<boolean>('db:chapter:remove', deleteData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>('chapter/remove', deleteData, token, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:remove', deleteData);
|
|
||||||
} else {
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
response = await System.authDeleteToServer<boolean>('chapter/remove', deleteData, token, lang);
|
addToQueue('db:chapter:remove', deleteData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -121,13 +126,16 @@ export default function MainChapter({chapters, setChapters}: MainChapterProps) {
|
|||||||
chapterOrder: newChapterOrder ? newChapterOrder : 0,
|
chapterOrder: newChapterOrder ? newChapterOrder : 0,
|
||||||
title: newChapterTitle,
|
title: newChapterTitle,
|
||||||
};
|
};
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
responseId = await window.electron.invoke<string>('db:chapter:add', chapterData);
|
responseId = await window.electron.invoke<string>('db:chapter:add', chapterData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
responseId = await System.authPostToServer<string>('chapter/add', chapterData, token);
|
||||||
responseId = await window.electron.invoke<string>('db:chapter:add', chapterData);
|
|
||||||
} else {
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
responseId = await System.authPostToServer<string>('chapter/add', chapterData, token);
|
addToQueue('db:chapter:add', {
|
||||||
|
...chapterData,
|
||||||
|
chapterId: responseId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!responseId) {
|
if (!responseId) {
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import Act from "@/components/book/settings/story/Act";
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
export const StoryContext = createContext<{
|
export const StoryContext = createContext<{
|
||||||
acts: ActType[];
|
acts: ActType[];
|
||||||
@@ -43,6 +46,8 @@ export function Story(props: any, ref: any) {
|
|||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext<LangContextProps>(LangContext);
|
const {lang} = useContext<LangContextProps>(LangContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
const bookId: string = book?.bookId ? book.bookId.toString() : '';
|
const bookId: string = book?.bookId ? book.bookId.toString() : '';
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
@@ -137,13 +142,13 @@ export function Story(props: any, ref: any) {
|
|||||||
mainChapters,
|
mainChapters,
|
||||||
issues,
|
issues,
|
||||||
};
|
};
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:book:story:update', storyData);
|
response = await window.electron.invoke<boolean>('db:book:story:update', storyData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authPostToServer<boolean>('book/story', storyData, userToken, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:book:story:update', storyData);
|
|
||||||
} else {
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
response = await System.authPostToServer<boolean>('book/story', storyData, userToken, lang);
|
addToQueue('db:book:story:update', storyData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import {useTranslations} from "next-intl";
|
|||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
import {BookContext} from "@/context/BookContext";
|
import {BookContext} from "@/context/BookContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
interface WorldElementInputProps {
|
interface WorldElementInputProps {
|
||||||
sectionLabel: string;
|
sectionLabel: string;
|
||||||
@@ -23,6 +26,8 @@ export default function WorldElementComponent({sectionLabel, sectionType}: World
|
|||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext<LangContextProps>(LangContext);
|
const {lang} = useContext<LangContextProps>(LangContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
const {worlds, setWorlds, selectedWorldIndex} = useContext(WorldContext);
|
const {worlds, setWorlds, selectedWorldIndex} = useContext(WorldContext);
|
||||||
const {errorMessage, successMessage} = useContext(AlertContext);
|
const {errorMessage, successMessage} = useContext(AlertContext);
|
||||||
@@ -37,19 +42,19 @@ export default function WorldElementComponent({sectionLabel, sectionType}: World
|
|||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
const elementId = (worlds[selectedWorldIndex][section] as WorldElement[])[index].id;
|
const elementId = (worlds[selectedWorldIndex][section] as WorldElement[])[index].id;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:book:world:element:remove', {
|
response = await window.electron.invoke<boolean>('db:book:world:element:remove', {
|
||||||
elementId: elementId,
|
elementId: elementId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authDeleteToServer<boolean>('book/world/element/delete', {
|
||||||
response = await window.electron.invoke<boolean>('db:book:world:element:remove', {
|
elementId: elementId,
|
||||||
|
}, session.accessToken, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
|
addToQueue('db:book:world:element:remove', {
|
||||||
elementId: elementId,
|
elementId: elementId,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
response = await System.authDeleteToServer<boolean>('book/world/element/delete', {
|
|
||||||
elementId: elementId,
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -77,25 +82,26 @@ export default function WorldElementComponent({sectionLabel, sectionType}: World
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let elementId: string;
|
let elementId: string;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
elementId = await window.electron.invoke<string>('db:book:world:element:add', {
|
elementId = await window.electron.invoke<string>('db:book:world:element:add', {
|
||||||
elementType: section,
|
elementType: section,
|
||||||
worldId: worlds[selectedWorldIndex].id,
|
worldId: worlds[selectedWorldIndex].id,
|
||||||
elementName: newElementName,
|
elementName: newElementName,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
elementId = await System.authPostToServer('book/world/element/add', {
|
||||||
elementId = await window.electron.invoke<string>('db:book:world:element:add', {
|
elementType: section,
|
||||||
|
worldId: worlds[selectedWorldIndex].id,
|
||||||
|
elementName: newElementName,
|
||||||
|
}, session.accessToken, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
|
addToQueue('db:book:world:element:add', {
|
||||||
elementType: section,
|
elementType: section,
|
||||||
worldId: worlds[selectedWorldIndex].id,
|
worldId: worlds[selectedWorldIndex].id,
|
||||||
|
elementId,
|
||||||
elementName: newElementName,
|
elementName: newElementName,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
elementId = await System.authPostToServer('book/world/element/add', {
|
|
||||||
elementType: section,
|
|
||||||
worldId: worlds[selectedWorldIndex].id,
|
|
||||||
elementName: newElementName,
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!elementId) {
|
if (!elementId) {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ import SelectBox from "@/components/form/SelectBox";
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
export interface ElementSection {
|
export interface ElementSection {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -28,6 +31,8 @@ export function WorldSetting(props: any, ref: any) {
|
|||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext<LangContextProps>(LangContext);
|
const {lang} = useContext<LangContextProps>(LangContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
const {errorMessage, successMessage} = useContext(AlertContext);
|
const {errorMessage, successMessage} = useContext(AlertContext);
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
@@ -89,22 +94,23 @@ export function WorldSetting(props: any, ref: any) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let worldId: string;
|
let worldId: string;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
worldId = await window.electron.invoke<string>('db:book:world:add', {
|
worldId = await window.electron.invoke<string>('db:book:world:add', {
|
||||||
worldName: newWorldName,
|
worldName: newWorldName,
|
||||||
bookId: bookId,
|
bookId: bookId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
worldId = await System.authPostToServer<string>('book/world/add', {
|
||||||
worldId = await window.electron.invoke<string>('db:book:world:add', {
|
worldName: newWorldName,
|
||||||
|
bookId: bookId,
|
||||||
|
}, session.accessToken, lang);
|
||||||
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
|
addToQueue('db:book:world:add', {
|
||||||
worldName: newWorldName,
|
worldName: newWorldName,
|
||||||
|
worldId,
|
||||||
bookId: bookId,
|
bookId: bookId,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
worldId = await System.authPostToServer<string>('book/world/add', {
|
|
||||||
worldName: newWorldName,
|
|
||||||
bookId: bookId,
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!worldId) {
|
if (!worldId) {
|
||||||
@@ -152,22 +158,17 @@ export function WorldSetting(props: any, ref: any) {
|
|||||||
async function handleUpdateWorld(): Promise<void> {
|
async function handleUpdateWorld(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
const worldData = {
|
||||||
response = await window.electron.invoke<boolean>('db:book:world:update', {
|
world: worlds[selectedWorldIndex],
|
||||||
world: worlds[selectedWorldIndex],
|
bookId: bookId,
|
||||||
bookId: bookId,
|
};
|
||||||
});
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
|
response = await window.electron.invoke<boolean>('db:book:world:update', worldData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authPutToServer<boolean>('book/world/update', worldData, session.accessToken, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:book:world:update', {
|
|
||||||
world: worlds[selectedWorldIndex],
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === bookId)) {
|
||||||
bookId: bookId,
|
addToQueue('db:book:world:update', worldData);
|
||||||
});
|
|
||||||
} else {
|
|
||||||
response = await System.authPutToServer<boolean>('book/world/update', {
|
|
||||||
world: worlds[selectedWorldIndex],
|
|
||||||
bookId: bookId,
|
|
||||||
}, session.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ import UserEditorSettings, {EditorDisplaySettings} from "@/components/editor/Use
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {LangContext, LangContextProps} from "@/context/LangContext";
|
import {LangContext, LangContextProps} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
interface ToolbarButton {
|
interface ToolbarButton {
|
||||||
action: () => void;
|
action: () => void;
|
||||||
@@ -141,7 +144,9 @@ export default function TextEditor() {
|
|||||||
const {errorMessage, successMessage} = useContext(AlertContext);
|
const {errorMessage, successMessage} = useContext(AlertContext);
|
||||||
const {session} = useContext(SessionContext);
|
const {session} = useContext(SessionContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
|
|
||||||
const [mainTimer, setMainTimer] = useState<number>(0);
|
const [mainTimer, setMainTimer] = useState<number>(0);
|
||||||
const [showDraftCompanion, setShowDraftCompanion] = useState<boolean>(false);
|
const [showDraftCompanion, setShowDraftCompanion] = useState<boolean>(false);
|
||||||
const [showGhostWriter, setShowGhostWriter] = useState<boolean>(false);
|
const [showGhostWriter, setShowGhostWriter] = useState<boolean>(false);
|
||||||
@@ -281,39 +286,28 @@ export default function TextEditor() {
|
|||||||
|
|
||||||
const saveContent: () => Promise<void> = useCallback(async (): Promise<void> => {
|
const saveContent: () => Promise<void> = useCallback(async (): Promise<void> => {
|
||||||
if (!editor || !chapter) return;
|
if (!editor || !chapter) return;
|
||||||
|
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
const content = editor.state.doc.toJSON();
|
const content = editor.state.doc.toJSON();
|
||||||
const chapterId: string = chapter.chapterId || '';
|
const chapterId: string = chapter.chapterId || '';
|
||||||
const version: number = chapter.chapterContent.version || 0;
|
const version: number = chapter.chapterContent.version || 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()){
|
const saveData = {
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:content:save',{
|
chapterId,
|
||||||
chapterId,
|
version,
|
||||||
version,
|
content,
|
||||||
content,
|
totalWordCount: editor.getText().length,
|
||||||
totalWordCount: editor.getText().length,
|
currentTime: mainTimer
|
||||||
currentTime: mainTimer
|
};
|
||||||
})
|
if (isCurrentlyOffline() || book?.localBook){
|
||||||
|
response = await window.electron.invoke<boolean>('db:chapter:content:save', saveData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook) {
|
response = await System.authPostToServer<boolean>(`chapter/content`, saveData, session?.accessToken, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:content:save',{
|
|
||||||
chapterId,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
version,
|
addToQueue('db:chapter:content:save', saveData);
|
||||||
content,
|
|
||||||
totalWordCount: editor.getText().length,
|
|
||||||
currentTime: mainTimer
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
response = await System.authPostToServer<boolean>(`chapter/content`, {
|
|
||||||
chapterId,
|
|
||||||
version,
|
|
||||||
content,
|
|
||||||
totalWordCount: editor.getText().length,
|
|
||||||
currentTime: mainTimer
|
|
||||||
}, session?.accessToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -332,7 +326,7 @@ export default function TextEditor() {
|
|||||||
}
|
}
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
}
|
}
|
||||||
}, [editor, chapter, mainTimer, session?.accessToken, successMessage, errorMessage]);
|
}, [editor, chapter, mainTimer, session?.accessToken, successMessage, errorMessage, addToQueue, book?.localBook, isCurrentlyOffline]);
|
||||||
|
|
||||||
const handleShowDraftCompanion: () => void = useCallback((): void => {
|
const handleShowDraftCompanion: () => void = useCallback((): void => {
|
||||||
setShowDraftCompanion((prev: boolean): boolean => !prev);
|
setShowDraftCompanion((prev: boolean): boolean => !prev);
|
||||||
|
|||||||
@@ -12,11 +12,16 @@ import {useTranslations} from "next-intl";
|
|||||||
import InlineAddInput from "@/components/form/InlineAddInput";
|
import InlineAddInput from "@/components/form/InlineAddInput";
|
||||||
import {LangContext} from "@/context/LangContext";
|
import {LangContext} from "@/context/LangContext";
|
||||||
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
|
||||||
|
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
|
||||||
|
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
|
||||||
|
import {SyncedBook} from "@/lib/models/SyncedBook";
|
||||||
|
|
||||||
export default function ScribeChapterComponent() {
|
export default function ScribeChapterComponent() {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {lang} = useContext(LangContext);
|
const {lang} = useContext(LangContext);
|
||||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||||
|
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
|
||||||
|
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
|
||||||
|
|
||||||
const {book} = useContext(BookContext);
|
const {book} = useContext(BookContext);
|
||||||
const {chapter, setChapter} = useContext(ChapterContext);
|
const {chapter, setChapter} = useContext(ChapterContext);
|
||||||
@@ -137,25 +142,18 @@ export default function ScribeChapterComponent() {
|
|||||||
async function handleChapterUpdate(chapterId: string, title: string, chapterOrder: number): Promise<void> {
|
async function handleChapterUpdate(chapterId: string, title: string, chapterOrder: number): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let response: boolean;
|
let response: boolean;
|
||||||
if (isCurrentlyOffline()) {
|
const updateData = {
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:update',{
|
chapterId: chapterId,
|
||||||
chapterId: chapterId,
|
chapterOrder: chapterOrder,
|
||||||
chapterOrder: chapterOrder,
|
title: title,
|
||||||
title: title,
|
};
|
||||||
})
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
|
response = await window.electron.invoke<boolean>('db:chapter:update', updateData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook){
|
response = await System.authPostToServer<boolean>('chapter/update', updateData, userToken, lang);
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:update',{
|
|
||||||
chapterId: chapterId,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
chapterOrder: chapterOrder,
|
addToQueue('db:chapter:update', updateData);
|
||||||
title: title,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
response = await System.authPostToServer<boolean>('chapter/update', {
|
|
||||||
chapterId: chapterId,
|
|
||||||
chapterOrder: chapterOrder,
|
|
||||||
title: title,
|
|
||||||
}, userToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -190,15 +188,17 @@ export default function ScribeChapterComponent() {
|
|||||||
try {
|
try {
|
||||||
setDeleteConfirmationMessage(false);
|
setDeleteConfirmationMessage(false);
|
||||||
let response:boolean = false;
|
let response:boolean = false;
|
||||||
if (isCurrentlyOffline()) {
|
if (isCurrentlyOffline() || book?.localBook) {
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:remove', removeChapterId)
|
response = await window.electron.invoke<boolean>('db:chapter:remove', removeChapterId);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook){
|
response = await System.authDeleteToServer<boolean>('chapter/remove', {
|
||||||
response = await window.electron.invoke<boolean>('db:chapter:remove', removeChapterId)
|
chapterId: removeChapterId,
|
||||||
} else {
|
}, userToken, lang);
|
||||||
response = await System.authDeleteToServer<boolean>('chapter/remove', {
|
|
||||||
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
|
addToQueue('db:chapter:remove', {
|
||||||
chapterId: removeChapterId,
|
chapterId: removeChapterId,
|
||||||
}, userToken, lang);
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -226,25 +226,21 @@ export default function ScribeChapterComponent() {
|
|||||||
const chapterTitle: string = chapterOrder >= 0 ? newChapterName : book?.title as string;
|
const chapterTitle: string = chapterOrder >= 0 ? newChapterName : book?.title as string;
|
||||||
try {
|
try {
|
||||||
let chapterId:string|null = null;
|
let chapterId:string|null = null;
|
||||||
if (isCurrentlyOffline()){
|
const addData = {
|
||||||
chapterId = await window.electron.invoke<string>('db:chapter:add', {
|
bookId: book?.bookId,
|
||||||
bookId: book?.bookId,
|
chapterOrder: chapterOrder,
|
||||||
chapterOrder: chapterOrder,
|
title: chapterTitle
|
||||||
title: chapterTitle
|
};
|
||||||
})
|
if (isCurrentlyOffline() || book?.localBook){
|
||||||
|
chapterId = await window.electron.invoke<string>('db:chapter:add', addData);
|
||||||
} else {
|
} else {
|
||||||
if (book?.localBook){
|
chapterId = await System.authPostToServer<string>('chapter/add', addData, userToken, lang);
|
||||||
chapterId = await window.electron.invoke<string>('db:chapter:add', {
|
|
||||||
bookId: book?.bookId,
|
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
|
||||||
chapterOrder: chapterOrder,
|
addToQueue('db:chapter:add', {
|
||||||
title: chapterTitle
|
...addData,
|
||||||
})
|
chapterId,
|
||||||
} else {
|
});
|
||||||
chapterId = await System.authPostToServer<string>('chapter/add', {
|
|
||||||
bookId: book?.bookId,
|
|
||||||
chapterOrder: chapterOrder,
|
|
||||||
title: chapterTitle
|
|
||||||
}, userToken, lang);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!chapterId) {
|
if (!chapterId) {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export interface BooksSyncContextProps {
|
|||||||
localSyncedBooks:SyncedBook[];
|
localSyncedBooks:SyncedBook[];
|
||||||
booksToSyncFromServer:BookSyncCompare[];
|
booksToSyncFromServer:BookSyncCompare[];
|
||||||
booksToSyncToServer:BookSyncCompare[];
|
booksToSyncToServer:BookSyncCompare[];
|
||||||
|
setServerSyncedBooks:Dispatch<SetStateAction<SyncedBook[]>>;
|
||||||
|
setLocalSyncedBooks:Dispatch<SetStateAction<SyncedBook[]>>;
|
||||||
setServerOnlyBooks:Dispatch<SetStateAction<SyncedBook[]>>;
|
setServerOnlyBooks:Dispatch<SetStateAction<SyncedBook[]>>;
|
||||||
setLocalOnlyBooks:Dispatch<SetStateAction<SyncedBook[]>>;
|
setLocalOnlyBooks:Dispatch<SetStateAction<SyncedBook[]>>;
|
||||||
serverOnlyBooks:SyncedBook[];
|
serverOnlyBooks:SyncedBook[];
|
||||||
@@ -19,6 +21,8 @@ export const BooksSyncContext:Context<BooksSyncContextProps> = createContext<Boo
|
|||||||
localSyncedBooks:[],
|
localSyncedBooks:[],
|
||||||
booksToSyncFromServer:[],
|
booksToSyncFromServer:[],
|
||||||
booksToSyncToServer:[],
|
booksToSyncToServer:[],
|
||||||
|
setServerSyncedBooks:():void => {},
|
||||||
|
setLocalSyncedBooks:():void => {},
|
||||||
setServerOnlyBooks:():void => {},
|
setServerOnlyBooks:():void => {},
|
||||||
setLocalOnlyBooks:():void => {},
|
setLocalOnlyBooks:():void => {},
|
||||||
serverOnlyBooks:[],
|
serverOnlyBooks:[],
|
||||||
|
|||||||
@@ -1611,10 +1611,11 @@ export default class Book {
|
|||||||
const encryptedLastName: string | null = character.last_name ? System.encryptDataWithUserKey(character.last_name, userKey) : null;
|
const encryptedLastName: string | null = character.last_name ? System.encryptDataWithUserKey(character.last_name, userKey) : null;
|
||||||
const encryptedCategory: string = System.encryptDataWithUserKey(character.category, userKey);
|
const encryptedCategory: string = System.encryptDataWithUserKey(character.category, userKey);
|
||||||
const encryptedCharTitle: string | null = character.title ? System.encryptDataWithUserKey(character.title, userKey) : null;
|
const encryptedCharTitle: string | null = character.title ? System.encryptDataWithUserKey(character.title, userKey) : null;
|
||||||
|
const encryptedImage: string | null = character.image ? System.encryptDataWithUserKey(character.image, userKey) : null;
|
||||||
const encryptedRole: string | null = character.role ? System.encryptDataWithUserKey(character.role, userKey) : null;
|
const encryptedRole: string | null = character.role ? System.encryptDataWithUserKey(character.role, userKey) : null;
|
||||||
const encryptedBiography: string | null = character.biography ? System.encryptDataWithUserKey(character.biography, userKey) : null;
|
const encryptedBiography: string | null = character.biography ? System.encryptDataWithUserKey(character.biography, userKey) : null;
|
||||||
const encryptedCharHistory: string | null = character.history ? System.encryptDataWithUserKey(character.history, userKey) : null;
|
const encryptedCharHistory: string | null = character.history ? System.encryptDataWithUserKey(character.history, userKey) : null;
|
||||||
return BookRepo.insertSyncCharacter(character.character_id, character.book_id, userId, encryptedFirstName, encryptedLastName, encryptedCategory, encryptedCharTitle, character.image, encryptedRole, encryptedBiography, encryptedCharHistory, character.last_update, lang);
|
return BookRepo.insertSyncCharacter(character.character_id, character.book_id, userId, encryptedFirstName, encryptedLastName, encryptedCategory, encryptedCharTitle, encryptedImage, encryptedRole, encryptedBiography, encryptedCharHistory, character.last_update, lang);
|
||||||
});
|
});
|
||||||
if (!charactersInserted) return false;
|
if (!charactersInserted) return false;
|
||||||
|
|
||||||
@@ -2064,10 +2065,18 @@ export default class Book {
|
|||||||
|
|
||||||
if (chapterContents && chapterContents.length > 0) {
|
if (chapterContents && chapterContents.length > 0) {
|
||||||
for (const chapterContent of chapterContents) {
|
for (const chapterContent of chapterContents) {
|
||||||
|
const isExist: boolean = ChapterRepo.isChapterContentExist(userId, chapterContent.content_id, lang);
|
||||||
const content: string = System.encryptDataWithUserKey(chapterContent.content ? JSON.stringify(chapterContent.content) : '', userKey);
|
const content: string = System.encryptDataWithUserKey(chapterContent.content ? JSON.stringify(chapterContent.content) : '', userKey);
|
||||||
const updated: boolean = ChapterRepo.updateChapterContent(userId, chapterContent.chapter_id, chapterContent.version, content, chapterContent.words_count, chapterContent.last_update);
|
if (isExist) {
|
||||||
if (!updated) {
|
const updated: boolean = ChapterRepo.updateChapterContent(userId, chapterContent.chapter_id, chapterContent.version, content, chapterContent.words_count, chapterContent.last_update);
|
||||||
return false;
|
if (!updated) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const insert: boolean = BookRepo.insertSyncChapterContent(chapterContent.content_id, chapterContent.chapter_id, userId, chapterContent.version, content, chapterContent.words_count, chapterContent.time_on_it, chapterContent.last_update, lang);
|
||||||
|
if (!insert) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2083,7 +2092,7 @@ export default class Book {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const insert: boolean = BookRepo.insertSyncChapterInfo(chapterInfo.chapter_info_id, chapterInfo.chapter_id, chapterInfo.act_id, chapterInfo.incident_id, chapterInfo.plot_point_id, bookId, chapterInfo.author_id, chapterInfo.summary, chapterInfo.goal, chapterInfo.last_update,lang);
|
const insert: boolean = BookRepo.insertSyncChapterInfo(chapterInfo.chapter_info_id, chapterInfo.chapter_id, chapterInfo.act_id, chapterInfo.incident_id, chapterInfo.plot_point_id, bookId, chapterInfo.author_id, summary, goal, chapterInfo.last_update,lang);
|
||||||
if (!insert) {
|
if (!insert) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,4 +441,20 @@ export default class ChapterRepo{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isChapterContentExist(userId: string, content_id: string, lang: "fr" | "en"): boolean {
|
||||||
|
try {
|
||||||
|
const db: Database = System.getDb();
|
||||||
|
const result: QueryResult | null = db.get('SELECT 1 FROM `book_chapter_content` WHERE `content_id`=? AND `author_id`=?', [content_id, userId]) || null;
|
||||||
|
return result !== null;
|
||||||
|
} catch (e: unknown) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
console.error(`DB Error: ${e.message}`);
|
||||||
|
throw new Error(lang === 'fr' ? `Impossible de vérifier l'existence du contenu du chapitre.` : `Unable to check chapter content existence.`);
|
||||||
|
} else {
|
||||||
|
console.error("An unknown error occurred.");
|
||||||
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user