1f4b1168bSBartosz Kaszubowskiimport { SearchSmIcon, XIcon } from '@expo/styleguide-icons'; 289d2c67fSBartosz Kaszubowskiimport { Command } from 'cmdk'; 3*0a4db0c7SBartosz Kaszubowski// eslint-disable-next-line lodash/import-scope 4*0a4db0c7SBartosz Kaszubowskiimport { groupBy } from 'lodash'; 589d2c67fSBartosz Kaszubowskiimport { useEffect, useState } from 'react'; 689d2c67fSBartosz Kaszubowskiimport type { Dispatch, SetStateAction } from 'react'; 789d2c67fSBartosz Kaszubowski 889d2c67fSBartosz Kaszubowskiimport { BarLoader } from './BarLoader'; 989d2c67fSBartosz Kaszubowskiimport { CommandFooter } from './CommandFooter'; 1089d2c67fSBartosz Kaszubowskiimport { RNDirectoryItem, RNDocsItem, ExpoDocsItem, ExpoItem } from './Items'; 1189d2c67fSBartosz Kaszubowskiimport { entries } from './expoEntries'; 1289d2c67fSBartosz Kaszubowskiimport { searchIconStyle, closeIconStyle } from './styles'; 1389d2c67fSBartosz Kaszubowskiimport type { ExpoItemType, RNDirectoryItemType, AlgoliaItemType } from './types'; 1489d2c67fSBartosz Kaszubowskiimport { getExpoDocsResults, getRNDocsResults, getDirectoryResults, getItemsAsync } from './utils'; 1589d2c67fSBartosz Kaszubowski 1689d2c67fSBartosz Kaszubowskiimport { CALLOUT } from '~/ui/components/Text'; 1789d2c67fSBartosz Kaszubowski 1889d2c67fSBartosz Kaszubowskitype Props = { 1989d2c67fSBartosz Kaszubowski version: string; 2089d2c67fSBartosz Kaszubowski open: boolean; 2189d2c67fSBartosz Kaszubowski setOpen: Dispatch<SetStateAction<boolean>>; 2289d2c67fSBartosz Kaszubowski}; 2389d2c67fSBartosz Kaszubowski 2489d2c67fSBartosz Kaszubowskiexport const CommandMenu = ({ version, open, setOpen }: Props) => { 258a411220SBartosz Kaszubowski const [initialized, setInitialized] = useState(false); 2689d2c67fSBartosz Kaszubowski const [loading, setLoading] = useState(false); 2789d2c67fSBartosz Kaszubowski const [query, setQuery] = useState(''); 2889d2c67fSBartosz Kaszubowski const [expoDocsItems, setExpoDocsItems] = useState<AlgoliaItemType[]>([]); 2989d2c67fSBartosz Kaszubowski const [expoItems, setExpoItems] = useState<ExpoItemType[]>([]); 3089d2c67fSBartosz Kaszubowski const [rnDocsItems, setRnDocsItems] = useState<AlgoliaItemType[]>([]); 3189d2c67fSBartosz Kaszubowski const [directoryItems, setDirectoryItems] = useState<RNDirectoryItemType[]>([]); 3289d2c67fSBartosz Kaszubowski 3389d2c67fSBartosz Kaszubowski const getExpoDocsItems = async () => 3489d2c67fSBartosz Kaszubowski getItemsAsync(query, getExpoDocsResults, setExpoDocsItems, version); 3589d2c67fSBartosz Kaszubowski const getRNDocsItems = async () => getItemsAsync(query, getRNDocsResults, setRnDocsItems); 3689d2c67fSBartosz Kaszubowski const getDirectoryItems = async () => 3789d2c67fSBartosz Kaszubowski getItemsAsync(query, getDirectoryResults, setDirectoryItems); 3889d2c67fSBartosz Kaszubowski 3989d2c67fSBartosz Kaszubowski const getExpoItems = async () => { 4089d2c67fSBartosz Kaszubowski setExpoItems(entries.filter(entry => entry.label.toLowerCase().includes(query.toLowerCase()))); 4189d2c67fSBartosz Kaszubowski }; 4289d2c67fSBartosz Kaszubowski 4389d2c67fSBartosz Kaszubowski const dismiss = () => setOpen(false); 4489d2c67fSBartosz Kaszubowski 458a411220SBartosz Kaszubowski const fetchData = (callback: () => void) => { 4689d2c67fSBartosz Kaszubowski Promise.all([getExpoDocsItems(), getRNDocsItems(), getDirectoryItems(), getExpoItems()]).then( 478a411220SBartosz Kaszubowski callback 4889d2c67fSBartosz Kaszubowski ); 4989d2c67fSBartosz Kaszubowski }; 5089d2c67fSBartosz Kaszubowski 5189d2c67fSBartosz Kaszubowski const onQueryChange = () => { 528a411220SBartosz Kaszubowski if (open) { 5389d2c67fSBartosz Kaszubowski setLoading(true); 548a411220SBartosz Kaszubowski const inputTimeout = setTimeout(() => fetchData(() => setLoading(false)), 150); 5589d2c67fSBartosz Kaszubowski return () => clearTimeout(inputTimeout); 568a411220SBartosz Kaszubowski } 5789d2c67fSBartosz Kaszubowski }; 5889d2c67fSBartosz Kaszubowski 598a411220SBartosz Kaszubowski const onMenuOpen = () => { 608a411220SBartosz Kaszubowski if (open && !initialized) { 618a411220SBartosz Kaszubowski fetchData(() => { 628a411220SBartosz Kaszubowski setInitialized(true); 638a411220SBartosz Kaszubowski setLoading(false); 648a411220SBartosz Kaszubowski }); 658a411220SBartosz Kaszubowski } 668a411220SBartosz Kaszubowski }; 678a411220SBartosz Kaszubowski 688a411220SBartosz Kaszubowski useEffect(onMenuOpen, [open]); 6989d2c67fSBartosz Kaszubowski useEffect(onQueryChange, [query]); 7089d2c67fSBartosz Kaszubowski 7189d2c67fSBartosz Kaszubowski const totalCount = 7289d2c67fSBartosz Kaszubowski expoDocsItems.length + rnDocsItems.length + directoryItems.length + expoItems.length; 7389d2c67fSBartosz Kaszubowski 74*0a4db0c7SBartosz Kaszubowski const expoDocsGroupedItems = groupBy( 75*0a4db0c7SBartosz Kaszubowski expoDocsItems.map((expoDocsItem: AlgoliaItemType) => ({ 76*0a4db0c7SBartosz Kaszubowski ...expoDocsItem, 77*0a4db0c7SBartosz Kaszubowski baseUrl: expoDocsItem.url.replace(/#.+/, ''), 78*0a4db0c7SBartosz Kaszubowski })), 79*0a4db0c7SBartosz Kaszubowski 'baseUrl' 80*0a4db0c7SBartosz Kaszubowski ); 81*0a4db0c7SBartosz Kaszubowski 8289d2c67fSBartosz Kaszubowski return ( 8389d2c67fSBartosz Kaszubowski <Command.Dialog open={open} onOpenChange={setOpen} label="Search Menu" shouldFilter={false}> 84f4b1168bSBartosz Kaszubowski <SearchSmIcon className="text-icon-secondary" css={searchIconStyle} /> 85f4b1168bSBartosz Kaszubowski <div css={closeIconStyle}> 86f4b1168bSBartosz Kaszubowski <XIcon className="text-icon-secondary" onClick={() => setOpen(false)} /> 87f4b1168bSBartosz Kaszubowski </div> 88e5be0ff4SAman Mittal <Command.Input value={query} onValueChange={setQuery} placeholder="Search…" /> 8989d2c67fSBartosz Kaszubowski <BarLoader isLoading={loading} /> 9089d2c67fSBartosz Kaszubowski <Command.List> 918a411220SBartosz Kaszubowski {initialized && ( 928a411220SBartosz Kaszubowski <> 9389d2c67fSBartosz Kaszubowski {expoDocsItems.length > 0 && ( 9489d2c67fSBartosz Kaszubowski <Command.Group heading="Expo documentation"> 95*0a4db0c7SBartosz Kaszubowski {Object.values(expoDocsGroupedItems).map(values => 96*0a4db0c7SBartosz Kaszubowski values 97*0a4db0c7SBartosz Kaszubowski .sort((a, b) => a.url.localeCompare(a.baseUrl) - b.url.localeCompare(b.baseUrl)) 98*0a4db0c7SBartosz Kaszubowski .slice(0, 6) 99*0a4db0c7SBartosz Kaszubowski .map((item, index) => ( 1008a411220SBartosz Kaszubowski <ExpoDocsItem 101*0a4db0c7SBartosz Kaszubowski isNested={index !== 0} 1028a411220SBartosz Kaszubowski item={item} 1038a411220SBartosz Kaszubowski onSelect={dismiss} 1048a411220SBartosz Kaszubowski key={`hit-expo-docs-${item.objectID}`} 1058a411220SBartosz Kaszubowski /> 106*0a4db0c7SBartosz Kaszubowski )) 107*0a4db0c7SBartosz Kaszubowski )} 10889d2c67fSBartosz Kaszubowski </Command.Group> 10989d2c67fSBartosz Kaszubowski )} 11089d2c67fSBartosz Kaszubowski {expoItems.length > 0 && ( 11189d2c67fSBartosz Kaszubowski <Command.Group heading="Expo dashboard"> 11289d2c67fSBartosz Kaszubowski {expoItems.map((item: ExpoItemType) => ( 1138a411220SBartosz Kaszubowski <ExpoItem 1148a411220SBartosz Kaszubowski item={item} 1158a411220SBartosz Kaszubowski onSelect={dismiss} 1168a411220SBartosz Kaszubowski key={`hit-expo-${item.url}`} 1178a411220SBartosz Kaszubowski query={query} 1188a411220SBartosz Kaszubowski /> 11989d2c67fSBartosz Kaszubowski ))} 12089d2c67fSBartosz Kaszubowski </Command.Group> 12189d2c67fSBartosz Kaszubowski )} 12289d2c67fSBartosz Kaszubowski {rnDocsItems.length > 0 && ( 12389d2c67fSBartosz Kaszubowski <Command.Group heading="React Native documentation"> 12489d2c67fSBartosz Kaszubowski {rnDocsItems.map(item => ( 12589d2c67fSBartosz Kaszubowski <RNDocsItem item={item} onSelect={dismiss} key={`hit-rn-docs-${item.objectID}`} /> 12689d2c67fSBartosz Kaszubowski ))} 12789d2c67fSBartosz Kaszubowski </Command.Group> 12889d2c67fSBartosz Kaszubowski )} 12989d2c67fSBartosz Kaszubowski {directoryItems.length > 0 && ( 13089d2c67fSBartosz Kaszubowski <Command.Group heading="React Native directory"> 13189d2c67fSBartosz Kaszubowski {directoryItems.map(item => ( 13289d2c67fSBartosz Kaszubowski <RNDirectoryItem 13389d2c67fSBartosz Kaszubowski item={item} 13489d2c67fSBartosz Kaszubowski onSelect={dismiss} 13589d2c67fSBartosz Kaszubowski key={`hit-rn-dir-${item.npmPkg}`} 13689d2c67fSBartosz Kaszubowski query={query} 13789d2c67fSBartosz Kaszubowski /> 13889d2c67fSBartosz Kaszubowski ))} 13989d2c67fSBartosz Kaszubowski </Command.Group> 14089d2c67fSBartosz Kaszubowski )} 1418a411220SBartosz Kaszubowski {!loading && totalCount === 0 && ( 14289d2c67fSBartosz Kaszubowski <Command.Empty> 14389d2c67fSBartosz Kaszubowski <CALLOUT theme="secondary">No results found.</CALLOUT> 14489d2c67fSBartosz Kaszubowski </Command.Empty> 14589d2c67fSBartosz Kaszubowski )} 1468a411220SBartosz Kaszubowski </> 1478a411220SBartosz Kaszubowski )} 14889d2c67fSBartosz Kaszubowski </Command.List> 14989d2c67fSBartosz Kaszubowski <CommandFooter /> 15089d2c67fSBartosz Kaszubowski </Command.Dialog> 15189d2c67fSBartosz Kaszubowski ); 15289d2c67fSBartosz Kaszubowski}; 153