'use client'; import {Dispatch, forwardRef, SetStateAction, useContext, useEffect, useImperativeHandle, useState} from 'react'; import {Attribute, CharacterProps} from "@/lib/models/Character"; import {SessionContext} from "@/context/SessionContext"; import CharacterList from './CharacterList'; import System from '@/lib/models/System'; import {AlertContext} from "@/context/AlertContext"; import {BookContext} from "@/context/BookContext"; import CharacterDetail from "@/components/book/settings/characters/CharacterDetail"; import {useTranslations} from "next-intl"; import {LangContext, LangContextProps} from "@/context/LangContext"; import OfflineContext, {OfflineContextType} from "@/context/OfflineContext"; interface CharacterDetailProps { selectedCharacter: CharacterProps | null; setSelectedCharacter: Dispatch>; handleCharacterChange: (key: keyof CharacterProps, value: string) => void; handleAddElement: (section: keyof CharacterProps, element: any) => void; handleRemoveElement: ( section: keyof CharacterProps, index: number, attrId: string, ) => void; handleSaveCharacter: () => void; } const initialCharacterState: CharacterProps = { id: null, name: '', lastName: '', category: 'none', title: '', role: '', image: 'https://via.placeholder.com/150', biography: '', history: '', physical: [], psychological: [], relations: [], skills: [], weaknesses: [], strengths: [], goals: [], motivations: [], }; export function CharacterComponent(props: any, ref: any) { const t = useTranslations(); const {lang} = useContext(LangContext) const {isCurrentlyOffline} = useContext(OfflineContext); const {session} = useContext(SessionContext); const {book} = useContext(BookContext); const {errorMessage, successMessage} = useContext(AlertContext); const [characters, setCharacters] = useState([]); const [selectedCharacter, setSelectedCharacter] = useState(null); useImperativeHandle(ref, function () { return { handleSave: handleSaveCharacter, }; }); useEffect((): void => { getCharacters().then(); }, []); async function getCharacters(): Promise { try { let response: CharacterProps[]; if (isCurrentlyOffline()) { response = await window.electron.invoke('db:character:list', {bookid: book?.bookId}); } else { response = await System.authGetQueryToServer(`character/list`, session.accessToken, lang, { bookid: book?.bookId, }); } if (response) { setCharacters(response); } } catch (e: unknown) { if (e instanceof Error) { errorMessage(e.message); } else { errorMessage(t("common.unknownError")); } } } function handleCharacterClick(character: CharacterProps): void { setSelectedCharacter({...character}); } function handleAddCharacter(): void { setSelectedCharacter({...initialCharacterState}); } async function handleSaveCharacter(): Promise { if (selectedCharacter) { const updatedCharacter: CharacterProps = {...selectedCharacter}; if (selectedCharacter.id === null) { await addNewCharacter(updatedCharacter); } else { await updateCharacter(updatedCharacter); } } } async function addNewCharacter(updatedCharacter: CharacterProps): Promise { if (!updatedCharacter.name) { errorMessage(t("characterComponent.errorNameRequired")); return; } if (updatedCharacter.category === 'none') { errorMessage(t("characterComponent.errorCategoryRequired")); return; } try { let characterId: string; if (isCurrentlyOffline()) { characterId = await window.electron.invoke('db:character:create', { bookId: book?.bookId, character: updatedCharacter, }); } else { characterId = await System.authPostToServer(`character/add`, { bookId: book?.bookId, character: updatedCharacter, }, session.accessToken, lang); } if (!characterId) { errorMessage(t("characterComponent.errorAddCharacter")); return; } updatedCharacter.id = characterId; setCharacters([...characters, updatedCharacter]); setSelectedCharacter(null); } catch (e: unknown) { if (e instanceof Error) { errorMessage(e.message); } else { errorMessage(t("common.unknownError")); } } } async function updateCharacter(updatedCharacter: CharacterProps,): Promise { try { let response: boolean; if (isCurrentlyOffline()) { response = await window.electron.invoke('db:character:update', { character: updatedCharacter, }); } else { response = await System.authPostToServer(`character/update`, { character: updatedCharacter, }, session.accessToken, lang); } if (!response) { errorMessage(t("characterComponent.errorUpdateCharacter")); return; } setCharacters( characters.map((char: CharacterProps): CharacterProps => char.id === updatedCharacter.id ? updatedCharacter : char, ), ); setSelectedCharacter(null); successMessage(t("characterComponent.successUpdate")); } catch (e: unknown) { if (e instanceof Error) { errorMessage(e.message); } else { errorMessage(t("common.unknownError")); } } } function handleCharacterChange( key: keyof CharacterProps, value: string, ): void { if (selectedCharacter) { setSelectedCharacter({...selectedCharacter, [key]: value}); } } async function handleAddElement( section: keyof CharacterProps, value: Attribute, ): Promise { if (selectedCharacter) { if (selectedCharacter.id === null) { const updatedSection: any[] = [ ...(selectedCharacter[section] as any[]), value, ]; setSelectedCharacter({...selectedCharacter, [section]: updatedSection}); } else { try { let attributeId: string; if (isCurrentlyOffline()) { attributeId = await window.electron.invoke('db:character:attribute:add', { characterId: selectedCharacter.id, type: section, name: value.name, }); } else { attributeId = await System.authPostToServer(`character/attribute/add`, { characterId: selectedCharacter.id, type: section, name: value.name, }, session.accessToken, lang); } if (!attributeId) { errorMessage(t("characterComponent.errorAddAttribute")); return; } const newValue: Attribute = { name: value.name, id: attributeId, }; const updatedSection: Attribute[] = [...(selectedCharacter[section] as Attribute[]), newValue,]; setSelectedCharacter({...selectedCharacter, [section]: updatedSection}); } catch (e: unknown) { if (e instanceof Error) { errorMessage(e.message); } else { errorMessage(t("common.unknownError")); } } } } } async function handleRemoveElement( section: keyof CharacterProps, index: number, attrId: string, ): Promise { if (selectedCharacter) { if (selectedCharacter.id === null) { const updatedSection: Attribute[] = ( selectedCharacter[section] as Attribute[] ).filter((_, i: number): boolean => i !== index); setSelectedCharacter({...selectedCharacter, [section]: updatedSection}); } else { try { let response: boolean; if (isCurrentlyOffline()) { response = await window.electron.invoke('db:character:attribute:delete', { attributeId: attrId, }); } else { response = await System.authDeleteToServer(`character/attribute/delete`, { attributeId: attrId, }, session.accessToken, lang); } if (!response) { errorMessage(t("characterComponent.errorRemoveAttribute")); return; } const updatedSection: Attribute[] = ( selectedCharacter[section] as Attribute[] ).filter((_, i: number): boolean => i !== index); setSelectedCharacter({ ...selectedCharacter, [section]: updatedSection, }); } catch (e: unknown) { if (e instanceof Error) { errorMessage(e.message); } else { errorMessage(t("common.unknownError")); } } } } } return (
{selectedCharacter ? ( ) : ( )}
); } export default forwardRef(CharacterComponent);