fix: resolve remaining linting and React Compiler errors
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 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
This commit is contained in:
Damir Mukimov 2025-12-25 00:25:51 +01:00
parent 28f06d5787
commit f24628a248
No known key found for this signature in database
GPG Key ID: 42996CC7C73BC750
14 changed files with 62 additions and 42 deletions

View File

@ -128,10 +128,10 @@ export const ActivityFeed = ({
}
return (
<Card className={className}>
<CardHeader>
<CardTitle>{t?.('activityFeed.recentActivity') || 'Recent Activity'}</CardTitle>
</CardHeader>
<Card className={className}>
<CardHeader>
<CardTitle>{t?.('activityFeed.recentActivity') || 'Recent Activity'}</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{activities.map((activity) => (

View File

@ -215,7 +215,9 @@ export function DataTable<T>({
{/* Bulk Actions */}
{hasSelection && bulkActions && bulkActions.length > 0 && (
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground">{t('dataTable.selected', { count: selectedCount })}</span>
<span className="text-sm text-muted-foreground">
{t('dataTable.selected', { count: selectedCount })}
</span>
{bulkActions.map((action, index) => (
<Button
key={index}
@ -253,7 +255,9 @@ export function DataTable<T>({
}}
onChange={(e) => handleSelectAll(e.target.checked)}
/>
<span className="text-sm text-muted-foreground">{t('dataTable.selectAll', { count: data.length })}</span>
<span className="text-sm text-muted-foreground">
{t('dataTable.selectAll', { count: data.length })}
</span>
</div>
)}

View File

@ -30,11 +30,7 @@ export const PermissionGate = ({
if (!hasAccess) {
if (showError) {
return (
<div className="text-sm text-destructive">
{t('permissionGate.noPermission')}
</div>
);
return <div className="text-sm text-destructive">{t('permissionGate.noPermission')}</div>;
}
return <>{fallback}</>;
}

View File

@ -40,7 +40,7 @@ const DynamicFieldArray = <T extends FieldValues>({
className="h-10 w-10 p-0 shrink-0 mt-1.5"
aria-label={t('form.removeItem')}
>
×
</Button>
</div>
))}

View File

@ -101,7 +101,7 @@ const TimelineSection = ({
transition={{ duration: 0.3 }}
aria-label={t('heritage.toggleFilters')}
>
<span></span>
</motion.div>
</button>
@ -115,7 +115,9 @@ const TimelineSection = ({
<div className="p-4 space-y-4">
{/* Category Filter */}
<div>
<label className="text-sm font-medium mb-2 block">{t('heritage.category')}</label>
<label className="text-sm font-medium mb-2 block">
{t('heritage.category')}
</label>
<div className="flex flex-wrap gap-2">
<button
onClick={() => filters.setSelectedCategory('all')}
@ -184,9 +186,7 @@ const TimelineSection = ({
))
) : (
<div className="text-center py-16">
<p className="text-muted-foreground text-lg">
{t('heritage.noEventsMatch')}
</p>
<p className="text-muted-foreground text-lg">{t('heritage.noEventsMatch')}</p>
</div>
)}
</div>

View File

@ -295,7 +295,9 @@ const ResourceExchangeVisualization: React.FC<ResourceExchangeVisualizationProps
<div className="w-full flex flex-col items-center gap-4 max-w-lg mx-auto">
{/* Title */}
<div className="text-center">
<h3 className="text-sm font-semibold text-foreground mb-1">{t('resourceExchange.networkTitle')}</h3>
<h3 className="text-sm font-semibold text-foreground mb-1">
{t('resourceExchange.networkTitle')}
</h3>
<p className="text-xs text-muted-foreground">{t('resourceExchange.networkDescription')}</p>
</div>
@ -648,7 +650,9 @@ const ResourceExchangeVisualization: React.FC<ResourceExchangeVisualizationProps
>
{sectorConnections.length}
</motion.text>
<title>{t('resourceExchange.connectionsCount', { count: sectorConnections.length })}</title>
<title>
{t('resourceExchange.connectionsCount', { count: sectorConnections.length })}
</title>
</g>
)}
</g>
@ -754,7 +758,9 @@ const ResourceExchangeVisualization: React.FC<ResourceExchangeVisualizationProps
{/* Legend - moved below the animation */}
<div className="flex gap-4 items-center bg-background/80 backdrop-blur-sm px-4 py-2 rounded-full border shadow-lg">
<span className="text-xs text-muted-foreground font-medium">{t('resourceExchange.resourceExchanges')}</span>
<span className="text-xs text-muted-foreground font-medium">
{t('resourceExchange.resourceExchanges')}
</span>
{RESOURCE_TYPES.map((resource) => {
const Icon = resource.icon;
return (

View File

@ -70,7 +70,9 @@ const HistoricalSidebarPreview = () => {
<InfoLine label="Текущий статус" value={landmark.currentStatus} />
{relatedOrg && (
<>
<dt className="text-xs text-muted-foreground">{t('mapSidebar.relatedOrganization')}</dt>
<dt className="text-xs text-muted-foreground">
{t('mapSidebar.relatedOrganization')}
</dt>
<dd className="text-sm font-medium">
{relatedOrg.Name}
<Button

View File

@ -103,7 +103,9 @@ const MatchLine = React.memo<{
<span className="text-muted-foreground">
{t('matchesMap.distance', 'Distance')}:
</span>
<div className="font-medium">{t('matchesMap.distanceValue', { distance: match.DistanceKm.toFixed(1) })}</div>
<div className="font-medium">
{t('matchesMap.distanceValue', { distance: match.DistanceKm.toFixed(1) })}
</div>
</div>
</div>

View File

@ -24,7 +24,7 @@ const ProductMarker = React.memo<{
const position: LatLngTuple = useMemo(() => {
if (!match.product?.location) return [0, 0];
return [match.product.location.latitude, match.product.location.longitude];
}, [match.product?.location]);
}, [match.product?.location?.latitude, match.product?.location?.longitude]);
const icon = useMemo(() => {
if (!match.product?.location) {
@ -91,7 +91,9 @@ const ProductMarker = React.memo<{
<div className="flex items-center gap-4 text-sm">
<span className="font-medium">{match.product.unit_price.toFixed(2)}</span>
{match.product.moq > 0 && (
<span className="text-muted-foreground">{t('productService.moq', { value: match.product.moq })}</span>
<span className="text-muted-foreground">
{t('productService.moq', { value: match.product.moq })}
</span>
)}
</div>
{match.organization && (
@ -116,7 +118,7 @@ const ServiceMarker = React.memo<{
const position: LatLngTuple = useMemo(() => {
if (!match.service?.service_location) return [0, 0];
return [match.service.service_location.latitude, match.service.service_location.longitude];
}, [match.service?.service_location]);
}, [match.service?.service_location?.latitude, match.service?.service_location?.longitude]);
const icon = useMemo(() => {
if (!match.service?.service_location) {
@ -181,9 +183,13 @@ const ServiceMarker = React.memo<{
</p>
)}
<div className="flex items-center gap-4 text-sm">
<span className="font-medium">{match.service.hourly_rate.toFixed(2)}/hour</span>
<span className="font-medium">
{t('productService.hourlyRate', { rate: match.service.hourly_rate.toFixed(2) })}
</span>
{match.service.service_area_km > 0 && (
<span className="text-muted-foreground">Area: {match.service.service_area_km}km</span>
<span className="text-muted-foreground">
{t('productService.serviceArea', { area: match.service.service_area_km })}
</span>
)}
</div>
{match.organization && (

View File

@ -121,7 +121,9 @@ const ResourceFlowMarker = React.memo<{
</div>
<div>
<span className="text-muted-foreground">{t('matchesMap.distance')}:</span>
<div className="font-medium">{match.DistanceKm.toFixed(1)} km</div>
<div className="font-medium">
{t('matchesMap.distanceValue', { distance: match.DistanceKm.toFixed(1) })}
</div>
</div>
</div>

View File

@ -39,7 +39,7 @@ const SymbiosisLine = React.memo<{
<Popup>
<div>
<p className="text-sm">
Connection to <strong>{match.org?.Name || 'Unknown'}</strong>
{t('symbiosis.connectionTo', { name: match.org?.Name || 'Unknown' })}
</p>
</div>
</Popup>

View File

@ -49,7 +49,7 @@ const MatchCard: React.FC<MatchCardProps> = ({ match, onViewDetails }) => {
<Flex align="center" gap="xs" className="mb-2">
<Badge variant={getStatusColor()}>{match.Status}</Badge>
<Badge variant="outline" className="text-xs">
Priority: {match.Priority}
{t('matches.priority', { priority: match.Priority })}
</Badge>
</Flex>
@ -69,17 +69,18 @@ const MatchCard: React.FC<MatchCardProps> = ({ match, onViewDetails }) => {
<Flex align="center" gap="md" className="text-sm text-muted-foreground">
<div className="flex items-center gap-1">
<MapPin className="h-4 w-4" />
<span>{match.DistanceKm.toFixed(1)} km</span>
<span>{t('matches.distance', { distance: match.DistanceKm.toFixed(1) })}</span>
</div>
{match.RiskAssessment && (
<div className="flex items-center gap-1">
<AlertTriangle className="h-4 w-4" />
<span>
Risk:{' '}
{formatScore(
(match.RiskAssessment.technical_risk + match.RiskAssessment.regulatory_risk) /
2
)}
{t('matches.riskScore', {
score: formatScore(
(match.RiskAssessment.technical_risk + match.RiskAssessment.regulatory_risk) /
2
)
})}
</span>
</div>
)}

View File

@ -16,10 +16,11 @@ const HistoricalContextCard = ({ landmark, onNavigate }: HistoricalContextCardPr
<div className="h-12 w-12 mx-auto rounded-full flex items-center justify-center bg-warning/20 text-warning-foreground mb-3">
<History className="h-4 h-6 text-current w-4 w-6" />
</div>
<h3 className="text-base font-semibold text-warning-foreground">Исторический контекст</h3>
<h3 className="text-base font-semibold text-warning-foreground">
{t('heritage.historicalContext')}
</h3>
<p className="text-sm text-warning-foreground/80 mt-1">
Это здание является историческим объектом:{' '}
<span className="font-semibold">{landmark.name}</span>, построенным в {landmark.period}.
{t('heritage.buildingDescription', { name: landmark.name, period: landmark.period })}
</p>
<Button
variant="ghost"
@ -27,7 +28,7 @@ const HistoricalContextCard = ({ landmark, onNavigate }: HistoricalContextCardPr
className="mt-3 text-warning-foreground hover:text-warning-foreground hover:bg-warning/20"
onClick={() => onNavigate('map')}
>
Посмотреть на карте
{t('heritage.viewOnMap')}
</Button>
</CardContent>
</Card>

View File

@ -214,9 +214,9 @@ export function NetworkGraph({
return (
<Card>
<CardHeader>
<CardTitle>Network Graph</CardTitle>
<CardTitle>{t('organization.networkGraph')}</CardTitle>
<p className="text-sm text-muted-foreground">
Explore how {organizationName} connects to other organizations, sites, and resources
{t('organization.networkGraphDescription', { name: organizationName })}
</p>
<div className="flex gap-2 mt-4">
{[1, 2, 3].map((d) => (