From 5b93f880a3280aba93c705ad38e55b75306a9cb3 Mon Sep 17 00:00:00 2001 From: Knacky Date: Sun, 21 Jun 2026 23:31:21 +0200 Subject: [PATCH] feat(frontend): i18n simulation pages (SimulationFormPage, SimulationList) Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/SimulationList.tsx | 39 ++++--- frontend/src/pages/SimulationFormPage.tsx | 112 +++++++++++---------- frontend/tests/SimulationFormPage.test.tsx | 46 ++++----- 3 files changed, 101 insertions(+), 96 deletions(-) diff --git a/frontend/src/components/SimulationList.tsx b/frontend/src/components/SimulationList.tsx index f20b194..5f2bf68 100644 --- a/frontend/src/components/SimulationList.tsx +++ b/frontend/src/components/SimulationList.tsx @@ -1,11 +1,13 @@ import { useEffect, useRef, useState } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { ChevronDown, Plus } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { extractApiError } from '@/api/client'; import type { SimulationTemplate } from '@/api/types'; import { useAuth } from '@/hooks/useAuth'; import { useEngagementSimulations, useCreateSimulation } from '@/hooks/useSimulations'; import { useToast } from '@/hooks/useToast'; +import { formatDateTime } from '@/lib/format'; import { LoadingState } from './LoadingState'; import { ErrorState } from './ErrorState'; import { EmptyState } from './EmptyState'; @@ -16,12 +18,8 @@ interface SimulationListProps { engagementId: number; } -function formatDate(value: string | null): string { - if (!value) return '—'; - return value.replace('T', ' ').slice(0, 16); -} - function NewSimulationDropdown({ engagementId }: { engagementId: number }): JSX.Element { + const { t } = useTranslation(); const navigate = useNavigate(); const { push } = useToast(); const [open, setOpen] = useState(false); @@ -61,10 +59,10 @@ function NewSimulationDropdown({ engagementId }: { engagementId: number }): JSX. try { const sim = await createMutation.mutateAsync({ name: template.name, template_id: template.id }); setShowPicker(false); - push(`Created "${sim.name}" from template`, 'success'); + push(t('simulation.form.toast.created'), 'success'); navigate(`/engagements/${engagementId}/simulations/${sim.id}/edit`); } catch (err) { - push(extractApiError(err, 'Could not create simulation from template'), 'error'); + push(extractApiError(err, t('simulation.form.error.create')), 'error'); } }; @@ -77,7 +75,7 @@ function NewSimulationDropdown({ engagementId }: { engagementId: number }): JSX. onClick={handleBlank} data-testid="new-simulation-btn" > - New + {t('simulation.list.new')}