264 lines
9.8 KiB
TypeScript
264 lines
9.8 KiB
TypeScript
'use client';
|
|
import React, {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";
|
|
|
|
interface CharacterDetailProps {
|
|
selectedCharacter: CharacterProps | null;
|
|
setSelectedCharacter: Dispatch<SetStateAction<CharacterProps | null>>;
|
|
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<LangContextProps>(LangContext)
|
|
const {session} = useContext(SessionContext);
|
|
const {book} = useContext(BookContext);
|
|
const {errorMessage, successMessage} = useContext(AlertContext);
|
|
const [characters, setCharacters] = useState<CharacterProps[]>([]);
|
|
const [selectedCharacter, setSelectedCharacter] = useState<CharacterProps | null>(null);
|
|
|
|
useImperativeHandle(ref, function () {
|
|
return {
|
|
handleSave: handleSaveCharacter,
|
|
};
|
|
});
|
|
|
|
useEffect((): void => {
|
|
getCharacters().then();
|
|
}, []);
|
|
|
|
async function getCharacters(): Promise<void> {
|
|
try {
|
|
const response: CharacterProps[] = await System.authGetQueryToServer<CharacterProps[]>(`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<void> {
|
|
if (selectedCharacter) {
|
|
const updatedCharacter: CharacterProps = {...selectedCharacter};
|
|
if (selectedCharacter.id === null) {
|
|
await addNewCharacter(updatedCharacter);
|
|
} else {
|
|
await updateCharacter(updatedCharacter);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function addNewCharacter(updatedCharacter: CharacterProps): Promise<void> {
|
|
if (!updatedCharacter.name) {
|
|
errorMessage(t("characterComponent.errorNameRequired"));
|
|
return;
|
|
}
|
|
if (updatedCharacter.category === 'none') {
|
|
errorMessage(t("characterComponent.errorCategoryRequired"));
|
|
return;
|
|
}
|
|
try {
|
|
const characterId: string = await System.authPostToServer<string>(`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<void> {
|
|
try {
|
|
const response: boolean = await System.authPostToServer<boolean>(`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<void> {
|
|
if (selectedCharacter) {
|
|
if (selectedCharacter.id === null) {
|
|
const updatedSection: any[] = [
|
|
...(selectedCharacter[section] as any[]),
|
|
value,
|
|
];
|
|
setSelectedCharacter({...selectedCharacter, [section]: updatedSection});
|
|
} else {
|
|
try {
|
|
const attributeId: string = await System.authPostToServer<string>(`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<void> {
|
|
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 {
|
|
const response: boolean = await System.authDeleteToServer<boolean>(`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 (
|
|
<div className="space-y-5">
|
|
{selectedCharacter ? (
|
|
<CharacterDetail
|
|
selectedCharacter={selectedCharacter}
|
|
setSelectedCharacter={setSelectedCharacter}
|
|
handleAddElement={handleAddElement}
|
|
handleRemoveElement={handleRemoveElement}
|
|
handleCharacterChange={handleCharacterChange}
|
|
handleSaveCharacter={handleSaveCharacter}
|
|
/>
|
|
) : (
|
|
<CharacterList
|
|
characters={characters}
|
|
handleAddCharacter={handleAddCharacter}
|
|
handleCharacterClick={handleCharacterClick}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default forwardRef(CharacterComponent); |