Linking backend data to frontend
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import detectorsData from '../../data/detectors.json'
|
||||
|
||||
interface Detector {
|
||||
detector_id: number
|
||||
@@ -45,12 +44,31 @@ const DetectorList: React.FC<DetectorListProps> = ({ objectId, selectedDetectors
|
||||
const [searchTerm, setSearchTerm] = useState<string>('')
|
||||
|
||||
useEffect(() => {
|
||||
const detectorsArray = Object.values(detectorsData.detectors).filter(
|
||||
(detector: RawDetector) => objectId ? detector.object === objectId : true
|
||||
)
|
||||
setDetectors(detectorsArray as Detector[])
|
||||
|
||||
|
||||
const loadDetectors = async () => {
|
||||
try {
|
||||
const res = await fetch('/api/get-detectors', { cache: 'no-store' })
|
||||
if (!res.ok) return
|
||||
const payload = await res.json()
|
||||
const detectorsData: Record<string, RawDetector> = payload?.data?.detectors ?? {}
|
||||
const rawArray: RawDetector[] = Object.values(detectorsData).filter(
|
||||
(detector) => (objectId ? detector.object === objectId : true)
|
||||
)
|
||||
const normalized: Detector[] = rawArray.map((d) => ({
|
||||
detector_id: d.detector_id,
|
||||
name: d.name,
|
||||
location: d.location,
|
||||
status: d.status,
|
||||
object: d.object,
|
||||
floor: d.floor,
|
||||
checked: false,
|
||||
}))
|
||||
console.log('[DetectorList] Payload:', payload)
|
||||
setDetectors(normalized)
|
||||
} catch (e) {
|
||||
console.error('Failed to load detectors:', e)
|
||||
}
|
||||
}
|
||||
loadDetectors()
|
||||
}, [objectId])
|
||||
|
||||
const filteredDetectors = detectors.filter(detector => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import Sidebar from '../ui/Sidebar'
|
||||
import useNavigationStore from '../../app/store/navigationStore'
|
||||
@@ -8,14 +8,34 @@ import ChartCard from './ChartCard'
|
||||
import AreaChart from './AreaChart'
|
||||
import BarChart from './BarChart'
|
||||
import DetectorChart from './DetectorChart'
|
||||
import detectorsData from '../../data/detectors.json'
|
||||
|
||||
|
||||
const Dashboard: React.FC = () => {
|
||||
const router = useRouter()
|
||||
const { currentObject, setCurrentSubmenu, closeMonitoring, closeFloorNavigation, closeNotifications } = useNavigationStore()
|
||||
const objectId = currentObject?.id
|
||||
const objectTitle = currentObject?.title
|
||||
|
||||
const [detectorsArray, setDetectorsArray] = useState<any[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
const loadDetectors = async () => {
|
||||
try {
|
||||
const res = await fetch('/api/get-detectors', { cache: 'no-store' })
|
||||
if (!res.ok) return
|
||||
const payload = await res.json()
|
||||
console.log('[Dashboard] GET /api/get-detectors', { status: res.status, payload })
|
||||
const detectorsData = payload?.data?.detectors ?? {}
|
||||
const arr = Object.values(detectorsData).filter(
|
||||
(detector: any) => (objectId ? detector.object === objectId : true)
|
||||
)
|
||||
setDetectorsArray(arr as any[])
|
||||
} catch (e) {
|
||||
console.error('Failed to load detectors:', e)
|
||||
}
|
||||
}
|
||||
loadDetectors()
|
||||
}, [objectId])
|
||||
|
||||
const handleBackClick = () => {
|
||||
router.push('/objects')
|
||||
}
|
||||
@@ -39,10 +59,6 @@ const Dashboard: React.FC = () => {
|
||||
}>
|
||||
}
|
||||
|
||||
const detectorsArray = Object.values(detectorsData.detectors).filter(
|
||||
(detector: DetectorData) => objectId ? detector.object === objectId : true
|
||||
)
|
||||
|
||||
// Статусы
|
||||
const statusCounts = detectorsArray.reduce((acc: { critical: number; warning: number; normal: number }, detector: DetectorData) => {
|
||||
if (detector.status === '#b3261e') acc.critical++
|
||||
|
||||
@@ -152,11 +152,32 @@ const ModelViewer: React.FC<ModelViewerProps> = ({
|
||||
setLoadingProgress(100)
|
||||
|
||||
console.log('GLTF Model loaded successfully!')
|
||||
console.log('\n=== Complete Model Object ===')
|
||||
console.log(result)
|
||||
console.log('\n=== Structure Overview ===')
|
||||
console.log('Meshes:', result.meshes?.length || 0)
|
||||
console.log('Transform Nodes:', result.transformNodes?.length || 0)
|
||||
console.log('\n=== IfcSensor Meshes ===')
|
||||
const sensorMeshes = (result.meshes || []).filter(m => (m.id ?? '').includes('IfcSensor'))
|
||||
console.log('IfcSensor Mesh count:', sensorMeshes.length)
|
||||
sensorMeshes.forEach(m => {
|
||||
const meta: any = (m as any).metadata
|
||||
const extras = meta?.extras ?? meta?.gltf?.extras
|
||||
console.group(`IfcSensor Mesh: ${m.id || m.name}`)
|
||||
console.log('id:', m.id)
|
||||
console.log('name:', m.name)
|
||||
console.log('uniqueId:', m.uniqueId)
|
||||
console.log('class:', typeof (m as any).getClassName === 'function' ? (m as any).getClassName() : 'Mesh')
|
||||
console.log('material:', m.material?.name)
|
||||
console.log('parent:', m.parent?.name)
|
||||
console.log('metadata:', meta)
|
||||
if (extras) console.log('extras:', extras)
|
||||
const bi = m.getBoundingInfo?.()
|
||||
const bb = bi?.boundingBox
|
||||
if (bb) {
|
||||
console.log('bounding.center:', bb.center)
|
||||
console.log('bounding.extendSize:', bb.extendSize)
|
||||
}
|
||||
const verts = (m as any).getTotalVertices?.()
|
||||
if (typeof verts === 'number') console.log('vertices:', verts)
|
||||
console.groupEnd()
|
||||
})
|
||||
|
||||
if (result.meshes.length > 0) {
|
||||
|
||||
const boundingBox = result.meshes[0].getHierarchyBoundingVectors()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { ButtonProps } from '@/app/types'
|
||||
import { ButtonProps } from '@/types'
|
||||
|
||||
const Button = ({
|
||||
onClick,
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
import React, { useState } from 'react'
|
||||
|
||||
interface ExportMenuProps {
|
||||
onExport: (format: 'csv' | 'pdf') => void
|
||||
onExport: (format: 'csv' | 'pdf', hours: number) => void
|
||||
}
|
||||
|
||||
const ExportMenu: React.FC<ExportMenuProps> = ({ onExport }) => {
|
||||
const [selectedFormat, setSelectedFormat] = useState<'csv' | 'pdf'>('csv')
|
||||
const [selectedHours, setSelectedHours] = useState<number>(168) // default: week
|
||||
|
||||
const handleExport = () => {
|
||||
onExport(selectedFormat)
|
||||
onExport(selectedFormat, selectedHours)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -40,6 +41,20 @@ const ExportMenu: React.FC<ExportMenuProps> = ({ onExport }) => {
|
||||
<span className="text-gray-300 text-sm">PDF</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 ml-4">
|
||||
<span className="text-gray-300 text-sm">Период:</span>
|
||||
<select
|
||||
className="bg-[#0e111a] text-gray-200 border border-gray-700 rounded px-2 py-1 text-sm"
|
||||
value={selectedHours}
|
||||
onChange={(e) => setSelectedHours(Number(e.target.value))}
|
||||
>
|
||||
<option value={24}>1 день</option>
|
||||
<option value={72}>3 дня</option>
|
||||
<option value={168}>Неделя</option>
|
||||
<option value={720}>Месяц</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleExport}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import toast from 'react-hot-toast'
|
||||
import { ToastProps } from '@/app/types'
|
||||
import { ToastProps } from '@/types'
|
||||
|
||||
const toastStyles = {
|
||||
success: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { TextInputProps } from '@/app/types'
|
||||
import { TextInputProps } from '@/types'
|
||||
import { HiOutlineEye, HiOutlineEyeOff } from 'react-icons/hi'
|
||||
|
||||
const TextInput = ({
|
||||
|
||||
Reference in New Issue
Block a user