Files
TREK/client/src/pages/FilesPage.tsx
T
Isaias Tavares 9c42a01391 fix(i18n): comprehensive translation audit and fixes across all 14 languages
- Fix critical bug: Photos and Files pages had German text hardcoded in JSX,
  now use t() keys visible correctly in all languages
- Add 16 new translation keys (photos/files UI, login validation, common errors,
  rate limit message) across all 14 language files
- Add missing keys in packing, memories, and budget sections for br, de, it, es,
  fr, nl, pl, cs, hu, ru, zh, zh-TW, ar
- Add 152+ missing keys for zh-TW (entire sections were absent)
- Change Vacay addon name to 'Férias' in pt-BR only
- Add client-side HTTP 429 interceptor that shows translated rate limit message
- Replace hardcoded English fallbacks in TripPlannerPage, DayPlanSidebar,
  DisplaySettingsTab, MapSettingsTab, AccountTab, and TodoListPanel with t()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 16:36:32 -03:00

98 lines
3.0 KiB
TypeScript

import React, { useEffect, useState } from 'react'
import { useParams, useNavigate, Link } from 'react-router-dom'
import { useTripStore } from '../store/tripStore'
import { tripsApi, placesApi } from '../api/client'
import Navbar from '../components/Layout/Navbar'
import FileManager from '../components/Files/FileManager'
import { ArrowLeft } from 'lucide-react'
import { useTranslation } from '../i18n'
import type { Trip, Place, TripFile } from '../types'
export default function FilesPage(): React.ReactElement {
const { t } = useTranslation()
const { id: tripId } = useParams<{ id: string }>()
const navigate = useNavigate()
const tripStore = useTripStore()
const [trip, setTrip] = useState<Trip | null>(null)
const [places, setPlaces] = useState<Place[]>([])
const [files, setFiles] = useState<TripFile[]>([])
const [isLoading, setIsLoading] = useState<boolean>(true)
useEffect(() => {
loadData()
}, [tripId])
const loadData = async (): Promise<void> => {
setIsLoading(true)
try {
const [tripData, placesData] = await Promise.all([
tripsApi.get(tripId),
placesApi.list(tripId),
])
setTrip(tripData.trip)
setPlaces(placesData.places)
await tripStore.loadFiles(tripId)
} catch (err: unknown) {
navigate('/dashboard')
} finally {
setIsLoading(false)
}
}
useEffect(() => {
setFiles(tripStore.files)
}, [tripStore.files])
const handleUpload = async (formData: FormData): Promise<void> => {
await tripStore.addFile(tripId, formData)
}
const handleDelete = async (fileId: number): Promise<void> => {
await tripStore.deleteFile(tripId, fileId)
}
if (isLoading) {
return (
<div className="min-h-screen flex items-center justify-center bg-slate-50">
<div className="w-10 h-10 border-4 border-slate-200 border-t-slate-700 rounded-full animate-spin"></div>
</div>
)
}
return (
<div className="min-h-screen bg-slate-50">
<Navbar tripTitle={trip?.name} tripId={tripId} showBack onBack={() => navigate(`/trips/${tripId}`)} />
<div style={{ paddingTop: 'var(--nav-h)' }}>
<div className="max-w-5xl mx-auto px-4 py-6">
<div className="flex items-center gap-3 mb-6">
<Link
to={`/trips/${tripId}`}
className="flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700"
>
<ArrowLeft className="w-4 h-4" />
{t('common.backToPlanning')}
</Link>
</div>
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-2xl font-bold text-gray-900">{t('files.pageTitle')}</h1>
<p className="text-gray-500 text-sm">{t('files.subtitle', { count: files.length, trip: trip?.name })}</p>
</div>
</div>
<FileManager
files={files}
onUpload={handleUpload}
onDelete={handleDelete}
places={places}
tripId={tripId}
/>
</div>
</div>
</div>
)
}