- Deleted redundant components (`AddActionButton`, `AlertBox`, `AlertStack`, `BackButton`, `CancelButton`, and `CollapsableArea`) and related files. - Removed unused models (`Book`, `BookSerie`, `BookTables`, `Character`, and `Chapter`) to reduce codebase clutter. - Updated project structure and references to reflect these removals.
202 lines
11 KiB
TypeScript
202 lines
11 KiB
TypeScript
import React, {useState} from 'react';
|
|
import {ChevronDown, ChevronUp, Plus, Trash2} from 'lucide-react';
|
|
import {Incident, PlotPoint} from '@/lib/types/book';
|
|
import {ActChapter, ChapterListProps} from '@/lib/types/chapter';
|
|
import SelectBox, {SelectBoxProps} from '@/components/form/SelectBox';
|
|
import ActChapterItem from './ActChapter';
|
|
import InputField from '@/components/form/InputField';
|
|
import TextInput from '@/components/form/TextInput';
|
|
import IconButton from '@/components/ui/IconButton';
|
|
import Collapse from '@/components/ui/Collapse';
|
|
import {useTranslations} from '@/lib/i18n';
|
|
|
|
interface ActPlotPointsProps {
|
|
plotPoints: PlotPoint[];
|
|
incidents: Incident[];
|
|
actId: number;
|
|
mainChapters: ChapterListProps[];
|
|
newPlotPointTitle: string;
|
|
setNewPlotPointTitle: (title: string) => void;
|
|
selectedIncidentId: string;
|
|
setSelectedIncidentId: (id: string) => void;
|
|
onAddPlotPoint: (actId: number) => Promise<void>;
|
|
onDeletePlotPoint: (actId: number, plotPointId: string) => Promise<void>;
|
|
onLinkChapter: (actId: number, chapterId: string, plotPointId: string) => Promise<void>;
|
|
onUpdateChapterSummary: (chapterId: string, summary: string, plotPointId: string) => void;
|
|
onUnlinkChapter: (chapterInfoId: string, chapterId: string, plotPointId: string) => Promise<void>;
|
|
sectionKey: string;
|
|
isExpanded: boolean;
|
|
onToggleSection: (sectionKey: string) => void;
|
|
}
|
|
|
|
export default function ActPlotPoints({
|
|
plotPoints,
|
|
incidents,
|
|
actId,
|
|
mainChapters,
|
|
newPlotPointTitle,
|
|
setNewPlotPointTitle,
|
|
selectedIncidentId,
|
|
setSelectedIncidentId,
|
|
onAddPlotPoint,
|
|
onDeletePlotPoint,
|
|
onLinkChapter,
|
|
onUpdateChapterSummary,
|
|
onUnlinkChapter,
|
|
sectionKey,
|
|
isExpanded,
|
|
onToggleSection,
|
|
}: ActPlotPointsProps) {
|
|
const t = useTranslations('actComponent');
|
|
const [expandedItems, setExpandedItems] = useState<{ [key: string]: boolean }>({});
|
|
const [selectedChapterId, setSelectedChapterId] = useState<string>('');
|
|
|
|
function toggleItem(itemKey: string): void {
|
|
setExpandedItems(prev => ({
|
|
...prev,
|
|
[itemKey]: !prev[itemKey],
|
|
}));
|
|
}
|
|
|
|
function getIncidentData(): SelectBoxProps[] {
|
|
return incidents.map((incident: Incident): SelectBoxProps => ({
|
|
value: incident.incidentId,
|
|
label: incident.title,
|
|
}));
|
|
}
|
|
|
|
return (
|
|
<Collapse title={t('plotPointsTitle')} defaultOpen={isExpanded}>
|
|
<div className="space-y-3">
|
|
{plotPoints && plotPoints.length > 0 ? (
|
|
plotPoints.map(function (item: PlotPoint): React.JSX.Element {
|
|
const itemKey: string = `plotpoint_${item.plotPointId}`;
|
|
const isItemExpanded: boolean = expandedItems[itemKey];
|
|
const linkedIncident: Incident | undefined = incidents.find(
|
|
function (inc: Incident): boolean {
|
|
return inc.incidentId === item.linkedIncidentId;
|
|
}
|
|
);
|
|
|
|
return (
|
|
<div key={`plot-point-${item.plotPointId}`}
|
|
className="bg-secondary rounded-xl overflow-hidden">
|
|
<button
|
|
className="flex justify-between items-center w-full p-3 text-left"
|
|
onClick={function (): void {
|
|
toggleItem(itemKey);
|
|
}}
|
|
>
|
|
<div>
|
|
<p className="font-bold text-text-primary">{item.title}</p>
|
|
{linkedIncident && (
|
|
<p className="text-text-secondary text-sm italic">
|
|
{t('linkedTo')}: {linkedIncident.title}
|
|
</p>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
{isItemExpanded
|
|
? <ChevronUp className="text-primary w-3.5 h-3.5" strokeWidth={1.75}/>
|
|
: <ChevronDown className="text-primary w-3.5 h-3.5" strokeWidth={1.75}/>
|
|
}
|
|
<div onClick={function (e: React.MouseEvent): void {
|
|
e.stopPropagation();
|
|
}}>
|
|
<IconButton
|
|
icon={Trash2}
|
|
variant="danger"
|
|
size="sm"
|
|
onClick={async function (): Promise<void> {
|
|
await onDeletePlotPoint(actId, item.plotPointId);
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
|
|
{isItemExpanded && (
|
|
<div className="p-3">
|
|
{item.chapters && item.chapters.length > 0 ? (
|
|
item.chapters.map(function (chapter: ActChapter): React.JSX.Element {
|
|
return (
|
|
<ActChapterItem
|
|
key={`plot-chapter-${chapter.chapterId}-${chapter.chapterInfoId}`}
|
|
chapter={chapter}
|
|
onUpdateSummary={function (chapterId: string, summary: string): void {
|
|
onUpdateChapterSummary(chapterId, summary, item.plotPointId);
|
|
}}
|
|
onUnlink={function (chapterInfoId: string, chapterId: string): Promise<void> {
|
|
return onUnlinkChapter(chapterInfoId, chapterId, item.plotPointId);
|
|
}}
|
|
/>
|
|
);
|
|
})
|
|
) : (
|
|
<p className="text-text-secondary text-center text-sm p-2">
|
|
{t('noLinkedChapter')}
|
|
</p>
|
|
)}
|
|
|
|
<InputField
|
|
input={
|
|
<SelectBox
|
|
onChangeCallBack={function (e: React.ChangeEvent<HTMLSelectElement>): void {
|
|
setSelectedChapterId(e.target.value);
|
|
}}
|
|
data={mainChapters.map(function (chapter: ChapterListProps): SelectBoxProps {
|
|
return {
|
|
label: `${chapter.chapterOrder}. ${chapter.title}`,
|
|
value: chapter.chapterId,
|
|
};
|
|
})}
|
|
defaultValue={selectedChapterId}
|
|
placeholder={t('selectChapterPlaceholder')}
|
|
/>
|
|
}
|
|
addButtonCallBack={function (): Promise<void> {
|
|
return onLinkChapter(actId, selectedChapterId, item.plotPointId);
|
|
}}
|
|
isAddButtonDisabled={!selectedChapterId}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
})
|
|
) : (
|
|
<p className="text-text-secondary text-center text-sm p-2">
|
|
{t('noPlotPointAdded')}
|
|
</p>
|
|
)}
|
|
|
|
<div className="space-y-2">
|
|
<TextInput
|
|
value={newPlotPointTitle}
|
|
setValue={function (e: React.ChangeEvent<HTMLInputElement>): void {
|
|
setNewPlotPointTitle(e.target.value);
|
|
}}
|
|
placeholder={t('newPlotPointPlaceholder')}
|
|
/>
|
|
<InputField
|
|
input={
|
|
<SelectBox
|
|
defaultValue=""
|
|
onChangeCallBack={function (e: React.ChangeEvent<HTMLSelectElement>): void {
|
|
setSelectedIncidentId(e.target.value);
|
|
}}
|
|
data={getIncidentData()}
|
|
/>
|
|
}
|
|
actionIcon={Plus}
|
|
addButtonCallBack={function (): Promise<void> {
|
|
return onAddPlotPoint(actId);
|
|
}}
|
|
isAddButtonDisabled={newPlotPointTitle.trim() === ''}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Collapse>
|
|
);
|
|
}
|