128 lines
4.8 KiB
TypeScript
128 lines
4.8 KiB
TypeScript
'use client'
|
||
|
||
import React, { useState, useEffect } from 'react'
|
||
import ObjectGallery from '../../../components/objects/ObjectGallery'
|
||
import { ObjectData } from '../../../components/objects/ObjectCard'
|
||
import Sidebar from '../../../components/ui/Sidebar'
|
||
import { useRouter } from 'next/navigation'
|
||
|
||
// Универсальная функция для преобразования объекта из бэкенда в ObjectData
|
||
const transformRawToObjectData = (raw: any): ObjectData => {
|
||
const rawId = raw?.id ?? raw?.object_id ?? raw?.uuid ?? raw?.name
|
||
const object_id = typeof rawId === 'number' ? `object_${rawId}` : String(rawId ?? '')
|
||
return {
|
||
object_id,
|
||
title: raw?.title ?? `Объект ${object_id}`,
|
||
description: raw?.description ?? `Описание объекта ${raw?.title ?? object_id}`,
|
||
image: raw?.image ?? '/images/test_image.png',
|
||
location: raw?.location ?? raw?.address ?? 'Не указано',
|
||
floors: Number(raw?.floors ?? 0),
|
||
area: String(raw?.area ?? ''),
|
||
type: raw?.type ?? 'object',
|
||
status: raw?.status ?? 'active',
|
||
}
|
||
}
|
||
|
||
const ObjectsPage: React.FC = () => {
|
||
const [objects, setObjects] = useState<ObjectData[]>([])
|
||
const [loading, setLoading] = useState(true)
|
||
const [error, setError] = useState<string | null>(null)
|
||
const [selectedObjectId, setSelectedObjectId] = useState<string | null>(null)
|
||
const router = useRouter()
|
||
|
||
useEffect(() => {
|
||
const loadData = async () => {
|
||
setLoading(true)
|
||
setError(null)
|
||
try {
|
||
const url = '/api/get-objects'
|
||
const res = await fetch(url, { cache: 'no-store' })
|
||
const payloadText = await res.text()
|
||
let payload: any
|
||
try { payload = JSON.parse(payloadText) } catch { payload = payloadText }
|
||
console.log('[ObjectsPage] GET /api/get-objects', { status: res.status, payload })
|
||
|
||
if (!res.ok) {
|
||
const errorMessage = typeof payload === 'string' ? payload : (payload?.error || 'Не удалось получить данные объектов')
|
||
|
||
if (errorMessage.includes('Authentication required') || res.status === 401) {
|
||
console.log('[ObjectsPage] Authentication required, redirecting to login')
|
||
router.push('/login')
|
||
return
|
||
}
|
||
|
||
throw new Error(errorMessage)
|
||
}
|
||
|
||
const data = (payload?.data ?? payload) as any
|
||
let rawObjectsArray: any[] = []
|
||
if (Array.isArray(data)) {
|
||
rawObjectsArray = data
|
||
} else if (Array.isArray(data?.objects)) {
|
||
rawObjectsArray = data.objects
|
||
} else if (data && typeof data === 'object') {
|
||
// если приходит как map { id: obj }
|
||
rawObjectsArray = Object.values(data)
|
||
}
|
||
|
||
const transformedObjects = rawObjectsArray.map(transformRawToObjectData)
|
||
setObjects(transformedObjects)
|
||
} catch (err: any) {
|
||
console.error('Ошибка при загрузке данных объектов:', err)
|
||
setError(err?.message || 'Произошла неизвестная ошибка')
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
loadData()
|
||
}, [router])
|
||
|
||
const handleObjectSelect = (objectId: string) => {
|
||
console.log('Object selected:', objectId)
|
||
setSelectedObjectId(objectId)
|
||
}
|
||
|
||
if (loading) {
|
||
return (
|
||
<div className="flex items-center justify-center min-h-screen bg-[#0e111a]">
|
||
<div className="text-center">
|
||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500 mx-auto mb-4"></div>
|
||
<p className="text-white">Загрузка объектов...</p>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
if (error) {
|
||
return (
|
||
<div className="flex items-center justify-center min-h-screen bg-[#0e111a]">
|
||
<div className="text-center">
|
||
<div className="text-red-500 mb-4">
|
||
<svg className="w-12 h-12 mx-auto" fill="currentColor" viewBox="0 0 24 24">
|
||
<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>
|
||
<p className="text-[#71717a] mb-4">{error}</p>
|
||
<p className="text-sm text-gray-500">Если проблема повторяется, обратитесь к администратору</p>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
return (
|
||
<div className="flex h-screen bg-[#0e111a]">
|
||
<Sidebar activeItem={null} />
|
||
<div className="flex-1 overflow-hidden">
|
||
<ObjectGallery
|
||
objects={objects}
|
||
title="Объекты"
|
||
onObjectSelect={handleObjectSelect}
|
||
selectedObjectId={selectedObjectId}
|
||
/>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default ObjectsPage |