Newer
Older
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,
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>
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
</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">
<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>
)
}