Improved authentication; added fallbacks to 3D; cleaner dashboard charts

This commit is contained in:
iv_vuytsik
2025-10-22 21:28:10 +03:00
parent 34e84213c7
commit 932b16d4f4
18 changed files with 478 additions and 171 deletions

View File

@@ -1,4 +1,5 @@
import React from 'react'
import AuthGuard from '@/components/auth/AuthGuard'
export default function ProtectedLayout({
children,
@@ -6,8 +7,10 @@ export default function ProtectedLayout({
children: React.ReactNode
}) {
return (
<div className="protected-layout">
{children}
</div>
<AuthGuard>
<div className="protected-layout">
{children}
</div>
</AuthGuard>
)
}

View File

@@ -79,6 +79,8 @@ const NavigationPage: React.FC = () => {
const [detectorsData, setDetectorsData] = useState<{ detectors: Record<string, DetectorType> }>({ detectors: {} })
const [detectorsError, setDetectorsError] = useState<string | null>(null)
const [modelError, setModelError] = useState<string | null>(null)
const [isModelReady, setIsModelReady] = useState(false)
const urlObjectId = searchParams.get('objectId')
const urlObjectTitle = searchParams.get('objectTitle')
@@ -86,10 +88,14 @@ const NavigationPage: React.FC = () => {
const objectTitle = currentObject.title || urlObjectTitle
const handleModelLoaded = useCallback(() => {
setIsModelReady(true)
setModelError(null)
}, [])
const handleModelError = useCallback((error: string) => {
console.error('Model loading error:', error)
setModelError(error)
setIsModelReady(false)
}, [])
useEffect(() => {
@@ -131,6 +137,12 @@ const NavigationPage: React.FC = () => {
serial_number: detector.serial_number,
})
// Проверяем, что детектор имеет необходимые данные
if (!detector || !detector.detector_id || !detector.serial_number) {
console.warn('[NavigationPage] Invalid detector data, skipping menu display:', detector)
return
}
if (selectedDetector?.detector_id === detector.detector_id && showDetectorMenu) {
setShowDetectorMenu(false)
setSelectedDetector(null)
@@ -197,6 +209,7 @@ const NavigationPage: React.FC = () => {
detectorsData={detectorsData}
onDetectorMenuClick={handleDetectorMenuClick}
onClose={closeFloorNavigation}
is3DReady={isModelReady && !modelError}
/>
</div>
</div>
@@ -263,24 +276,40 @@ const NavigationPage: React.FC = () => {
<div className="flex-1 overflow-hidden">
<div className="h-full">
<ModelViewer
modelPath='/static-models/AerBIM_Monitor_ASM_HT_Viewer_Expo2017Astana_Level_+1430_custom_prop.glb'
onModelLoaded={handleModelLoaded}
onError={handleModelError}
focusSensorId={selectedDetector?.serial_number ?? null}
renderOverlay={({ anchor }) => (
selectedDetector && showDetectorMenu && anchor ? (
<DetectorMenu
detector={selectedDetector}
isOpen={true}
onClose={closeDetectorMenu}
getStatusText={getStatusText}
compact={true}
anchor={anchor}
/>
) : null
)}
/>
{modelError ? (
<div className="h-full flex items-center justify-center bg-[#0e111a]">
<div className="text-center p-8 bg-[#161824] rounded-lg border border-gray-700 max-w-md">
<div className="text-red-400 text-lg font-semibold mb-4">
Ошибка загрузки 3D модели
</div>
<div className="text-gray-300 mb-4">
{modelError}
</div>
<div className="text-sm text-gray-400">
Используйте навигацию по этажам для просмотра детекторов
</div>
</div>
</div>
) : (
<ModelViewer
modelPath='/static-models/AerBIM_Monitor_ASM_HT_Viewer_Expo2017Astana_Level_+1430_custom_prop.glb'
onModelLoaded={handleModelLoaded}
onError={handleModelError}
focusSensorId={selectedDetector?.serial_number ?? null}
renderOverlay={({ anchor }) => (
selectedDetector && showDetectorMenu && anchor ? (
<DetectorMenu
detector={selectedDetector}
isOpen={true}
onClose={closeDetectorMenu}
getStatusText={getStatusText}
compact={true}
anchor={anchor}
/>
) : null
)}
/>
)}
</div>
</div>
</div>

View File

@@ -93,14 +93,9 @@ const ObjectsPage: React.FC = () => {
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
</svg>
</div>
<h3 className="text-lg font-medium text-white mb-2">Ошибка загрузки</h3>
<h3 className="text-lg font-medium text-white mb-2">Ошибка загрузки данных</h3>
<p className="text-[#71717a] mb-4">{error}</p>
<button
onClick={() => window.location.reload()}
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-[#3193f5] hover:bg-[#2563eb] focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition-colors duration-200"
>
Попробовать снова
</button>
<p className="text-sm text-gray-500">Если проблема повторяется, обратитесь к администратору</p>
</div>
</div>
)