Skip to content
Snippets Groups Projects
devices.box.view.tsx 6.83 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { useDeviceBoxViewModel } from '@component/devices/view_model/device.box.viewmodel'
    
    import { faPenToSquare, faPlus, faTrashCan } from '@fortawesome/free-solid-svg-icons'
    
    import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
    import { insertMarkTags } from '@helper/text'
    import { Scrollbar } from '@shared/components/scrollbar/Scrollbar.view'
    import DOMPurify from 'dompurify'
    import { RefObject, useCallback } from 'react'
    import { Button, Col, Form, OverlayTrigger, Row, Tooltip } from 'react-bootstrap'
    import { useTranslation } from 'react-i18next'
    import { Device } from '../../reducer/device.reducer'
    import AddDeviceModal from '../subcomponent/modal.view'
    
    export const DeviceList = ({ searchRef }: { searchRef: RefObject<HTMLInputElement> }) => {
        const { t } = useTranslation('common')
        const {
            filteredDevices,
            handleItemClick,
            selectedDevice,
            pnds,
            addModal,
            openAddModal,
            closeModal,
            searchValue,
            handleSearch,
    
            removeDevice,
        } = useDeviceBoxViewModel()
    
    
        const cropUUID = (uuid: string): string => {
            return uuid.substring(0, 3) + '...' + uuid.substring(uuid.length - 3, uuid.length)
        }
    
        const renderDeviceItem = useCallback(
            (device: 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 isSelected = selectedDevice?.device.id === deviceId
    
                return (
                    <div
                        key={deviceId}
                        className={`border-bottom border-primary p-2 transitions ${
                            isSelected && 'bg-gradient-fade py-2'
                        } ${!isSelected && 'text-disabled disabled-hover'}`}
                        onClick={() => handleItemClick(device)}>
    
                        <Row className="align-items-center clickable device-row">
                            <Col xs={12} sm={4}>
    
                                <span
                                    dangerouslySetInnerHTML={{
                                        __html: searchValue
                                            ? insertMarkTags(devicename, searchValue)
                                            : DOMPurify.sanitize(devicename),
                                    }}
                                />
                            </Col>
                            <Col xs={12} sm={3}>
                                <OverlayTrigger overlay={<Tooltip id={deviceId}>{deviceId}</Tooltip>}>
                                    <span
                                        className="text-gray-500"
                                        dangerouslySetInnerHTML={{
                                            __html: searchValue
                                                ? insertMarkTags(croppedId, searchValue)
                                                : DOMPurify.sanitize(croppedId),
                                        }}
                                    />
                                </OverlayTrigger>
                            </Col>
                            <Col xs={12} sm={4}>
                                <span
                                    className="text-gray-500"
                                    dangerouslySetInnerHTML={{
                                        __html: searchValue
                                            ? insertMarkTags(username, searchValue)
                                            : DOMPurify.sanitize(username),
                                    }}
                                />
                            </Col>
    
                            <Col xs={12} sm={1}>
                                <div className="d-flex icons justify-content-end align-items-center">
                                    <FontAwesomeIcon icon={faPenToSquare} size="sm" />
                                    <FontAwesomeIcon
                                        icon={faTrashCan}
                                        size="sm"
                                        onClick={() => removeDevice(device)}
                                    />
                                </div>
                            </Col>
    
                        </Row>
                    </div>
                )
            },
            [selectedDevice, pnds, handleItemClick, searchValue],
        )
    
        return (
            <div className="d-flex flex-column h-100">
                {/* Fixed top section */}
                <div className="flex-shrink-0">
                    <Row className="mb-3 align-items-center">
                        <Col xs={12} md={6} lg={8}>
                            <Form.Group controlId="device.search">
                                <Form.Control
                                    type="text"
                                    placeholder={t('device.search.placeholder')}
                                    ref={searchRef}
                                    value={searchValue}
                                    onChange={e => handleSearch(e.target.value)}
                                />
                            </Form.Group>
                        </Col>
                        <Col xs={12} md={6} lg={4} className="mt-3 mt-md-0 text-md-end">
                            <Button
                                variant="primary::button"
                                className="btn-primary-button"
                                onClick={openAddModal}>
                                <FontAwesomeIcon icon={faPlus} className="me-2" />
                                {t('device.add_device_button')}
                            </Button>
    
                            <AddDeviceModal show={addModal} onHide={closeModal} />
                        </Col>
                    </Row>
                </div>
    
                {/* Scrollable list section */}
                <Scrollbar className="flex-grow-1 overflow-y-auto overflow-x-hidden" scrollX={false}>
                    <div className="rounded border border-primary">
                        {/* Fixed header */}
                        <div className="sticky-top bg-white border-bottom border-primary">
                            <Row className="px-2 py-2 mx-0">
    
                                <Col xs={12} sm={4}>
    
                                    <span className="font-medium">{t('device.table.header.name')}</span>
                                </Col>
                                <Col xs={12} sm={3}>
                                    <span className="font-medium">{t('device.table.header.uuid')}</span>
                                </Col>
                                <Col xs={12} sm={4}>
                                    <span className="font-medium">{t('device.table.header.user')}</span>
                                </Col>
                            </Row>
                        </div>
    
                        {/* Scrollable content */}
                        <div className="device-list-content">
                            {filteredDevices.map(renderDeviceItem)}
                        </div>
                    </div>
                </Scrollbar>
            </div>
        )
    }