import { Box, Icon, Table, Tag, TextInput } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import React, { useCallback, useState, useEffect, useContext, useMemo, memo } from 'react'; import AppAvatar from '../../components/basic/avatar/AppAvatar'; import GenericTable from '../../components/GenericTable'; import { useRoute } from '../../contexts/RouterContext'; import { useTranslation } from '../../contexts/TranslationContext'; import { useResizeInlineBreakpoint } from '../../hooks/useResizeInlineBreakpoint'; import { useFilteredApps } from './hooks/useFilteredApps'; import AppMenu from './AppMenu'; import AppStatus from './AppStatus'; import PriceDisplay from './PriceDisplay'; import { AppDataContext } from './AppProvider'; const FilterByText = React.memo(({ setFilter, ...props }) => { const t = useTranslation(); const [text, setText] = useState(''); const handleChange = useCallback((event) => setText(event.currentTarget.value), []); useEffect(() => { setFilter({ text }); }, [setFilter, text]); return e.preventDefault(), [])} display='flex' flexDirection='column' {...props}> } onChange={handleChange} value={text} /> ; }); const MarketplaceRow = memo(function MarketplaceRow({ medium, large, ...props }) { const { author: { name: authorName }, name, id, description, categories, purchaseType, pricingPlans, price, iconFileData, marketplaceVersion, iconFileContent, installed, } = props; const t = useTranslation(); const [isFocused, setFocused] = useState(false); const [isHovered, setHovered] = useState(false); const isStatusVisible = isFocused || isHovered; const marketplaceRoute = useRoute('admin-marketplace'); const handleClick = () => { marketplaceRoute.push({ context: 'details', version: marketplaceVersion, id, }); }; const handleKeyDown = (e) => { if (!['Enter', 'Space'].includes(e.nativeEvent.code)) { return; } handleClick(); }; const preventClickPropagation = (e) => { e.stopPropagation(); }; return setFocused(true)} onBlur={() => setFocused(false)} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} > {name} {`${ t('By') } ${ authorName }`} {large && {description} {categories && {categories.map((current) => {current})} } } {medium && } {installed && } ; }); function MarketplaceTable() { const t = useTranslation(); const [ref, onLargeBreakpoint, onMediumBreakpoint] = useResizeInlineBreakpoint([800, 600], 200); const [params, setParams] = useState({ text: '', current: 0, itemsPerPage: 25 }); const [sort, setSort] = useState(['name', 'asc']); const { text, current, itemsPerPage } = params; const { data, dataCache, finishedLoading } = useContext(AppDataContext); const [filteredApps, filteredAppsCount] = useFilteredApps({ filterFunction: useCallback( (text) => ({ name, marketplace }) => marketplace !== false && name.toLowerCase().indexOf(text.toLowerCase()) > -1, [], ), text: useDebouncedValue(text, 500), current, itemsPerPage, sort: useDebouncedValue(sort, 200), data: useMemo( () => (data.length ? data : null), [dataCache], ), dataCache, }); const [sortBy, sortDirection] = sort; const onHeaderCellClick = (id) => { setSort( ([sortBy, sortDirection]) => ( sortBy === id ? [id, sortDirection === 'asc' ? 'desc' : 'asc'] : [id, 'asc'] ), ); }; return {t('Name')} {onLargeBreakpoint && {t('Details')} } {onMediumBreakpoint && {t('Price')} } {t('Status')} } results={(filteredApps?.length || finishedLoading) && filteredApps} total={filteredAppsCount} setParams={setParams} params={params} FilterComponent={FilterByText} > {(props) => } ; } export default MarketplaceTable;