Skip to content
Snippets Groups Projects
device.view.table.tsx 4.73 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { faChevronDown } from "@fortawesome/free-solid-svg-icons";
    import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
    
    import { insertMarkTags } from "@helper/text";
    
    import { useAppSelector } from "@hooks";
    
    import DOMPurify from 'dompurify';
    
    import { RefObject, useCallback, useRef, useState } from 'react';
    import { Collapse, OverlayTrigger, Tooltip } from 'react-bootstrap';
    
    import { useTranslation } from "react-i18next";
    
    import { Device } from "../reducer/device.reducer";
    
    import { useDeviceTableViewModel } from "../view_model/device.table.viewmodel";
    
    import { DeviceListCollapsable } from "./subcomponent/device.view.list-detail";
    
    const cropUUID = (uuid: string): string => {
        return uuid.substring(0, 3) + "..." + uuid.substring(uuid.length - 3, uuid.length);
    
    export const DeviceList = ({ searchRef }: { searchRef: RefObject<HTMLInputElement> }) => {
    
        const { devices, pnds, selected: selectedDevice } = useAppSelector(state => state.device);
    
        const { t } = useTranslation('common');
    
        const [expandedId, setExpandedId] = useState<string | null | undefined>(null);
        const listRef = useRef<HTMLDivElement>(null);
        const { dispatchDevice } = useDeviceTableViewModel(searchRef, listRef);
    
        const handleItemClick = useCallback((device: Device) => {
            dispatchDevice(device)
    
            const { id } = device
            setExpandedId(expandedId === id ? null : id);
        }, [expandedId]);
    
        const getDeviceList = useCallback(() => {
            const search = searchRef?.current?.value;
            let filtered = devices;
    
            if (search) {
                filtered = devices.filter((device) => {
                    const user = pnds.find(pnd => pnd.id === device.pid);
                    return device.id?.includes(search) ||
                        device.name?.includes(search) ||
                        user?.name?.includes(search);
    
            return filtered.map((device) => {
    
                const user = pnds.find(pnd => pnd.id === device.pid);
    
                const username = user?.name || '';
    
                const deviceId = device.id!;
    
                const croppedId = cropUUID(deviceId);
    
                const devicename = device.name || '';
    
                const isExpanded = expandedId === deviceId;
                const isSelected = selectedDevice?.device.id === deviceId;
    
                return (
    
                        className={`border-bottom border-primary p-2 transitions ${isSelected && 'bg-gradient-fade py-2'} ${!isSelected && 'text-disabled disabled-hover'}`}
                        onClick={() => !isExpanded && handleItemClick(device)}
    
                    >
                        <div
                            aria-expanded={isExpanded}
    
                            className="d-flex justify-content-between py-2 clickable"
                            onClick={() => isExpanded && handleItemClick(device)}
                        >
    
                            <FontAwesomeIcon icon={faChevronDown} rotation={isExpanded ? undefined : 270} />
                            <span dangerouslySetInnerHTML={{
                                __html: search ? insertMarkTags(devicename, search) : DOMPurify.sanitize(devicename)
                            }} />
                            <OverlayTrigger overlay={<Tooltip id={deviceId}>{deviceId}</Tooltip>}>
                                <span className="text-gray-500" dangerouslySetInnerHTML={{
                                    __html: search ? insertMarkTags(croppedId, search) : DOMPurify.sanitize(croppedId)
                                }} />
                            </OverlayTrigger>
                            <span className="text-gray-500" dangerouslySetInnerHTML={{
                                __html: search ? insertMarkTags(username, search) : DOMPurify.sanitize(username)
                            }} />
                        </div>
    
                        <Collapse in={isExpanded}>
                            <div>
                                <DeviceListCollapsable deviceId={deviceId} username={username} search={search} />
                            </div>
                        </Collapse>
                    </div>
                );
            });
        }, [devices, searchRef, pnds, selectedDevice, expandedId, handleItemClick]);
    
            <div className="rounded border border-primary mt-2">
    
                <div className="border-bottom border-primary d-flex justify-content-between px-4 py-2 clickable">
    
                    <FontAwesomeIcon icon={faChevronDown} className="opacity-0" />
                    <span className="font-medium">{t('device.table.header.name')}</span>
                    <span className="font-medium">{t('device.table.header.uuid')}</span>
                    <span className="font-medium">{t('device.table.header.user')}</span>
                </div>
                <div ref={listRef}>{getDeviceList()}</div>
            </div>
        );
    };