'use client'; import React, {ChangeEvent, Dispatch, SetStateAction, useContext, useEffect, useRef, useState} from "react"; import {AlertContext} from "@/context/AlertContext"; import System from "@/lib/models/System"; import {SessionContext} from "@/context/SessionContext"; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faBook, faCheck, faLayerGroup, faPencilAlt, faX} from "@fortawesome/free-solid-svg-icons"; import InputField from "@/components/form/InputField"; import TextInput from "@/components/form/TextInput"; import TexteAreaInput from "@/components/form/TexteAreaInput"; import CancelButton from "@/components/form/CancelButton"; import SubmitButtonWLoading from "@/components/form/SubmitButtonWLoading"; import {useTranslations} from "next-intl"; import {LangContext, LangContextProps} from "@/context/LangContext"; import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext"; import {SyncedBook} from "@/lib/models/SyncedBook"; import OfflineContext, {OfflineContextType} from "@/context/OfflineContext"; import {SeriesSyncContext, SeriesSyncContextProps} from "@/context/SeriesSyncContext"; import {SyncedSeries, SyncedSeriesBook} from "@/lib/models/SyncedSeries"; interface AddNewSeriesFormProps { setCloseForm: Dispatch>; onSeriesCreated?: (seriesId: string, name: string) => void; } export default function AddNewSeriesForm({setCloseForm, onSeriesCreated}: AddNewSeriesFormProps) { const t = useTranslations(); const {lang} = useContext(LangContext); const {session} = useContext(SessionContext); const {errorMessage, successMessage} = useContext(AlertContext); const {serverSyncedBooks, setServerSyncedBooks, localSyncedBooks, setLocalSyncedBooks} = useContext(BooksSyncContext); const {isCurrentlyOffline} = useContext(OfflineContext); const {serverSyncedSeries, localSyncedSeries} = useContext(SeriesSyncContext); // Get all bookIds already in a series const booksAlreadyInSeries: Set = new Set( (isCurrentlyOffline() ? localSyncedSeries : serverSyncedSeries) .flatMap((series: SyncedSeries): string[] => series.books.map((book: SyncedSeriesBook): string => book.bookId) ) ); const modalRef: React.RefObject = useRef(null); const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [selectedBookIds, setSelectedBookIds] = useState([]); const [isAddingSeries, setIsAddingSeries] = useState(false); const token: string = session?.accessToken ?? ''; useEffect((): () => void => { document.body.style.overflow = 'hidden'; return (): void => { document.body.style.overflow = 'auto'; }; }, []); function toggleBookSelection(bookId: string): void { setSelectedBookIds((prev: string[]): string[] => { if (prev.includes(bookId)) { return prev.filter((id: string): boolean => id !== bookId); } return [...prev, bookId]; }); } async function handleAddSeries(): Promise { if (!name) { errorMessage(t('addNewSeriesForm.error.nameMissing')); return; } if (name.length < 2) { errorMessage(t('addNewSeriesForm.error.nameTooShort')); return; } if (name.length > 100) { errorMessage(t('addNewSeriesForm.error.nameTooLong')); return; } setIsAddingSeries(true); try { const createData = { name: name, description: description || null, bookIds: selectedBookIds, }; let response: string; if (isCurrentlyOffline()) { response = await window.electron.invoke('db:series:create', createData); } else { response = await System.authPostToServer( 'series/add', createData, token, lang ); } if (!response) { errorMessage(t('addNewSeriesForm.error.addingSeries')); setIsAddingSeries(false); return; } successMessage(t('addNewSeriesForm.success')); if (selectedBookIds.length > 0) { if (isCurrentlyOffline()) { setLocalSyncedBooks((prev: SyncedBook[]): SyncedBook[] => prev.map((book: SyncedBook): SyncedBook => selectedBookIds.includes(book.id) ? {...book, seriesId: response} : book ) ); } else { setServerSyncedBooks((prev: SyncedBook[]): SyncedBook[] => prev.map((book: SyncedBook): SyncedBook => selectedBookIds.includes(book.id) ? {...book, seriesId: response} : book ) ); } } if (onSeriesCreated) { onSeriesCreated(response, name); } setIsAddingSeries(false); setCloseForm(false); } catch (e: unknown) { if (e instanceof Error) { errorMessage(e.message); } else { errorMessage(t('addNewSeriesForm.error.addingSeries')); } setIsAddingSeries(false); } } return (

{t("addNewSeriesForm.title")}

): void => setName(e.target.value)} placeholder={t("addNewSeriesForm.namePlaceholder")} /> }/> ): void => setDescription(e.target.value)} placeholder={t("addNewSeriesForm.descriptionPlaceholder")} /> } />
{t("addNewSeriesForm.selectBooks")} {selectedBookIds.length > 0 && ( ({selectedBookIds.length} {t("addNewSeriesForm.selected")}) )}
{(isCurrentlyOffline() ? localSyncedBooks : serverSyncedBooks) .filter((book: SyncedBook): boolean => !booksAlreadyInSeries.has(book.id)).length === 0 ? (

{t("addNewSeriesForm.noBooks")}

) : (
{(isCurrentlyOffline() ? localSyncedBooks : serverSyncedBooks) .filter((book: SyncedBook): boolean => !booksAlreadyInSeries.has(book.id)) .map((book: SyncedBook) => { const isSelected: boolean = selectedBookIds.includes(book.id); return ( ); })}
)}
setCloseForm(false)}/>
); }