import { Dispatch, FC, SetStateAction, use, useCallback, useMemo, useState } from 'react'; import { Base, Grid, Flex, NitroCardView, NitroCardHeaderView, NitroCardTabsView, NitroCardTabsItemView, NitroCardContentView, Text } from '../../common'; import { useRoom } from '../../hooks'; import { GetOptionalConfigurationValue } from '../../api'; import { configFileUrl } from '../../secure-assets'; interface ItemData { id: number; } interface BackgroundsViewProps { setIsVisible: Dispatch>; selectedBackground: number; setSelectedBackground: Dispatch>; selectedStand: number; setSelectedStand: Dispatch>; selectedOverlay: number; setSelectedOverlay: Dispatch>; selectedCardBackground: number; setSelectedCardBackground: Dispatch>; selectedBorder: number; setSelectedBorder: Dispatch>; } const TABS = ['backgrounds', 'stands', 'overlays', 'cards', 'borders'] as const; type TabType = typeof TABS[number]; type RemoteData = Partial>; let backgroundsDataPromise: Promise | null = null; const fetchBackgroundsData = (): Promise => { if(backgroundsDataPromise) return backgroundsDataPromise; backgroundsDataPromise = fetch(configFileUrl('infostand_backgrounds.json'), { credentials: 'omit' }) .then(r => r.ok ? r.json() : null) .then(json => (json && typeof json === 'object') ? json as RemoteData : null) .catch(() => null); return backgroundsDataPromise; }; export const BackgroundsView: FC = ({ setIsVisible, selectedBackground, setSelectedBackground, selectedStand, setSelectedStand, selectedOverlay, setSelectedOverlay, selectedCardBackground, setSelectedCardBackground, selectedBorder, setSelectedBorder }) => { const [activeTab, setActiveTab] = useState('backgrounds'); const remoteData = use(fetchBackgroundsData()); const { roomSession } = useRoom(); const processData = useCallback((configData: any[], idField: string): ItemData[] => { if (!configData?.length) return []; return configData.map(item => ({ id: typeof item === 'number' ? item : item[idField] })); }, []); const readData = useCallback((key: 'backgrounds.data' | 'stands.data' | 'overlays.data' | 'cards.data' | 'borders.data'): any[] => { const fromRemote = remoteData?.[key]; if(Array.isArray(fromRemote)) return fromRemote; return GetOptionalConfigurationValue(key, []) || []; }, [remoteData]); const allData = useMemo(() => ({ backgrounds: processData(readData('backgrounds.data'), 'backgroundId'), stands: processData(readData('stands.data'), 'standId'), overlays: processData(readData('overlays.data'), 'overlayId'), cards: processData(readData('cards.data').length ? readData('cards.data') : readData('backgrounds.data'), 'backgroundId'), borders: processData(readData('borders.data'), 'borderId') }), [processData, readData]); const handleSelection = useCallback((id: number) => { if (!roomSession) return; const setters = { backgrounds: setSelectedBackground, stands: setSelectedStand, overlays: setSelectedOverlay, cards: setSelectedCardBackground, borders: setSelectedBorder }; const currentValues = { backgrounds: selectedBackground, stands: selectedStand, overlays: selectedOverlay, cards: selectedCardBackground, borders: selectedBorder }; setters[activeTab](id); const newValues = { ...currentValues, [activeTab]: id }; roomSession.sendBackgroundMessage( newValues.backgrounds, newValues.stands, newValues.overlays, newValues.cards, newValues.borders ); }, [activeTab, roomSession, selectedBackground, selectedStand, selectedOverlay, selectedCardBackground, selectedBorder, setSelectedBackground, setSelectedStand, setSelectedOverlay, setSelectedCardBackground, setSelectedBorder]); const itemTypeFor = (tab: TabType): string => { if(tab === 'cards') return 'card-background'; if(tab === 'borders') return 'border'; return tab.slice(0, -1); }; const renderItem = useCallback((item: ItemData, type: string) => ( handleSelection(item.id)} > ), [handleSelection]); return ( setIsVisible(false)} /> {TABS.map(tab => ( setActiveTab(tab)} > {tab.charAt(0).toUpperCase() + tab.slice(1)} ))} Select an Option {allData[activeTab].map(item => renderItem(item, itemTypeFor(activeTab)))} ); };