refacto react component

This commit is contained in:
Matthieu
2025-08-11 22:30:36 +02:00
parent 43ee493f9e
commit 160aea6128
10 changed files with 42 additions and 43 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react'; import { useState, useEffect } from 'react';
import { Settings, MessageSquare, Sword, Users, Code, FileText, Upload } from 'lucide-react'; import { Settings, MessageSquare, Sword, Users, Code, FileText, Upload } from 'lucide-react';
import type { NPCConfiguration, DialogueConfiguration } from './types/npc'; import type { NPCConfiguration, DialogueConfiguration } from './types/npc';
import { NPCBasicSettings } from './components/NPCBasicSettings'; import { NPCBasicSettings } from './components/NPCBasicSettings';
@@ -26,8 +26,7 @@ function App() {
const [dialogueConfig, setDialogueConfig] = useState<DialogueConfiguration | null>(null); const [dialogueConfig, setDialogueConfig] = useState<DialogueConfiguration | null>(null);
// Handle dialogue creation when interaction type changes to dialogue useEffect(() => {
React.useEffect(() => {
if (npcConfig.interaction.type === 'dialogue' && !dialogueConfig) { if (npcConfig.interaction.type === 'dialogue' && !dialogueConfig) {
const newDialogue: DialogueConfiguration = { const newDialogue: DialogueConfiguration = {
speakers: { speakers: {
@@ -49,7 +48,7 @@ function App() {
}; };
setDialogueConfig(newDialogue); setDialogueConfig(newDialogue);
} }
}, [npcConfig.interaction.type, dialogueConfig]); }, [npcConfig.interaction.type]);
const tabs = [ const tabs = [
{ id: 'basic', name: 'Basic Settings', icon: Settings }, { id: 'basic', name: 'Basic Settings', icon: Settings },

View File

@@ -1,4 +1,3 @@
import React from 'react';
import { Plus, Trash2 } from 'lucide-react'; import { Plus, Trash2 } from 'lucide-react';
import type { NPCConfiguration, MoLangConfigVariable } from '../types/npc'; import type { NPCConfiguration, MoLangConfigVariable } from '../types/npc';
@@ -7,7 +6,7 @@ interface ConfigVariablesEditorProps {
onChange: (config: NPCConfiguration) => void; onChange: (config: NPCConfiguration) => void;
} }
export const ConfigVariablesEditor: React.FC<ConfigVariablesEditorProps> = ({ config, onChange }) => { export function ConfigVariablesEditor({ config, onChange }: ConfigVariablesEditorProps) {
const addVariable = () => { const addVariable = () => {
const newVariable: MoLangConfigVariable = { const newVariable: MoLangConfigVariable = {
variableName: '', variableName: '',
@@ -166,4 +165,4 @@ export const ConfigVariablesEditor: React.FC<ConfigVariablesEditorProps> = ({ co
)} )}
</div> </div>
); );
}; }

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react'; import { useState } from 'react';
import { Plus, Trash2, MessageCircle } from 'lucide-react'; import { Plus, Trash2, MessageCircle } from 'lucide-react';
import type { DialogueConfiguration, DialoguePage, DialogueSpeaker } from '../types/npc'; import type { DialogueConfiguration, DialoguePage, DialogueSpeaker } from '../types/npc';
@@ -7,7 +7,7 @@ interface DialogueEditorProps {
onChange: (dialogue: DialogueConfiguration) => void; onChange: (dialogue: DialogueConfiguration) => void;
} }
export const DialogueEditor: React.FC<DialogueEditorProps> = ({ dialogue, onChange }) => { export function DialogueEditor({ dialogue, onChange }: DialogueEditorProps) {
const [selectedPageId, setSelectedPageId] = useState<string | null>(null); const [selectedPageId, setSelectedPageId] = useState<string | null>(null);
const [speakerEditMode, setSpeakerEditMode] = useState(false); const [speakerEditMode, setSpeakerEditMode] = useState(false);
@@ -268,9 +268,12 @@ export const DialogueEditor: React.FC<DialogueEditorProps> = ({ dialogue, onChan
<div className="font-medium text-sm">{page.id}</div> <div className="font-medium text-sm">{page.id}</div>
<div className="text-xs text-gray-500">Speaker: {page.speaker}</div> <div className="text-xs text-gray-500">Speaker: {page.speaker}</div>
<div className="text-xs text-gray-600 truncate"> <div className="text-xs text-gray-600 truncate">
{Array.isArray(page.lines) {page.lines.length > 0
? (typeof page.lines[0] === 'string' ? page.lines[0] : page.lines[0]?.text || 'Expression') ? (typeof page.lines[0] === 'string'
: (typeof page.lines === 'string' ? page.lines : page.lines?.text || 'Expression')} ? page.lines[0]
: (page.lines[0] as { text?: string }).text || 'Expression'
)
: 'No lines'}
</div> </div>
</div> </div>
<button <button
@@ -306,7 +309,7 @@ export const DialogueEditor: React.FC<DialogueEditorProps> = ({ dialogue, onChan
</div> </div>
</div> </div>
); );
}; }
interface PageEditorProps { interface PageEditorProps {
page: DialoguePage; page: DialoguePage;
@@ -314,7 +317,7 @@ interface PageEditorProps {
onChange: (page: DialoguePage) => void; onChange: (page: DialoguePage) => void;
} }
const PageEditor: React.FC<PageEditorProps> = ({ page, speakers, onChange }) => { function PageEditor({ page, speakers, onChange }: PageEditorProps) {
const updatePage = (field: keyof DialoguePage, value: any) => { const updatePage = (field: keyof DialoguePage, value: any) => {
onChange({ ...page, [field]: value }); onChange({ ...page, [field]: value });
}; };
@@ -411,4 +414,4 @@ const PageEditor: React.FC<PageEditorProps> = ({ page, speakers, onChange }) =>
</div> </div>
</div> </div>
); );
}; }

View File

@@ -1,4 +1,4 @@
import React, { useRef } from 'react'; import { useRef, useState } from 'react';
import { Upload, Download, FileText, AlertTriangle } from 'lucide-react'; import { Upload, Download, FileText, AlertTriangle } from 'lucide-react';
import type { NPCConfiguration, DialogueConfiguration } from '../types/npc'; import type { NPCConfiguration, DialogueConfiguration } from '../types/npc';
@@ -9,16 +9,16 @@ interface ImportExportProps {
onDialogueConfigLoad: (config: DialogueConfiguration) => void; onDialogueConfigLoad: (config: DialogueConfiguration) => void;
} }
export const ImportExport: React.FC<ImportExportProps> = ({ export function ImportExport({
npcConfig, npcConfig,
dialogueConfig, dialogueConfig,
onNPCConfigLoad, onNPCConfigLoad,
onDialogueConfigLoad onDialogueConfigLoad
}) => { }: ImportExportProps) {
const npcFileInputRef = useRef<HTMLInputElement>(null); const npcFileInputRef = useRef<HTMLInputElement>(null);
const dialogueFileInputRef = useRef<HTMLInputElement>(null); const dialogueFileInputRef = useRef<HTMLInputElement>(null);
const [importError, setImportError] = React.useState<string | null>(null); const [importError, setImportError] = useState<string | null>(null);
const [importSuccess, setImportSuccess] = React.useState<string | null>(null); const [importSuccess, setImportSuccess] = useState<string | null>(null);
const handleFileRead = ( const handleFileRead = (
file: File, file: File,
@@ -313,4 +313,4 @@ export const ImportExport: React.FC<ImportExportProps> = ({
</div> </div>
</div> </div>
); );
}; }

View File

@@ -1,4 +1,4 @@
import React from 'react'; import { useState } from 'react';
import { Download, Copy, Check } from 'lucide-react'; import { Download, Copy, Check } from 'lucide-react';
import type { NPCConfiguration, DialogueConfiguration } from '../types/npc'; import type { NPCConfiguration, DialogueConfiguration } from '../types/npc';
import { ValidationPanel } from './ValidationPanel'; import { ValidationPanel } from './ValidationPanel';
@@ -8,9 +8,9 @@ interface JSONPreviewProps {
dialogueConfig: DialogueConfiguration | null; dialogueConfig: DialogueConfiguration | null;
} }
export const JSONPreview: React.FC<JSONPreviewProps> = ({ npcConfig, dialogueConfig }) => { export function JSONPreview({ npcConfig, dialogueConfig }: JSONPreviewProps) {
const [copiedNPC, setCopiedNPC] = React.useState(false); const [copiedNPC, setCopiedNPC] = useState(false);
const [copiedDialogue, setCopiedDialogue] = React.useState(false); const [copiedDialogue, setCopiedDialogue] = useState(false);
const cleanNPCConfig = (config: NPCConfiguration) => { const cleanNPCConfig = (config: NPCConfiguration) => {
const cleaned = { ...config }; const cleaned = { ...config };
@@ -189,4 +189,4 @@ export const JSONPreview: React.FC<JSONPreviewProps> = ({ npcConfig, dialogueCon
</div> </div>
</div> </div>
); );
}; }

View File

@@ -1,4 +1,3 @@
import React from 'react';
import type { NPCConfiguration, NPCHitboxValue } from '../types/npc'; import type { NPCConfiguration, NPCHitboxValue } from '../types/npc';
interface NPCBasicSettingsProps { interface NPCBasicSettingsProps {
@@ -6,7 +5,7 @@ interface NPCBasicSettingsProps {
onChange: (config: NPCConfiguration) => void; onChange: (config: NPCConfiguration) => void;
} }
export const NPCBasicSettings: React.FC<NPCBasicSettingsProps> = ({ config, onChange }) => { export function NPCBasicSettings({ config, onChange }: NPCBasicSettingsProps) {
const handleChange = (field: keyof NPCConfiguration, value: any) => { const handleChange = (field: keyof NPCConfiguration, value: any) => {
onChange({ ...config, [field]: value }); onChange({ ...config, [field]: value });
}; };
@@ -196,4 +195,4 @@ export const NPCBasicSettings: React.FC<NPCBasicSettingsProps> = ({ config, onCh
</div> </div>
</div> </div>
); );
}; }

View File

@@ -1,4 +1,3 @@
import React from 'react';
import type { NPCConfiguration } from '../types/npc'; import type { NPCConfiguration } from '../types/npc';
interface NPCBattleConfigurationProps { interface NPCBattleConfigurationProps {
@@ -6,7 +5,7 @@ interface NPCBattleConfigurationProps {
onChange: (config: NPCConfiguration) => void; onChange: (config: NPCConfiguration) => void;
} }
export const NPCBattleConfiguration: React.FC<NPCBattleConfigurationProps> = ({ config, onChange }) => { export function NPCBattleConfiguration({ config, onChange }: NPCBattleConfigurationProps) {
const handleChange = (field: keyof NPCConfiguration, value: any) => { const handleChange = (field: keyof NPCConfiguration, value: any) => {
onChange({ ...config, [field]: value }); onChange({ ...config, [field]: value });
}; };
@@ -126,4 +125,4 @@ export const NPCBattleConfiguration: React.FC<NPCBattleConfigurationProps> = ({
</div> </div>
</div> </div>
); );
}; }

View File

@@ -1,4 +1,3 @@
import React from 'react';
import type { NPCConfiguration, NPCInteraction } from '../types/npc'; import type { NPCConfiguration, NPCInteraction } from '../types/npc';
interface NPCInteractionEditorProps { interface NPCInteractionEditorProps {
@@ -6,7 +5,7 @@ interface NPCInteractionEditorProps {
onChange: (config: NPCConfiguration) => void; onChange: (config: NPCConfiguration) => void;
} }
export const NPCInteractionEditor: React.FC<NPCInteractionEditorProps> = ({ config, onChange }) => { export function NPCInteractionEditor({ config, onChange }: NPCInteractionEditorProps) {
const handleInteractionChange = (interaction: NPCInteraction) => { const handleInteractionChange = (interaction: NPCInteraction) => {
onChange({ ...config, interaction }); onChange({ ...config, interaction });
}; };
@@ -112,4 +111,4 @@ export const NPCInteractionEditor: React.FC<NPCInteractionEditorProps> = ({ conf
)} )}
</div> </div>
); );
}; }

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react'; import { useState } from 'react';
import { Plus, Trash2 } from 'lucide-react'; import { Plus, Trash2 } from 'lucide-react';
import type { NPCConfiguration, NPCPartyProvider, SimplePartyProvider, PoolPartyProvider, PoolEntry } from '../types/npc'; import type { NPCConfiguration, NPCPartyProvider, SimplePartyProvider, PoolPartyProvider, PoolEntry } from '../types/npc';
@@ -7,7 +7,7 @@ interface NPCPartyBuilderProps {
onChange: (config: NPCConfiguration) => void; onChange: (config: NPCConfiguration) => void;
} }
export const NPCPartyBuilder: React.FC<NPCPartyBuilderProps> = ({ config, onChange }) => { export function NPCPartyBuilder({ config, onChange }: NPCPartyBuilderProps) {
const [partyType, setPartyType] = useState<'simple' | 'pool' | 'script'>(config.party?.type || 'simple'); const [partyType, setPartyType] = useState<'simple' | 'pool' | 'script'>(config.party?.type || 'simple');
const handlePartyChange = (party: NPCPartyProvider) => { const handlePartyChange = (party: NPCPartyProvider) => {
@@ -323,4 +323,4 @@ export const NPCPartyBuilder: React.FC<NPCPartyBuilderProps> = ({ config, onChan
{partyType === 'script' && renderScriptParty()} {partyType === 'script' && renderScriptParty()}
</div> </div>
); );
}; }

View File

@@ -1,4 +1,3 @@
import React from 'react';
import { AlertTriangle, CheckCircle, XCircle, AlertCircle } from 'lucide-react'; import { AlertTriangle, CheckCircle, XCircle, AlertCircle } from 'lucide-react';
import type { NPCConfiguration, DialogueConfiguration } from '../types/npc'; import type { NPCConfiguration, DialogueConfiguration } from '../types/npc';
import { validateNPCConfiguration, validateDialogueConfiguration, getValidationSummary } from '../utils/validation'; import { validateNPCConfiguration, validateDialogueConfiguration, getValidationSummary } from '../utils/validation';
@@ -9,14 +8,15 @@ interface ValidationPanelProps {
dialogueConfig: DialogueConfiguration | null; dialogueConfig: DialogueConfiguration | null;
} }
export const ValidationPanel: React.FC<ValidationPanelProps> = ({ npcConfig, dialogueConfig }) => { export function ValidationPanel({ npcConfig, dialogueConfig }: ValidationPanelProps) {
const npcErrors = validateNPCConfiguration(npcConfig); const npcErrors = validateNPCConfiguration(npcConfig);
const dialogueErrors = dialogueConfig ? validateDialogueConfiguration(dialogueConfig) : []; const dialogueErrors = dialogueConfig ? validateDialogueConfiguration(dialogueConfig) : [];
const allErrors = [...npcErrors, ...dialogueErrors]; const allErrors = [...npcErrors, ...dialogueErrors];
const summary = getValidationSummary(allErrors); const summary = getValidationSummary(allErrors);
const ErrorItem: React.FC<{ error: ValidationError }> = ({ error }) => ( function ErrorItem({ error }: { error: ValidationError }) {
return (
<div className={`flex items-start space-x-2 p-2 rounded ${ <div className={`flex items-start space-x-2 p-2 rounded ${
error.severity === 'error' ? 'bg-red-50 text-red-800' : 'bg-yellow-50 text-yellow-800' error.severity === 'error' ? 'bg-red-50 text-red-800' : 'bg-yellow-50 text-yellow-800'
}`}> }`}>
@@ -30,7 +30,8 @@ export const ValidationPanel: React.FC<ValidationPanelProps> = ({ npcConfig, dia
<p className="text-xs">{error.message}</p> <p className="text-xs">{error.message}</p>
</div> </div>
</div> </div>
); );
}
if (allErrors.length === 0) { if (allErrors.length === 0) {
return ( return (
@@ -123,4 +124,4 @@ export const ValidationPanel: React.FC<ValidationPanelProps> = ({ npcConfig, dia
</div> </div>
</div> </div>
); );
}; }