Files
Nitro-V3/src/components/furni-editor/FurniEditorView.tsx
T
simoleo89 535fa71020 ESLint --fix: auto-fix brace-style, indent, semi, no-trailing-spaces
Run eslint --fix across src/ to clear ~1900 mechanical lint errors
surfaced by the @typescript-eslint v8 + react-hooks v7 + react-compiler
upgrade in the React 19 modernization PR.

Issues fixed automatically:
- brace-style (Allman): try/catch one-liners reformatted to multi-line
- indent: tab-vs-space and depth corrections
- semi: missing trailing semicolons
- no-trailing-spaces

No semantic changes. Remaining 701 errors are real-code issues
(set-state-in-effect, rules-of-hooks, no-unsafe-* type checks) that
need manual per-file review.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:50 +00:00

165 lines
5.2 KiB
TypeScript

import { AddLinkEventTracker, ILinkEventTracker, RemoveLinkEventTracker } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { GetSessionDataManager } from '../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { useFurniEditor } from '../../hooks/furni-editor';
import { FurniEditorEditView } from './views/FurniEditorEditView';
import { FurniEditorSearchView } from './views/FurniEditorSearchView';
const TAB_SEARCH = 0;
const TAB_EDIT = 1;
export const FurniEditorView: FC<{}> = () =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ activeTab, setActiveTab ] = useState(TAB_SEARCH);
const {
items, total, page, loading, error, clearError,
selectedItem, setSelectedItem, furniDataEntry,
interactions,
searchItems, loadDetail, loadBySpriteId, updateItem, deleteItem, loadInteractions
} = useFurniEditor();
const isMod = GetSessionDataManager()?.isModerator;
// Auto-switch to edit tab when an item is selected
useEffect(() =>
{
if(selectedItem) setActiveTab(TAB_EDIT);
}, [ selectedItem ]);
useEffect(() =>
{
if(!isMod) return;
const linkTracker: ILinkEventTracker = {
linkReceived: (url: string) =>
{
const parts = url.split('/');
if(parts.length < 2) return;
switch(parts[1])
{
case 'show':
setIsVisible(true);
return;
case 'hide':
setIsVisible(false);
return;
case 'toggle':
setIsVisible(prev => !prev);
return;
}
},
eventUrlPrefix: 'furni-editor/'
};
AddLinkEventTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ isMod ]);
useEffect(() =>
{
if(isVisible) loadInteractions();
}, [ isVisible ]);
// Escape to close
useEffect(() =>
{
if(!isVisible) return;
const handler = (e: KeyboardEvent) =>
{
if(e.key === 'Escape') setIsVisible(false);
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, [ isVisible ]);
useEffect(() =>
{
if(!isMod) return;
const handler = (e: CustomEvent<{ spriteId: number }>) =>
{
const { spriteId } = e.detail;
setIsVisible(true);
loadBySpriteId(spriteId);
};
window.addEventListener('furni-editor:open', handler);
return () => window.removeEventListener('furni-editor:open', handler);
}, [ isMod, loadBySpriteId ]);
const handleSelect = useCallback((id: number) =>
{
loadDetail(id);
}, [ loadDetail ]);
const handleBack = useCallback(() =>
{
setSelectedItem(null);
setActiveTab(TAB_SEARCH);
}, [ setSelectedItem ]);
const handleClose = useCallback(() =>
{
setIsVisible(false);
}, []);
if(!isVisible || !isMod) return null;
return (
<NitroCardView uniqueKey="furni-editor" className="w-[620px] h-[520px]">
<NitroCardHeaderView headerText="Furni Editor" onCloseClick={ handleClose } />
<NitroCardTabsView>
<NitroCardTabsItemView isActive={ activeTab === TAB_SEARCH } onClick={ () => setActiveTab(TAB_SEARCH) }>
Search
</NitroCardTabsItemView>
<NitroCardTabsItemView isActive={ activeTab === TAB_EDIT } onClick={ () => selectedItem && setActiveTab(TAB_EDIT) }>
Edit
</NitroCardTabsItemView>
</NitroCardTabsView>
<NitroCardContentView>
{ error &&
<div className="bg-[#f8d7da] border border-[#f5c6cb] rounded p-2 text-[#721c24] text-xs mb-1 flex justify-between items-center">
<span>{ error }</span>
<span className="cursor-pointer font-bold" onClick={ clearError }>x</span>
</div>
}
{ activeTab === TAB_SEARCH &&
<FurniEditorSearchView
items={ items }
total={ total }
page={ page }
loading={ loading }
onSearch={ searchItems }
onSelect={ handleSelect }
/>
}
{ activeTab === TAB_EDIT && selectedItem &&
<FurniEditorEditView
item={ selectedItem }
furniDataEntry={ furniDataEntry }
interactions={ interactions }
loading={ loading }
onUpdate={ updateItem }
onDelete={ deleteItem }
onBack={ handleBack }
/>
}
</NitroCardContentView>
</NitroCardView>
);
};