turash/bugulma/frontend/components/map/HistoricalSidebarPreview.tsx
Damir Mukimov f24628a248
Some checks failed
CI/CD Pipeline / backend-build (push) Has been skipped
CI/CD Pipeline / backend-lint (push) Failing after 31s
CI/CD Pipeline / frontend-lint (push) Failing after 1m26s
CI/CD Pipeline / frontend-build (push) Has been skipped
CI/CD Pipeline / e2e-test (push) Has been skipped
fix: resolve remaining linting and React Compiler errors
- Fix prettier formatting issues in multiple components
- Fix React Compiler memoization issues in ProductServiceMarkers.tsx
- Replace literal strings with i18n keys across components
- Address i18n issues in heritage, network graph, and match components
- Fix dependency arrays in useMemo hooks to match React Compiler expectations
2025-12-25 00:25:51 +01:00

119 lines
4.1 KiB
TypeScript

import React, { useMemo } from 'react';
import { useMapActions, useMapInteraction } from '@/contexts/MapContexts.tsx';
import { useTranslation } from '@/hooks/useI18n.tsx';
import { useOrganizations } from '@/hooks/useOrganizations.ts';
import { ExternalLink } from 'lucide-react';
import { Building2 } from 'lucide-react';
import Button from '@/components/ui/Button.tsx';
import Separator from '@/components/ui/Separator.tsx';
import HistoricalContextAI from '@/components/map/HistoricalContextAI.tsx';
const InfoLine = ({ label, value }: { label: string; value?: string | React.ReactNode }) => {
if (!value) return null;
return (
<>
<dt className="text-xs text-muted-foreground">{label}</dt>
<dd className="text-sm font-medium mb-3">{value}</dd>
</>
);
};
const HistoricalSidebarPreview = () => {
const { organizations } = useOrganizations();
const { t } = useTranslation();
const { selectedLandmark: landmark } = useMapInteraction();
const { handleViewOrganization: onViewOrganization } = useMapActions();
const relatedOrg = useMemo(() => {
if (!landmark?.relatedOrgId) return null;
return organizations.find((org) => org.ID === landmark.relatedOrgId) || null;
}, [landmark, organizations]);
if (!landmark) return null;
return (
<div className="p-4 space-y-4">
{landmark.imageUrl ? (
<div className="w-full h-40 rounded-lg overflow-hidden bg-muted">
<img
src={landmark.imageUrl}
alt={landmark.name}
className="w-full h-full object-cover"
loading="lazy"
decoding="async"
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
}}
/>
</div>
) : (
<div className="w-full h-40 rounded-lg bg-muted flex items-center justify-center">
<Building2 className="h-16 h-4 text-current text-muted-foreground w-16 w-4" />
</div>
)}
<div>
<p className="text-sm text-primary">{landmark.period}</p>
<h3 className="text-lg font-semibold">{landmark.name}</h3>
</div>
<Separator />
<HistoricalContextAI landmark={landmark} />
<Separator />
<div>
<h4 className="text-base font-semibold mb-3">{t('mapSidebar.locationAndStatus')}</h4>
<dl>
<InfoLine label="Адрес" value={landmark.address} />
<InfoLine label="Текущий статус" value={landmark.currentStatus} />
{relatedOrg && (
<>
<dt className="text-xs text-muted-foreground">
{t('mapSidebar.relatedOrganization')}
</dt>
<dd className="text-sm font-medium">
{relatedOrg.Name}
<Button
size="sm"
className="w-full mt-2"
onClick={() => onViewOrganization(relatedOrg)}
>
<ExternalLink className="h-4 mr-2 text-current text-primary-foreground w-4" />
{t('mapSidebar.details.viewOrganization')}
</Button>
</dd>
</>
)}
</dl>
</div>
<Separator />
<div>
<h4 className="text-base font-semibold mb-3">{t('mapSidebar.historicalContext')}</h4>
<dl>
<InfoLine label="Основатель/Владелец" value={landmark.builder} />
<InfoLine label="Архитектор" value={landmark.architect} />
<InfoLine label="Изначальное назначение" value={landmark.originalPurpose} />
{landmark.historicalNotes && landmark.historicalNotes.length > 0 && (
<InfoLine
label="Историческая справка"
value={
<ul className="space-y-1 list-disc list-inside">
{landmark.historicalNotes.map((note, i) => (
<li key={i}>{note}</li>
))}
</ul>
}
/>
)}
</dl>
</div>
</div>
);
};
export default HistoricalSidebarPreview;