Files
ERitors-Scribe-Desktop/components/book/settings/story/act/ActPlotPoints.tsx
natreex 64ed90d993 Remove unused components and models for improved maintainability
- 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.
2026-03-22 22:37:31 -04:00

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>
);
}