257 lines
6.6 KiB
JavaScript

// SpotlightTooltip.js
import PropTypes from 'prop-types'
import {
message,
Descriptions,
Card,
Flex,
Typography,
Skeleton,
Spin,
Badge
} from 'antd'
import { LoadingOutlined, ExportOutlined } from '@ant-design/icons'
import React, { useEffect, useState, useContext, useCallback } from 'react'
import axios from 'axios'
import { AuthContext } from '../context/AuthContext'
import config from '../../../config'
import IdText from './IdText'
import TimeDisplay from './TimeDisplay'
import { Tag } from 'antd'
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
import PrinterState from './PrinterState'
import JobState from './JobState'
import FilamentStockState from './FilamentStockState'
import SubJobState from './SubJobState'
const { Text, Link } = Typography
const SpotlightTooltip = ({ query, type }) => {
const [spotlightData, setSpotlightData] = useState(null)
const [loading, setLoading] = useState(true)
const [messageApi] = message.useMessage()
const { authenticated } = useContext(AuthContext)
const fetchSpotlightData = useCallback(async () => {
if (!authenticated) {
return
}
setLoading(true)
try {
const response = await axios.get(
`${config.backendUrl}/spotlight/${query}`,
{
headers: {
Accept: 'application/json'
},
withCredentials: true // Important for including cookies
}
)
setSpotlightData(response.data)
setLoading(false)
} catch (error) {
setLoading(false)
if (error.response) {
messageApi.error(
`Error fetching spotlight data: ${error.response.status}`
)
} else {
messageApi.error(
'An unexpected error occurred. Please try again later.'
)
}
}
}, [authenticated, messageApi, query])
useEffect(() => {
if (authenticated) {
fetchSpotlightData()
}
}, [authenticated, fetchSpotlightData])
if (!spotlightData && !loading) {
return (
<Card className='spotlight-tooltip'>
<Flex
justify='center'
gap={'small'}
style={{ height: '100%', minWidth: '270px' }}
align='center'
>
<Text type='secondary'>
<InfoCircleIcon />
</Text>
<Text type='secondary'>No spotlight data.</Text>
</Flex>
</Card>
)
}
// Helper to render value nicely
const renderValue = (key, value) => {
if (key === '_id' || key === 'id') {
return (
<IdText
id={value}
type={type}
showCopy={true}
longId={false}
showSpotlight={false}
/>
)
}
if (key === 'state') {
if (type === 'printer') {
return (
<PrinterState
printer={spotlightData}
showControls={false}
showPrinterName={false}
/>
)
}
if (type === 'job') {
return (
<JobState job={spotlightData} showId={false} showQuantity={false} />
)
}
if (type === 'subjob') {
return (
<SubJobState
subJob={spotlightData}
showId={false}
showQuantity={false}
/>
)
}
if (type === 'filamentstock') {
return (
<FilamentStockState
filamentStock={spotlightData}
showProgress={false}
/>
)
}
}
if (key === 'tags' && Array.isArray(value)) {
if (value.length == 0) {
return <Text>n/a</Text>
}
return value.map((tag) => (
<Tag key={tag} color='blue'>
{tag}
</Tag>
))
}
if (key === 'email') {
return (
<Link href={`mailto:${value}`}>
{value + ' '}
<ExportOutlined />
</Link>
)
}
if (key === 'color') {
return <Badge color={value} text={value} />
}
if (
typeof value === 'string' &&
value.match(/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}/)
) {
// Format ISO date strings
return (
<TimeDisplay
dateTime={value}
showDate={true}
showTime={true}
showSince={true}
/>
)
}
if (Array.isArray(value)) {
return value.join(', ')
}
if (typeof value === 'object' && value !== null) {
// For nested objects, show JSON string
return JSON.stringify(value)
}
if (value == '' || value.length == 0) {
return <Text>n/a</Text>
}
if (value != null) {
return <Text>{value.toString()}</Text>
}
return <Text>n/a</Text>
}
// Map of property names to user-friendly labels
const LABEL_MAP = {
name: 'Name',
state: 'State',
tags: 'Tags',
email: 'Email',
updatedAt: 'Updated At',
_id: 'ID'
// Add more mappings as needed
}
return (
<div className='spotlight-tooltip'>
<Spin indicator={<LoadingOutlined />} spinning={loading}>
<Descriptions bordered column={1} size='small'>
{loading ? (
<>
<Descriptions.Item
label={
<Skeleton.Input active size='small' style={{ width: 80 }} />
}
>
<Skeleton.Input active size='small' style={{ width: 120 }} />
</Descriptions.Item>
<Descriptions.Item
label={
<Skeleton.Input active size='small' style={{ width: 80 }} />
}
>
<Skeleton.Input active size='small' style={{ width: 120 }} />
</Descriptions.Item>
<Descriptions.Item
label={
<Skeleton.Input active size='small' style={{ width: 80 }} />
}
>
<Skeleton.Input active size='small' style={{ width: 120 }} />
</Descriptions.Item>
</>
) : (
Object.entries(spotlightData).map(([key, value]) =>
value !== undefined && value !== null && value !== '' ? (
<Descriptions.Item
key={key}
label={
LABEL_MAP[key] || key.charAt(0).toUpperCase() + key.slice(1)
}
>
{renderValue(
key,
key === 'state' && value.type ? value.type : value
)}
</Descriptions.Item>
) : null
)
)}
</Descriptions>
</Spin>
</div>
)
}
SpotlightTooltip.propTypes = {
query: PropTypes.string.isRequired,
type: PropTypes.string.isRequired
}
export default SpotlightTooltip